actual-css 0.1.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 +11 -0
- package/LICENSE +21 -0
- package/README.md +166 -0
- package/dist/actual.css +4929 -0
- package/dist/actual.js +3 -0
- package/dist/actual.js.map +31 -0
- package/dist/actual.min.css +1 -0
- package/docs/README.md +26 -0
- package/docs/components.md +860 -0
- package/docs/design-notes/accessibility-decisions.md +32 -0
- package/docs/design-notes/browser-support.md +93 -0
- package/docs/design-notes/cascade-layer.md +52 -0
- package/docs/design-notes/css-anchor.md +33 -0
- package/docs/design-notes/naming.md +37 -0
- package/docs/design-notes/previous-work.md +5 -0
- package/docs/design-notes/references.md +324 -0
- package/docs/forms.md +1265 -0
- package/docs/javascript.md +426 -0
- package/docs/layout.md +480 -0
- package/docs/mental-model.md +73 -0
- package/docs/patterns.md +415 -0
- package/docs/reserved.md +7 -0
- package/docs/tokens.md +455 -0
- package/docs/typography.md +159 -0
- package/docs/ui.md +937 -0
- package/docs/utilities.md +384 -0
- package/llms.txt +17 -0
- package/package.json +101 -0
- package/src/css/actual.css +17 -0
- package/src/css/actual.full.css +2 -0
- package/src/css/actual.layer.css +3 -0
- package/src/css/base.css +70 -0
- package/src/css/components/accordion.css +97 -0
- package/src/css/components/actions.css +21 -0
- package/src/css/components/alert.css +137 -0
- package/src/css/components/avatar.css +199 -0
- package/src/css/components/badge.css +143 -0
- package/src/css/components/breadcrumb.css +56 -0
- package/src/css/components/busy.css +44 -0
- package/src/css/components/button.css +216 -0
- package/src/css/components/card.css +140 -0
- package/src/css/components/drawer.css +122 -0
- package/src/css/components/flyout.css +243 -0
- package/src/css/components/index.css +41 -0
- package/src/css/components/join.css +106 -0
- package/src/css/components/key.css +25 -0
- package/src/css/components/meter.css +81 -0
- package/src/css/components/modal.css +162 -0
- package/src/css/components/navbar.css +98 -0
- package/src/css/components/overline.css +49 -0
- package/src/css/components/pagination.css +30 -0
- package/src/css/components/progress.css +126 -0
- package/src/css/components/scrollspy.css +27 -0
- package/src/css/components/skeleton.css +67 -0
- package/src/css/components/spinner.css +60 -0
- package/src/css/components/status-bar.css +82 -0
- package/src/css/components/surface.css +48 -0
- package/src/css/components/tab.css +128 -0
- package/src/css/components/table.css +64 -0
- package/src/css/components/tooltip.css +107 -0
- package/src/css/dialog-fallback.css +56 -0
- package/src/css/focus.css +13 -0
- package/src/css/forms/choice-card.css +158 -0
- package/src/css/forms/choice.css +196 -0
- package/src/css/forms/control.css +106 -0
- package/src/css/forms/custom-select.css +93 -0
- package/src/css/forms/form-actions.css +43 -0
- package/src/css/forms/form.css +57 -0
- package/src/css/forms/index.css +15 -0
- package/src/css/forms/input-icon.css +36 -0
- package/src/css/forms/native.css +68 -0
- package/src/css/forms/select.css +36 -0
- package/src/css/forms/switch.css +127 -0
- package/src/css/forms/validation.css +63 -0
- package/src/css/grid.css +95 -0
- package/src/css/intents.css +33 -0
- package/src/css/layout.css +80 -0
- package/src/css/optional/index.css +5 -0
- package/src/css/optional/layout-extra.css +55 -0
- package/src/css/optional/scroll-snap.css +51 -0
- package/src/css/optional/scroller.css +51 -0
- package/src/css/optional/typography-fluid.css +48 -0
- package/src/css/optional/utilities-extra.css +289 -0
- package/src/css/print.css +47 -0
- package/src/css/prose.css +187 -0
- package/src/css/reset.css +56 -0
- package/src/css/theme.css +186 -0
- package/src/css/themes/corporate.css +60 -0
- package/src/css/themes/cyberpunk.css +60 -0
- package/src/css/themes/dark.css +32 -0
- package/src/css/themes/dim.css +33 -0
- package/src/css/themes/edge.css +143 -0
- package/src/css/themes/forest.css +65 -0
- package/src/css/themes/gradient.css +97 -0
- package/src/css/themes/index.css +43 -0
- package/src/css/themes/lavender.css +66 -0
- package/src/css/themes/mono.css +60 -0
- package/src/css/themes/neon.css +66 -0
- package/src/css/themes/ocean.css +60 -0
- package/src/css/themes/petrol.css +64 -0
- package/src/css/themes/spruce.css +64 -0
- package/src/css/themes/square.css +68 -0
- package/src/css/themes/sunset.css +66 -0
- package/src/css/tokens.css +122 -0
- package/src/css/utilities.css +162 -0
- package/src/css/variants.css +118 -0
- package/src/js/command.js +165 -0
- package/src/js/context-menu.js +291 -0
- package/src/js/dialog-fallback.js +163 -0
- package/src/js/dialog.js +503 -0
- package/src/js/enhance.js +208 -0
- package/src/js/events.js +22 -0
- package/src/js/filter.js +122 -0
- package/src/js/floating.js +462 -0
- package/src/js/flyout.js +187 -0
- package/src/js/focus.js +35 -0
- package/src/js/index.js +26 -0
- package/src/js/input.js +47 -0
- package/src/js/keys.js +30 -0
- package/src/js/mask.js +184 -0
- package/src/js/menu.js +88 -0
- package/src/js/password.js +98 -0
- package/src/js/scrollspy.js +121 -0
- package/src/js/selectors.js +59 -0
- package/src/js/status.js +158 -0
- package/src/js/surface.js +358 -0
- package/src/js/tab.js +173 -0
- package/src/js/tooltip.js +374 -0
- package/src/js/validation.js +419 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Progress — native progress bar with theme-aware track and value.
|
|
3
|
+
*
|
|
4
|
+
* Consumes the shared --intent/--primary for the value bar and --bar-height
|
|
5
|
+
* for thickness. Indeterminate state animates a shimmer using --duration-shimmer.
|
|
6
|
+
*/
|
|
7
|
+
/* Intent boundary — inherited intents do not tint this component.
|
|
8
|
+
Local intent classes still win because :where() has zero specificity. */
|
|
9
|
+
:where(.progress) {
|
|
10
|
+
/* @sync intent-boundary */
|
|
11
|
+
--intent: initial;
|
|
12
|
+
--intent-fg: initial;
|
|
13
|
+
--ui-bg: initial;
|
|
14
|
+
--ui-fg: initial;
|
|
15
|
+
--ui-border: initial;
|
|
16
|
+
--ui-hover-bg: initial;
|
|
17
|
+
/* @sync intent-boundary */
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.progress {
|
|
21
|
+
--progress-track: var(--surface-subtle);
|
|
22
|
+
--progress-value: var(--intent, var(--primary));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.progress {
|
|
26
|
+
appearance: none;
|
|
27
|
+
-webkit-appearance: none;
|
|
28
|
+
display: block;
|
|
29
|
+
inline-size: 100%;
|
|
30
|
+
block-size: var(--bar-height);
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
border: 0;
|
|
33
|
+
border-radius: var(--radius-full);
|
|
34
|
+
background: var(--progress-track);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.progress::-webkit-progress-bar {
|
|
38
|
+
block-size: var(--bar-height);
|
|
39
|
+
border-radius: var(--radius-full);
|
|
40
|
+
background: var(--progress-track);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.progress::-webkit-progress-value {
|
|
44
|
+
block-size: var(--bar-height);
|
|
45
|
+
border-radius: var(--radius-full);
|
|
46
|
+
background: var(--progress-value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.progress::-moz-progress-bar {
|
|
50
|
+
block-size: var(--bar-height);
|
|
51
|
+
border-radius: var(--radius-full);
|
|
52
|
+
background: var(--progress-value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Indeterminate progress */
|
|
56
|
+
.progress:indeterminate {
|
|
57
|
+
background:
|
|
58
|
+
linear-gradient(to right, var(--progress-value) 30%, var(--progress-track) 30%) top left / 150%
|
|
59
|
+
150% no-repeat,
|
|
60
|
+
var(--progress-track);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.progress:indeterminate::-webkit-progress-bar {
|
|
64
|
+
background: transparent;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.progress:indeterminate::-webkit-progress-value {
|
|
68
|
+
background: transparent;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.progress:indeterminate::-moz-progress-bar {
|
|
72
|
+
background: transparent;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
76
|
+
.progress:indeterminate {
|
|
77
|
+
animation: actual-progress-indeterminate var(--duration-shimmer) ease-in-out infinite;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
:where([dir="rtl"] .progress:indeterminate) {
|
|
81
|
+
animation-direction: reverse;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@keyframes actual-progress-indeterminate {
|
|
86
|
+
0% {
|
|
87
|
+
background-position: 200% 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
20% {
|
|
91
|
+
background-position: 100% 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
80% {
|
|
95
|
+
background-position: -100% 0;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
100% {
|
|
99
|
+
background-position: -200% 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@media (forced-colors: active) {
|
|
104
|
+
.progress {
|
|
105
|
+
border: var(--border-width) solid ButtonText;
|
|
106
|
+
background: Canvas;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.progress::-webkit-progress-bar {
|
|
110
|
+
background: Canvas;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.progress::-webkit-progress-value {
|
|
114
|
+
background: Highlight;
|
|
115
|
+
forced-color-adjust: none;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.progress::-moz-progress-bar {
|
|
119
|
+
background: Highlight;
|
|
120
|
+
forced-color-adjust: none;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.progress:indeterminate {
|
|
124
|
+
background: Canvas;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Scrollspy — behavior hook for navigation that marks the active section
|
|
3
|
+
* while the page scrolls.
|
|
4
|
+
*
|
|
5
|
+
* Does not add visual styles by itself. scrollspy.js watches
|
|
6
|
+
* <nav class="scrollspy">
|
|
7
|
+
* containing <a href="#section"> links and toggles aria-current="location" on
|
|
8
|
+
* the link whose target is in view. Pair with .nav-list and .nav-link, or style
|
|
9
|
+
* [aria-current] yourself.
|
|
10
|
+
*
|
|
11
|
+
* Progressive enhancement: on browsers that support :target-current,
|
|
12
|
+
* this file enables the native target group and marks the active link.
|
|
13
|
+
*
|
|
14
|
+
* Falls back gracefully: links still work when IntersectionObserver or
|
|
15
|
+
* :target-current is unavailable.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
@supports selector(.scrollspy a:target-current) {
|
|
19
|
+
.scrollspy {
|
|
20
|
+
scroll-target-group: auto;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.scrollspy a:target-current {
|
|
24
|
+
color: var(--text);
|
|
25
|
+
font-weight: var(--font-weight-medium);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Skeleton placeholders for loading states.
|
|
3
|
+
*
|
|
4
|
+
* Shows approximate loading structure without implying real content hierarchy.
|
|
5
|
+
* Geometry, animation, and color stay theme-aware.
|
|
6
|
+
*/
|
|
7
|
+
.skeleton {
|
|
8
|
+
--skeleton-size: 1rem;
|
|
9
|
+
--skeleton-width: 100%;
|
|
10
|
+
--skeleton-radius: var(--radius);
|
|
11
|
+
--skeleton-track: var(--surface-subtle);
|
|
12
|
+
--skeleton-highlight: var(--surface-raised);
|
|
13
|
+
|
|
14
|
+
display: block;
|
|
15
|
+
inline-size: var(--skeleton-width);
|
|
16
|
+
max-inline-size: 100%;
|
|
17
|
+
block-size: var(--skeleton-size);
|
|
18
|
+
border-radius: var(--skeleton-radius);
|
|
19
|
+
background:
|
|
20
|
+
linear-gradient(90deg, var(--skeleton-track), var(--skeleton-highlight), var(--skeleton-track))
|
|
21
|
+
0 0 / 200% 100%;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
25
|
+
.skeleton {
|
|
26
|
+
animation: actual-skeleton var(--duration-shimmer) ease-in-out infinite;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.skeleton[data-shape="text"] {
|
|
31
|
+
--skeleton-size: 0.85rem;
|
|
32
|
+
--skeleton-width: 32rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.skeleton[data-shape="title"] {
|
|
36
|
+
--skeleton-size: 1.4rem;
|
|
37
|
+
--skeleton-width: 18rem;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.skeleton[data-shape="avatar"] {
|
|
41
|
+
--skeleton-size: var(--avatar-size, 2.25rem);
|
|
42
|
+
--skeleton-width: var(--skeleton-size);
|
|
43
|
+
--skeleton-radius: var(--radius-full);
|
|
44
|
+
|
|
45
|
+
flex: 0 0 auto;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.skeleton[data-shape="box"] {
|
|
49
|
+
--skeleton-size: 8rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@media (forced-colors: active) {
|
|
53
|
+
.skeleton {
|
|
54
|
+
border: var(--border-width) solid ButtonText;
|
|
55
|
+
background: GrayText;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@keyframes actual-skeleton {
|
|
60
|
+
from {
|
|
61
|
+
background-position: 200% 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
to {
|
|
65
|
+
background-position: -200% 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Spinner — compact loading feedback.
|
|
3
|
+
*
|
|
4
|
+
* Uses currentColor so it adapts to buttons, alerts, badges, and text. The
|
|
5
|
+
* [aria-busy] overlay composition lives in components/busy.css.
|
|
6
|
+
*/
|
|
7
|
+
/* Intent boundary — inherited intents do not tint this component.
|
|
8
|
+
Local intent classes still win because :where() has zero specificity. */
|
|
9
|
+
:where(.spinner) {
|
|
10
|
+
/* @sync intent-boundary */
|
|
11
|
+
--intent: initial;
|
|
12
|
+
--intent-fg: initial;
|
|
13
|
+
--ui-bg: initial;
|
|
14
|
+
--ui-fg: initial;
|
|
15
|
+
--ui-border: initial;
|
|
16
|
+
--ui-hover-bg: initial;
|
|
17
|
+
/* @sync intent-boundary */
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.spinner {
|
|
21
|
+
--spinner-size: 1.5rem;
|
|
22
|
+
--spinner-width: 2px;
|
|
23
|
+
--spinner-track: currentColor;
|
|
24
|
+
--spinner-value: transparent;
|
|
25
|
+
|
|
26
|
+
color: var(--intent, currentColor);
|
|
27
|
+
display: inline-block;
|
|
28
|
+
flex-shrink: 0;
|
|
29
|
+
inline-size: var(--spinner-size);
|
|
30
|
+
block-size: var(--spinner-size);
|
|
31
|
+
border: var(--spinner-width) solid var(--spinner-track);
|
|
32
|
+
border-inline-end-color: var(--spinner-value);
|
|
33
|
+
border-radius: var(--radius-full);
|
|
34
|
+
opacity: 0.85;
|
|
35
|
+
animation: actual-spin var(--duration-spin) linear infinite;
|
|
36
|
+
vertical-align: text-bottom;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@supports (color: color-mix(in oklch, red, white)) {
|
|
40
|
+
.spinner {
|
|
41
|
+
--spinner-track: color-mix(in oklch, currentColor, transparent 70%);
|
|
42
|
+
--spinner-value: currentColor;
|
|
43
|
+
opacity: 1;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.spinner.sm {
|
|
48
|
+
--spinner-size: 1rem;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.spinner.lg {
|
|
52
|
+
--spinner-size: 3rem;
|
|
53
|
+
--spinner-width: 3px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@keyframes actual-spin {
|
|
57
|
+
to {
|
|
58
|
+
transform: rotate(360deg);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Status bar — singleton floating status area.
|
|
3
|
+
*
|
|
4
|
+
* One element in the HTML, empty by default, hidden when :empty but kept in the
|
|
5
|
+
* accessibility tree so it stays a reliable live region. JavaScript only sets
|
|
6
|
+
* text content; the visual shows and hides with the content.
|
|
7
|
+
*
|
|
8
|
+
* Consumes intent like badge or alert. No need for status-bar-specific modifier
|
|
9
|
+
* classes — .danger / .success / .warning / .neutral from intents.css drive
|
|
10
|
+
* the coloring via --intent / --intent-fg. status.js applies these as plain
|
|
11
|
+
* classes on the target; it does not know their names or that they exist.
|
|
12
|
+
*
|
|
13
|
+
* Public API: .status-bar + [data-status], both required — status.js reads
|
|
14
|
+
* the class name from js/selectors.js rather than hardcoding it, but still
|
|
15
|
+
* needs it to scope its document-wide lookup away from unrelated elements
|
|
16
|
+
* that carry their own generic `data-status`.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/* Intent boundary — inherited intents do not tint this component.
|
|
20
|
+
Local intent classes still win because :where() has zero specificity. */
|
|
21
|
+
:where(.status-bar) {
|
|
22
|
+
/* @sync intent-boundary */
|
|
23
|
+
--intent: initial;
|
|
24
|
+
--intent-fg: initial;
|
|
25
|
+
--ui-bg: initial;
|
|
26
|
+
--ui-fg: initial;
|
|
27
|
+
--ui-border: initial;
|
|
28
|
+
--ui-hover-bg: initial;
|
|
29
|
+
/* @sync intent-boundary */
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.status-bar {
|
|
33
|
+
--status-bg: var(--intent, var(--text));
|
|
34
|
+
--status-fg: var(--intent-fg, var(--surface));
|
|
35
|
+
|
|
36
|
+
position: fixed;
|
|
37
|
+
inset-block-end: var(--space-4);
|
|
38
|
+
inset-inline: var(--space-4);
|
|
39
|
+
z-index: var(--z-status, 60);
|
|
40
|
+
|
|
41
|
+
display: inline-flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: center;
|
|
44
|
+
gap: var(--space-2);
|
|
45
|
+
|
|
46
|
+
inline-size: fit-content;
|
|
47
|
+
max-inline-size: min(calc(100vw - var(--space-6)), 32rem);
|
|
48
|
+
margin-inline: auto;
|
|
49
|
+
overflow-wrap: anywhere;
|
|
50
|
+
|
|
51
|
+
padding-block: var(--space-2);
|
|
52
|
+
padding-inline: var(--space-3);
|
|
53
|
+
|
|
54
|
+
border-radius: var(--radius-full);
|
|
55
|
+
background: var(--status-bg);
|
|
56
|
+
color: var(--status-fg);
|
|
57
|
+
box-shadow: var(--shadow-popout);
|
|
58
|
+
|
|
59
|
+
opacity: 1;
|
|
60
|
+
scale: 1;
|
|
61
|
+
translate: 0 0;
|
|
62
|
+
pointer-events: none;
|
|
63
|
+
|
|
64
|
+
transition:
|
|
65
|
+
opacity var(--duration-slow) var(--ease, ease),
|
|
66
|
+
scale var(--duration-slow) var(--ease, ease),
|
|
67
|
+
translate var(--duration-slow) var(--ease, ease);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.status-bar:empty {
|
|
71
|
+
opacity: 0;
|
|
72
|
+
scale: 0.96;
|
|
73
|
+
translate: 0 var(--space-2);
|
|
74
|
+
pointer-events: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@media (forced-colors: active) {
|
|
78
|
+
.status-bar {
|
|
79
|
+
border: var(--border-width) solid ButtonText;
|
|
80
|
+
box-shadow: none;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Surface — shared modal scrim and backdrop for flyout and drawer.
|
|
3
|
+
*
|
|
4
|
+
* Drawn by .drawer::backdrop (native dialog top-layer) and .surface-backdrop
|
|
5
|
+
* (custom fixed div for flyout sheets on coarse pointers). The native
|
|
6
|
+
* .modal::backdrop uses the same fill and animates opacity from 0 to 1
|
|
7
|
+
* (modal.css), so the scrim strength stays consistent across the dialog
|
|
8
|
+
* family.
|
|
9
|
+
*
|
|
10
|
+
* .surface-backdrop, .is-sheet, and .is-open are runtime markers set by
|
|
11
|
+
* surface.js. Authors opt in via [data-flyout-mobile="sheet|auto|none|anchored"]
|
|
12
|
+
* — the JS resolves "auto" into .is-sheet at run time.
|
|
13
|
+
*/
|
|
14
|
+
/* Custom backdrop for overlays that do not use the native dialog top-layer.
|
|
15
|
+
* Its z-index sits just below the flyout it accompanies. */
|
|
16
|
+
.surface-backdrop {
|
|
17
|
+
position: fixed;
|
|
18
|
+
inset: 0;
|
|
19
|
+
z-index: calc(var(--z-menu) - 1);
|
|
20
|
+
background: var(--backdrop-fill);
|
|
21
|
+
opacity: 1;
|
|
22
|
+
transition: opacity var(--duration) var(--ease, ease);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.surface-backdrop[hidden] {
|
|
26
|
+
display: none;
|
|
27
|
+
opacity: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@starting-style {
|
|
31
|
+
.surface-backdrop:not([hidden]) {
|
|
32
|
+
opacity: 0;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@supports (transition-behavior: allow-discrete) {
|
|
37
|
+
.surface-backdrop {
|
|
38
|
+
transition:
|
|
39
|
+
opacity var(--duration) var(--ease, ease),
|
|
40
|
+
display var(--duration) allow-discrete;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@media (forced-colors: active) {
|
|
45
|
+
.surface-backdrop {
|
|
46
|
+
background: Canvas;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tabs — in-place panel switcher with real tab semantics.
|
|
3
|
+
*
|
|
4
|
+
* JavaScript owns roving tabindex, aria-selected, panel visibility,
|
|
5
|
+
* and arrow-key navigation. CSS owns the tab strip appearance and
|
|
6
|
+
* active indicator.
|
|
7
|
+
*/
|
|
8
|
+
/* Intent boundary — inherited intents do not tint this component.
|
|
9
|
+
Local intent classes still win because :where() has zero specificity. */
|
|
10
|
+
:where(.tab) {
|
|
11
|
+
/* @sync intent-boundary */
|
|
12
|
+
--intent: initial;
|
|
13
|
+
--intent-fg: initial;
|
|
14
|
+
--ui-bg: initial;
|
|
15
|
+
--ui-fg: initial;
|
|
16
|
+
--ui-border: initial;
|
|
17
|
+
--ui-hover-bg: initial;
|
|
18
|
+
/* @sync intent-boundary */
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.tabs {
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-wrap: wrap;
|
|
24
|
+
gap: var(--space-1);
|
|
25
|
+
margin: 0;
|
|
26
|
+
padding: 0;
|
|
27
|
+
border-block-end: var(--border-width) solid var(--border);
|
|
28
|
+
list-style: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.tabs[aria-orientation="vertical"] {
|
|
32
|
+
display: grid;
|
|
33
|
+
align-content: start;
|
|
34
|
+
justify-items: stretch;
|
|
35
|
+
border-block-end: 0;
|
|
36
|
+
border-inline-end: var(--border-width) solid var(--border);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.tab {
|
|
40
|
+
display: inline-flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
min-block-size: var(--control-size);
|
|
43
|
+
padding-inline: var(--space-3);
|
|
44
|
+
border: 0;
|
|
45
|
+
border-block-end: 2px solid transparent;
|
|
46
|
+
border-radius: 0;
|
|
47
|
+
background: transparent;
|
|
48
|
+
color: var(--text-muted);
|
|
49
|
+
font: inherit;
|
|
50
|
+
font-weight: var(--font-weight-strong);
|
|
51
|
+
text-decoration: none;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.tabs[aria-orientation="vertical"] .tab {
|
|
56
|
+
justify-content: flex-start;
|
|
57
|
+
border-block-end: 0;
|
|
58
|
+
border-inline-end: 2px solid transparent;
|
|
59
|
+
padding-inline-end: var(--space-4);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.tab:is(:disabled, [aria-disabled="true"]) {
|
|
63
|
+
cursor: not-allowed;
|
|
64
|
+
opacity: var(--disabled-opacity);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@media (hover: hover) {
|
|
68
|
+
.tab:hover:not(:where(:disabled, [aria-disabled="true"])) {
|
|
69
|
+
color: var(--text);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.tab:focus-visible {
|
|
74
|
+
outline: var(--focus-outline);
|
|
75
|
+
outline-offset: -2px;
|
|
76
|
+
border-radius: var(--radius-sm) var(--radius-sm) 0 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.tab[aria-selected="true"],
|
|
80
|
+
.tab[aria-current]:not([aria-current="false"]),
|
|
81
|
+
.tab[aria-pressed="true"] {
|
|
82
|
+
border-block-end-color: var(--intent, var(--primary));
|
|
83
|
+
color: var(--intent, var(--primary));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.tabs[aria-orientation="vertical"] .tab[aria-selected="true"],
|
|
87
|
+
.tabs[aria-orientation="vertical"] .tab[aria-current]:not([aria-current="false"]),
|
|
88
|
+
.tabs[aria-orientation="vertical"] .tab[aria-pressed="true"] {
|
|
89
|
+
border-block-end-color: transparent;
|
|
90
|
+
border-inline-end-color: var(--intent, var(--primary));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@media (forced-colors: active) {
|
|
94
|
+
.tabs {
|
|
95
|
+
border-block-end-color: ButtonText;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.tabs[aria-orientation="vertical"] {
|
|
99
|
+
border-block-end-color: transparent;
|
|
100
|
+
border-inline-end-color: ButtonText;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.tab {
|
|
104
|
+
color: ButtonText;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@media (hover: hover) {
|
|
108
|
+
.tab:hover:not(:where(:disabled, [aria-disabled="true"])) {
|
|
109
|
+
color: ButtonText;
|
|
110
|
+
text-decoration: underline;
|
|
111
|
+
text-underline-offset: 0.18em;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.tab[aria-selected="true"],
|
|
116
|
+
.tab[aria-current]:not([aria-current="false"]),
|
|
117
|
+
.tab[aria-pressed="true"] {
|
|
118
|
+
border-block-end-color: Highlight;
|
|
119
|
+
color: Highlight;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.tabs[aria-orientation="vertical"] .tab[aria-selected="true"],
|
|
123
|
+
.tabs[aria-orientation="vertical"] .tab[aria-current]:not([aria-current="false"]),
|
|
124
|
+
.tabs[aria-orientation="vertical"] .tab[aria-pressed="true"] {
|
|
125
|
+
border-block-end-color: transparent;
|
|
126
|
+
border-inline-end-color: Highlight;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Table — structured tabular data.
|
|
3
|
+
*
|
|
4
|
+
* .table-wrap provides the scroll container and outer chrome; .table owns row
|
|
5
|
+
* and cell rules. Tokens are sourced from the shared scale.
|
|
6
|
+
*/
|
|
7
|
+
.table-wrap {
|
|
8
|
+
inline-size: 100%;
|
|
9
|
+
max-inline-size: 100%;
|
|
10
|
+
min-inline-size: 0;
|
|
11
|
+
overflow-x: auto;
|
|
12
|
+
border: var(--border-width) solid var(--border);
|
|
13
|
+
border-radius: var(--radius-lg);
|
|
14
|
+
background: var(--surface-raised);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.table {
|
|
18
|
+
--table-min: 100%;
|
|
19
|
+
--table-cell-pad: var(--space-3);
|
|
20
|
+
|
|
21
|
+
inline-size: max(var(--table-min), 100%);
|
|
22
|
+
border-collapse: collapse;
|
|
23
|
+
background: transparent;
|
|
24
|
+
color: var(--text);
|
|
25
|
+
font-size: var(--font-size-md);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.table caption {
|
|
29
|
+
padding: var(--table-cell-pad);
|
|
30
|
+
color: var(--text-muted);
|
|
31
|
+
text-align: var(--text-align, start);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.table th,
|
|
35
|
+
.table td {
|
|
36
|
+
padding: var(--table-cell-pad);
|
|
37
|
+
border-block-end: var(--border-width) solid var(--border);
|
|
38
|
+
text-align: var(--text-align, start);
|
|
39
|
+
vertical-align: baseline;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.table thead th {
|
|
43
|
+
vertical-align: bottom;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.table th {
|
|
47
|
+
color: var(--text-muted);
|
|
48
|
+
font-weight: var(--font-weight-strong);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.table thead {
|
|
52
|
+
background: var(--surface-subtle);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@media (hover: hover) {
|
|
56
|
+
.table tbody tr:hover {
|
|
57
|
+
background-color: var(--hover-overlay);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.table > tr:last-child > *,
|
|
62
|
+
.table > :last-child > tr:last-child > * {
|
|
63
|
+
border-block-end: 0;
|
|
64
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tooltip — supplemental label overlaid near a trigger.
|
|
3
|
+
*
|
|
4
|
+
* Position, placement, and arrow position are managed by JavaScript
|
|
5
|
+
* via position: fixed, left, top, data-placement, and --arrow-x.
|
|
6
|
+
* Visibility is managed with hidden; CSS owns entry and exit animation.
|
|
7
|
+
*/
|
|
8
|
+
.tooltip {
|
|
9
|
+
--tooltip-bg: var(--surface-solid);
|
|
10
|
+
--tooltip-fg: var(--surface);
|
|
11
|
+
--tooltip-arrow-size: 5px;
|
|
12
|
+
|
|
13
|
+
position: fixed;
|
|
14
|
+
z-index: var(--z-tooltip);
|
|
15
|
+
max-inline-size: min(24rem, calc(var(--viewport-inline) - 2rem));
|
|
16
|
+
padding: 0.25em 0.6em;
|
|
17
|
+
border-radius: var(--radius-sm);
|
|
18
|
+
background: var(--tooltip-bg);
|
|
19
|
+
color: var(--tooltip-fg);
|
|
20
|
+
font-size: var(--font-size-xs);
|
|
21
|
+
line-height: var(--line-height-tight);
|
|
22
|
+
overflow-wrap: anywhere;
|
|
23
|
+
pointer-events: auto;
|
|
24
|
+
user-select: none;
|
|
25
|
+
opacity: 1;
|
|
26
|
+
scale: 1;
|
|
27
|
+
transition:
|
|
28
|
+
opacity var(--duration-fast, var(--duration)) var(--ease, ease),
|
|
29
|
+
scale var(--duration-fast, var(--duration)) var(--ease, ease);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.tooltip[hidden] {
|
|
33
|
+
display: none;
|
|
34
|
+
opacity: 0;
|
|
35
|
+
scale: 0.96;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@starting-style {
|
|
39
|
+
.tooltip:not([hidden]) {
|
|
40
|
+
opacity: 0;
|
|
41
|
+
scale: 0.96;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@supports (transition-behavior: allow-discrete) {
|
|
46
|
+
.tooltip {
|
|
47
|
+
transition:
|
|
48
|
+
opacity var(--duration-fast, var(--duration)) var(--ease, ease),
|
|
49
|
+
scale var(--duration-fast, var(--duration)) var(--ease, ease),
|
|
50
|
+
display var(--duration-fast, var(--duration)) allow-discrete;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* ── Arrow — clipped triangle ──────────────────────── */
|
|
55
|
+
|
|
56
|
+
.tooltip::before {
|
|
57
|
+
content: "";
|
|
58
|
+
position: absolute;
|
|
59
|
+
inline-size: calc(var(--tooltip-arrow-size) * 2);
|
|
60
|
+
block-size: var(--tooltip-arrow-size);
|
|
61
|
+
background: var(--tooltip-bg);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.tooltip[data-placement^="top"]::before {
|
|
65
|
+
bottom: calc(-0.98 * var(--tooltip-arrow-size));
|
|
66
|
+
left: var(--arrow-x, 50%);
|
|
67
|
+
translate: -50% 0;
|
|
68
|
+
clip-path: polygon(50% 100%, 0 0, 100% 0);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.tooltip[data-placement^="bottom"]::before {
|
|
72
|
+
top: calc(-0.98 * var(--tooltip-arrow-size));
|
|
73
|
+
left: var(--arrow-x, 50%);
|
|
74
|
+
translate: -50% 0;
|
|
75
|
+
clip-path: polygon(50% 0, 0 100%, 100% 100%);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.tooltip[data-placement^="left"]::before {
|
|
79
|
+
right: calc(-0.98 * var(--tooltip-arrow-size));
|
|
80
|
+
top: var(--arrow-y, 50%);
|
|
81
|
+
inline-size: var(--tooltip-arrow-size);
|
|
82
|
+
block-size: calc(var(--tooltip-arrow-size) * 2);
|
|
83
|
+
translate: 0 -50%;
|
|
84
|
+
clip-path: polygon(100% 50%, 0 0, 0 100%);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.tooltip[data-placement^="right"]::before {
|
|
88
|
+
left: calc(-0.98 * var(--tooltip-arrow-size));
|
|
89
|
+
top: var(--arrow-y, 50%);
|
|
90
|
+
inline-size: var(--tooltip-arrow-size);
|
|
91
|
+
block-size: calc(var(--tooltip-arrow-size) * 2);
|
|
92
|
+
translate: 0 -50%;
|
|
93
|
+
clip-path: polygon(0 50%, 100% 0, 100% 100%);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@media (forced-colors: active) {
|
|
97
|
+
.tooltip {
|
|
98
|
+
--tooltip-bg: Canvas;
|
|
99
|
+
--tooltip-fg: CanvasText;
|
|
100
|
+
|
|
101
|
+
border: var(--border-width) solid ButtonText;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.tooltip::before {
|
|
105
|
+
display: none;
|
|
106
|
+
}
|
|
107
|
+
}
|