actual-css 0.11.0 → 0.11.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.
- package/CHANGELOG.md +26 -0
- package/README.md +4 -0
- package/components.json +12 -2
- package/dist/actual.full.css +169 -22
- package/dist/actual.full.min.css +1 -1
- package/docs/navigation.json +2 -1
- package/docs/pages/components/bleed.md +5 -4
- package/docs/pages/components/close.md +9 -3
- package/docs/pages/components/dialog.md +140 -11
- package/docs/pages/components/meter.md +2 -0
- package/docs/pages/examples/overview.md +1 -0
- package/docs/pages/guides/design-tools.md +36 -0
- package/package.json +2 -1
- package/skills/actual-css/references/enhancements.md +35 -0
- package/src/cli/actual-css.js +49 -6
- package/src/css/components/bleed.css +5 -5
- package/src/css/components/button.css +14 -1
- package/src/css/components/close.css +17 -6
- package/src/css/components/meter.css +5 -2
- package/src/css/components/modal.css +123 -7
- package/src/css/forms/native.css +5 -1
- package/src/tooling/design-components.js +286 -0
- package/src/tooling/design-export.js +69 -0
- package/src/tooling/design-tokens.js +466 -0
- package/src/tooling/penpot-plugin/manifest.json +7 -0
- package/src/tooling/penpot-plugin/plugin.js +272 -0
- package/src/tooling/penpot-plugin/ui.html +58 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.11.1] - 2026-09-30
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `dialog.modal > header` provides aligned icon/title/action chrome through `--modal-header-bg`; modal body wrappers expose `--modal-pad` and support `.bleed` bands.
|
|
10
|
+
- `actual-css design` (Bun) exports a theme to Figma and Penpot tokens; see `docs/pages/guides/design-tools.md`.
|
|
11
|
+
- `actual-css design` writes a Penpot plugin that builds Button, Input, Badge, Alert and Card bound to those tokens.
|
|
12
|
+
- Soft fills and borders export as recipe tokens named `<variant>-<intent>-<role>` (`soft-danger-bg`).
|
|
13
|
+
- `scripts/serve.js --cors` serves the repository to another origin, such as penpot.app loading a local plugin.
|
|
14
|
+
- `--meter-track` sets the `.meter` track, matching `--progress-track`.
|
|
15
|
+
- `--close-bg` sets the dialog corner `.close` background, so a dialog over a painted band can drop the default chip.
|
|
16
|
+
- `--close-color` and `--close-hover-color` set the X ink at rest and on hover, so a bare X can take a painted band's foreground.
|
|
17
|
+
- `--close-hover-overlay` routes the `.close` hover/active wash (matching `--btn-hover-overlay`); the modal/drawer corner sets it transparent so only the ink changes.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- `dialog.modal` is borderless: the raised surface and shadow define the panel, so a full-bleed header, footer, or hero band no longer meets a hard edge; a forced-colors border keeps the outline.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- A corner `.close` that is a direct child of `dialog.modal > header` reserves inline room for itself; previously only the wrapper `<header>` did, so a long chrome title could run under it.
|
|
26
|
+
- `dialog.modal` derives one `--dialog-inner-radius` for the body wrapper, the header band, and the `.dialog-confirmation` footer, so an edge band keeps the panel corner instead of taking its own radius.
|
|
27
|
+
- The `.dialog-confirmation` action band spreads a two-action decision to its edges, keeping a cancel action apart from the committing one.
|
|
28
|
+
- `.dialog-confirmation` centers its leading icon on the title while keeping supporting copy in the same text column.
|
|
29
|
+
- `.btn` and the `.file` selector button take their borders out of the block padding, so they match `.input` height at every size instead of standing 2px taller outside a `.join`.
|
|
30
|
+
- `tests/browser/control-geometry.test.js` measures controls outside a `.join`, whose stretch had hidden the mismatch.
|
|
5
31
|
|
|
6
32
|
## [0.11.0] - 2026-09-30
|
|
7
33
|
|
package/README.md
CHANGED
|
@@ -42,6 +42,10 @@ Flatten the composition for production with
|
|
|
42
42
|
resolves package subpaths and relative files, then inlines them without
|
|
43
43
|
transpiling modern CSS.
|
|
44
44
|
|
|
45
|
+
Hand your theme to designers with `bunx actual-css design --theme theme.css --out design/`:
|
|
46
|
+
Figma and Penpot tokens, plus a Penpot plugin that builds the core components.
|
|
47
|
+
See [Design tools](docs/pages/guides/design-tools.md).
|
|
48
|
+
|
|
45
49
|
### Full bundle (zero-config)
|
|
46
50
|
|
|
47
51
|
The bare `actual-css` entrypoint and `actual-css/full` both resolve to the
|
package/components.json
CHANGED
|
@@ -135,7 +135,8 @@
|
|
|
135
135
|
"source": "src/css/components/bleed.css",
|
|
136
136
|
"cssImport": "actual-css/css/components/bleed",
|
|
137
137
|
"classes": [
|
|
138
|
-
"bleed"
|
|
138
|
+
"bleed",
|
|
139
|
+
"stack"
|
|
139
140
|
],
|
|
140
141
|
"publicHooks": [
|
|
141
142
|
"--bleed-pad"
|
|
@@ -198,6 +199,7 @@
|
|
|
198
199
|
"--btn-default-hover-bg",
|
|
199
200
|
"--btn-border-block-end-color",
|
|
200
201
|
"--btn-border-block-end-width",
|
|
202
|
+
"--btn-border-block",
|
|
201
203
|
"--spinner-width"
|
|
202
204
|
],
|
|
203
205
|
"states": [
|
|
@@ -262,7 +264,11 @@
|
|
|
262
264
|
],
|
|
263
265
|
"publicHooks": [
|
|
264
266
|
"--close-size",
|
|
265
|
-
"--close-icon-size"
|
|
267
|
+
"--close-icon-size",
|
|
268
|
+
"--close-bg",
|
|
269
|
+
"--close-color",
|
|
270
|
+
"--close-hover-color",
|
|
271
|
+
"--close-hover-overlay"
|
|
266
272
|
]
|
|
267
273
|
},
|
|
268
274
|
{
|
|
@@ -444,6 +450,7 @@
|
|
|
444
450
|
"meter"
|
|
445
451
|
],
|
|
446
452
|
"publicHooks": [
|
|
453
|
+
"--meter-track",
|
|
447
454
|
"--meter-value",
|
|
448
455
|
"--bar-height"
|
|
449
456
|
]
|
|
@@ -463,11 +470,14 @@
|
|
|
463
470
|
],
|
|
464
471
|
"publicHooks": [
|
|
465
472
|
"--modal-size",
|
|
473
|
+
"--modal-pad",
|
|
474
|
+
"--modal-header-bg",
|
|
466
475
|
"--dialog-viewport-gap",
|
|
467
476
|
"--dialog-icon-size",
|
|
468
477
|
"--dialog-icon-glyph-size"
|
|
469
478
|
],
|
|
470
479
|
"internalHooks": [
|
|
480
|
+
"--dialog-inner-radius",
|
|
471
481
|
"--dialog-focus-bleed",
|
|
472
482
|
"--dialog-viewport-block",
|
|
473
483
|
"--dialog-viewport-gap-default",
|
package/dist/actual.full.css
CHANGED
|
@@ -2448,7 +2448,11 @@ small {
|
|
|
2448
2448
|
the whole control, not just the filename text. */
|
|
2449
2449
|
min-block-size: var(--control-size);
|
|
2450
2450
|
padding-block: var(--space-10);
|
|
2451
|
-
|
|
2451
|
+
/* Border-box height: both borders come out of the padding, as on .btn. */
|
|
2452
|
+
padding-block: max(
|
|
2453
|
+
var(--space-10),
|
|
2454
|
+
calc((var(--control-size) - 1lh - 2 * var(--border-width)) / 2)
|
|
2455
|
+
);
|
|
2452
2456
|
padding-inline: var(--space-20);
|
|
2453
2457
|
border: var(--border-width) solid var(--border);
|
|
2454
2458
|
border-radius: var(--radius-sm);
|
|
@@ -3735,6 +3739,7 @@ small {
|
|
|
3735
3739
|
* --btn-default-hover-bg
|
|
3736
3740
|
* --btn-border-block-end-color
|
|
3737
3741
|
* --btn-border-block-end-width
|
|
3742
|
+
* --btn-border-block
|
|
3738
3743
|
* --spinner-width
|
|
3739
3744
|
*/
|
|
3740
3745
|
|
|
@@ -3760,6 +3765,10 @@ small {
|
|
|
3760
3765
|
--btn-default-hover-bg: var(--btn-bg);
|
|
3761
3766
|
--btn-radius: var(--radius);
|
|
3762
3767
|
--btn-hover-overlay: var(--hover-overlay, rgb(0 0 0 / 0.08));
|
|
3768
|
+
--btn-border-block: calc(
|
|
3769
|
+
var(--border-width) +
|
|
3770
|
+
var(--btn-border-block-end-width, var(--border-width))
|
|
3771
|
+
);
|
|
3763
3772
|
|
|
3764
3773
|
/* Positioning context for indicators, overlays, and grouped states. */
|
|
3765
3774
|
position: relative;
|
|
@@ -3769,7 +3778,13 @@ small {
|
|
|
3769
3778
|
gap: var(--btn-gap, 0.375em);
|
|
3770
3779
|
min-block-size: var(--btn-min-size);
|
|
3771
3780
|
padding-block: var(--space-20);
|
|
3772
|
-
|
|
3781
|
+
/* why: centres one line in --btn-min-size and keeps that rhythm when the
|
|
3782
|
+
label wraps. min-block-size is a border-box length, so both borders come
|
|
3783
|
+
out of it; without them .btn stood 2px taller than .input. */
|
|
3784
|
+
padding-block: max(
|
|
3785
|
+
var(--space-10),
|
|
3786
|
+
calc((var(--btn-min-size) - 1lh - var(--btn-border-block)) / 2)
|
|
3787
|
+
);
|
|
3773
3788
|
padding-inline: var(--btn-pad-x);
|
|
3774
3789
|
border: var(--border-width) solid var(--btn-border-color, var(--btn-border));
|
|
3775
3790
|
border-block-end-color: var(
|
|
@@ -3866,6 +3881,8 @@ small {
|
|
|
3866
3881
|
--ui-fg: var(--intent, currentColor);
|
|
3867
3882
|
--ui-border: transparent;
|
|
3868
3883
|
--btn-radius: var(--radius-sm);
|
|
3884
|
+
/* border: 0 below; the padding must not subtract a border it lacks. */
|
|
3885
|
+
--btn-border-block: 0px;
|
|
3869
3886
|
|
|
3870
3887
|
min-block-size: auto;
|
|
3871
3888
|
padding-inline: 0;
|
|
@@ -3957,8 +3974,17 @@ a.btn[aria-disabled="true"] {
|
|
|
3957
3974
|
* Public hooks:
|
|
3958
3975
|
* --close-size
|
|
3959
3976
|
* --close-icon-size
|
|
3977
|
+
* --close-bg
|
|
3978
|
+
* --close-color
|
|
3979
|
+
* --close-hover-color
|
|
3980
|
+
* --close-hover-overlay
|
|
3960
3981
|
*/
|
|
3961
3982
|
.close {
|
|
3983
|
+
/* Routes the hover/active wash, as --btn-hover-overlay does for .btn. A
|
|
3984
|
+
context that wants ink-only feedback (the dialog corner) sets it
|
|
3985
|
+
transparent. */
|
|
3986
|
+
--close-hover-overlay: var(--hover-overlay);
|
|
3987
|
+
|
|
3962
3988
|
display: inline-grid;
|
|
3963
3989
|
place-items: center;
|
|
3964
3990
|
flex: none;
|
|
@@ -3985,12 +4011,12 @@ a.btn[aria-disabled="true"] {
|
|
|
3985
4011
|
the control (the dialog corner's --surface-subtle) instead of replacing it. */
|
|
3986
4012
|
@media (hover: hover) {
|
|
3987
4013
|
.close:hover {
|
|
3988
|
-
box-shadow: inset 0 0 0 999px var(--hover-overlay);
|
|
4014
|
+
box-shadow: inset 0 0 0 999px var(--close-hover-overlay);
|
|
3989
4015
|
}
|
|
3990
4016
|
}
|
|
3991
4017
|
|
|
3992
4018
|
.close:active {
|
|
3993
|
-
box-shadow: inset 0 0 0 999px var(--hover-overlay);
|
|
4019
|
+
box-shadow: inset 0 0 0 999px var(--close-hover-overlay);
|
|
3994
4020
|
}
|
|
3995
4021
|
|
|
3996
4022
|
.close:focus-visible {
|
|
@@ -4002,23 +4028,25 @@ a.btn[aria-disabled="true"] {
|
|
|
4002
4028
|
surface rather than to the header or a scroll container inside it. Matched
|
|
4003
4029
|
on the documented positions (the dialog, its form, its header, or a form
|
|
4004
4030
|
inside that header) so a .close inside content — an alert in the body —
|
|
4005
|
-
keeps its own place. */
|
|
4031
|
+
keeps its own place. The corner drops the wash: only the ink changes. */
|
|
4006
4032
|
:where(dialog):is(.modal, .drawer) > .close,
|
|
4007
4033
|
:where(dialog):is(.modal, .drawer) > :is(form, header) > .close,
|
|
4008
4034
|
:where(dialog):is(.modal, .drawer) > :is(form, header) > :is(form, header) > .close {
|
|
4035
|
+
--close-hover-overlay: transparent;
|
|
4036
|
+
|
|
4009
4037
|
position: absolute;
|
|
4010
4038
|
z-index: 1;
|
|
4011
4039
|
inset-block-start: var(--space-20);
|
|
4012
4040
|
inset-inline-end: var(--space-20);
|
|
4013
|
-
background: var(--surface-subtle);
|
|
4014
|
-
color: var(--text-muted);
|
|
4041
|
+
background: var(--close-bg, var(--surface-subtle));
|
|
4042
|
+
color: var(--close-color, var(--text-muted));
|
|
4015
4043
|
}
|
|
4016
4044
|
|
|
4017
4045
|
@media (hover: hover) {
|
|
4018
4046
|
:where(dialog):is(.modal, .drawer) > .close:hover,
|
|
4019
4047
|
:where(dialog):is(.modal, .drawer) > :is(form, header) > .close:hover,
|
|
4020
4048
|
:where(dialog):is(.modal, .drawer) > :is(form, header) > :is(form, header) > .close:hover {
|
|
4021
|
-
color: var(--text);
|
|
4049
|
+
color: var(--close-hover-color, var(--text));
|
|
4022
4050
|
}
|
|
4023
4051
|
}
|
|
4024
4052
|
|
|
@@ -4703,6 +4731,8 @@ a.badge[aria-disabled="true"] {
|
|
|
4703
4731
|
*
|
|
4704
4732
|
* Public hooks:
|
|
4705
4733
|
* --modal-size
|
|
4734
|
+
* --modal-pad
|
|
4735
|
+
* --modal-header-bg
|
|
4706
4736
|
* --dialog-viewport-gap
|
|
4707
4737
|
* --dialog-icon-size
|
|
4708
4738
|
* --dialog-icon-glyph-size
|
|
@@ -4710,6 +4740,7 @@ a.badge[aria-disabled="true"] {
|
|
|
4710
4740
|
* The corner close control is .close (components/close.css).
|
|
4711
4741
|
*
|
|
4712
4742
|
* Internal:
|
|
4743
|
+
* --dialog-inner-radius
|
|
4713
4744
|
* --dialog-focus-bleed
|
|
4714
4745
|
* --dialog-viewport-block
|
|
4715
4746
|
* --dialog-viewport-gap-default
|
|
@@ -4728,6 +4759,11 @@ a.badge[aria-disabled="true"] {
|
|
|
4728
4759
|
var(--dialog-viewport-gap, var(--dialog-viewport-gap-default))
|
|
4729
4760
|
);
|
|
4730
4761
|
|
|
4762
|
+
/* The panel is borderless, so its inner and outer radius are the same. Kept
|
|
4763
|
+
as one name for the padded wrapper and any edge band (header,
|
|
4764
|
+
confirmation footer) so none of them drifts from the corner. */
|
|
4765
|
+
--dialog-inner-radius: var(--radius-lg);
|
|
4766
|
+
|
|
4731
4767
|
/* Keep the surface anchored to the viewport in the top layer. This also
|
|
4732
4768
|
provides the containing block for the absolutely positioned close button. */
|
|
4733
4769
|
position: fixed;
|
|
@@ -4741,7 +4777,9 @@ a.badge[aria-disabled="true"] {
|
|
|
4741
4777
|
dynamic token; only the modal pins the small viewport. */
|
|
4742
4778
|
--dialog-viewport-block: var(--viewport-block);
|
|
4743
4779
|
max-block-size: calc(var(--dialog-viewport-block) - var(--dialog-viewport-gap-2x));
|
|
4744
|
-
|
|
4780
|
+
/* Zero rather than absent: the UA stylesheet draws `border: solid` on
|
|
4781
|
+
dialog, and an authored edge reads as a hard seam against .bleed bands. */
|
|
4782
|
+
border: 0;
|
|
4745
4783
|
border-radius: var(--radius-lg);
|
|
4746
4784
|
background: var(--surface-raised);
|
|
4747
4785
|
color: var(--text);
|
|
@@ -4763,14 +4801,73 @@ a.badge[aria-disabled="true"] {
|
|
|
4763
4801
|
transform var(--duration) var(--ease-exit);
|
|
4764
4802
|
}
|
|
4765
4803
|
|
|
4804
|
+
@media (forced-colors: active) {
|
|
4805
|
+
/* With no authored border the panel edge disappears once colors collapse.
|
|
4806
|
+
The browser forces the border color, so only the width is authored. */
|
|
4807
|
+
:where(dialog).modal {
|
|
4808
|
+
border: var(--border-width) solid CanvasText;
|
|
4809
|
+
}
|
|
4810
|
+
}
|
|
4811
|
+
|
|
4766
4812
|
:where(dialog).modal > form,
|
|
4767
4813
|
:where(dialog).modal > .stack {
|
|
4814
|
+
--surface-pad: var(--modal-pad, var(--space-40));
|
|
4815
|
+
|
|
4768
4816
|
display: grid;
|
|
4769
4817
|
gap: var(--space-40);
|
|
4770
4818
|
max-block-size: calc(var(--dialog-viewport-block) - var(--dialog-viewport-gap-2x));
|
|
4819
|
+
border-radius: var(--dialog-inner-radius);
|
|
4771
4820
|
overflow: auto;
|
|
4772
4821
|
overscroll-behavior: contain;
|
|
4773
|
-
padding: var(--
|
|
4822
|
+
padding: var(--surface-pad);
|
|
4823
|
+
}
|
|
4824
|
+
|
|
4825
|
+
/* Optional dialog chrome lives beside the padded body wrapper. Its leading
|
|
4826
|
+
region and trailing controls share one center axis; wrapping the close in
|
|
4827
|
+
the trailing cluster keeps it in flow instead of invoking the absolute
|
|
4828
|
+
corner treatment from close.css. */
|
|
4829
|
+
:where(dialog).modal > header {
|
|
4830
|
+
display: flex;
|
|
4831
|
+
align-items: center;
|
|
4832
|
+
justify-content: space-between;
|
|
4833
|
+
gap: var(--space-30);
|
|
4834
|
+
min-block-size: var(--close-size, var(--control-size));
|
|
4835
|
+
padding: var(--modal-pad, var(--space-40));
|
|
4836
|
+
border-start-start-radius: var(--dialog-inner-radius);
|
|
4837
|
+
border-start-end-radius: var(--dialog-inner-radius);
|
|
4838
|
+
background: var(--modal-header-bg, var(--surface-subtle));
|
|
4839
|
+
}
|
|
4840
|
+
|
|
4841
|
+
:where(dialog).modal > header > .media {
|
|
4842
|
+
flex: 1 1 auto;
|
|
4843
|
+
min-inline-size: 0;
|
|
4844
|
+
}
|
|
4845
|
+
|
|
4846
|
+
:where(dialog).modal > header > .media > :is(h1, h2, h3, h4, h5, h6) {
|
|
4847
|
+
display: flex;
|
|
4848
|
+
align-items: center;
|
|
4849
|
+
min-block-size: var(--close-size, var(--control-size));
|
|
4850
|
+
margin-block: 0;
|
|
4851
|
+
}
|
|
4852
|
+
|
|
4853
|
+
:where(dialog).modal > header > .cluster {
|
|
4854
|
+
--cluster-wrap: nowrap;
|
|
4855
|
+
|
|
4856
|
+
flex: none;
|
|
4857
|
+
}
|
|
4858
|
+
|
|
4859
|
+
@supports selector(dialog:has(> header)) {
|
|
4860
|
+
/* The header stays fixed while the body wrapper owns overflow. Without
|
|
4861
|
+
:has(), compact dialogs keep ordinary block flow as the fallback. */
|
|
4862
|
+
:where(dialog).modal[open]:has(> header) {
|
|
4863
|
+
display: grid;
|
|
4864
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
4865
|
+
}
|
|
4866
|
+
|
|
4867
|
+
:where(dialog).modal:has(> header) > :is(form, .stack) {
|
|
4868
|
+
min-block-size: 0;
|
|
4869
|
+
max-block-size: none;
|
|
4870
|
+
}
|
|
4774
4871
|
}
|
|
4775
4872
|
|
|
4776
4873
|
@supports (block-size: 100svh) {
|
|
@@ -4822,12 +4919,32 @@ a.badge[aria-disabled="true"] {
|
|
|
4822
4919
|
margin-block-end: 0;
|
|
4823
4920
|
}
|
|
4824
4921
|
|
|
4922
|
+
/* A media row inside the structural header is title anatomy, so its heading
|
|
4923
|
+
does not bring prose margins into the icon alignment. */
|
|
4924
|
+
:where(dialog).modal > :where(form, .stack) > header > .media > :is(h1, h2, h3, h4, h5, h6) {
|
|
4925
|
+
margin-block: 0;
|
|
4926
|
+
}
|
|
4927
|
+
|
|
4825
4928
|
/* The close button is anchored to the dialog at top inline-end, out of the
|
|
4826
4929
|
content flow; headers reserve inline room so titles never run under it.
|
|
4827
4930
|
The form/.stack anatomy is structural, so it stays in :where() and never
|
|
4828
4931
|
lends .stack's specificity to a bare <form>. */
|
|
4829
4932
|
:where(dialog).modal > :where(form, .stack) > header {
|
|
4830
|
-
padding-inline-end: calc(
|
|
4933
|
+
padding-inline-end: calc(
|
|
4934
|
+
var(--close-size, var(--control-size)) +
|
|
4935
|
+
var(--space-20) +
|
|
4936
|
+
var(--space-30)
|
|
4937
|
+
);
|
|
4938
|
+
}
|
|
4939
|
+
|
|
4940
|
+
/* A corner .close that is a direct child of the chrome header needs the same
|
|
4941
|
+
reserve, but never below the header's own pad. Kept as its own rule so an
|
|
4942
|
+
unsupported :has() drops only this geometry, not the wrapper reserve. */
|
|
4943
|
+
:where(dialog).modal > header:has(> .close) {
|
|
4944
|
+
padding-inline-end: max(
|
|
4945
|
+
var(--modal-pad, var(--space-40)),
|
|
4946
|
+
calc(var(--close-size, var(--control-size)) + var(--space-20) + var(--space-30))
|
|
4947
|
+
);
|
|
4831
4948
|
}
|
|
4832
4949
|
|
|
4833
4950
|
:where(dialog).modal > :where(form, .stack) > footer {
|
|
@@ -4841,19 +4958,25 @@ a.badge[aria-disabled="true"] {
|
|
|
4841
4958
|
action band. The media primitive owns icon/content alignment; this variant
|
|
4842
4959
|
only removes the standard form inset so both regions can own their padding. */
|
|
4843
4960
|
:where(dialog).modal.dialog-confirmation > form {
|
|
4961
|
+
--surface-pad: 0px;
|
|
4962
|
+
|
|
4844
4963
|
gap: 0;
|
|
4845
4964
|
padding: 0;
|
|
4846
4965
|
}
|
|
4847
4966
|
|
|
4848
|
-
:where(dialog).modal.dialog-confirmation > form > .media {
|
|
4967
|
+
:where(dialog).modal.dialog-confirmation > form > :is(.media, header) {
|
|
4849
4968
|
gap: var(--space-40);
|
|
4850
4969
|
padding: var(--space-50);
|
|
4851
4970
|
}
|
|
4852
4971
|
|
|
4972
|
+
/* The action band splits a decision pair: the cancel-style action holds the
|
|
4973
|
+
leading edge and the committing action the trailing one, so the destructive
|
|
4974
|
+
choice is never adjacent to the dismiss. */
|
|
4853
4975
|
:where(dialog).modal.dialog-confirmation > form > footer {
|
|
4976
|
+
justify-content: space-between;
|
|
4854
4977
|
padding: var(--space-40) var(--space-50);
|
|
4855
|
-
border-end-start-radius:
|
|
4856
|
-
border-end-end-radius:
|
|
4978
|
+
border-end-start-radius: var(--dialog-inner-radius);
|
|
4979
|
+
border-end-end-radius: var(--dialog-inner-radius);
|
|
4857
4980
|
background: var(--surface-subtle);
|
|
4858
4981
|
}
|
|
4859
4982
|
|
|
@@ -4890,8 +5013,29 @@ a.badge[aria-disabled="true"] {
|
|
|
4890
5013
|
line-height: 1;
|
|
4891
5014
|
}
|
|
4892
5015
|
|
|
5016
|
+
:where(dialog).modal.dialog-confirmation > form > .media > header {
|
|
5017
|
+
display: grid;
|
|
5018
|
+
gap: var(--space-20);
|
|
5019
|
+
}
|
|
5020
|
+
|
|
5021
|
+
:where(dialog).modal.dialog-confirmation > form > .media > header > * {
|
|
5022
|
+
margin-block: 0;
|
|
5023
|
+
}
|
|
5024
|
+
|
|
5025
|
+
/* The first heading occupies the icon row, so its text centers on the icon
|
|
5026
|
+
without a font-relative nudge. Following copy stays in the same column. */
|
|
5027
|
+
:where(dialog).modal.dialog-confirmation
|
|
5028
|
+
> form
|
|
5029
|
+
> .media
|
|
5030
|
+
> header
|
|
5031
|
+
> :is(h1, h2, h3, h4, h5, h6):first-child {
|
|
5032
|
+
display: flex;
|
|
5033
|
+
align-items: center;
|
|
5034
|
+
min-block-size: var(--dialog-icon-size, 3rem);
|
|
5035
|
+
}
|
|
5036
|
+
|
|
4893
5037
|
@media (max-width: 30rem) {
|
|
4894
|
-
:where(dialog).modal.dialog-confirmation > form > .media,
|
|
5038
|
+
:where(dialog).modal.dialog-confirmation > form > :is(.media, header),
|
|
4895
5039
|
:where(dialog).modal.dialog-confirmation > form > footer {
|
|
4896
5040
|
padding: var(--space-40);
|
|
4897
5041
|
}
|
|
@@ -5217,9 +5361,9 @@ html.has-modal-open.had-scrollbar {
|
|
|
5217
5361
|
*
|
|
5218
5362
|
* A surface that insets its direct children relays that inset to them as
|
|
5219
5363
|
* --surface-pad; a direct .bleed child cancels it and reaches the surface
|
|
5220
|
-
* edge. Card and drawer pad at the container level,
|
|
5221
|
-
*
|
|
5222
|
-
* owns it and the item does not.
|
|
5364
|
+
* edge. Card and drawer pad at the container level, while modal pads its inner
|
|
5365
|
+
* wrapper; each owns the token where that inset lives. The accordion pads its
|
|
5366
|
+
* summary and panel instead, so the panel owns it and the item does not.
|
|
5223
5367
|
*
|
|
5224
5368
|
* Why the token is handed to the children rather than declared on the surface:
|
|
5225
5369
|
* custom properties inherit, so a surface-level declaration would also reach a
|
|
@@ -5240,11 +5384,11 @@ html.has-modal-open.had-scrollbar {
|
|
|
5240
5384
|
* Framework plumbing:
|
|
5241
5385
|
* --surface-pad (declared by the surface)
|
|
5242
5386
|
*/
|
|
5243
|
-
:where(.card, .drawer, .accordion details > summary + *) > * * {
|
|
5387
|
+
:where(.card, .drawer, dialog.modal > :is(form, .stack), .accordion details > summary + *) > * * {
|
|
5244
5388
|
--bleed-pad: initial;
|
|
5245
5389
|
}
|
|
5246
5390
|
|
|
5247
|
-
:where(.card, .drawer, .accordion details > summary + *) > * {
|
|
5391
|
+
:where(.card, .drawer, dialog.modal > :is(form, .stack), .accordion details > summary + *) > * {
|
|
5248
5392
|
--bleed-pad: var(--surface-pad);
|
|
5249
5393
|
}
|
|
5250
5394
|
|
|
@@ -8158,11 +8302,14 @@ a.list-item[aria-current]::before {
|
|
|
8158
8302
|
* .sm/.lg are deliberately not supported.
|
|
8159
8303
|
*
|
|
8160
8304
|
* Public hooks:
|
|
8305
|
+
* --meter-track
|
|
8161
8306
|
* --meter-value
|
|
8162
8307
|
* --bar-height
|
|
8163
8308
|
*/
|
|
8164
8309
|
|
|
8165
8310
|
.meter {
|
|
8311
|
+
--meter-track: var(--surface-subtle);
|
|
8312
|
+
|
|
8166
8313
|
appearance: none;
|
|
8167
8314
|
-webkit-appearance: none;
|
|
8168
8315
|
display: block;
|
|
@@ -8171,7 +8318,7 @@ a.list-item[aria-current]::before {
|
|
|
8171
8318
|
overflow: hidden;
|
|
8172
8319
|
border: 0;
|
|
8173
8320
|
border-radius: var(--radius-full);
|
|
8174
|
-
background: var(--
|
|
8321
|
+
background: var(--meter-track);
|
|
8175
8322
|
}
|
|
8176
8323
|
|
|
8177
8324
|
/* A non-native meter is a weighted flex container. The element type keeps the
|
|
@@ -8198,7 +8345,7 @@ a.list-item[aria-current]::before {
|
|
|
8198
8345
|
block-size: var(--bar-height);
|
|
8199
8346
|
border: 0;
|
|
8200
8347
|
border-radius: var(--radius-full);
|
|
8201
|
-
background: var(--
|
|
8348
|
+
background: var(--meter-track);
|
|
8202
8349
|
}
|
|
8203
8350
|
|
|
8204
8351
|
.meter::-webkit-meter-optimum-value {
|