actual-css 0.8.0 → 0.9.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.
@@ -106,8 +106,13 @@ trailing link or button is content, not anatomy, so it lives in the text column:
106
106
  wrap the row in a `.cluster` and push the two ends apart. Same recipe as any
107
107
  split / spread row — there is no `.alert-action` class.
108
108
 
109
+ The alert aligns its columns to the block start, so a multi-line message keeps
110
+ its icon on the first line. A trailing control makes that row taller than a line
111
+ of text: add `.items-center` to put the icon, the text and the button on one
112
+ center.
113
+
109
114
  ```html demo
110
- <div class="alert surface">
115
+ <div class="alert surface items-center">
111
116
  <i class="ti ti-info-circle alert-icon" aria-hidden="true"></i>
112
117
  <div class="cluster justify-content-space-between">
113
118
  <strong>New message!</strong>
@@ -170,6 +170,11 @@ hidden` (and reserves the scrollbar gutter with `scrollbar-gutter: stable` when
170
170
  one was present). The height cap follows the small viewport, so the panel keeps
171
171
  a stable size while mobile browser chrome expands or collapses.
172
172
 
173
+ The scrolling body is a scroll container, and browsers make one
174
+ keyboard-focusable so it can be scrolled without a pointer — it takes a focus
175
+ ring like any other focusable element, and it can claim initial focus when
176
+ nothing focusable precedes it. Mark the control you want focused `autofocus`.
177
+
173
178
  ```html demo
174
179
  <button class="btn"
175
180
  type="button"
@@ -21,8 +21,21 @@
21
21
  - Use `closedby="none"` when the drawer must not be dismissed by the user at all
22
22
  (e.g. a form with unsaved changes): no backdrop close and no Escape close.
23
23
  - Use `[data-side="end"]` for a right-side drawer.
24
+ - Put the body between a `header` and a `footer`: the panel is a three-row grid
25
+ whose middle region scrolls, so the footer stays reachable however long the
26
+ content gets.
24
27
  - Permanent desktop sidebars belong in layout, not here.
25
28
 
29
+ The panel is `--viewport-block` tall, so it follows the space a mobile browser
30
+ actually leaves on screen as its URL bar collapses. A shell that fakes a
31
+ viewport (an embedded preview) overrides that token rather than the drawer.
32
+
33
+ The body region is a scroll container, and browsers make one keyboard-focusable
34
+ so it can be scrolled without a pointer — it takes a focus ring like any other
35
+ focusable element. `showModal()` focuses the first focusable thing in the
36
+ drawer, so put the close button in the `header` (as both examples do) or mark
37
+ your intended target `autofocus`; otherwise the body claims initial focus.
38
+
26
39
  ```html demo
27
40
  <button class="btn ghost"
28
41
  type="button"
@@ -37,4 +37,6 @@
37
37
  - `--skeleton-highlight` — sweeping highlight color.
38
38
  - `--skeleton-radius` — corner radius; `data-shape` presets override it.
39
39
  - `--skeleton-size` — block size; `data-shape` presets override it.
40
- - `--skeleton-width` — inline size; `data-shape` presets override it.
40
+ - `--skeleton-width` — maximum inline size. A placeholder fills its container
41
+ and stops here, so it never gives an ancestor a width floor. `data-shape`
42
+ presets set it; `avatar` ignores it and stays square.
@@ -506,8 +506,22 @@ delay; a number sets the delay in milliseconds.
506
506
 
507
507
  ## CSS hooks
508
508
 
509
- - `--flyout-inline-size` — panel width.
510
- - `--flyout-max-inline-size` — panel width cap.
509
+ - `--flyout-inline-size` — preferred width. Takes intrinsic values such as
510
+ `max-content`, its default.
511
+ - `--flyout-max-inline-size` — width cap, a `<length-percentage>` the runtime
512
+ also clamps to the viewport. Defaults to `20rem`, independently of the
513
+ preferred width — the same way `width: 42rem; max-width: 20rem` renders at
514
+ 20rem. A panel wider than the cap therefore sets both:
515
+
516
+ ```css
517
+ .mega-panel {
518
+ --flyout-inline-size: 42rem;
519
+ --flyout-max-inline-size: 42rem;
520
+ }
521
+ ```
522
+
523
+ The repetition is the point: the two hooks are different contracts, and only
524
+ the cap may enter the runtime's `min()`.
511
525
  - `--menu-item-size` — minimum row height of `.menu-item`.
512
526
  - `--menu-item-icon-size` — shared leading-column width for icons and checked-state indicators.
513
527
 
@@ -105,7 +105,8 @@ Plain `.check` / `.radio` controls expose two hooks:
105
105
  type. The switch track derives from it too, so a checkbox and a switch on the
106
106
  same line stay proportionate. A `.choice.sm` or `.choice.lg` scales it through
107
107
  the surrounding typography.
108
- - `--choice-control-offset` — top offset that aligns the control with the first
109
- line of a multi-line label. Left unset, each control derives its own offset
110
- from its height and the line box, which keeps a checkbox and a taller switch
111
- level with each other. Setting one constant applies it to both.
108
+ - `--choice-control-nudge` — block correction added to the derived first-line
109
+ offset, for every control in the row. Left unset, each control centres itself
110
+ on the first line's cap height, measured from its own block size — so a
111
+ checkbox and a taller switch stay level with each other, and with the text,
112
+ whatever the font, line-height or control size.
package/package.json CHANGED
@@ -1,158 +1,159 @@
1
- {
2
- "name": "actual-css",
3
- "version": "0.8.0",
4
- "description": "Plain CSS component framework with semantic classes, universal variants, small tokens, theme hooks, and progressive enhancements.",
5
- "type": "module",
6
- "packageManager": "bun@1.4.2",
7
- "license": "MIT",
8
- "author": "Thomas <thomas@lekoala.be>",
9
- "repository": {
10
- "type": "git",
11
- "url": "https://github.com/lekoala/actual-css.git"
12
- },
13
- "homepage": "https://github.com/lekoala/actual-css",
14
- "bugs": {
15
- "url": "https://github.com/lekoala/actual-css/issues"
16
- },
17
- "keywords": [
18
- "css",
19
- "css-framework",
20
- "component-library",
21
- "semantic",
22
- "accessibility",
23
- "dark-mode",
24
- "themable",
25
- "no-build",
26
- "progressive-enhancement"
27
- ],
28
- "exports": {
29
- ".": "./dist/actual.min.css",
30
- "./full": "./dist/actual.full.min.css",
31
- "./css": "./src/css/actual.css",
32
- "./css/components": "./src/css/components/index.css",
33
- "./css/components/*": "./src/css/components/*.css",
34
- "./css/effects": "./src/css/effects/index.css",
35
- "./css/effects/*": "./src/css/effects/*.css",
36
- "./css/forms": "./src/css/forms/base.css",
37
- "./css/forms/all": "./src/css/forms/index.css",
38
- "./css/forms/*": "./src/css/forms/*.css",
39
- "./css/full": "./src/css/actual.full.css",
40
- "./css/layer": "./src/css/actual.layer.css",
41
- "./css/layout": "./src/css/layout/index.css",
42
- "./css/layout/*": "./src/css/layout/*.css",
43
- "./css/themes": null,
44
- "./css/themes/*": null,
45
- "./css/typography": "./src/css/typography/index.css",
46
- "./css/typography/*": "./src/css/typography/*.css",
47
- "./css/utilities": "./src/css/utilities/index.css",
48
- "./css/utilities/*": "./src/css/utilities/*.css",
49
- "./js": "./src/js/index.js",
50
- "./js/full": "./src/js/full.js",
51
- "./js/command": "./src/js/command.js",
52
- "./js/context-menu": "./src/js/context-menu.js",
53
- "./js/dialog": "./src/js/dialog.js",
54
- "./js/dismiss": "./src/js/dismiss.js",
55
- "./js/escape": "./src/js/escape.js",
56
- "./js/enhance": "./src/js/enhance.js",
57
- "./js/enhancement-loader": "./src/js/enhancement-loader.js",
58
- "./js/parse-config": "./src/js/parse-config.js",
59
- "./js/events": "./src/js/events.js",
60
- "./js/filter": "./src/js/filter.js",
61
- "./js/flyout": "./src/js/flyout.js",
62
- "./js/focus": "./src/js/focus.js",
63
- "./js/focus-group": "./src/js/focus-group.js",
64
- "./js/input": "./src/js/input.js",
65
- "./js/keys": "./src/js/keys.js",
66
- "./js/mask": "./src/js/mask.js",
67
- "./js/menu": "./src/js/menu.js",
68
- "./js/password": "./src/js/password.js",
69
- "./js/scrollspy": "./src/js/scrollspy.js",
70
- "./js/selectors": "./src/js/selectors.js",
71
- "./js/tab": "./src/js/tab.js",
72
- "./js/tooltip": "./src/js/tooltip.js",
73
- "./js/validation": "./src/js/validation.js",
74
- "./js/status": "./src/js/status.js",
75
- "./js/surface": "./src/js/surface.js",
76
- "./reserved-classes.json": "./reserved-classes.json",
77
- "./components.json": "./components.json",
78
- "./package.json": "./package.json"
79
- },
80
- "bin": {
81
- "actual-css": "./src/cli/actual-css.js"
82
- },
83
- "main": "./dist/actual.js",
84
- "style": "./dist/actual.min.css",
85
- "unpkg": "./dist/actual.min.css",
86
- "jsdelivr": "./dist/actual.min.css",
87
- "sideEffects": true,
88
- "files": [
89
- "dist",
90
- "src/css/*.css",
91
- "src/css/core",
92
- "src/css/layout",
93
- "src/css/typography",
94
- "src/css/forms",
95
- "src/css/components",
96
- "src/css/effects",
97
- "src/css/utilities",
98
- "src/cli",
99
- "src/js",
100
- "src/tooling",
101
- "reserved-classes.json",
102
- "components.json",
103
- "docs",
104
- "CHANGELOG.md",
105
- "llms.txt",
106
- "LICENSE",
107
- "README.md"
108
- ],
109
- "engines": {
110
- "bun": ">=1.4.0",
111
- "node": ">=18"
112
- },
113
- "scripts": {
114
- "lint": "biome check",
115
- "lint:fix": "biome check --write",
116
- "build:docs": "bun run build:themes && bun scripts/build-docs.js",
117
- "watch:docs": "bun run build:themes && bun scripts/build-docs.js --watch",
118
- "check:docs": "bun scripts/check-docs.js",
119
- "format:docs": "bun scripts/format-doc-tables.js",
120
- "check:doc-classes": "bun scripts/check-doc-classes.js",
121
- "check:compat": "bun scripts/check-compat.js",
122
- "check:css-api": "bun scripts/check-css-api.js",
123
- "check:color-space": "bun scripts/check-color-space.js",
124
- "report:theme-contrast": "bun scripts/report-theme-contrast.js",
125
- "report:neutral-ramp": "bun scripts/report-neutral-ramp.js",
126
- "report:dead-css": "bun scripts/report-dead-css.js",
127
- "check:architecture": "bun scripts/check-css-architecture.js",
128
- "build:dist": "bun scripts/build-dist.js",
129
- "build:js": "bun scripts/build-js.js",
130
- "build:themes": "bun scripts/build-themes.js",
131
- "build:size": "bun scripts/build-size.js",
132
- "check:enhance": "bun run scripts/check-enhance.js",
133
- "generate:reserved": "bun scripts/generate-reserved-classes.js",
134
- "check:reserved": "bun scripts/check-reserved.js",
135
- "generate:catalog": "bun scripts/build-catalog.js",
136
- "check:catalog": "bun scripts/check-catalog.js",
137
- "check:links": "bun scripts/check-doc-links.js",
138
- "check:templates": "bun scripts/check-templates.js",
139
- "check:markup": "bun scripts/check-markup.js",
140
- "shot:forced": "bun scripts/forced-colors-shot.js",
141
- "shot:multi": "bun scripts/multi-shot.js",
142
- "shot:page": "bun scripts/page-shot.js",
143
- "probe": "bun scripts/probe.js",
144
- "serve": "bun scripts/serve.js",
145
- "check:sync": "bun scripts/check-sync.js",
146
- "test": "bun test",
147
- "test:changed": "bun test --changed=master",
148
- "build:all": "bun run lint && bun run build:dist && bun run build:js && bun run format:docs && bun run build:docs && bun run check:docs && bun run check:doc-classes && bun run check:compat && bun run check:css-api && bun run check:color-space && bun run check:architecture && bun run check:enhance && bun run generate:reserved && bun run check:reserved && bun run generate:catalog && bun run check:catalog && bun run check:sync && bun run check:links && bun run check:templates && bun run check:markup && bun run test && bun run build:size",
149
- "prepublishOnly": "bun run build:all"
150
- },
151
- "devDependencies": {
152
- "@biomejs/biome": "^2.5.12",
153
- "happy-dom": "^20.14.0"
154
- },
155
- "dependencies": {
156
- "@lekoala/floating": "^0.2.0"
157
- }
158
- }
1
+ {
2
+ "name": "actual-css",
3
+ "version": "0.9.0",
4
+ "description": "Plain CSS component framework with semantic classes, universal variants, small tokens, theme hooks, and progressive enhancements.",
5
+ "type": "module",
6
+ "packageManager": "bun@1.4.2",
7
+ "license": "MIT",
8
+ "author": "Thomas <thomas@lekoala.be>",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/lekoala/actual-css.git"
12
+ },
13
+ "homepage": "https://github.com/lekoala/actual-css",
14
+ "bugs": {
15
+ "url": "https://github.com/lekoala/actual-css/issues"
16
+ },
17
+ "keywords": [
18
+ "css",
19
+ "css-framework",
20
+ "component-library",
21
+ "semantic",
22
+ "accessibility",
23
+ "dark-mode",
24
+ "themable",
25
+ "no-build",
26
+ "progressive-enhancement"
27
+ ],
28
+ "exports": {
29
+ ".": "./dist/actual.min.css",
30
+ "./full": "./dist/actual.full.min.css",
31
+ "./css": "./src/css/actual.css",
32
+ "./css/components": "./src/css/components/index.css",
33
+ "./css/components/*": "./src/css/components/*.css",
34
+ "./css/effects": "./src/css/effects/index.css",
35
+ "./css/effects/*": "./src/css/effects/*.css",
36
+ "./css/forms": "./src/css/forms/base.css",
37
+ "./css/forms/all": "./src/css/forms/index.css",
38
+ "./css/forms/*": "./src/css/forms/*.css",
39
+ "./css/full": "./src/css/actual.full.css",
40
+ "./css/layer": "./src/css/actual.layer.css",
41
+ "./css/layout": "./src/css/layout/index.css",
42
+ "./css/layout/*": "./src/css/layout/*.css",
43
+ "./css/themes": null,
44
+ "./css/themes/*": null,
45
+ "./css/typography": "./src/css/typography/index.css",
46
+ "./css/typography/*": "./src/css/typography/*.css",
47
+ "./css/utilities": "./src/css/utilities/index.css",
48
+ "./css/utilities/*": "./src/css/utilities/*.css",
49
+ "./js": "./src/js/index.js",
50
+ "./js/full": "./src/js/full.js",
51
+ "./js/command": "./src/js/command.js",
52
+ "./js/context-menu": "./src/js/context-menu.js",
53
+ "./js/dialog": "./src/js/dialog.js",
54
+ "./js/dismiss": "./src/js/dismiss.js",
55
+ "./js/escape": "./src/js/escape.js",
56
+ "./js/enhance": "./src/js/enhance.js",
57
+ "./js/enhancement-loader": "./src/js/enhancement-loader.js",
58
+ "./js/parse-config": "./src/js/parse-config.js",
59
+ "./js/events": "./src/js/events.js",
60
+ "./js/filter": "./src/js/filter.js",
61
+ "./js/flyout": "./src/js/flyout.js",
62
+ "./js/focus": "./src/js/focus.js",
63
+ "./js/focus-group": "./src/js/focus-group.js",
64
+ "./js/input": "./src/js/input.js",
65
+ "./js/keys": "./src/js/keys.js",
66
+ "./js/mask": "./src/js/mask.js",
67
+ "./js/menu": "./src/js/menu.js",
68
+ "./js/password": "./src/js/password.js",
69
+ "./js/scrollspy": "./src/js/scrollspy.js",
70
+ "./js/selectors": "./src/js/selectors.js",
71
+ "./js/tab": "./src/js/tab.js",
72
+ "./js/tooltip": "./src/js/tooltip.js",
73
+ "./js/validation": "./src/js/validation.js",
74
+ "./js/status": "./src/js/status.js",
75
+ "./js/surface": "./src/js/surface.js",
76
+ "./reserved-classes.json": "./reserved-classes.json",
77
+ "./components.json": "./components.json",
78
+ "./package.json": "./package.json"
79
+ },
80
+ "bin": {
81
+ "actual-css": "./src/cli/actual-css.js"
82
+ },
83
+ "main": "./dist/actual.js",
84
+ "style": "./dist/actual.min.css",
85
+ "unpkg": "./dist/actual.min.css",
86
+ "jsdelivr": "./dist/actual.min.css",
87
+ "sideEffects": true,
88
+ "files": [
89
+ "dist",
90
+ "src/css/*.css",
91
+ "src/css/core",
92
+ "src/css/layout",
93
+ "src/css/typography",
94
+ "src/css/forms",
95
+ "src/css/components",
96
+ "src/css/effects",
97
+ "src/css/utilities",
98
+ "src/cli",
99
+ "src/js",
100
+ "src/tooling",
101
+ "reserved-classes.json",
102
+ "components.json",
103
+ "docs",
104
+ "CHANGELOG.md",
105
+ "llms.txt",
106
+ "LICENSE",
107
+ "README.md"
108
+ ],
109
+ "engines": {
110
+ "bun": ">=1.4.0",
111
+ "node": ">=18"
112
+ },
113
+ "scripts": {
114
+ "lint": "biome check",
115
+ "lint:fix": "biome check --write",
116
+ "build:docs": "bun run build:themes && bun scripts/build-docs.js",
117
+ "watch:docs": "bun run build:themes && bun scripts/build-docs.js --watch",
118
+ "check:docs": "bun scripts/check-docs.js",
119
+ "format:docs": "bun scripts/format-doc-tables.js",
120
+ "check:doc-classes": "bun scripts/check-doc-classes.js",
121
+ "check:compat": "bun scripts/check-compat.js",
122
+ "check:css-api": "bun scripts/check-css-api.js",
123
+ "check:color-space": "bun scripts/check-color-space.js",
124
+ "report:theme-contrast": "bun scripts/report-theme-contrast.js",
125
+ "report:neutral-ramp": "bun scripts/report-neutral-ramp.js",
126
+ "report:dead-css": "bun scripts/report-dead-css.js",
127
+ "report:overflow": "bun scripts/report-overflow.js",
128
+ "check:architecture": "bun scripts/check-css-architecture.js",
129
+ "build:dist": "bun scripts/build-dist.js",
130
+ "build:js": "bun scripts/build-js.js",
131
+ "build:themes": "bun scripts/build-themes.js",
132
+ "build:size": "bun scripts/build-size.js",
133
+ "check:enhance": "bun run scripts/check-enhance.js",
134
+ "generate:reserved": "bun scripts/generate-reserved-classes.js",
135
+ "check:reserved": "bun scripts/check-reserved.js",
136
+ "generate:catalog": "bun scripts/build-catalog.js",
137
+ "check:catalog": "bun scripts/check-catalog.js",
138
+ "check:links": "bun scripts/check-doc-links.js",
139
+ "check:templates": "bun scripts/check-templates.js",
140
+ "check:markup": "bun scripts/check-markup.js",
141
+ "shot:forced": "bun scripts/forced-colors-shot.js",
142
+ "shot:multi": "bun scripts/multi-shot.js",
143
+ "shot:page": "bun scripts/page-shot.js",
144
+ "probe": "bun scripts/probe.js",
145
+ "serve": "bun scripts/serve.js",
146
+ "check:sync": "bun scripts/check-sync.js",
147
+ "test": "bun test",
148
+ "test:changed": "bun test --changed=master",
149
+ "build:all": "bun run lint && bun run build:dist && bun run build:js && bun run build:size && bun run format:docs && bun run build:docs && bun run check:docs && bun run check:doc-classes && bun run check:compat && bun run check:css-api && bun run check:color-space && bun run check:architecture && bun run check:enhance && bun run generate:reserved && bun run check:reserved && bun run generate:catalog && bun run check:catalog && bun run check:sync && bun run check:links && bun run check:templates && bun run check:markup && bun run test",
150
+ "prepublishOnly": "bun run build:all"
151
+ },
152
+ "devDependencies": {
153
+ "@biomejs/biome": "^2.5.12",
154
+ "happy-dom": "^20.14.0"
155
+ },
156
+ "dependencies": {
157
+ "@lekoala/floating": "^0.2.0"
158
+ }
159
+ }
@@ -26,15 +26,24 @@ dialog.drawer {
26
26
 
27
27
  /* Keep the surface anchored to the viewport in the top layer. This also
28
28
  provides the containing block for the absolutely positioned close button.
29
- A percentage height resolves against the fixed containing viewport, while
30
- dynamic viewport units can be stale in embedded previews. */
29
+
30
+ The panel reaches both viewport edges, so it has to follow the space that
31
+ is actually on screen: --viewport-block resolves to 100dvh and tracks a
32
+ mobile browser's collapsing URL bar. A percentage resolves against the
33
+ layout viewport instead, which those browsers size as if the bar were
34
+ hidden — that put the footer below the fold for as long as it showed. The
35
+ modal pins the small viewport for the opposite reason: it floats, so a
36
+ stable height beats a panel that breathes while the bar moves.
37
+
38
+ An embedded preview that fakes a viewport overrides --viewport-block on
39
+ its own shell; the component does not degrade to a percentage for it. */
31
40
  position: fixed;
32
41
  inset-block-start: 0;
33
42
 
34
43
  inline-size: min(calc(var(--viewport-inline) * 0.9), var(--drawer-size));
35
- block-size: 100%;
44
+ block-size: var(--viewport-block);
36
45
  max-inline-size: none;
37
- max-block-size: 100%;
46
+ max-block-size: var(--viewport-block);
38
47
  margin: 0;
39
48
  padding: var(--drawer-pad);
40
49
  border: 0;
@@ -106,10 +115,16 @@ dialog.drawer[open]::backdrop {
106
115
  }
107
116
  }
108
117
 
109
- /* Scrollable navigation region inside the drawer. */
110
- dialog.drawer nav {
118
+ /* The body region absorbs the panel's height and scrolls. A drawer is a
119
+ full-height shell by definition, so it always scrolls its body — unlike the
120
+ modal, which sizes to its content and opts in with .scrollable. Header and
121
+ footer keep their own tracks; .drawer-close is named because a generic
122
+ exclusion list is easier to trust than its `position: absolute`. */
123
+ dialog.drawer > :not(:is(header, footer, form, .drawer-close)),
124
+ dialog.drawer > form > :not(:is(header, footer, .drawer-close)) {
111
125
  min-block-size: 0;
112
- overflow-y: auto;
126
+ overflow: auto;
127
+ overscroll-behavior: contain;
113
128
  }
114
129
 
115
130
  @supports (transition-behavior: allow-discrete) {
@@ -38,7 +38,7 @@ dialog.modal {
38
38
  /* --modal-size stays fallback-only: declaring it on dialog.modal gives it
39
39
  type+class specificity, which a single author class cannot outrank, so the
40
40
  public hook would silently keep this default. Same reason choice.css never
41
- declares --choice-control-offset. */
41
+ declares --choice-control-nudge. */
42
42
  max-inline-size: min(calc(100% - var(--dialog-viewport-gap-2x)), var(--modal-size, 32rem));
43
43
 
44
44
  /* Stable viewport cap for the panel: dvh tracks the dynamic browser toolbar
@@ -11,16 +11,24 @@
11
11
  * --skeleton-track
12
12
  * --skeleton-highlight
13
13
  */
14
+ /* A placeholder fills its container up to --skeleton-width; the preset widths
15
+ are a cap, never an intrinsic size. Stated the other way round — a rem
16
+ `inline-size` capped by a percentage `max-inline-size` — the cap is ignored
17
+ during intrinsic sizing, so every shrink-to-fit ancestor inherits the
18
+ preset as a min-content floor: a card holding a title placeholder could not
19
+ go below 18rem and pushed a phone's layout sideways. A percentage
20
+ `inline-size` contributes nothing intrinsically and a rem cap only lowers
21
+ the contribution, so the same geometry costs no floor. */
14
22
  .skeleton {
15
23
  --skeleton-size: 1rem;
16
- --skeleton-width: 100%;
24
+ --skeleton-width: none;
17
25
  --skeleton-radius: var(--radius);
18
26
  --skeleton-track: var(--surface-subtle);
19
27
  --skeleton-highlight: var(--surface-raised);
20
28
 
21
29
  display: block;
22
- inline-size: var(--skeleton-width);
23
- max-inline-size: 100%;
30
+ inline-size: 100%;
31
+ max-inline-size: var(--skeleton-width);
24
32
  block-size: var(--skeleton-size);
25
33
  border-radius: var(--skeleton-radius);
26
34
  background:
@@ -44,11 +52,14 @@
44
52
  --skeleton-width: 18rem;
45
53
  }
46
54
 
55
+ /* The one preset with a real intrinsic width: a disc is square, so it sizes
56
+ rather than caps. The floor it does carry is the avatar size, which is small
57
+ enough never to widen a layout. */
47
58
  .skeleton[data-shape="avatar"] {
48
59
  --skeleton-size: var(--avatar-size, 2.25rem);
49
- --skeleton-width: var(--skeleton-size);
50
60
  --skeleton-radius: var(--radius-full);
51
61
 
62
+ inline-size: var(--skeleton-size);
52
63
  flex: 0 0 auto;
53
64
  }
54
65
 
@@ -9,6 +9,14 @@
9
9
  * --table-cell-pad
10
10
  */
11
11
  .table-wrap {
12
+ /* Containing block for anything absolutely positioned inside the table —
13
+ `.sr-only` on a column header above all. Without it that box resolves
14
+ against the initial containing block, so it keeps the static position of a
15
+ cell that may be a thousand pixels along the scrolled row, escapes this
16
+ scroller, and extends the *document's* scrollable width. The page then
17
+ scrolls sideways on a phone with nothing painted out there. */
18
+ position: relative;
19
+
12
20
  inline-size: 100%;
13
21
  max-inline-size: 100%;
14
22
  min-inline-size: 0;