actual-css 0.4.2 → 0.5.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.
- package/CHANGELOG.md +49 -2
- package/README.md +2 -2
- package/dist/actual.css +53 -14
- package/dist/actual.full.css +287 -91
- package/dist/actual.full.js +1 -1
- package/dist/actual.full.min.css +1 -1
- package/dist/actual.min.css +1 -1
- package/docs/design-notes/spacing-units.md +286 -0
- package/docs/navigation.json +1 -0
- package/docs/pages/components/alert.md +1 -1
- package/docs/pages/components/app-navigation.md +2 -0
- package/docs/pages/components/badge.md +17 -3
- package/docs/pages/components/button.md +9 -2
- package/docs/pages/components/card.md +13 -0
- package/docs/pages/components/data-list.md +72 -0
- package/docs/pages/components/dialog.md +2 -0
- package/docs/pages/components/drawer.md +2 -0
- package/docs/pages/components/fab.md +2 -0
- package/docs/pages/components/meter.md +56 -1
- package/docs/pages/components/progress.md +10 -0
- package/docs/pages/components/skeleton.md +2 -0
- package/docs/pages/components/steps.md +10 -2
- package/docs/pages/components/table.md +1 -0
- package/docs/pages/enhancements/flyout.md +2 -0
- package/docs/pages/enhancements/status-bar.md +10 -1
- package/docs/pages/examples/overview.md +2 -1
- package/docs/pages/forms/joined-controls.md +2 -0
- package/docs/pages/forms/overview.md +1 -1
- package/docs/pages/forms/range.md +2 -0
- package/docs/pages/forms/states-and-sizes.md +1 -1
- package/docs/pages/forms/validation.md +2 -0
- package/docs/pages/foundations/philosophy.md +11 -1
- package/docs/pages/foundations/tokens.md +7 -3
- package/docs/pages/foundations/typography.md +10 -2
- package/docs/pages/guides/introduction.md +1 -1
- package/docs/pages/layout/scroll-snap.md +2 -0
- package/docs/pages/layout/sidebar-layout.md +2 -0
- package/docs/pages/layout/topbar.md +2 -0
- package/docs/pages/utilities/accessibility.md +18 -0
- package/package.json +1 -1
- package/scripts/reserved-classes.json +4 -0
- package/src/css/components/data-list.css +27 -0
- package/src/css/components/drawer.css +30 -11
- package/src/css/components/flyout.css +17 -12
- package/src/css/components/index.css +1 -0
- package/src/css/components/meter.css +28 -1
- package/src/css/components/modal.css +28 -11
- package/src/css/components/progress.css +5 -0
- package/src/css/components/status-bar.css +31 -15
- package/src/css/components/steps.css +35 -9
- package/src/css/components/surface.css +5 -3
- package/src/css/components/tooltip.css +5 -8
- package/src/css/core/base.css +7 -1
- package/src/css/core/intents.css +6 -0
- package/src/css/core/tokens.css +23 -9
- package/src/css/core/variants.css +17 -4
- package/src/css/forms/form.css +4 -4
- package/src/css/typography/prose.css +2 -3
- package/src/css/utilities/base.css +16 -0
- package/src/js/selectors.js +1 -0
- package/src/js/status.js +88 -7
- package/src/js/surface.js +2 -11
- package/src/js/transition.js +20 -0
package/dist/actual.full.css
CHANGED
|
@@ -60,8 +60,8 @@ select {
|
|
|
60
60
|
*
|
|
61
61
|
* Derived: "Theme-derived aliases" and "State tokens" reference intent and
|
|
62
62
|
* surface tokens and follow the theme; do not hard-code values into them.
|
|
63
|
-
* Internal: indicator offsets, --
|
|
64
|
-
*
|
|
63
|
+
* Internal: indicator offsets, --disabled-opacity and the like are
|
|
64
|
+
* consumed by components, not authored.
|
|
65
65
|
*
|
|
66
66
|
* Component-local hooks and internal state relays live with their
|
|
67
67
|
* components. See docs/pages/foundations/tokens.md for the public/internal
|
|
@@ -85,9 +85,10 @@ select {
|
|
|
85
85
|
--font-size-md: 1rem;
|
|
86
86
|
--font-size-lg: 1.125rem;
|
|
87
87
|
|
|
88
|
-
/* Spacing — official steps are named in tens so the scale stays open
|
|
89
|
-
|
|
90
|
-
--space-45…)
|
|
88
|
+
/* Spacing — official steps are named in tens so the scale stays open.
|
|
89
|
+
Actual CSS will never define a --space-* that is not a multiple of 10:
|
|
90
|
+
the intermediate names (--space-15, --space-45…) are reserved for
|
|
91
|
+
applications, and no future framework step can collide with them. */
|
|
91
92
|
--gap: 0.75rem;
|
|
92
93
|
--density-space: var(--space-40);
|
|
93
94
|
--density-compact-size: 1.5rem;
|
|
@@ -105,14 +106,25 @@ select {
|
|
|
105
106
|
--shadow-popout: 0 0.25rem 0.75rem rgb(0 0 0 / 0.15);
|
|
106
107
|
|
|
107
108
|
/* Motion — see reset.css for the prefers-reduced-motion hard reset.
|
|
108
|
-
--duration
|
|
109
|
-
animation rates below tune one-shot open/close and decorative loops.
|
|
109
|
+
--duration scales component transitions (hover/focus); the dedicated
|
|
110
|
+
animation rates below tune one-shot open/close and decorative loops.
|
|
111
|
+
Generic state/interaction motion uses the CSS default `ease` directly
|
|
112
|
+
(registered nowhere). --ease-enter/--ease-exit express the character of
|
|
113
|
+
one-shot presence changes, owned by the open/closed state rules that
|
|
114
|
+
separate them (status-bar, drawer, modal). The pair follows the standard
|
|
115
|
+
M3 rhythm; the more aggressive emphasized-decelerate entrance is
|
|
116
|
+
deliberately not offered because it only pays off on 250–400ms motions,
|
|
117
|
+
beyond this vocabulary. Toggles that share one transition list at
|
|
118
|
+
--duration-fast (flyout, tooltip) and pure-opacity backdrops stay on
|
|
119
|
+
`ease`: at 100ms the curve has almost no resolving time, and a scrim is
|
|
120
|
+
not traveling anywhere. */
|
|
110
121
|
--duration: 150ms;
|
|
111
122
|
--duration-fast: 100ms;
|
|
112
123
|
--duration-slow: 200ms;
|
|
113
124
|
--duration-spin: 0.75s;
|
|
114
125
|
--duration-shimmer: 1.2s;
|
|
115
|
-
--ease:
|
|
126
|
+
--ease-enter: cubic-bezier(0.2, 0, 0, 1);
|
|
127
|
+
--ease-exit: cubic-bezier(0.4, 0, 1, 1);
|
|
116
128
|
|
|
117
129
|
/* Focus ring — shared by every interactive component's :focus-visible */
|
|
118
130
|
--focus-outline-color: currentColor;
|
|
@@ -130,7 +142,9 @@ select {
|
|
|
130
142
|
--backdrop-opacity: 0.45;
|
|
131
143
|
--backdrop-fill: rgb(0 0 0 / var(--backdrop-opacity));
|
|
132
144
|
|
|
133
|
-
/*
|
|
145
|
+
/* Bar thickness shared by .progress and .meter — two conceptual variants of
|
|
146
|
+
the same geometry. Public: set it on the element or on an application
|
|
147
|
+
class rather than reaching for a size variant. */
|
|
134
148
|
--bar-height: 0.65rem;
|
|
135
149
|
|
|
136
150
|
/* Controls — inputs and buttons share --control-size so heights always match.
|
|
@@ -453,6 +467,9 @@ select {
|
|
|
453
467
|
*
|
|
454
468
|
* Sits between reset (browser defaults) and prose (rich content scope).
|
|
455
469
|
* These styles apply everywhere — cards, dialogs, heroes — not only in prose.
|
|
470
|
+
*
|
|
471
|
+
* Public hooks:
|
|
472
|
+
* --link
|
|
456
473
|
*/
|
|
457
474
|
|
|
458
475
|
body {
|
|
@@ -462,8 +479,11 @@ body {
|
|
|
462
479
|
line-height: var(--line-height);
|
|
463
480
|
}
|
|
464
481
|
|
|
482
|
+
/* Bare links inherit their ink by default, so nothing changes unless a theme
|
|
483
|
+
opts in by setting --link. Because this is an element selector, any component
|
|
484
|
+
rule that colors its own anchors still wins. */
|
|
465
485
|
a {
|
|
466
|
-
color: inherit;
|
|
486
|
+
color: var(--link, inherit);
|
|
467
487
|
text-underline-offset: 0.18em;
|
|
468
488
|
}
|
|
469
489
|
|
|
@@ -547,11 +567,17 @@ small {
|
|
|
547
567
|
--intent-fg: var(--neutral-fg);
|
|
548
568
|
}
|
|
549
569
|
|
|
570
|
+
/* Paint an inherited or local intent on a simple foreground element without
|
|
571
|
+
turning the intent classes into general-purpose color utilities. */
|
|
572
|
+
.intent-color {
|
|
573
|
+
color: var(--intent);
|
|
574
|
+
}
|
|
575
|
+
|
|
550
576
|
/*
|
|
551
577
|
* Cross-cutting variant token mapping.
|
|
552
578
|
*
|
|
553
|
-
* Variant scope: .solid/.soft/.outline set --ui-* for components that
|
|
554
|
-
* shared variants. .inverted is a surface modifier, not a variant: it paints
|
|
579
|
+
* Variant scope: .solid/.soft/.outline/.surface set --ui-* for components that
|
|
580
|
+
* opt into shared variants. .inverted is a surface modifier, not a variant: it paints
|
|
555
581
|
* the element directly (background/color/border-color) so it works on any bare
|
|
556
582
|
* block, and remaps the shared --ui-* tokens so participating components
|
|
557
583
|
* (.card, .navbar, .alert, .badge) invert through their own rules. Loaded
|
|
@@ -570,8 +596,10 @@ small {
|
|
|
570
596
|
* components may consume --density-* when the density context should affect
|
|
571
597
|
* their local rhythm. Compact components may consume --density-compact-size.
|
|
572
598
|
* Components with bespoke sizing (spinner, avatar) define local .sm/.lg;
|
|
573
|
-
* applying .sm/.lg to card, dialog, accordion, navbar, table
|
|
574
|
-
* a no-op.
|
|
599
|
+
* applying .sm/.lg to card, dialog, accordion, navbar, table, progress, meter
|
|
600
|
+
* is a no-op. Progress and meter are deliberate: a bar keeps its inline size
|
|
601
|
+
* and only changes thickness, which --bar-height expresses better than a
|
|
602
|
+
* three-step scale.
|
|
575
603
|
*
|
|
576
604
|
* Intent list source of truth: intents.css. Components consume --intent* tokens
|
|
577
605
|
* instead of re-listing intent classes.
|
|
@@ -594,6 +622,17 @@ small {
|
|
|
594
622
|
--ui-border: var(--intent, currentColor);
|
|
595
623
|
}
|
|
596
624
|
|
|
625
|
+
/* Neutral chrome, intent only in the ink: the page surface with the theme
|
|
626
|
+
border. .soft is the intent-tinted treatment (its baseline fallback uses
|
|
627
|
+
--surface-subtle) and .outline has no fill at all, so neither can express
|
|
628
|
+
it. Deliberately literal — no color-mix enhancement — so this stays the one
|
|
629
|
+
variant that reads exactly as the theme's own surface. */
|
|
630
|
+
.surface {
|
|
631
|
+
--ui-bg: var(--surface);
|
|
632
|
+
--ui-fg: var(--intent, var(--text));
|
|
633
|
+
--ui-border: var(--border);
|
|
634
|
+
}
|
|
635
|
+
|
|
597
636
|
/* Inverse surface treatment. Paints the element directly (so it works on any
|
|
598
637
|
bare block) and remaps the shared --ui-* tokens so opt-in components
|
|
599
638
|
(.card, .navbar) invert through their own rules. Because this loads before
|
|
@@ -776,9 +815,8 @@ small {
|
|
|
776
815
|
font-size: var(--prose-h4);
|
|
777
816
|
}
|
|
778
817
|
|
|
779
|
-
/*
|
|
780
|
-
|
|
781
|
-
it without having to restate the rule. */
|
|
818
|
+
/* --link is a theme-level token (core/base.css also reads it for bare links);
|
|
819
|
+
prose falls back to --primary so a theme that never sets it is unaffected. */
|
|
782
820
|
.prose :where(a) {
|
|
783
821
|
color: var(--link, var(--primary));
|
|
784
822
|
text-decoration-line: underline;
|
|
@@ -1822,6 +1860,10 @@ small {
|
|
|
1822
1860
|
* Individual controls keep their own files; .choice label layout lives in
|
|
1823
1861
|
* choice.css; .form-actions lives in form-actions.css.
|
|
1824
1862
|
*
|
|
1863
|
+
* .field-group owns its own box only. Distance between sibling groups is a
|
|
1864
|
+
* composition concern (.stack on the form), never a sibling margin here: the
|
|
1865
|
+
* component cannot know whether its siblings are stacked or gridded.
|
|
1866
|
+
*
|
|
1825
1867
|
* Public API: .field, .field-label, .field-help, .field-error, .field-group,
|
|
1826
1868
|
* .required-mark.
|
|
1827
1869
|
*
|
|
@@ -1842,10 +1884,6 @@ small {
|
|
|
1842
1884
|
border-radius: var(--radius);
|
|
1843
1885
|
}
|
|
1844
1886
|
|
|
1845
|
-
.field-group + .field-group {
|
|
1846
|
-
margin-block-start: var(--space-40);
|
|
1847
|
-
}
|
|
1848
|
-
|
|
1849
1887
|
.field-label,
|
|
1850
1888
|
.field-group > legend {
|
|
1851
1889
|
color: var(--text);
|
|
@@ -4161,7 +4199,9 @@ a.badge[aria-disabled="true"] {
|
|
|
4161
4199
|
z-index: calc(var(--z-menu) - 1);
|
|
4162
4200
|
background: var(--backdrop-fill);
|
|
4163
4201
|
opacity: 1;
|
|
4164
|
-
|
|
4202
|
+
/* A scrim never travels; it fades on the neutral `ease`. Duration matches
|
|
4203
|
+
the flyout sheet it accompanies so it never lags the panel. */
|
|
4204
|
+
transition: opacity var(--duration-fast) ease;
|
|
4165
4205
|
}
|
|
4166
4206
|
|
|
4167
4207
|
.surface-backdrop[hidden] {
|
|
@@ -4178,8 +4218,8 @@ a.badge[aria-disabled="true"] {
|
|
|
4178
4218
|
@supports (transition-behavior: allow-discrete) {
|
|
4179
4219
|
.surface-backdrop {
|
|
4180
4220
|
transition:
|
|
4181
|
-
opacity var(--duration)
|
|
4182
|
-
display var(--duration) allow-discrete;
|
|
4221
|
+
opacity var(--duration-fast) ease,
|
|
4222
|
+
display var(--duration-fast) allow-discrete;
|
|
4183
4223
|
}
|
|
4184
4224
|
}
|
|
4185
4225
|
@media print {
|
|
@@ -4229,12 +4269,14 @@ dialog.modal {
|
|
|
4229
4269
|
* Keep the open dialog root untransformed. Fixed overlays mounted inside a
|
|
4230
4270
|
* modal dialog use viewport coordinates; transform/translate/scale on this
|
|
4231
4271
|
* element would make them position against the dialog instead. The closed
|
|
4232
|
-
* state can still carry a small transform for enter/exit motion.
|
|
4272
|
+
* state can still carry a small transform for enter/exit motion. The lift
|
|
4273
|
+
* is a pure vertical offset: scaling a wide panel around its center drags
|
|
4274
|
+
* both edges, which reads as horizontal movement.
|
|
4233
4275
|
*/
|
|
4234
|
-
transform: translateY(0.35rem)
|
|
4276
|
+
transform: translateY(0.35rem);
|
|
4235
4277
|
transition:
|
|
4236
|
-
opacity var(--duration),
|
|
4237
|
-
transform var(--duration);
|
|
4278
|
+
opacity var(--duration) var(--ease-exit),
|
|
4279
|
+
transform var(--duration) var(--ease-exit);
|
|
4238
4280
|
}
|
|
4239
4281
|
|
|
4240
4282
|
dialog.modal > form,
|
|
@@ -4353,33 +4395,46 @@ dialog.modal.dialog-confirmation > form > footer {
|
|
|
4353
4395
|
dialog.modal[open] {
|
|
4354
4396
|
opacity: 1;
|
|
4355
4397
|
transform: none;
|
|
4398
|
+
transition:
|
|
4399
|
+
opacity var(--duration) var(--ease-enter),
|
|
4400
|
+
transform var(--duration) var(--ease-enter);
|
|
4356
4401
|
}
|
|
4357
4402
|
|
|
4358
4403
|
@starting-style {
|
|
4359
4404
|
dialog.modal[open] {
|
|
4360
4405
|
opacity: 0;
|
|
4361
|
-
transform: translateY(0.35rem)
|
|
4406
|
+
transform: translateY(0.35rem);
|
|
4362
4407
|
}
|
|
4363
4408
|
}
|
|
4364
4409
|
|
|
4365
4410
|
dialog.modal::backdrop {
|
|
4366
4411
|
background: var(--backdrop-fill);
|
|
4367
4412
|
opacity: 0;
|
|
4368
|
-
|
|
4413
|
+
/* Scrim curve stays neutral `ease`; only the panel carries the character
|
|
4414
|
+
curves. */
|
|
4415
|
+
transition: opacity var(--duration) ease;
|
|
4369
4416
|
}
|
|
4370
4417
|
|
|
4371
4418
|
@supports (transition-behavior: allow-discrete) {
|
|
4372
4419
|
dialog.modal {
|
|
4373
4420
|
transition:
|
|
4374
|
-
opacity var(--duration),
|
|
4375
|
-
transform var(--duration),
|
|
4421
|
+
opacity var(--duration) var(--ease-exit),
|
|
4422
|
+
transform var(--duration) var(--ease-exit),
|
|
4423
|
+
overlay var(--duration) allow-discrete,
|
|
4424
|
+
display var(--duration) allow-discrete;
|
|
4425
|
+
}
|
|
4426
|
+
|
|
4427
|
+
dialog.modal[open] {
|
|
4428
|
+
transition:
|
|
4429
|
+
opacity var(--duration) var(--ease-enter),
|
|
4430
|
+
transform var(--duration) var(--ease-enter),
|
|
4376
4431
|
overlay var(--duration) allow-discrete,
|
|
4377
4432
|
display var(--duration) allow-discrete;
|
|
4378
4433
|
}
|
|
4379
4434
|
|
|
4380
4435
|
dialog.modal::backdrop {
|
|
4381
4436
|
transition:
|
|
4382
|
-
opacity var(--duration),
|
|
4437
|
+
opacity var(--duration) ease,
|
|
4383
4438
|
overlay var(--duration) allow-discrete,
|
|
4384
4439
|
display var(--duration) allow-discrete;
|
|
4385
4440
|
}
|
|
@@ -4404,13 +4459,15 @@ html.has-modal-open.had-scrollbar {
|
|
|
4404
4459
|
}
|
|
4405
4460
|
|
|
4406
4461
|
@media (prefers-reduced-motion: no-preference) {
|
|
4462
|
+
/* Wrong-close feedback and view-transition transport are motion quirks, not
|
|
4463
|
+
presence enter/exit, so they stay on the plain CSS default easing. */
|
|
4407
4464
|
dialog.modal.is-static {
|
|
4408
|
-
animation: actual-dialog-static var(--duration-slow)
|
|
4465
|
+
animation: actual-dialog-static var(--duration-slow) ease;
|
|
4409
4466
|
}
|
|
4410
4467
|
|
|
4411
4468
|
::view-transition-group(actual-dialog) {
|
|
4412
4469
|
animation-duration: var(--duration);
|
|
4413
|
-
animation-timing-function:
|
|
4470
|
+
animation-timing-function: ease;
|
|
4414
4471
|
}
|
|
4415
4472
|
}
|
|
4416
4473
|
|
|
@@ -4509,11 +4566,16 @@ html.has-modal-open.had-scrollbar {
|
|
|
4509
4566
|
*
|
|
4510
4567
|
* Internal:
|
|
4511
4568
|
* --drawer-closed-translate (side/RTL positioning state)
|
|
4569
|
+
* --drawer-motion-duration (shared by panel and ::backdrop so exit duration
|
|
4570
|
+
* changes in one place; entry state redefines it longer)
|
|
4512
4571
|
*/
|
|
4513
4572
|
dialog.drawer {
|
|
4514
4573
|
--drawer-size: 20rem;
|
|
4515
4574
|
--drawer-pad: var(--space-40);
|
|
4516
4575
|
--drawer-closed-translate: -100%;
|
|
4576
|
+
/* Exit is shorter than entry so the panel clears quickly; the scrim reads
|
|
4577
|
+
the same variable through inheritance and never lags the panel. */
|
|
4578
|
+
--drawer-motion-duration: var(--duration);
|
|
4517
4579
|
|
|
4518
4580
|
/* Keep the surface anchored to the viewport in the top layer. This also
|
|
4519
4581
|
provides the containing block for the absolutely positioned close button.
|
|
@@ -4537,16 +4599,20 @@ dialog.drawer {
|
|
|
4537
4599
|
opacity: 0;
|
|
4538
4600
|
transform: translateX(var(--drawer-closed-translate));
|
|
4539
4601
|
transition:
|
|
4540
|
-
opacity var(--duration-
|
|
4541
|
-
transform var(--duration-
|
|
4602
|
+
opacity var(--drawer-motion-duration) var(--ease-exit),
|
|
4603
|
+
transform var(--drawer-motion-duration) var(--ease-exit);
|
|
4542
4604
|
}
|
|
4543
4605
|
|
|
4544
4606
|
dialog.drawer[open] {
|
|
4607
|
+
--drawer-motion-duration: var(--duration-slow);
|
|
4545
4608
|
display: grid;
|
|
4546
4609
|
grid-template-rows: auto minmax(0, 1fr) auto;
|
|
4547
4610
|
gap: var(--space-40);
|
|
4548
4611
|
opacity: 1;
|
|
4549
4612
|
transform: translateX(0);
|
|
4613
|
+
transition:
|
|
4614
|
+
opacity var(--drawer-motion-duration) var(--ease-enter),
|
|
4615
|
+
transform var(--drawer-motion-duration) var(--ease-enter);
|
|
4550
4616
|
}
|
|
4551
4617
|
|
|
4552
4618
|
/* Backdrop color sourced from components/surface.css so it matches .modal
|
|
@@ -4554,7 +4620,9 @@ dialog.drawer[open] {
|
|
|
4554
4620
|
dialog.drawer::backdrop {
|
|
4555
4621
|
background: var(--backdrop-fill);
|
|
4556
4622
|
opacity: 0;
|
|
4557
|
-
|
|
4623
|
+
/* Scrim curve stays neutral `ease`; only the panel's character curves
|
|
4624
|
+
apply. Duration follows --drawer-motion-duration through inheritance. */
|
|
4625
|
+
transition: opacity var(--drawer-motion-duration) ease;
|
|
4558
4626
|
}
|
|
4559
4627
|
|
|
4560
4628
|
dialog.drawer[data-side="end"] {
|
|
@@ -4590,17 +4658,25 @@ dialog.drawer nav {
|
|
|
4590
4658
|
@supports (transition-behavior: allow-discrete) {
|
|
4591
4659
|
dialog.drawer {
|
|
4592
4660
|
transition:
|
|
4593
|
-
opacity var(--duration-
|
|
4594
|
-
transform var(--duration-
|
|
4595
|
-
overlay var(--duration
|
|
4596
|
-
display var(--duration
|
|
4661
|
+
opacity var(--drawer-motion-duration) var(--ease-exit),
|
|
4662
|
+
transform var(--drawer-motion-duration) var(--ease-exit),
|
|
4663
|
+
overlay var(--drawer-motion-duration) allow-discrete,
|
|
4664
|
+
display var(--drawer-motion-duration) allow-discrete;
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4667
|
+
dialog.drawer[open] {
|
|
4668
|
+
transition:
|
|
4669
|
+
opacity var(--drawer-motion-duration) var(--ease-enter),
|
|
4670
|
+
transform var(--drawer-motion-duration) var(--ease-enter),
|
|
4671
|
+
overlay var(--drawer-motion-duration) allow-discrete,
|
|
4672
|
+
display var(--drawer-motion-duration) allow-discrete;
|
|
4597
4673
|
}
|
|
4598
4674
|
|
|
4599
4675
|
dialog.drawer::backdrop {
|
|
4600
4676
|
transition:
|
|
4601
|
-
opacity var(--duration
|
|
4602
|
-
overlay var(--duration
|
|
4603
|
-
display var(--duration
|
|
4677
|
+
opacity var(--drawer-motion-duration) ease,
|
|
4678
|
+
overlay var(--drawer-motion-duration) allow-discrete,
|
|
4679
|
+
display var(--drawer-motion-duration) allow-discrete;
|
|
4604
4680
|
}
|
|
4605
4681
|
}
|
|
4606
4682
|
|
|
@@ -4636,7 +4712,7 @@ dialog.drawer nav {
|
|
|
4636
4712
|
|
|
4637
4713
|
@media (prefers-reduced-motion: no-preference) {
|
|
4638
4714
|
dialog.drawer.is-static {
|
|
4639
|
-
animation: actual-dialog-static var(--duration-slow)
|
|
4715
|
+
animation: actual-dialog-static var(--duration-slow) ease;
|
|
4640
4716
|
}
|
|
4641
4717
|
}
|
|
4642
4718
|
|
|
@@ -4730,11 +4806,10 @@ dialog.drawer > form > header {
|
|
|
4730
4806
|
box-shadow: var(--shadow-popout);
|
|
4731
4807
|
list-style: none;
|
|
4732
4808
|
opacity: 1;
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
translate var(--duration-fast) var(--ease);
|
|
4809
|
+
/* Anchored flyouts fade in and out; scaling around the center would detach
|
|
4810
|
+
the anchored edge from its trigger on wide panels. The sheet presentation
|
|
4811
|
+
below adds its own translate motion. */
|
|
4812
|
+
transition: opacity var(--duration-fast) ease;
|
|
4738
4813
|
}
|
|
4739
4814
|
|
|
4740
4815
|
.flyout.is-open:not(.is-sheet) {
|
|
@@ -4744,7 +4819,6 @@ dialog.drawer > form > header {
|
|
|
4744
4819
|
@starting-style {
|
|
4745
4820
|
.flyout.is-open {
|
|
4746
4821
|
opacity: 0;
|
|
4747
|
-
scale: 0.98;
|
|
4748
4822
|
}
|
|
4749
4823
|
}
|
|
4750
4824
|
|
|
@@ -4766,22 +4840,24 @@ dialog.drawer > form > header {
|
|
|
4766
4840
|
max(var(--space-30), env(safe-area-inset-bottom));
|
|
4767
4841
|
border-end-start-radius: 0;
|
|
4768
4842
|
border-end-end-radius: 0;
|
|
4843
|
+
/* Sheet motion is a directional slide from the viewport edge; it replaces
|
|
4844
|
+
the base fade-only recipe. */
|
|
4845
|
+
transition:
|
|
4846
|
+
opacity var(--duration-fast) ease,
|
|
4847
|
+
translate var(--duration-fast) ease;
|
|
4769
4848
|
}
|
|
4770
4849
|
|
|
4771
4850
|
.flyout[hidden] {
|
|
4772
4851
|
display: none;
|
|
4773
4852
|
opacity: 0;
|
|
4774
|
-
scale: 0.98;
|
|
4775
4853
|
}
|
|
4776
4854
|
|
|
4777
4855
|
.flyout.is-sheet[hidden] {
|
|
4778
|
-
scale: 1;
|
|
4779
4856
|
translate: 0 var(--space-30);
|
|
4780
4857
|
}
|
|
4781
4858
|
|
|
4782
4859
|
@starting-style {
|
|
4783
4860
|
.flyout.is-sheet.is-open {
|
|
4784
|
-
scale: 1;
|
|
4785
4861
|
translate: 0 var(--space-30);
|
|
4786
4862
|
}
|
|
4787
4863
|
}
|
|
@@ -4789,9 +4865,14 @@ dialog.drawer > form > header {
|
|
|
4789
4865
|
@supports (transition-behavior: allow-discrete) {
|
|
4790
4866
|
.flyout {
|
|
4791
4867
|
transition:
|
|
4792
|
-
opacity var(--duration-fast)
|
|
4793
|
-
|
|
4794
|
-
|
|
4868
|
+
opacity var(--duration-fast) ease,
|
|
4869
|
+
display var(--duration-fast) allow-discrete;
|
|
4870
|
+
}
|
|
4871
|
+
|
|
4872
|
+
.flyout.is-sheet {
|
|
4873
|
+
transition:
|
|
4874
|
+
opacity var(--duration-fast) ease,
|
|
4875
|
+
translate var(--duration-fast) ease,
|
|
4795
4876
|
display var(--duration-fast) allow-discrete;
|
|
4796
4877
|
}
|
|
4797
4878
|
}
|
|
@@ -4996,31 +5077,28 @@ dialog.drawer > form > header {
|
|
|
4996
5077
|
overflow-wrap: anywhere;
|
|
4997
5078
|
pointer-events: auto;
|
|
4998
5079
|
user-select: none;
|
|
5080
|
+
/* Tooltips fade only: the anchor edge, marked by the arrow, must stay put
|
|
5081
|
+
during motion, and a 4% scale was perceptible on small text. Scaling moves
|
|
5082
|
+
the arrow tip away from its trigger on every placement. */
|
|
4999
5083
|
opacity: 1;
|
|
5000
|
-
|
|
5001
|
-
transition:
|
|
5002
|
-
opacity var(--duration-fast) var(--ease),
|
|
5003
|
-
scale var(--duration-fast) var(--ease);
|
|
5084
|
+
transition: opacity var(--duration-fast) ease;
|
|
5004
5085
|
}
|
|
5005
5086
|
|
|
5006
5087
|
.tooltip[hidden] {
|
|
5007
5088
|
display: none;
|
|
5008
5089
|
opacity: 0;
|
|
5009
|
-
scale: 0.96;
|
|
5010
5090
|
}
|
|
5011
5091
|
|
|
5012
5092
|
@starting-style {
|
|
5013
5093
|
.tooltip:not([hidden]) {
|
|
5014
5094
|
opacity: 0;
|
|
5015
|
-
scale: 0.96;
|
|
5016
5095
|
}
|
|
5017
5096
|
}
|
|
5018
5097
|
|
|
5019
5098
|
@supports (transition-behavior: allow-discrete) {
|
|
5020
5099
|
.tooltip {
|
|
5021
5100
|
transition:
|
|
5022
|
-
opacity var(--duration-fast)
|
|
5023
|
-
scale var(--duration-fast) var(--ease),
|
|
5101
|
+
opacity var(--duration-fast) ease,
|
|
5024
5102
|
display var(--duration-fast) allow-discrete;
|
|
5025
5103
|
}
|
|
5026
5104
|
}
|
|
@@ -5361,9 +5439,14 @@ dialog.drawer > form > header {
|
|
|
5361
5439
|
* Consumes the shared --intent/--primary for the value bar and --bar-height
|
|
5362
5440
|
* for thickness. Indeterminate state animates a shimmer using --duration-shimmer.
|
|
5363
5441
|
*
|
|
5442
|
+
* Thickness is a dimension, not a density step: the bar always spans its
|
|
5443
|
+
* container and only gets thinner or thicker, so --bar-height is the API and
|
|
5444
|
+
* .sm/.lg are deliberately not supported.
|
|
5445
|
+
*
|
|
5364
5446
|
* Public hooks:
|
|
5365
5447
|
* --progress-track
|
|
5366
5448
|
* --progress-value
|
|
5449
|
+
* --bar-height
|
|
5367
5450
|
*/
|
|
5368
5451
|
/* Intent boundary — inherited intents do not tint this component.
|
|
5369
5452
|
Local intent classes still win because :where() has zero specificity. */
|
|
@@ -5467,9 +5550,12 @@ dialog.drawer > form > header {
|
|
|
5467
5550
|
/*
|
|
5468
5551
|
* Status bar — singleton floating status area.
|
|
5469
5552
|
*
|
|
5470
|
-
* One element in the HTML, empty by default
|
|
5471
|
-
*
|
|
5472
|
-
*
|
|
5553
|
+
* One element in the HTML, empty by default. .is-open is the visual state, set
|
|
5554
|
+
* by status.js like any other surface: it lands after the message is written
|
|
5555
|
+
* and lifts before the bar is cleared, so the bar leaves in the exact state it
|
|
5556
|
+
* was shown in — same text, same width, same intent color — instead of snapping
|
|
5557
|
+
* to a neutral empty pill mid-exit. Emptying the text is the *end* of the exit,
|
|
5558
|
+
* not its trigger.
|
|
5473
5559
|
*
|
|
5474
5560
|
* Consumes intent like badge or alert. No need for status-bar-specific modifier
|
|
5475
5561
|
* classes — .danger / .success / .warning / .neutral from intents.css drive
|
|
@@ -5483,6 +5569,7 @@ dialog.drawer > form > header {
|
|
|
5483
5569
|
* Internal:
|
|
5484
5570
|
* --status-bg
|
|
5485
5571
|
* --status-fg
|
|
5572
|
+
* --status-viewport-offset (written by status.js while the bar is open)
|
|
5486
5573
|
*/
|
|
5487
5574
|
|
|
5488
5575
|
/* Intent boundary — inherited intents do not tint this component.
|
|
@@ -5497,7 +5584,9 @@ dialog.drawer > form > header {
|
|
|
5497
5584
|
--status-fg: var(--intent-fg, var(--surface));
|
|
5498
5585
|
|
|
5499
5586
|
position: fixed;
|
|
5500
|
-
|
|
5587
|
+
/* Fixed positioning tracks the layout viewport, which the mobile software
|
|
5588
|
+
keyboard covers. status.js writes the occluded band into the offset. */
|
|
5589
|
+
inset-block-end: calc(var(--space-40) + var(--status-viewport-offset, 0px));
|
|
5501
5590
|
inset-inline: var(--space-40);
|
|
5502
5591
|
z-index: var(--z-status);
|
|
5503
5592
|
|
|
@@ -5519,22 +5608,32 @@ dialog.drawer > form > header {
|
|
|
5519
5608
|
color: var(--status-fg);
|
|
5520
5609
|
box-shadow: var(--shadow-popout);
|
|
5521
5610
|
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5611
|
+
/* Closed by default. Opacity, not visibility or display: the bar has to stay
|
|
5612
|
+
in the accessibility tree to work as a live region. */
|
|
5613
|
+
opacity: 0;
|
|
5614
|
+
translate: 0 var(--space-30);
|
|
5525
5615
|
pointer-events: none;
|
|
5526
5616
|
|
|
5617
|
+
/* Exit is shorter than entry so dismissed feedback gets out of the way.
|
|
5618
|
+
background stays a shorthand so --status-bg still accepts gradients;
|
|
5619
|
+
solid colors expose an interpolable computed background-color. The
|
|
5620
|
+
intent color follows the state/interaction `ease`, not the presence
|
|
5621
|
+
curves. */
|
|
5527
5622
|
transition:
|
|
5528
|
-
opacity var(--duration-
|
|
5529
|
-
|
|
5530
|
-
|
|
5623
|
+
opacity var(--duration-fast) var(--ease-exit),
|
|
5624
|
+
translate var(--duration) var(--ease-exit),
|
|
5625
|
+
background-color var(--duration) ease;
|
|
5531
5626
|
}
|
|
5532
5627
|
|
|
5533
|
-
.status-bar
|
|
5534
|
-
opacity:
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5628
|
+
.status-bar.is-open {
|
|
5629
|
+
opacity: 1;
|
|
5630
|
+
translate: 0 0;
|
|
5631
|
+
/* Entry takes a little longer and decelerates, making the message legible
|
|
5632
|
+
before its motion settles. */
|
|
5633
|
+
transition:
|
|
5634
|
+
opacity var(--duration) var(--ease-enter),
|
|
5635
|
+
translate var(--duration-slow) var(--ease-enter),
|
|
5636
|
+
background-color var(--duration) ease;
|
|
5538
5637
|
}
|
|
5539
5638
|
@media print {
|
|
5540
5639
|
.status-bar {
|
|
@@ -6232,31 +6331,57 @@ a.avatar[aria-disabled="true"] {
|
|
|
6232
6331
|
content: none;
|
|
6233
6332
|
}
|
|
6234
6333
|
|
|
6235
|
-
|
|
6334
|
+
/* Three states must be readable without a check glyph: future stays neutral,
|
|
6335
|
+
complete is a filled marker, current is an outlined one. Filled reads as
|
|
6336
|
+
"done", outlined as "you are here" — the distinction survives a numbered
|
|
6337
|
+
stepper that never sets --step-complete-mark. */
|
|
6338
|
+
.steps > .complete {
|
|
6236
6339
|
--step-marker-bg: var(--state-selected);
|
|
6237
6340
|
--step-marker-border: var(--state-selected);
|
|
6238
6341
|
--step-marker-fg: var(--state-selected-fg);
|
|
6342
|
+
--step-line: var(--state-selected);
|
|
6239
6343
|
|
|
6240
6344
|
color: var(--text);
|
|
6241
6345
|
}
|
|
6242
6346
|
|
|
6243
|
-
/*
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6347
|
+
/* Declared after .complete at equal specificity, and it wins on every channel
|
|
6348
|
+
including the connector: the accented line means "already walked", so the
|
|
6349
|
+
segment leaving the current step must stay neutral. The line reaching the
|
|
6350
|
+
current step is owned by the previous step, which is complete. */
|
|
6351
|
+
.steps > [aria-current="step"] {
|
|
6352
|
+
--step-marker-bg: var(--surface);
|
|
6353
|
+
--step-marker-border: var(--state-selected);
|
|
6354
|
+
--step-marker-fg: var(--state-selected);
|
|
6355
|
+
--step-line: var(--border);
|
|
6356
|
+
|
|
6357
|
+
color: var(--text);
|
|
6247
6358
|
}
|
|
6248
6359
|
|
|
6249
|
-
|
|
6250
|
-
|
|
6360
|
+
/* Thicker border is the current affordance in every mode — structural, so it
|
|
6361
|
+
survives forced colors, and it never competes with the outline channel owned
|
|
6362
|
+
by focus. */
|
|
6363
|
+
.steps > [aria-current="step"]::before {
|
|
6364
|
+
border-width: calc(var(--border-width) * 2);
|
|
6251
6365
|
}
|
|
6252
6366
|
|
|
6253
6367
|
/* A finished step may replace its number with a mark (e.g. a check glyph):
|
|
6254
6368
|
--step-complete-mark accepts any content value and falls back to the
|
|
6255
|
-
counter, so existing numbered steppers are unchanged.
|
|
6256
|
-
|
|
6369
|
+
counter, so existing numbered steppers are unchanged. Excluded on the
|
|
6370
|
+
current step so "current wins" holds on the glyph too, not only on color. */
|
|
6371
|
+
.steps > .complete:not([aria-current="step"])::before {
|
|
6257
6372
|
content: var(--step-complete-mark, counter(actual-step));
|
|
6258
6373
|
}
|
|
6259
6374
|
|
|
6375
|
+
/* Forced colors drop the accent fill, which would leave complete and future
|
|
6376
|
+
markers identical — current keeps its thicker ring, complete needs a system
|
|
6377
|
+
color to stay filled. Same exclusion, for the same reason. */
|
|
6378
|
+
@media (forced-colors: active) {
|
|
6379
|
+
.steps > .complete:not([aria-current="step"])::before {
|
|
6380
|
+
background: Highlight;
|
|
6381
|
+
color: HighlightText;
|
|
6382
|
+
}
|
|
6383
|
+
}
|
|
6384
|
+
|
|
6260
6385
|
|
|
6261
6386
|
/* Navigation */
|
|
6262
6387
|
/*
|
|
@@ -6658,6 +6783,34 @@ a.avatar[aria-disabled="true"] {
|
|
|
6658
6783
|
|
|
6659
6784
|
|
|
6660
6785
|
/* Data */
|
|
6786
|
+
/*
|
|
6787
|
+
* Data list — term/value pairs for the properties of a single object.
|
|
6788
|
+
*
|
|
6789
|
+
* Expects alternating <dt>/<dd> children: one term, one value per property.
|
|
6790
|
+
* A plain <dl> handles richer relationships (several terms or descriptions)
|
|
6791
|
+
* and stays untouched by this component.
|
|
6792
|
+
*
|
|
6793
|
+
* Why margin resets: neutralizes .prose list margins if .data-list appears
|
|
6794
|
+
* inside an authored rich-text scope; the grid owns row/column rhythm.
|
|
6795
|
+
*/
|
|
6796
|
+
.data-list {
|
|
6797
|
+
display: grid;
|
|
6798
|
+
grid-template-columns: max-content minmax(0, 1fr);
|
|
6799
|
+
align-items: baseline;
|
|
6800
|
+
gap: var(--space-20) var(--space-40);
|
|
6801
|
+
}
|
|
6802
|
+
|
|
6803
|
+
.data-list > dt {
|
|
6804
|
+
min-inline-size: 0;
|
|
6805
|
+
margin-block-start: 0;
|
|
6806
|
+
font-weight: var(--font-weight-strong);
|
|
6807
|
+
}
|
|
6808
|
+
|
|
6809
|
+
.data-list > dd {
|
|
6810
|
+
min-inline-size: 0;
|
|
6811
|
+
margin: 0;
|
|
6812
|
+
}
|
|
6813
|
+
|
|
6661
6814
|
/*
|
|
6662
6815
|
* Application list — repeated rows with optional leading and trailing regions.
|
|
6663
6816
|
* Content determines the number of lines; the component only owns the row
|
|
@@ -6816,10 +6969,18 @@ a.list-item:hover {
|
|
|
6816
6969
|
}
|
|
6817
6970
|
|
|
6818
6971
|
/*
|
|
6819
|
-
* Meter — native
|
|
6972
|
+
* Meter — native and segmented gauges for known-range values.
|
|
6820
6973
|
*
|
|
6821
6974
|
* Maps the three standard meter zones (optimum / suboptimum / even-less-good)
|
|
6822
6975
|
* to the shared success / warning / danger intent colors.
|
|
6976
|
+
*
|
|
6977
|
+
* Thickness is a dimension, not a density step: the bar always spans its
|
|
6978
|
+
* container and only gets thinner or thicker, so --bar-height is the API and
|
|
6979
|
+
* .sm/.lg are deliberately not supported.
|
|
6980
|
+
*
|
|
6981
|
+
* Public hooks:
|
|
6982
|
+
* --meter-value
|
|
6983
|
+
* --bar-height
|
|
6823
6984
|
*/
|
|
6824
6985
|
|
|
6825
6986
|
.meter {
|
|
@@ -6834,6 +6995,25 @@ a.list-item:hover {
|
|
|
6834
6995
|
background: var(--surface-subtle);
|
|
6835
6996
|
}
|
|
6836
6997
|
|
|
6998
|
+
/* A non-native meter is a weighted flex container. The element type keeps the
|
|
6999
|
+
native <meter> API and the composed segmented API distinct without another
|
|
7000
|
+
public variant class. */
|
|
7001
|
+
.meter:not(meter) {
|
|
7002
|
+
--intent: initial;
|
|
7003
|
+
|
|
7004
|
+
display: flex;
|
|
7005
|
+
}
|
|
7006
|
+
|
|
7007
|
+
.meter:not(meter) > * {
|
|
7008
|
+
flex: var(--meter-value, 1) 1 0;
|
|
7009
|
+
min-inline-size: 0;
|
|
7010
|
+
background: var(--intent);
|
|
7011
|
+
}
|
|
7012
|
+
|
|
7013
|
+
.meter:not(meter) > * + * {
|
|
7014
|
+
border-inline-start: var(--border-width) solid var(--surface);
|
|
7015
|
+
}
|
|
7016
|
+
|
|
6837
7017
|
.meter::-webkit-meter-bar {
|
|
6838
7018
|
-webkit-appearance: none;
|
|
6839
7019
|
block-size: var(--bar-height);
|
|
@@ -7112,6 +7292,22 @@ a.list-item:hover {
|
|
|
7112
7292
|
border: 0;
|
|
7113
7293
|
}
|
|
7114
7294
|
|
|
7295
|
+
/* Enlarge a small control's touch target on touch-primary devices without
|
|
7296
|
+
growing the visual. Opt-in — apply to genuinely small targets only. The
|
|
7297
|
+
::after exists only under (pointer: coarse), so on fine pointers the class
|
|
7298
|
+
is fully neutral. */
|
|
7299
|
+
@media (pointer: coarse) {
|
|
7300
|
+
.touch-target {
|
|
7301
|
+
position: relative;
|
|
7302
|
+
}
|
|
7303
|
+
|
|
7304
|
+
.touch-target::after {
|
|
7305
|
+
content: "";
|
|
7306
|
+
position: absolute;
|
|
7307
|
+
inset: calc(var(--space-20) * -1);
|
|
7308
|
+
}
|
|
7309
|
+
}
|
|
7310
|
+
|
|
7115
7311
|
.overflow-auto {
|
|
7116
7312
|
overflow: auto;
|
|
7117
7313
|
}
|