actual-css 0.4.0 → 0.4.2
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 +84 -35
- package/dist/actual.css +1 -20
- package/dist/actual.full.css +692 -221
- 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/app-ui.md +33 -0
- package/docs/design-notes/enhancement-contract.md +25 -0
- package/docs/design-notes/grid.md +177 -4
- package/docs/design-notes/references.md +1 -1
- package/docs/navigation.json +7 -1
- package/docs/pages/components/alert.md +5 -0
- package/docs/pages/components/app-navigation.md +34 -0
- package/docs/pages/components/avatar.md +10 -0
- package/docs/pages/components/badge.md +2 -0
- package/docs/pages/components/button.md +30 -0
- package/docs/pages/components/card.md +5 -1
- package/docs/pages/components/fab.md +2 -0
- package/docs/pages/components/indicator.md +52 -0
- package/docs/pages/components/list.md +62 -0
- package/docs/pages/components/navbar.md +6 -0
- package/docs/pages/components/rating.md +68 -0
- package/docs/pages/components/steps.md +57 -0
- package/docs/pages/enhancements/flyout.md +2 -2
- package/docs/pages/enhancements/tabs.md +1 -2
- package/docs/pages/examples/overview.md +8 -0
- package/docs/pages/forms/otp.md +32 -0
- package/docs/pages/forms/states-and-sizes.md +3 -3
- package/docs/pages/guides/integrating-actual-css.md +6 -0
- package/docs/pages/layout/app-layout.md +57 -0
- package/docs/pages/layout/app-shell.md +28 -7
- package/docs/pages/layout/center.md +12 -1
- package/docs/pages/layout/choosing.md +15 -0
- package/docs/pages/layout/grid.md +41 -8
- package/docs/pages/layout/sidebar-layout.md +19 -0
- package/docs/pages/layout/stack.md +17 -0
- package/docs/pages/patterns/icon-slot.md +61 -0
- package/docs/pages/patterns/structured-lists.md +38 -40
- package/package.json +3 -2
- package/scripts/reserved-classes.json +17 -0
- package/src/css/components/actions.css +1 -0
- package/src/css/components/app-nav.css +76 -0
- package/src/css/components/avatar.css +4 -0
- package/src/css/components/badge.css +1 -13
- package/src/css/components/breadcrumb.css +1 -0
- package/src/css/components/button.css +8 -38
- package/src/css/components/card.css +11 -11
- package/src/css/components/chat.css +0 -6
- package/src/css/components/drawer.css +0 -6
- package/src/css/components/fab.css +1 -7
- package/src/css/components/index.css +5 -0
- package/src/css/components/indicator.css +47 -0
- package/src/css/components/list.css +83 -0
- package/src/css/components/menu.css +0 -7
- package/src/css/components/modal.css +0 -17
- package/src/css/components/navbar.css +8 -15
- package/src/css/components/pagination.css +1 -0
- package/src/css/components/rating.css +101 -0
- package/src/css/components/steps.css +123 -0
- package/src/css/components/tab.css +21 -22
- package/src/css/components/tooltip.css +1 -10
- package/src/css/core/focus.css +0 -8
- package/src/css/core/theme.css +0 -10
- package/src/css/core/tokens.css +1 -2
- package/src/css/effects/aura.css +1 -10
- package/src/css/forms/choice-card.css +6 -15
- package/src/css/forms/form-actions.css +1 -0
- package/src/css/forms/otp.css +7 -2
- package/src/css/forms/range.css +14 -4
- package/src/css/layout/app-layout.css +102 -0
- package/src/css/layout/app-shell.css +1 -1
- package/src/css/layout/center.css +1 -0
- package/src/css/layout/cluster.css +1 -0
- package/src/css/layout/container-query.css +6 -4
- package/src/css/layout/grid.css +25 -11
- package/src/css/layout/index.css +4 -2
- package/src/css/layout/scroll-snap.css +1 -0
- package/src/css/layout/sidebar-layout.css +23 -1
- package/src/css/layout/switcher.css +1 -0
- package/src/css/layout/topbar.css +1 -0
- package/src/css/typography/prose.css +4 -0
- package/src/js/tooltip.js +2 -1
- package/docs/pages/layout/list.md +0 -41
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
.navbar {
|
|
20
20
|
display: flex;
|
|
21
|
+
flex-direction: row;
|
|
21
22
|
flex-wrap: wrap;
|
|
22
23
|
align-items: center;
|
|
23
24
|
justify-content: space-between;
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
|
|
46
47
|
.navbar-nav {
|
|
47
48
|
display: flex;
|
|
49
|
+
flex-direction: row;
|
|
48
50
|
flex-wrap: wrap;
|
|
49
51
|
align-items: center;
|
|
50
52
|
gap: var(--space-10);
|
|
@@ -67,6 +69,7 @@
|
|
|
67
69
|
.nav-link:where([aria-current]:not([aria-current="false"])) {
|
|
68
70
|
background: var(--surface-subtle);
|
|
69
71
|
color: var(--text);
|
|
72
|
+
font-weight: var(--font-weight-bold);
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
.nav-link:hover {
|
|
@@ -74,7 +77,9 @@
|
|
|
74
77
|
color: var(--text);
|
|
75
78
|
}
|
|
76
79
|
|
|
77
|
-
/* Nav list — a vertical navigation list. Used by .drawer for stacked links.
|
|
80
|
+
/* Nav list — a vertical navigation list. Used by .drawer for stacked links.
|
|
81
|
+
Links fill each row so the whole line is an interactive target; the
|
|
82
|
+
horizontal .navbar-nav links keep their intrinsic size. */
|
|
78
83
|
.nav-list {
|
|
79
84
|
display: grid;
|
|
80
85
|
--gap: var(--space-20);
|
|
@@ -88,18 +93,6 @@
|
|
|
88
93
|
margin: 0;
|
|
89
94
|
}
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
outline: var(--border-width) solid Highlight;
|
|
94
|
-
background: Highlight;
|
|
95
|
-
color: HighlightText;
|
|
96
|
-
forced-color-adjust: none;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.nav-link:hover:not(:where([aria-current]:not([aria-current="false"]))) {
|
|
100
|
-
outline: var(--border-width) solid ButtonText;
|
|
101
|
-
outline-offset: 2px;
|
|
102
|
-
background: Canvas;
|
|
103
|
-
color: CanvasText;
|
|
104
|
-
}
|
|
96
|
+
.nav-list .nav-link {
|
|
97
|
+
inline-size: 100%;
|
|
105
98
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Rating — integer star rating drawn on native radio inputs.
|
|
3
|
+
*
|
|
4
|
+
* The checked radio remains the functional baseline. :has() progressively
|
|
5
|
+
* fills preceding stars without reversing DOM or keyboard order. Forced
|
|
6
|
+
* colors restores the platform radio presentation.
|
|
7
|
+
*
|
|
8
|
+
* Public hooks:
|
|
9
|
+
* --rating-size
|
|
10
|
+
* --rating-gap
|
|
11
|
+
* --rating-color
|
|
12
|
+
* --rating-empty
|
|
13
|
+
* --rating-star
|
|
14
|
+
*/
|
|
15
|
+
:where(.rating) {
|
|
16
|
+
--intent: initial;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.rating {
|
|
20
|
+
--rating-size: 1.25rem;
|
|
21
|
+
--rating-gap: 0.1rem;
|
|
22
|
+
--rating-color: var(--intent, var(--warning));
|
|
23
|
+
--rating-empty: var(--border);
|
|
24
|
+
--rating-star: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='2 2 16 16'%3E%3Cpath d='M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 0 0 .95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 0 0-.364 1.118l1.07 3.292c.3.922-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 0 0-1.175 0l-2.8 2.034c-.783.57-1.838-.196-1.539-1.118l1.07-3.292a1 1 0 0 0-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 0 0 .951-.69l1.07-3.292Z'/%3E%3C/svg%3E");
|
|
25
|
+
|
|
26
|
+
display: inline-flex;
|
|
27
|
+
gap: 0;
|
|
28
|
+
color: var(--rating-color);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.rating > input[type="radio"] {
|
|
32
|
+
appearance: none;
|
|
33
|
+
flex: 0 0 auto;
|
|
34
|
+
inline-size: calc(var(--rating-size) + var(--rating-gap));
|
|
35
|
+
block-size: var(--rating-size);
|
|
36
|
+
margin: 0;
|
|
37
|
+
border: 0;
|
|
38
|
+
background: var(--rating-empty);
|
|
39
|
+
/* Contiguous radio boxes own hit-testing; the centered mask preserves the
|
|
40
|
+
star's proportions while leaving a purely visual gap between values. */
|
|
41
|
+
-webkit-mask: var(--rating-star) center / var(--rating-size) var(--rating-size) no-repeat;
|
|
42
|
+
mask: var(--rating-star) center / var(--rating-size) var(--rating-size) no-repeat;
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
transition: background-color var(--duration);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.rating > input[type="radio"]:checked {
|
|
48
|
+
background: var(--rating-color);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.rating > input[type="radio"]:disabled {
|
|
52
|
+
cursor: not-allowed;
|
|
53
|
+
opacity: var(--disabled-opacity);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.rating > input[type="radio"]:focus-visible {
|
|
57
|
+
outline: var(--focus-outline);
|
|
58
|
+
outline-offset: var(--focus-outline-offset);
|
|
59
|
+
background: var(--rating-color);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Browsers without :has() still show the selected native radio as one filled
|
|
63
|
+
star. The enhancement only adds cumulative checked and hover previews. */
|
|
64
|
+
@supports selector(:has(*)) {
|
|
65
|
+
.rating > input[type="radio"]:has(~ input[type="radio"]:checked) {
|
|
66
|
+
background: var(--rating-color);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@media (hover: hover) {
|
|
70
|
+
.rating > input[type="radio"]:not(:disabled):hover,
|
|
71
|
+
.rating > input[type="radio"]:has(~ input[type="radio"]:not(:disabled):hover) {
|
|
72
|
+
background: var(--rating-color);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* A hovered value previews exactly that value: later stars are emptied,
|
|
76
|
+
including a previously checked star beyond the pointer. */
|
|
77
|
+
.rating > input[type="radio"]:not(:disabled):hover ~ input[type="radio"] {
|
|
78
|
+
background: var(--rating-empty);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.rating.sm {
|
|
84
|
+
--rating-size: 1rem;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.rating.lg {
|
|
88
|
+
--rating-size: 1.75rem;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@media (forced-colors: active) {
|
|
92
|
+
.rating > input[type="radio"] {
|
|
93
|
+
appearance: auto;
|
|
94
|
+
inline-size: auto;
|
|
95
|
+
block-size: auto;
|
|
96
|
+
background: Canvas;
|
|
97
|
+
-webkit-mask: none;
|
|
98
|
+
mask: none;
|
|
99
|
+
opacity: 1;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Steps — semantic ordered-list progression. One intrinsic layout: items fill
|
|
3
|
+
* the row when they fit and hold a minimum width otherwise, so the sequence
|
|
4
|
+
* scrolls horizontally only when it genuinely cannot fit. No breakpoint decides
|
|
5
|
+
* this — the item minimum tracks the real content, not an arbitrary width.
|
|
6
|
+
*
|
|
7
|
+
* Markers come from the list counter; state stays in .complete and
|
|
8
|
+
* aria-current="step", so the component needs no runtime.
|
|
9
|
+
*
|
|
10
|
+
* Public hooks:
|
|
11
|
+
* --step-size
|
|
12
|
+
* --step-min
|
|
13
|
+
* --step-gap
|
|
14
|
+
* --step-line-size
|
|
15
|
+
* --step-marker-radius
|
|
16
|
+
* --step-complete-mark
|
|
17
|
+
* --step-connector
|
|
18
|
+
*
|
|
19
|
+
* Internal:
|
|
20
|
+
* --step-marker-bg
|
|
21
|
+
* --step-marker-border
|
|
22
|
+
* --step-marker-fg
|
|
23
|
+
* --step-line
|
|
24
|
+
*/
|
|
25
|
+
.steps {
|
|
26
|
+
--step-size: 1.75rem;
|
|
27
|
+
--step-min: 7rem;
|
|
28
|
+
--step-gap: var(--space-20);
|
|
29
|
+
--step-line-size: var(--border-width);
|
|
30
|
+
--step-marker-bg: var(--surface);
|
|
31
|
+
--step-marker-border: var(--border);
|
|
32
|
+
--step-marker-fg: var(--text-muted);
|
|
33
|
+
--step-marker-radius: var(--radius-full);
|
|
34
|
+
--step-line: var(--border);
|
|
35
|
+
|
|
36
|
+
counter-reset: actual-step;
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: row;
|
|
39
|
+
inline-size: 100%;
|
|
40
|
+
margin: 0;
|
|
41
|
+
padding: 0;
|
|
42
|
+
list-style: none;
|
|
43
|
+
/* Fill when it fits, scroll when it cannot: items never shrink below
|
|
44
|
+
--step-min, so labels keep a readable width and the sequence scrolls
|
|
45
|
+
horizontally instead of squishing. overscroll-behavior keeps the scroll
|
|
46
|
+
from chaining to the page. */
|
|
47
|
+
overflow-x: auto;
|
|
48
|
+
overscroll-behavior-inline: contain;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.steps > li {
|
|
52
|
+
position: relative;
|
|
53
|
+
display: grid;
|
|
54
|
+
flex: 1 0 var(--step-min);
|
|
55
|
+
grid-template-rows: var(--step-size) auto;
|
|
56
|
+
gap: var(--step-gap);
|
|
57
|
+
justify-items: center;
|
|
58
|
+
min-inline-size: max(var(--step-size), var(--step-min));
|
|
59
|
+
color: var(--text-muted);
|
|
60
|
+
text-align: center;
|
|
61
|
+
counter-increment: actual-step;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.steps > li::before {
|
|
65
|
+
content: counter(actual-step);
|
|
66
|
+
position: relative;
|
|
67
|
+
z-index: 1;
|
|
68
|
+
display: inline-grid;
|
|
69
|
+
place-items: center;
|
|
70
|
+
inline-size: var(--step-size);
|
|
71
|
+
block-size: var(--step-size);
|
|
72
|
+
border: var(--border-width) solid var(--step-marker-border);
|
|
73
|
+
border-radius: var(--step-marker-radius);
|
|
74
|
+
background: var(--step-marker-bg);
|
|
75
|
+
color: var(--step-marker-fg);
|
|
76
|
+
font-size: var(--font-size-sm);
|
|
77
|
+
font-weight: var(--font-weight-strong);
|
|
78
|
+
line-height: 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.steps > li::after {
|
|
82
|
+
content: "";
|
|
83
|
+
position: absolute;
|
|
84
|
+
inset-block-start: calc((var(--step-size) - var(--step-line-size)) / 2);
|
|
85
|
+
inset-inline-start: calc(50% + var(--step-size) / 2);
|
|
86
|
+
inline-size: calc(100% - var(--step-size));
|
|
87
|
+
block-size: var(--step-line-size);
|
|
88
|
+
/* A custom property resolves its var() before inheritance, so a default
|
|
89
|
+
--step-connector: var(--step-line) on .steps would freeze the parent line
|
|
90
|
+
color and a .complete child's connector would never follow its own line.
|
|
91
|
+
Falling back to the local --step-line here keeps each connector in sync;
|
|
92
|
+
an explicit --step-connector still wins when the author sets one. */
|
|
93
|
+
background: var(--step-connector, var(--step-line));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.steps > li:last-child::after {
|
|
97
|
+
content: none;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.steps > :is(.complete, [aria-current="step"]) {
|
|
101
|
+
--step-marker-bg: var(--state-selected);
|
|
102
|
+
--step-marker-border: var(--state-selected);
|
|
103
|
+
--step-marker-fg: var(--state-selected-fg);
|
|
104
|
+
|
|
105
|
+
color: var(--text);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Thicker border is the selected affordance in every mode — structural, and it
|
|
109
|
+
never competes with the outline channel owned by focus. */
|
|
110
|
+
.steps > :is(.complete, [aria-current="step"])::before {
|
|
111
|
+
border-width: calc(var(--border-width) * 2);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.steps > .complete {
|
|
115
|
+
--step-line: var(--state-selected);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* A finished step may replace its number with a mark (e.g. a check glyph):
|
|
119
|
+
--step-complete-mark accepts any content value and falls back to the
|
|
120
|
+
counter, so existing numbered steppers are unchanged. */
|
|
121
|
+
.steps > .complete::before {
|
|
122
|
+
content: var(--step-complete-mark, counter(actual-step));
|
|
123
|
+
}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
.tabs {
|
|
18
18
|
display: flex;
|
|
19
|
+
flex-direction: row;
|
|
19
20
|
flex-wrap: wrap;
|
|
20
21
|
gap: var(--space-10);
|
|
21
22
|
margin: 0;
|
|
@@ -33,13 +34,14 @@
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
.tab {
|
|
37
|
+
/* Positioning context for the selected indicator pseudo. */
|
|
38
|
+
position: relative;
|
|
36
39
|
display: inline-flex;
|
|
37
40
|
align-items: center;
|
|
38
41
|
gap: var(--tab-gap, 0.375em);
|
|
39
42
|
min-block-size: var(--control-size);
|
|
40
43
|
padding-inline: var(--space-30);
|
|
41
44
|
border: 0;
|
|
42
|
-
border-block-end: 2px solid transparent;
|
|
43
45
|
border-radius: 0;
|
|
44
46
|
background: transparent;
|
|
45
47
|
color: var(--text-muted);
|
|
@@ -51,8 +53,6 @@
|
|
|
51
53
|
|
|
52
54
|
.tabs[aria-orientation="vertical"] .tab {
|
|
53
55
|
justify-content: flex-start;
|
|
54
|
-
border-block-end: 0;
|
|
55
|
-
border-inline-end: 2px solid transparent;
|
|
56
56
|
padding-inline-end: var(--space-40);
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -73,28 +73,27 @@
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
.tab[aria-selected="true"] {
|
|
76
|
-
border-block-end-color: var(--intent, var(--state-selected));
|
|
77
76
|
color: var(--intent, var(--state-selected));
|
|
77
|
+
/* Second, layout-free selected cue — the underline alone is color-only in
|
|
78
|
+
forced colors. */
|
|
79
|
+
font-weight: var(--font-weight-bold);
|
|
78
80
|
}
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
/* The selected indicator lives on a positioned pseudo so that only the active
|
|
83
|
+
tab owns an underline: a transparent border on every tab would surface in
|
|
84
|
+
forced colors and erase the distinction. currentColor follows the palette the
|
|
85
|
+
UA forces, so no forced-colors block is needed. */
|
|
86
|
+
.tab[aria-selected="true"]::after {
|
|
87
|
+
content: "";
|
|
88
|
+
position: absolute;
|
|
89
|
+
inset-inline: 0;
|
|
90
|
+
inset-block-end: 0;
|
|
91
|
+
border-block-end: 2px solid currentColor;
|
|
83
92
|
}
|
|
84
93
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
.tab[aria-selected="true"] {
|
|
92
|
-
border-block-end-color: Highlight;
|
|
93
|
-
color: Highlight;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.tabs[aria-orientation="vertical"] .tab[aria-selected="true"] {
|
|
97
|
-
border-block-end-color: transparent;
|
|
98
|
-
border-inline-end-color: Highlight;
|
|
99
|
-
}
|
|
94
|
+
.tabs[aria-orientation="vertical"] .tab[aria-selected="true"]::after {
|
|
95
|
+
inset-block: 0;
|
|
96
|
+
inset-inline: auto 0;
|
|
97
|
+
border-block-end: 0;
|
|
98
|
+
border-inline-end: 2px solid currentColor;
|
|
100
99
|
}
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
max-inline-size: min(24rem, calc(var(--viewport-inline) - 2rem));
|
|
25
25
|
padding: 0.25em 0.6em;
|
|
26
26
|
border-radius: var(--radius-sm);
|
|
27
|
+
border: var(--border-width) solid transparent;
|
|
27
28
|
background: var(--tooltip-bg);
|
|
28
29
|
color: var(--tooltip-fg);
|
|
29
30
|
font-size: var(--font-size-xs);
|
|
@@ -102,16 +103,6 @@
|
|
|
102
103
|
clip-path: polygon(0 50%, 100% 0, 100% 100%);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
@media (forced-colors: active) {
|
|
106
|
-
.tooltip {
|
|
107
|
-
--tooltip-bg: Canvas;
|
|
108
|
-
--tooltip-fg: CanvasText;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.tooltip::before {
|
|
112
|
-
display: none;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
106
|
@media print {
|
|
116
107
|
.tooltip {
|
|
117
108
|
display: none !important;
|
package/src/css/core/focus.css
CHANGED
|
@@ -15,12 +15,4 @@
|
|
|
15
15
|
:focus:not(:focus-visible) {
|
|
16
16
|
outline: none;
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
/* Pointer focus must still signal in high-contrast mode, where the shared
|
|
20
|
-
box-shadow rings are disabled (--focus-ring-shadow: none). */
|
|
21
|
-
@media (forced-colors: active) {
|
|
22
|
-
:focus:not(:focus-visible) {
|
|
23
|
-
outline: var(--focus-outline);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
18
|
}
|
package/src/css/core/theme.css
CHANGED
|
@@ -188,16 +188,6 @@
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
@media (forced-colors: active) {
|
|
192
|
-
:root,
|
|
193
|
-
[data-theme] {
|
|
194
|
-
--focus-outline-color: Highlight;
|
|
195
|
-
--focus-ring-shadow: none;
|
|
196
|
-
|
|
197
|
-
--backdrop-fill: Canvas;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
191
|
@media (prefers-contrast: more) {
|
|
202
192
|
:root,
|
|
203
193
|
/* The repeated attribute intentionally outranks single-attribute preset
|
package/src/css/core/tokens.css
CHANGED
package/src/css/effects/aura.css
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
display: inline-grid;
|
|
33
33
|
padding: var(--aura-width);
|
|
34
34
|
border-radius: calc(var(--aura-radius) + var(--aura-width));
|
|
35
|
+
border: var(--border-width) solid transparent;
|
|
35
36
|
background: var(--aura-color);
|
|
36
37
|
background: conic-gradient(from var(--aura-angle), transparent 0 65%, var(--aura-color));
|
|
37
38
|
}
|
|
@@ -81,13 +82,3 @@
|
|
|
81
82
|
--aura-radius: var(--radius-full);
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
|
-
|
|
85
|
-
@media (forced-colors: active) {
|
|
86
|
-
.aura {
|
|
87
|
-
background: CanvasText;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.aura::before {
|
|
91
|
-
display: none;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
@@ -131,27 +131,18 @@
|
|
|
131
131
|
transform: scale(1);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/* The native input is hidden and the checked marker is custom-drawn: without
|
|
135
|
+
this repair, forced colors pushes disc and check to the same system color
|
|
136
|
+
and the state disappears. Highlight/Canvas/HighlightText are preserved as-is,
|
|
137
|
+
so no forced-color-adjust is needed. The pseudo is not focusable — the
|
|
138
|
+
outline is a separator against the card, not a focus channel. */
|
|
134
139
|
@media (forced-colors: active) {
|
|
135
|
-
.choice-card {
|
|
136
|
-
--choice-card-border: ButtonText;
|
|
137
|
-
--choice-card-bg: Canvas;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.choice-card:has(:checked) {
|
|
141
|
-
--choice-card-border: Highlight;
|
|
142
|
-
/* Pin the selected surface to the system canvas: only the essential
|
|
143
|
-
marker pseudos opt out of remapping, never the interactive card host. */
|
|
144
|
-
--choice-card-bg: Canvas;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
140
|
.choice-card:has(:checked)::before {
|
|
148
141
|
background: Highlight;
|
|
149
|
-
|
|
150
|
-
forced-color-adjust: none;
|
|
142
|
+
outline: 2px solid Canvas;
|
|
151
143
|
}
|
|
152
144
|
|
|
153
145
|
.choice-card:has(:checked)::after {
|
|
154
146
|
background: HighlightText;
|
|
155
|
-
forced-color-adjust: none;
|
|
156
147
|
}
|
|
157
148
|
}
|
package/src/css/forms/otp.css
CHANGED
|
@@ -79,7 +79,12 @@
|
|
|
79
79
|
but it sits in the clipped input extension once every cell is filled, so
|
|
80
80
|
the focused edge must be unambiguous on its own — hence the doubled width,
|
|
81
81
|
not only the color swap. Width is safe to change: box-sizing is border-box
|
|
82
|
-
and the cells have a fixed inline/block size, so nothing reflows.
|
|
82
|
+
and the cells have a fixed inline/block size, so nothing reflows.
|
|
83
|
+
|
|
84
|
+
The <input> must be the first direct child, with one cell <span> per
|
|
85
|
+
character after it: the state rules select the cells as following siblings
|
|
86
|
+
(input:focus ~ span, input:disabled ~ span, …), so that order is part of the
|
|
87
|
+
contract. */
|
|
83
88
|
.otp > input:focus ~ span {
|
|
84
89
|
--otp-cell-border: var(--focus);
|
|
85
90
|
--otp-cell-border-width: calc(var(--border-width) * 2);
|
|
@@ -103,7 +108,7 @@
|
|
|
103
108
|
|
|
104
109
|
.otp > input:disabled ~ span {
|
|
105
110
|
--otp-cell-bg: var(--surface-subtle);
|
|
106
|
-
|
|
111
|
+
--otp-cell-border: var(--state-disabled);
|
|
107
112
|
opacity: var(--disabled-opacity);
|
|
108
113
|
}
|
|
109
114
|
|
package/src/css/forms/range.css
CHANGED
|
@@ -93,11 +93,21 @@
|
|
|
93
93
|
opacity: var(--disabled-opacity);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
/* Forced colors:
|
|
97
|
-
|
|
96
|
+
/* Forced colors: the track must stay a visible line against the page (Canvas
|
|
97
|
+
would merge with it) and the thumb needs a real boundary to remain
|
|
98
|
+
distinguishable from the track. Disabled keeps GrayText via :disabled.
|
|
99
|
+
Focus stays on the transparent outline of :focus-visible. */
|
|
98
100
|
@media (forced-colors: active) {
|
|
99
101
|
.range {
|
|
100
|
-
--range-
|
|
101
|
-
--range-
|
|
102
|
+
--range-track-bg: CanvasText;
|
|
103
|
+
--range-thumb-bg: ButtonFace;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.range::-webkit-slider-thumb {
|
|
107
|
+
border: var(--border-width) solid ButtonText;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.range::-moz-range-thumb {
|
|
111
|
+
border: var(--border-width) solid ButtonText;
|
|
102
112
|
}
|
|
103
113
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Specialized application shell recipe: one exact DOM structure uses a
|
|
3
|
+
* bottom navigation bar when narrow and a labelled side navigation when space
|
|
4
|
+
* permits. The main region owns scrolling, keeping both pieces of application
|
|
5
|
+
* chrome available without fixed offsets. This is not a generic page wrapper
|
|
6
|
+
* or a public-site layout; all three direct regions are part of the contract.
|
|
7
|
+
*
|
|
8
|
+
* Public hook:
|
|
9
|
+
* --app-nav-side-size
|
|
10
|
+
*/
|
|
11
|
+
.app-layout {
|
|
12
|
+
--app-nav-side-size: 12rem;
|
|
13
|
+
|
|
14
|
+
display: grid;
|
|
15
|
+
grid-template:
|
|
16
|
+
"topbar" auto
|
|
17
|
+
"main" minmax(0, 1fr)
|
|
18
|
+
"nav" auto
|
|
19
|
+
/ minmax(0, 1fr);
|
|
20
|
+
block-size: var(--viewport-block);
|
|
21
|
+
min-inline-size: 0;
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.app-layout > .topbar {
|
|
26
|
+
grid-area: topbar;
|
|
27
|
+
padding-block-start: calc(var(--space-30) + env(safe-area-inset-top));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.app-layout > .app-main {
|
|
31
|
+
grid-area: main;
|
|
32
|
+
min-inline-size: 0;
|
|
33
|
+
min-block-size: 0;
|
|
34
|
+
overflow: auto;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.app-layout > .app-nav {
|
|
38
|
+
grid-area: nav;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* The main grid area keeps the FAB clear of bottom navigation without making
|
|
42
|
+
either component copy the other's geometry. */
|
|
43
|
+
.app-layout > .fab {
|
|
44
|
+
position: relative;
|
|
45
|
+
grid-area: main;
|
|
46
|
+
place-self: end;
|
|
47
|
+
inset: auto;
|
|
48
|
+
margin: var(--fab-offset);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@media (min-width: 48rem) {
|
|
52
|
+
.app-layout {
|
|
53
|
+
grid-template:
|
|
54
|
+
"nav topbar" auto
|
|
55
|
+
"nav main" minmax(0, 1fr)
|
|
56
|
+
/ var(--app-nav-side-size) minmax(0, 1fr);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.app-layout > .app-nav {
|
|
60
|
+
position: sticky;
|
|
61
|
+
inset-block: 0;
|
|
62
|
+
grid-auto-flow: row;
|
|
63
|
+
grid-auto-rows: minmax(var(--control-size-lg), auto);
|
|
64
|
+
grid-auto-columns: auto;
|
|
65
|
+
align-content: start;
|
|
66
|
+
gap: var(--space-20);
|
|
67
|
+
min-block-size: 0;
|
|
68
|
+
padding-block: max(var(--space-20), env(safe-area-inset-top))
|
|
69
|
+
max(var(--space-20), env(safe-area-inset-bottom));
|
|
70
|
+
padding-inline: var(--space-20);
|
|
71
|
+
border-block-start: 0;
|
|
72
|
+
border-inline-end: var(--border-width) solid var(--ui-border, var(--border));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.app-layout > .app-nav > a {
|
|
76
|
+
grid-template-rows: auto;
|
|
77
|
+
grid-template-columns: 1.5rem minmax(0, 1fr);
|
|
78
|
+
place-content: center start;
|
|
79
|
+
align-items: center;
|
|
80
|
+
justify-items: start;
|
|
81
|
+
gap: var(--space-30);
|
|
82
|
+
padding-inline: var(--space-30);
|
|
83
|
+
text-align: start;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Side navigation no longer occupies the viewport's bottom safe area. */
|
|
87
|
+
.app-layout > .fab {
|
|
88
|
+
margin-block-end: max(var(--fab-offset), env(safe-area-inset-bottom));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@media print {
|
|
93
|
+
.app-layout {
|
|
94
|
+
display: block;
|
|
95
|
+
block-size: auto;
|
|
96
|
+
overflow: visible;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.app-layout > .app-main {
|
|
100
|
+
overflow: visible;
|
|
101
|
+
}
|
|
102
|
+
}
|