@codenhub/styles 0.7.0 → 0.8.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/README.es.md +8 -7
- package/README.md +7 -6
- package/README.pt-BR.md +8 -7
- package/dist/aesthetics/chunky-tile.css +1 -1
- package/dist/aesthetics/cyber.css +1 -1
- package/dist/aesthetics/glass.css +1 -1
- package/dist/aesthetics/index.css +2 -2
- package/dist/aesthetics/neobrutalism.css +1 -1
- package/dist/aesthetics/sketch.css +1 -1
- package/dist/cli.js +189 -0
- package/dist/components.css +2 -2
- package/dist/index.css +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/native.css +2 -2
- package/dist/palette.css +1 -1
- package/dist/theme.css +2 -2
- package/docs/accessibility.md +46 -27
- package/docs/changelog/0.8.0.md +70 -0
- package/docs/changelog/index.md +1 -0
- package/docs/es/accessibility.md +47 -28
- package/docs/es/index.md +3 -2
- package/docs/es/integrating/index.md +38 -10
- package/docs/es/integrating/tailwind.md +78 -8
- package/docs/es/integrating/without-a-bundler.md +128 -5
- package/docs/es/setup.md +42 -34
- package/docs/es/usage/aesthetics.md +19 -13
- package/docs/es/usage/buttons.md +6 -2
- package/docs/es/usage/composing.md +6 -2
- package/docs/es/usage/content-and-layout.md +8 -4
- package/docs/es/usage/customizing.md +19 -13
- package/docs/es/usage/feedback.md +5 -1
- package/docs/es/usage/forms.md +29 -4
- package/docs/es/usage/index.md +6 -2
- package/docs/es/usage/presets.md +92 -0
- package/docs/es/usage/solo.md +4 -2
- package/docs/es/usage/theming.md +28 -15
- package/docs/index.md +2 -1
- package/docs/integrating/index.md +38 -10
- package/docs/integrating/tailwind.md +77 -7
- package/docs/integrating/without-a-bundler.md +127 -4
- package/docs/pt-BR/accessibility.md +47 -28
- package/docs/pt-BR/index.md +3 -2
- package/docs/pt-BR/integrating/index.md +38 -10
- package/docs/pt-BR/integrating/tailwind.md +78 -8
- package/docs/pt-BR/integrating/without-a-bundler.md +128 -5
- package/docs/pt-BR/setup.md +42 -34
- package/docs/pt-BR/usage/aesthetics.md +19 -13
- package/docs/pt-BR/usage/buttons.md +6 -2
- package/docs/pt-BR/usage/composing.md +6 -2
- package/docs/pt-BR/usage/content-and-layout.md +8 -4
- package/docs/pt-BR/usage/customizing.md +19 -13
- package/docs/pt-BR/usage/feedback.md +5 -1
- package/docs/pt-BR/usage/forms.md +29 -4
- package/docs/pt-BR/usage/index.md +6 -2
- package/docs/pt-BR/usage/presets.md +92 -0
- package/docs/pt-BR/usage/solo.md +4 -2
- package/docs/pt-BR/usage/theming.md +21 -8
- package/docs/setup.md +30 -22
- package/docs/usage/aesthetics.md +18 -12
- package/docs/usage/buttons.md +5 -1
- package/docs/usage/composing.md +5 -1
- package/docs/usage/content-and-layout.md +7 -3
- package/docs/usage/customizing.md +18 -12
- package/docs/usage/feedback.md +4 -0
- package/docs/usage/forms.md +28 -3
- package/docs/usage/index.md +5 -1
- package/docs/usage/presets.md +91 -0
- package/docs/usage/solo.md +3 -1
- package/docs/usage/theming.md +20 -7
- package/llms-full.txt +592 -115
- package/package.json +113 -63
- package/{dist/tw → tw}/aesthetics/chunky-tile.css +39 -19
- package/{dist/tw → tw}/aesthetics/cyber.css +15 -24
- package/{dist/tw → tw}/aesthetics/glass.css +105 -36
- package/{dist/tw → tw}/aesthetics/neobrutalism.css +37 -20
- package/{dist/tw → tw}/aesthetics/sketch.css +152 -133
- package/{dist/tw → tw}/box.css +89 -12
- package/tw/components/button.css +11 -0
- package/tw/components/button.rules.css +187 -0
- package/tw/components/feedback.css +11 -0
- package/{dist/tw/components/feedback.css → tw/components/feedback.rules.css} +134 -30
- package/tw/components/form.css +11 -0
- package/{dist/tw/components/form.css → tw/components/form.rules.css} +524 -111
- package/tw/components/index.css +16 -0
- package/tw/components/rules.css +41 -0
- package/tw/components/surface.css +11 -0
- package/tw/components/surface.rules.css +222 -0
- package/tw/components/tooltip.css +11 -0
- package/{dist/tw/components/tooltip.css → tw/components/tooltip.rules.css} +43 -27
- package/{dist/tw → tw}/corner.css +18 -12
- package/{dist/tw → tw}/elevation.css +23 -17
- package/{dist/tw → tw}/index.css +11 -9
- package/tw/index.d.ts +1 -0
- package/tw/intent.css +312 -0
- package/tw/modifiers.css +127 -0
- package/tw/native.css +320 -0
- package/tw/presentation.css +139 -0
- package/tw/reset.css +10 -0
- package/{dist/tw/reset.css → tw/reset.rules.css} +7 -8
- package/tw/size.css +34 -0
- package/tw/surface.css +9 -0
- package/tw/surface.rules.css +212 -0
- package/{dist/tw → tw}/theme.css +92 -28
- package/tw/typography.css +8 -0
- package/{dist/tw/typography.css → tw/typography.rules.css} +0 -3
- package/{dist/tw → tw}/utilities/content.css +183 -63
- package/tw/utilities/index.css +11 -0
- package/tw/utilities/layout.css +208 -0
- package/tw/utilities/rules.css +8 -0
- package/dist/tw/components/button.css +0 -139
- package/dist/tw/components/index.css +0 -35
- package/dist/tw/components/surface.css +0 -184
- package/dist/tw/intent.css +0 -229
- package/dist/tw/native.css +0 -203
- package/dist/tw/palette.css +0 -460
- package/dist/tw/presentation.css +0 -68
- package/dist/tw/surface.css +0 -61
- package/dist/tw/utilities/index.css +0 -6
- package/dist/tw/utilities/layout.css +0 -144
- /package/{dist/tw → tw}/aesthetics/index.css +0 -0
- /package/{dist/tw → tw}/aesthetics/pixel.css +0 -0
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
@reference "tailwindcss";
|
|
2
|
-
@import "../theme.css";
|
|
3
|
-
@reference "../box.css";
|
|
4
|
-
|
|
5
1
|
/* What all six text controls share: the box, the chrome, and two bounds that
|
|
6
2
|
exist because presentation cascades -- a cascaded-fill cap so a container's
|
|
7
3
|
`.solid` cannot fill a field with its own text colour, and an edge floor so a
|
|
@@ -24,6 +20,13 @@
|
|
|
24
20
|
--_d-fg-on-fill: 0%;
|
|
25
21
|
--_d-border: 100%;
|
|
26
22
|
|
|
23
|
+
/* A field's fill is at most a wash, never a plate, so it never holds an ink
|
|
24
|
+
of its own, even under a `.solid` it or a container names: it prints in
|
|
25
|
+
the ink it was handed. */
|
|
26
|
+
--_held-ink: inherit;
|
|
27
|
+
--_held-on: inherit;
|
|
28
|
+
--_own-hold: 0%;
|
|
29
|
+
|
|
27
30
|
/* 6% is a quiet wash, and it is the cap rather than a presentation: `.soft`
|
|
28
31
|
names the tint it wants and takes it whole below, so what this governs is
|
|
29
32
|
`.solid` and the container that cascades one onto a field nobody classed. A
|
|
@@ -37,8 +40,16 @@
|
|
|
37
40
|
|
|
38
41
|
The fill and the ink are `box`'s own, unrestated: its `--_capped` reads
|
|
39
42
|
this cap, so the plate and the ink ramp stay in step at every bound,
|
|
40
|
-
including the checked state below that lifts it.
|
|
41
|
-
|
|
43
|
+
including the checked state below that lifts it.
|
|
44
|
+
|
|
45
|
+
The element's own fill class names its own cap: `.soft` its 12% whole,
|
|
46
|
+
`.solid` 20%, which clears `.soft` and matches the plate a `.solid`
|
|
47
|
+
badge draws. Read from `--_own-fill`, which the class writes and which
|
|
48
|
+
does not inherit, so the 6% still answers a container's class. Raised
|
|
49
|
+
here rather than written as a fill (P6), which is what keeps `.soft` <
|
|
50
|
+
`.solid`. See
|
|
51
|
+
model.md#the-bounds-that-survive-and-the-test-for-keeping-one. */
|
|
52
|
+
--_fill-cap: max(6%, min(var(--_own-fill), 20%));
|
|
42
53
|
/* The resting line is a fraction of the intent rather than all of it, and the
|
|
43
54
|
fraction is what makes the pointer visible. Drawn at full strength a control
|
|
44
55
|
already sits at its intent's darkest, and hover moves it to a neighbouring
|
|
@@ -52,6 +63,13 @@
|
|
|
52
63
|
back to 100% -- its line is a silhouette rather than a field's edge, and
|
|
53
64
|
there is nothing else marking an unchecked box. */
|
|
54
65
|
--_line-rest: 60%;
|
|
66
|
+
/* Someone who asks for more contrast gets the line whole: above 4:1
|
|
67
|
+
against the page in both themes, where the quiet line is under 3:1. Hover
|
|
68
|
+
and focus then change nothing in the tone, which is the trade the
|
|
69
|
+
preference asks for. See docs/accessibility.md. */
|
|
70
|
+
@media (prefers-contrast: more) {
|
|
71
|
+
--_line-rest: 100%;
|
|
72
|
+
}
|
|
55
73
|
/* Two seams rather than one composed result. `--_line-tone` is what colour
|
|
56
74
|
the line is, and the states below move it; `--_line` folds in the fill,
|
|
57
75
|
walking the line toward the intent colour by the fill amount, so a state
|
|
@@ -70,20 +88,26 @@
|
|
|
70
88
|
typing goes and a toggle with no silhouette at all (WCAG 1.4.11). That is
|
|
71
89
|
our own cascade producing the broken result, so our own floor answers it.
|
|
72
90
|
|
|
73
|
-
An element's own `.edgeless` lowers the floor --
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
line, so removing it removes the control
|
|
78
|
-
|
|
91
|
+
An element's own `.edgeless` lowers the floor -- `--_own-edge`, which
|
|
92
|
+
the class writes and which does not inherit -- because that is a consumer
|
|
93
|
+
naming what they want rather than a cascade reaching something nobody
|
|
94
|
+
classed. `.checkbox` and `.radio` restate the floor absolute: they have
|
|
95
|
+
nothing outside their line, so removing it removes the control, and
|
|
96
|
+
`.edgeless` on them is published unsupported. `.input-group` keeps the
|
|
97
|
+
lowering because the group is the field boundary. */
|
|
98
|
+
--_edge-floor: var(--_own-edge);
|
|
79
99
|
|
|
80
100
|
@apply w-full appearance-none;
|
|
81
101
|
|
|
82
102
|
/* The surrounding font rather than the user agent's smaller field one, on
|
|
83
|
-
every entry: `/components` carries no reset to say so.
|
|
103
|
+
every entry: `/components` carries no reset to say so. Its tracking is
|
|
104
|
+
typed text's own, `normal`, rather than the page's: body copy's wider
|
|
105
|
+
tracking is set on `body`, and Preflight's `letter-spacing: inherit` on
|
|
106
|
+
`/tw` handed it, or a container's, to every field. */
|
|
84
107
|
font-family: inherit;
|
|
85
108
|
font-size: inherit;
|
|
86
109
|
line-height: inherit;
|
|
110
|
+
letter-spacing: normal;
|
|
87
111
|
|
|
88
112
|
&::placeholder {
|
|
89
113
|
color: var(--color-text-secondary);
|
|
@@ -112,12 +136,115 @@
|
|
|
112
136
|
--_line-tone: var(--intent-color);
|
|
113
137
|
}
|
|
114
138
|
|
|
139
|
+
/* The forced-colours ring, carried so `@apply text-control` draws it: the
|
|
140
|
+
unlayered block at the end of this file names the package's own classes,
|
|
141
|
+
and `reset.css` names only typed native fields, so an applied control --
|
|
142
|
+
an `<input>` with no `type`, a `contenteditable` -- kept the 3px ring in a
|
|
143
|
+
system colour instead of the 2px `Highlight` one beside a `.text-control`.
|
|
144
|
+
|
|
145
|
+
`!important`, as the reset's ring is: the copy lands in whichever layer the
|
|
146
|
+
consumer applied it in, and an accessibility override has to win over any
|
|
147
|
+
layered rule there. So it cannot be suppressed and is kept off a control
|
|
148
|
+
inside an `.input-group`, which draws the field's ring and has the control
|
|
149
|
+
inside draw none; the offset and the cleared shadow are not important and
|
|
150
|
+
reach that control too, as the unlayered block's do. */
|
|
151
|
+
@media (forced-colors: active) {
|
|
152
|
+
&:focus-visible {
|
|
153
|
+
outline-offset: 2px;
|
|
154
|
+
box-shadow: none;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
&:focus-visible:where(:not(.input-group > *)) {
|
|
158
|
+
outline: 2px solid Highlight !important;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Everything below until `:checked` is keyed on the class, and lives inside
|
|
163
|
+
the utility so `@apply text-control` carries it: `@apply` copies this body
|
|
164
|
+
with the consumer's own selector, and a rule naming `.text-control` from
|
|
165
|
+
outside it never reaches their element. See model.md#the-composition-api.
|
|
166
|
+
|
|
167
|
+
The neutral reset, for an element that carries none of the package's own
|
|
168
|
+
text-control classes -- a consumer's `.my-control { @apply text-control }`.
|
|
169
|
+
Those classes keep the reset in `intent.css`, in `components`; this one
|
|
170
|
+
lands in `utilities` and would beat a consumer's own intent class declared
|
|
171
|
+
in `components` there. It writes the values that reset and the control
|
|
172
|
+
line do, so a field inside a `.card.success` stays neutral and draws the
|
|
173
|
+
3:1 control line rather than `--color-border`.
|
|
174
|
+
|
|
175
|
+
Zero specificity, and never on an element with an intent class, so it
|
|
176
|
+
cannot overrule one: the intent class is excluded, and every rule that
|
|
177
|
+
writes an intent slot in `utilities` -- `aria-invalid` below, the
|
|
178
|
+
`:checked` arm, `.input-group`'s inherited `--intent-strong` -- carries at
|
|
179
|
+
least 0-1-0. `.neutral` is not excluded, so `.neutral` takes the control
|
|
180
|
+
line here as it does on `.ipt.neutral`. */
|
|
181
|
+
/* In `families`, beside the intent classes: applied with an intent --
|
|
182
|
+
`@apply text-control info` -- the reset and the intent land in one layer, where the
|
|
183
|
+
intent's 0-1-0 beats this. Left in the rule's own layer it would beat
|
|
184
|
+
every intent applied with it. */
|
|
185
|
+
@layer families {
|
|
186
|
+
:where(
|
|
187
|
+
&:not(
|
|
188
|
+
.text-control,
|
|
189
|
+
.ipt,
|
|
190
|
+
.textarea,
|
|
191
|
+
.select,
|
|
192
|
+
.input-group,
|
|
193
|
+
.checkbox,
|
|
194
|
+
.radio,
|
|
195
|
+
.switch,
|
|
196
|
+
.primary,
|
|
197
|
+
.secondary,
|
|
198
|
+
.success,
|
|
199
|
+
.warning,
|
|
200
|
+
.destructive,
|
|
201
|
+
.info
|
|
202
|
+
)
|
|
203
|
+
) {
|
|
204
|
+
--intent-color: var(--color-text);
|
|
205
|
+
--intent-contrast: var(--color-text-contrast);
|
|
206
|
+
--intent-hover: var(--color-text-hover);
|
|
207
|
+
--intent-strong: var(--color-text-strong);
|
|
208
|
+
--intent-subtle: var(--color-surface);
|
|
209
|
+
--intent-border: var(--ui-control-ink, var(--ui-ink, var(--color-control-border)));
|
|
210
|
+
--intent-fill-max: 20%;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* The component seams: rules that beat their own component's body on
|
|
215
|
+
specificity, 0-2-0 against 0-1-0, in `utilities`. They write only package
|
|
216
|
+
privates or a state's intent slots, so nothing a consumer writes competes
|
|
217
|
+
with them. */
|
|
218
|
+
|
|
219
|
+
/* An invalid control is destructive whatever else it was asked to be. In
|
|
220
|
+
`utilities` above every intent class in `utilities.families` and both
|
|
221
|
+
resets in `components`, and
|
|
222
|
+
0-2-0 so it also outranks the control's own body and the reset above; a
|
|
223
|
+
consumer's utility setting an intent slot on an invalid field loses to it
|
|
224
|
+
too, because state wins over every choice (model.md#precedence).
|
|
225
|
+
`--intent-hover` is redirected with the others so the line does not go grey
|
|
226
|
+
under the pointer, and `--intent-strong` so typed text is destructive too.
|
|
227
|
+
`--intent-contrast` and `--intent-subtle` go with them, so an invalid
|
|
228
|
+
toggle is a destructive one in every part: left neutral, a checked invalid
|
|
229
|
+
checkbox in the dark theme drew the near-black neutral mark on a red plate
|
|
230
|
+
(3.28:1). The bare elements and the `.input-group` bridge are below the
|
|
231
|
+
utility, since they name no class `@apply` could carry. */
|
|
232
|
+
&[aria-invalid="true"] {
|
|
233
|
+
--intent-color: var(--color-destructive);
|
|
234
|
+
--intent-contrast: var(--color-destructive-contrast);
|
|
235
|
+
--intent-hover: var(--color-destructive-hover);
|
|
236
|
+
--intent-border: var(--color-destructive);
|
|
237
|
+
--intent-strong: var(--color-destructive-strong);
|
|
238
|
+
--intent-subtle: var(--color-destructive-subtle);
|
|
239
|
+
}
|
|
240
|
+
|
|
115
241
|
/* S1, P6: `:checked` is a state, so it re-declares the presentation inputs --
|
|
116
242
|
a full fill and full contrast ink -- and lifts the cap that would bound
|
|
117
243
|
them, and `box` composes the rest. It does not write a result: pinning
|
|
118
244
|
`--_fill` and `--_fg` directly would make a checked toggle ignore its own
|
|
119
245
|
aesthetic and elevation along with presentation. It sits in `utilities` at
|
|
120
|
-
0-2-0, above the fill classes in `
|
|
246
|
+
0-2-0, above the fill classes in `utilities.families`, so a checked toggle
|
|
247
|
+
renders
|
|
121
248
|
one plate whatever presentation it or a container asks for, and a
|
|
122
249
|
consumer's utility loses to it because state wins over every choice
|
|
123
250
|
(model.md#precedence). A toggle is a void `<input>`, so the inputs it
|
|
@@ -178,37 +305,21 @@
|
|
|
178
305
|
}
|
|
179
306
|
}
|
|
180
307
|
|
|
181
|
-
/* The
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
consumer writes competes with them. See
|
|
308
|
+
/* The seams that name no class `@apply text-control` could carry: bare
|
|
309
|
+
elements, the toggles' shared lift, and one component's own combination.
|
|
310
|
+
Placed in `utilities` and winning there on specificity, like the seams inside
|
|
311
|
+
the utility. They write only package privates or a state's intent slots, so
|
|
312
|
+
nothing a consumer writes competes with them. See
|
|
186
313
|
docs/internal/model.md#cascade-layers. */
|
|
187
314
|
@layer utilities {
|
|
188
|
-
/* A fill class on the element names its own cap; the 6% cascade cap in the
|
|
189
|
-
utility is for a container reaching a field nobody classed. Both raise
|
|
190
|
-
`--_fill-cap` rather than writing `--_fill` (P6), which is also what keeps
|
|
191
|
-
`.soft` < `.solid`: written as a rewrite, the louder name renders the
|
|
192
|
-
quieter box. 20% clears `.soft`'s 12% and matches the plate a `.solid`
|
|
193
|
-
badge draws.
|
|
194
|
-
|
|
195
|
-
`.switch` is deliberately absent: its track caps at 40% in its own utility,
|
|
196
|
-
and a 0-2-0 rule here would overrule that. See
|
|
197
|
-
model.md#the-bounds-that-survive-and-the-test-for-keeping-one. */
|
|
198
|
-
:is(.text-control, .ipt, .textarea, .select, .input-group).soft {
|
|
199
|
-
--_fill-cap: 12%;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
:is(.text-control, .ipt, .textarea, .select, .input-group).solid {
|
|
203
|
-
--_fill-cap: 20%;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
315
|
/* A checked text-control fills with its own intent, so neutral has to drop its
|
|
207
316
|
20% cap here. No toggle needs this arm any more (see below), but a text
|
|
208
317
|
input is never `:checked` in practice either -- kept for whatever custom
|
|
209
|
-
`.text-control` composition does check itself
|
|
210
|
-
`
|
|
211
|
-
|
|
318
|
+
`.text-control` composition does check itself; only an `<input>` can be,
|
|
319
|
+
so the `input` arm reaches an `@apply text-control` one too. A plain rule
|
|
320
|
+
at 0-2-0 in `utilities`, above every intent class in
|
|
321
|
+
`utilities.families`, so
|
|
322
|
+
`.neutral` on the element cannot put the cap back. */
|
|
212
323
|
:is(.text-control, input):checked {
|
|
213
324
|
--intent-fill-max: 100%;
|
|
214
325
|
}
|
|
@@ -222,60 +333,28 @@
|
|
|
222
333
|
controls carry no intent class at all, and it has to look like a present,
|
|
223
334
|
interactive box rather than a washed-out one just because nothing colored
|
|
224
335
|
it. Declared where the intents are, for the reason given above. */
|
|
225
|
-
:is(.checkbox, .radio, .switch) {
|
|
226
|
-
--intent-fill-max: 100%;
|
|
227
|
-
}
|
|
228
336
|
|
|
229
|
-
/*
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
/*
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
(`.soft`/`.solid`/default all rest above 0%), so only this pairing needs
|
|
244
|
-
the floor held up. `.switch.ghost.edgeless` therefore renders identically
|
|
245
|
-
to `.switch.ghost.edged`, and is published unsupported as a distinct look.
|
|
246
|
-
Higher specificity than the rule above (three classes, not an `:is()` of
|
|
247
|
-
one) wins regardless of source order. */
|
|
248
|
-
.switch.ghost.edgeless {
|
|
249
|
-
--_edge-floor: 100%;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/* An invalid control is destructive whatever else it was asked to be. It sits
|
|
253
|
-
in `utilities`, above every intent class and both intent resets in
|
|
254
|
-
`components`, and `:is()` gives it 0-2-0 so it also outranks the control's
|
|
255
|
-
own utility; a consumer's utility setting an intent slot on an invalid
|
|
256
|
-
field loses to it too, because state wins over every choice
|
|
257
|
-
(model.md#precedence). `--intent-hover` is redirected with the others so
|
|
258
|
-
the line does not go grey under the pointer, and `--intent-strong` so typed
|
|
259
|
-
text is destructive too. The `:has()` arm bridges an
|
|
260
|
-
inner control's state to an `.input-group`. */
|
|
261
|
-
:is(
|
|
262
|
-
.text-control,
|
|
263
|
-
.ipt,
|
|
264
|
-
.textarea,
|
|
265
|
-
.select,
|
|
266
|
-
.checkbox,
|
|
267
|
-
.radio,
|
|
268
|
-
.switch,
|
|
269
|
-
.input-group,
|
|
270
|
-
input,
|
|
271
|
-
textarea,
|
|
272
|
-
select
|
|
273
|
-
)[aria-invalid="true"],
|
|
337
|
+
/* `.switch`'s one exception to the `.edgeless` opt-out in `text-control`:
|
|
338
|
+
`.ghost` already asks for zero fill, so a `.switch.ghost.edgeless` track
|
|
339
|
+
would have neither a line nor a plate and disappear -- nothing would mark
|
|
340
|
+
its bounds but the floating knob. Every other fill on this component has
|
|
341
|
+
something to paint (`.soft`/`.solid`/default all rest above 0%), so only
|
|
342
|
+
this pairing needs the floor held up. `.switch.ghost.edgeless` therefore
|
|
343
|
+
renders identically to `.switch.ghost.edged`, and is published unsupported
|
|
344
|
+
as a distinct look. Three classes against the opt-out's two, so it wins
|
|
345
|
+
regardless of source order. */
|
|
346
|
+
|
|
347
|
+
/* `text-control`'s invalid state, for a bare field no class reaches and for
|
|
348
|
+
the `.input-group` whose control is invalid. The values are the
|
|
349
|
+
utility's; see the state there. */
|
|
350
|
+
:is(input, textarea, select)[aria-invalid="true"],
|
|
274
351
|
.input-group:has(> :is(.ipt, .textarea, .select, .text-control, input, textarea, select)[aria-invalid="true"]) {
|
|
275
352
|
--intent-color: var(--color-destructive);
|
|
353
|
+
--intent-contrast: var(--color-destructive-contrast);
|
|
276
354
|
--intent-hover: var(--color-destructive-hover);
|
|
277
355
|
--intent-border: var(--color-destructive);
|
|
278
356
|
--intent-strong: var(--color-destructive-strong);
|
|
357
|
+
--intent-subtle: var(--color-destructive-subtle);
|
|
279
358
|
}
|
|
280
359
|
}
|
|
281
360
|
|
|
@@ -296,9 +375,31 @@
|
|
|
296
375
|
4.5:1 there for several intents. On the three text inputs, not
|
|
297
376
|
`text-control`, because a toggle's mark takes `box`'s composed `--_fg`
|
|
298
377
|
instead. See docs/internal/model.md#intent. */
|
|
299
|
-
--_fg: var(--intent-strong);
|
|
300
|
-
|
|
301
|
-
|
|
378
|
+
--_fg-own: var(--intent-strong);
|
|
379
|
+
|
|
380
|
+
/* The button's size steps, so an `.ipt.sm` and a `.btn.sm` line up in a row:
|
|
381
|
+
the same 2rem and 3rem heights, the same text sizes, and the same
|
|
382
|
+
`--_scale-size` step `box` scales the corner by. Flags, read here, for the
|
|
383
|
+
reason `btn` gives. */
|
|
384
|
+
--_sm-h: var(--_size-sm) 2rem;
|
|
385
|
+
--_lg-h: var(--_size-lg) 3rem;
|
|
386
|
+
--_sm-px: var(--_size-sm) 0.625rem;
|
|
387
|
+
--_lg-px: var(--_size-lg) 1rem;
|
|
388
|
+
--_sm-py: var(--_size-sm) 0.25rem;
|
|
389
|
+
--_lg-py: var(--_size-lg) 0.625rem;
|
|
390
|
+
--_sm-text: var(--_size-sm) var(--text-sm);
|
|
391
|
+
--_lg-text: var(--_size-lg) 1.0625rem;
|
|
392
|
+
--_sm-leading: var(--_size-sm) var(--tw-leading, var(--text-sm--line-height));
|
|
393
|
+
--_sm-scale: var(--_size-sm) 0.75;
|
|
394
|
+
--_lg-scale: var(--_size-lg) 1.25;
|
|
395
|
+
--_scale-size: var(--_sm-scale, var(--_lg-scale));
|
|
396
|
+
|
|
397
|
+
height: var(--_sm-h, var(--_lg-h, var(--control-height, 2.5rem)));
|
|
398
|
+
min-height: var(--_sm-h, var(--_lg-h, var(--control-height)));
|
|
399
|
+
padding-inline: var(--_sm-px, var(--_lg-px, 0.75rem));
|
|
400
|
+
padding-block: var(--_sm-py, var(--_lg-py, 0.5rem));
|
|
401
|
+
font-size: var(--_sm-text, var(--_lg-text, inherit));
|
|
402
|
+
line-height: var(--_sm-leading, inherit);
|
|
302
403
|
}
|
|
303
404
|
|
|
304
405
|
@utility field {
|
|
@@ -308,9 +409,13 @@
|
|
|
308
409
|
}
|
|
309
410
|
|
|
310
411
|
@utility label {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
412
|
+
/* In `:where()`: a label's type is a default, and Tailwind emits this rule
|
|
413
|
+
after its own type utilities, so at 0-1-0 `.label.text-sm` stayed 16px. */
|
|
414
|
+
:where(&) {
|
|
415
|
+
font-size: 1rem;
|
|
416
|
+
font-weight: 500;
|
|
417
|
+
letter-spacing: 0.025em;
|
|
418
|
+
}
|
|
314
419
|
}
|
|
315
420
|
|
|
316
421
|
/* A hint wraps, so it takes `text-sm`'s leading like the package's other 14px
|
|
@@ -322,8 +427,15 @@
|
|
|
322
427
|
font-weight: 400;
|
|
323
428
|
letter-spacing: 0.05em;
|
|
324
429
|
|
|
325
|
-
|
|
326
|
-
|
|
430
|
+
/* A named intent prints its readable tone, `--intent-strong`, the colour
|
|
431
|
+
typed text takes: a hint is text on the page, and `--intent-color` is a
|
|
432
|
+
fill colour that reads below 4.5:1 there (destructive measured 3.28:1 on
|
|
433
|
+
the dark page). No intent, or `.neutral`, keeps the secondary grey that
|
|
434
|
+
marks a hint as helper text. A hint is not a component, so the intent
|
|
435
|
+
reset does not reach it and an intent on a container does not recolour
|
|
436
|
+
it; only a class on the hint itself does. */
|
|
437
|
+
&:is(.primary, .secondary, .success, .warning, .destructive, .info) {
|
|
438
|
+
color: var(--intent-strong);
|
|
327
439
|
}
|
|
328
440
|
}
|
|
329
441
|
|
|
@@ -341,9 +453,27 @@
|
|
|
341
453
|
4.5:1 there for several intents. On the three text inputs, not
|
|
342
454
|
`text-control`, because a toggle's mark takes `box`'s composed `--_fg`
|
|
343
455
|
instead. See docs/internal/model.md#intent. */
|
|
344
|
-
--_fg: var(--intent-strong);
|
|
456
|
+
--_fg-own: var(--intent-strong);
|
|
345
457
|
|
|
346
458
|
@apply min-h-28 resize-y;
|
|
459
|
+
|
|
460
|
+
/* The size steps `ipt` takes, for its text, padding, and corner. Its
|
|
461
|
+
height is its rows, so it keeps its own floor. */
|
|
462
|
+
--_sm-px: var(--_size-sm) 0.625rem;
|
|
463
|
+
--_lg-px: var(--_size-lg) 1rem;
|
|
464
|
+
--_sm-py: var(--_size-sm) 0.25rem;
|
|
465
|
+
--_lg-py: var(--_size-lg) 0.625rem;
|
|
466
|
+
--_sm-text: var(--_size-sm) var(--text-sm);
|
|
467
|
+
--_lg-text: var(--_size-lg) 1.0625rem;
|
|
468
|
+
--_sm-leading: var(--_size-sm) var(--tw-leading, var(--text-sm--line-height));
|
|
469
|
+
--_sm-scale: var(--_size-sm) 0.75;
|
|
470
|
+
--_lg-scale: var(--_size-lg) 1.25;
|
|
471
|
+
--_scale-size: var(--_sm-scale, var(--_lg-scale));
|
|
472
|
+
|
|
473
|
+
padding-inline: var(--_sm-px, var(--_lg-px, 0.75rem));
|
|
474
|
+
padding-block: var(--_sm-py, var(--_lg-py, 0.5rem));
|
|
475
|
+
font-size: var(--_sm-text, var(--_lg-text, inherit));
|
|
476
|
+
line-height: var(--_sm-leading, inherit);
|
|
347
477
|
}
|
|
348
478
|
|
|
349
479
|
/* The same control with a native list behind it. The chevron is drawn from two
|
|
@@ -362,7 +492,7 @@
|
|
|
362
492
|
4.5:1 there for several intents. On the three text inputs, not
|
|
363
493
|
`text-control`, because a toggle's mark takes `box`'s composed `--_fg`
|
|
364
494
|
instead. See docs/internal/model.md#intent. */
|
|
365
|
-
--_fg: var(--intent-strong);
|
|
495
|
+
--_fg-own: var(--intent-strong);
|
|
366
496
|
|
|
367
497
|
min-height: var(--control-height);
|
|
368
498
|
background-image:
|
|
@@ -374,6 +504,27 @@
|
|
|
374
504
|
background-repeat: no-repeat;
|
|
375
505
|
background-size: 0.3125rem 0.3125rem;
|
|
376
506
|
|
|
507
|
+
/* The size steps `ipt` takes. The inline end keeps the chevron's room. */
|
|
508
|
+
--_sm-h: var(--_size-sm) 2rem;
|
|
509
|
+
--_lg-h: var(--_size-lg) 3rem;
|
|
510
|
+
--_sm-px: var(--_size-sm) 0.625rem;
|
|
511
|
+
--_lg-px: var(--_size-lg) 1rem;
|
|
512
|
+
--_sm-py: var(--_size-sm) 0.25rem;
|
|
513
|
+
--_lg-py: var(--_size-lg) 0.625rem;
|
|
514
|
+
--_sm-text: var(--_size-sm) var(--text-sm);
|
|
515
|
+
--_lg-text: var(--_size-lg) 1.0625rem;
|
|
516
|
+
--_sm-leading: var(--_size-sm) var(--tw-leading, var(--text-sm--line-height));
|
|
517
|
+
--_sm-scale: var(--_size-sm) 0.75;
|
|
518
|
+
--_lg-scale: var(--_size-lg) 1.25;
|
|
519
|
+
--_scale-size: var(--_sm-scale, var(--_lg-scale));
|
|
520
|
+
|
|
521
|
+
height: var(--_sm-h, var(--_lg-h, var(--control-height, 2.5rem)));
|
|
522
|
+
min-height: var(--_sm-h, var(--_lg-h, var(--control-height)));
|
|
523
|
+
padding-inline-start: var(--_sm-px, var(--_lg-px, 0.75rem));
|
|
524
|
+
padding-block: var(--_sm-py, var(--_lg-py, 0.5rem));
|
|
525
|
+
font-size: var(--_sm-text, var(--_lg-text, inherit));
|
|
526
|
+
line-height: var(--_sm-leading, inherit);
|
|
527
|
+
|
|
377
528
|
/* The chevron sits at the inline end, like the padding kept for it, so a
|
|
378
529
|
right-to-left select draws it at the left. `background-position` has no
|
|
379
530
|
logical form, so the mirror is named here. */
|
|
@@ -436,12 +587,29 @@
|
|
|
436
587
|
--_d-border: 100%;
|
|
437
588
|
--_d-elevation: 0;
|
|
438
589
|
|
|
590
|
+
/* The size steps `ipt` takes, on the group rather than the control inside:
|
|
591
|
+
the group is the field, and the control and its adornments inherit the
|
|
592
|
+
text size. The control's height is the group's (below), so the group's
|
|
593
|
+
floor is its height. */
|
|
594
|
+
--_sm-h: var(--_size-sm) 2rem;
|
|
595
|
+
--_lg-h: var(--_size-lg) 3rem;
|
|
596
|
+
--_sm-px: var(--_size-sm) 0.625rem;
|
|
597
|
+
--_lg-px: var(--_size-lg) 1rem;
|
|
598
|
+
--_sm-text: var(--_size-sm) var(--text-sm);
|
|
599
|
+
--_lg-text: var(--_size-lg) 1.0625rem;
|
|
600
|
+
--_sm-leading: var(--_size-sm) var(--tw-leading, var(--text-sm--line-height));
|
|
601
|
+
--_sm-scale: var(--_size-sm) 0.75;
|
|
602
|
+
--_lg-scale: var(--_size-lg) 1.25;
|
|
603
|
+
--_scale-size: var(--_sm-scale, var(--_lg-scale));
|
|
604
|
+
|
|
439
605
|
--input-group-gap: 0.5rem;
|
|
440
|
-
--input-group-pad: 0.75rem;
|
|
606
|
+
--input-group-pad: var(--_sm-px, var(--_lg-px, 0.75rem));
|
|
441
607
|
|
|
442
|
-
min-height: var(--control-height);
|
|
608
|
+
min-height: var(--_sm-h, var(--_lg-h, var(--control-height)));
|
|
443
609
|
gap: var(--input-group-gap);
|
|
444
610
|
padding-inline: var(--input-group-pad);
|
|
611
|
+
font-size: var(--_sm-text, var(--_lg-text, inherit));
|
|
612
|
+
line-height: var(--_sm-leading, inherit);
|
|
445
613
|
|
|
446
614
|
/* The focus ring the wrapper cannot get from `:focus-visible` -- a `<div>` is
|
|
447
615
|
not focusable, and `:has(:focus-visible)` is unreliable because the inner
|
|
@@ -454,27 +622,92 @@
|
|
|
454
622
|
&:focus-within {
|
|
455
623
|
--_line-tone: var(--intent-color);
|
|
456
624
|
|
|
457
|
-
outline: var(--focus-ring-width) solid var(--focus-ring);
|
|
625
|
+
outline: var(--focus-ring-width) solid var(--focus-ring, color-mix(in srgb, var(--color-primary) 64%, transparent));
|
|
458
626
|
outline-offset: var(--focus-ring-offset, calc(-1 * var(--ui-border-width, var(--border-width))));
|
|
459
|
-
box-shadow: var(--_focus-stack, var(--_shadow));
|
|
627
|
+
box-shadow: var(--_focus-stack, var(--_shadow), inset 0 0 0 2px var(--_focus-gap));
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/* Focus on anything but the field -- the clear button the docs show, a
|
|
631
|
+
toggle -- is focus on that control, so it keeps its own ring and the group
|
|
632
|
+
drops the field's. Enter presses a focused button rather than typing into
|
|
633
|
+
the field, and two rings around one target say neither. The line keeps its
|
|
634
|
+
focus tone: something in the field still has focus. A separate rule rather
|
|
635
|
+
than a `:not(:has())` on the ring above, so an engine without `:has()`
|
|
636
|
+
drops only this rule and keeps the group's ring. */
|
|
637
|
+
&:has(> :not(.ipt, .textarea, .select, .text-control, input, textarea, select):focus) {
|
|
638
|
+
outline: none;
|
|
639
|
+
box-shadow: var(--_shadow);
|
|
460
640
|
}
|
|
461
641
|
|
|
462
642
|
/* A disabled control inside dims the whole group. `.input-group.disabled` and
|
|
463
643
|
the aria/data spellings are already handled by `box`'s own rule, carried in
|
|
464
644
|
by `text-control`; this is the child-driven case a wrapper cannot see
|
|
465
645
|
without `:has()`. */
|
|
466
|
-
&:has(
|
|
646
|
+
&:has(
|
|
647
|
+
> :is(.ipt, .textarea, .select, .text-control, input, textarea, select):where(
|
|
648
|
+
:not(
|
|
649
|
+
.checkbox,
|
|
650
|
+
.radio,
|
|
651
|
+
.switch,
|
|
652
|
+
.btn,
|
|
653
|
+
[type="checkbox"],
|
|
654
|
+
[type="radio"],
|
|
655
|
+
[type="button"],
|
|
656
|
+
[type="submit"],
|
|
657
|
+
[type="reset"],
|
|
658
|
+
[type="image"],
|
|
659
|
+
[type="range"],
|
|
660
|
+
[type="color"],
|
|
661
|
+
[type="file"],
|
|
662
|
+
[type="hidden"]
|
|
663
|
+
)
|
|
664
|
+
):disabled
|
|
665
|
+
) {
|
|
467
666
|
@apply cursor-not-allowed;
|
|
468
667
|
|
|
469
668
|
opacity: 0.58;
|
|
470
669
|
}
|
|
471
670
|
|
|
472
|
-
/* The control
|
|
671
|
+
/* "The control inside" is a text field. Every selector below that names it
|
|
672
|
+
ends in the same `:where(:not(...))`, which takes out the toggles, the
|
|
673
|
+
button-like inputs, and the inputs that draw their own widget: matched,
|
|
674
|
+
a checkbox in a group lost its box and its line, and stretched like a
|
|
675
|
+
field. In `:where()`, so the exclusion adds no specificity.
|
|
676
|
+
|
|
677
|
+
The control goes flush: the group drew the box, so the control paints no
|
|
473
678
|
fill, no line and no ring, and gives its horizontal padding to the group.
|
|
474
679
|
`border: none` rather than a transparent 1px, so the control does not add
|
|
475
|
-
its own width inside the group.
|
|
476
|
-
|
|
680
|
+
its own width inside the group.
|
|
681
|
+
|
|
682
|
+
The typed text is the one paint the control keeps, and it is the group's
|
|
683
|
+
intent: the control resets its intent to neutral at its own root, like
|
|
684
|
+
every component, so an `.input-group.success` drew a success line around
|
|
685
|
+
neutral text. `--intent-strong` is the only slot the text reads, so it
|
|
686
|
+
alone inherits, and an invalid group -- by its own `aria-invalid` or the
|
|
687
|
+
control's, through the `:has()` arm -- prints destructive text the way a
|
|
688
|
+
lone invalid field does. The group owns the field, so an intent class on
|
|
689
|
+
the control inside does not colour its text. */
|
|
690
|
+
&
|
|
691
|
+
> :is(.ipt, .textarea, .select, .text-control, input, textarea, select):where(
|
|
692
|
+
:not(
|
|
693
|
+
.checkbox,
|
|
694
|
+
.radio,
|
|
695
|
+
.switch,
|
|
696
|
+
.btn,
|
|
697
|
+
[type="checkbox"],
|
|
698
|
+
[type="radio"],
|
|
699
|
+
[type="button"],
|
|
700
|
+
[type="submit"],
|
|
701
|
+
[type="reset"],
|
|
702
|
+
[type="image"],
|
|
703
|
+
[type="range"],
|
|
704
|
+
[type="color"],
|
|
705
|
+
[type="file"],
|
|
706
|
+
[type="hidden"]
|
|
707
|
+
)
|
|
708
|
+
) {
|
|
477
709
|
--_fill-cap: 0%;
|
|
710
|
+
--intent-strong: inherit;
|
|
478
711
|
|
|
479
712
|
flex: 1 1 auto;
|
|
480
713
|
min-width: 0;
|
|
@@ -487,6 +720,46 @@
|
|
|
487
720
|
outline: none;
|
|
488
721
|
box-shadow: none;
|
|
489
722
|
}
|
|
723
|
+
|
|
724
|
+
/* The group dims for a disabled control, so the control does not dim
|
|
725
|
+
again inside it: opacity multiplies, and the two 0.58s left the value
|
|
726
|
+
at about 0.34. Only `:disabled`, the state the group's `:has()` above
|
|
727
|
+
bridges; a control disabled by class or aria dims itself as a lone one
|
|
728
|
+
does, because the group does not dim for it. */
|
|
729
|
+
&:disabled {
|
|
730
|
+
opacity: 1;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/* A one-row control gives its height to the group too. Keeping its own
|
|
735
|
+
`--control-height` inside a box that draws its own line made the group
|
|
736
|
+
42px next to 40px fields and buttons. It stretches to the group's inside
|
|
737
|
+
instead, with no block padding, so the group is the control height and the
|
|
738
|
+
whole of its inside still takes a click. A textarea and a list box keep
|
|
739
|
+
their own height: their rows are the height. */
|
|
740
|
+
&
|
|
741
|
+
> :is(.ipt, .select, input, select):not([multiple], [size]:not([size="1"])):where(
|
|
742
|
+
:not(
|
|
743
|
+
.checkbox,
|
|
744
|
+
.radio,
|
|
745
|
+
.switch,
|
|
746
|
+
.btn,
|
|
747
|
+
[type="checkbox"],
|
|
748
|
+
[type="radio"],
|
|
749
|
+
[type="button"],
|
|
750
|
+
[type="submit"],
|
|
751
|
+
[type="reset"],
|
|
752
|
+
[type="image"],
|
|
753
|
+
[type="range"],
|
|
754
|
+
[type="color"],
|
|
755
|
+
[type="file"],
|
|
756
|
+
[type="hidden"]
|
|
757
|
+
)
|
|
758
|
+
) {
|
|
759
|
+
align-self: stretch;
|
|
760
|
+
height: auto;
|
|
761
|
+
min-height: 0;
|
|
762
|
+
padding-block: 0;
|
|
490
763
|
}
|
|
491
764
|
|
|
492
765
|
/* Except a drop-down's end: its chevron is the select's own background,
|
|
@@ -498,12 +771,45 @@
|
|
|
498
771
|
}
|
|
499
772
|
|
|
500
773
|
/* Anything else in the group -- an icon, affix text -- does not stretch and
|
|
501
|
-
reads as secondary. A
|
|
502
|
-
|
|
774
|
+
reads as secondary. A button, a link button, and any `<input>` keep their
|
|
775
|
+
own styling. Zero specificity: it is a default for unstyled content, and at
|
|
776
|
+
the 0-2-0 it had, a badge or a text utility on the adornment lost its
|
|
777
|
+
colour to this grey. */
|
|
778
|
+
:where(& > :not(.ipt, .textarea, .select, .text-control, input, textarea, select, button, .btn)) {
|
|
503
779
|
@apply inline-flex flex-none items-center;
|
|
504
780
|
|
|
505
781
|
color: var(--color-text-secondary);
|
|
506
782
|
}
|
|
783
|
+
|
|
784
|
+
/* The group is destructive when its control is invalid. Carried here for an
|
|
785
|
+
applied group; the package's own keeps the plain rule above the utility. */
|
|
786
|
+
&:has(
|
|
787
|
+
> :is(.ipt, .textarea, .select, .text-control, input, textarea, select):where(
|
|
788
|
+
:not(
|
|
789
|
+
.checkbox,
|
|
790
|
+
.radio,
|
|
791
|
+
.switch,
|
|
792
|
+
.btn,
|
|
793
|
+
[type="checkbox"],
|
|
794
|
+
[type="radio"],
|
|
795
|
+
[type="button"],
|
|
796
|
+
[type="submit"],
|
|
797
|
+
[type="reset"],
|
|
798
|
+
[type="image"],
|
|
799
|
+
[type="range"],
|
|
800
|
+
[type="color"],
|
|
801
|
+
[type="file"],
|
|
802
|
+
[type="hidden"]
|
|
803
|
+
)
|
|
804
|
+
)[aria-invalid="true"]
|
|
805
|
+
) {
|
|
806
|
+
--intent-color: var(--color-destructive);
|
|
807
|
+
--intent-contrast: var(--color-destructive-contrast);
|
|
808
|
+
--intent-hover: var(--color-destructive-hover);
|
|
809
|
+
--intent-border: var(--color-destructive);
|
|
810
|
+
--intent-strong: var(--color-destructive-strong);
|
|
811
|
+
--intent-subtle: var(--color-destructive-subtle);
|
|
812
|
+
}
|
|
507
813
|
}
|
|
508
814
|
|
|
509
815
|
/* The three toggles compose `text-control` for its bounds, not its chrome: the
|
|
@@ -523,6 +829,8 @@
|
|
|
523
829
|
--_d-fill: 12%;
|
|
524
830
|
--_d-fg-on-fill: 0%;
|
|
525
831
|
--_fill-cap: 40%;
|
|
832
|
+
/* Absolute, whatever the element's own edge class: see `text-control`. */
|
|
833
|
+
--_edge-floor: 100%;
|
|
526
834
|
--_line-rest: 100%;
|
|
527
835
|
--_d-border: 100%;
|
|
528
836
|
--_d-elevation: 0;
|
|
@@ -548,7 +856,9 @@
|
|
|
548
856
|
rather than as an `outline`, so a clipping aesthetic clips it with
|
|
549
857
|
everything else and its own inset focus layer still paints over the top. */
|
|
550
858
|
&:focus-visible {
|
|
551
|
-
--_shadow:
|
|
859
|
+
--_shadow:
|
|
860
|
+
var(--_shadow-parts) var(--_halo-layer,),
|
|
861
|
+
0 0 0 var(--focus-ring-width) var(--focus-ring, color-mix(in srgb, var(--color-primary) 64%, transparent));
|
|
552
862
|
}
|
|
553
863
|
|
|
554
864
|
&::after {
|
|
@@ -593,6 +903,33 @@
|
|
|
593
903
|
transition-duration: 0.01ms;
|
|
594
904
|
}
|
|
595
905
|
}
|
|
906
|
+
|
|
907
|
+
/* The toggle's cap is its own (`--_fill-cap`), whatever the intent: a
|
|
908
|
+
neutral fill stops at 20% elsewhere because it is the page's ink, and a
|
|
909
|
+
neutral checkbox is the common case and has to look like a present,
|
|
910
|
+
interactive box. In the body so `@apply` carries it; it beats the intent
|
|
911
|
+
classes from here as it did as a plain rule in `utilities`. */
|
|
912
|
+
--intent-fill-max: 100%;
|
|
913
|
+
|
|
914
|
+
/* Forced colours, carried for an applied toggle. The package's own classes
|
|
915
|
+
also keep the unlayered copy at the foot of this file, which beats every
|
|
916
|
+
layered rule. */
|
|
917
|
+
@media (forced-colors: active) {
|
|
918
|
+
forced-color-adjust: none;
|
|
919
|
+
background-color: Canvas;
|
|
920
|
+
border-color: CanvasText;
|
|
921
|
+
transition: none;
|
|
922
|
+
|
|
923
|
+
&:checked,
|
|
924
|
+
&:indeterminate {
|
|
925
|
+
background-color: Highlight;
|
|
926
|
+
border-color: Highlight;
|
|
927
|
+
|
|
928
|
+
&::after {
|
|
929
|
+
background-color: HighlightText;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
596
933
|
}
|
|
597
934
|
|
|
598
935
|
/* The same control with a round silhouette and a dot for its mark, and the
|
|
@@ -605,6 +942,8 @@
|
|
|
605
942
|
--_d-fill: 12%;
|
|
606
943
|
--_d-fg-on-fill: 0%;
|
|
607
944
|
--_fill-cap: 40%;
|
|
945
|
+
/* Absolute, whatever the element's own edge class: see `text-control`. */
|
|
946
|
+
--_edge-floor: 100%;
|
|
608
947
|
--_line-rest: 100%;
|
|
609
948
|
--_d-border: 100%;
|
|
610
949
|
--_d-elevation: 0;
|
|
@@ -619,7 +958,9 @@
|
|
|
619
958
|
|
|
620
959
|
/* The ring, for the reason given on `checkbox`. */
|
|
621
960
|
&:focus-visible {
|
|
622
|
-
--_shadow:
|
|
961
|
+
--_shadow:
|
|
962
|
+
var(--_shadow-parts) var(--_halo-layer,),
|
|
963
|
+
0 0 0 var(--focus-ring-width) var(--focus-ring, color-mix(in srgb, var(--color-primary) 64%, transparent));
|
|
623
964
|
}
|
|
624
965
|
|
|
625
966
|
&::after {
|
|
@@ -660,6 +1001,32 @@
|
|
|
660
1001
|
transition-duration: 0.01ms;
|
|
661
1002
|
}
|
|
662
1003
|
}
|
|
1004
|
+
|
|
1005
|
+
/* The toggle's cap is its own (`--_fill-cap`), whatever the intent: a
|
|
1006
|
+
neutral fill stops at 20% elsewhere because it is the page's ink, and a
|
|
1007
|
+
neutral checkbox is the common case and has to look like a present,
|
|
1008
|
+
interactive box. In the body so `@apply` carries it; it beats the intent
|
|
1009
|
+
classes from here as it did as a plain rule in `utilities`. */
|
|
1010
|
+
--intent-fill-max: 100%;
|
|
1011
|
+
|
|
1012
|
+
/* Forced colours, carried for an applied toggle. The package's own classes
|
|
1013
|
+
also keep the unlayered copy at the foot of this file, which beats every
|
|
1014
|
+
layered rule. */
|
|
1015
|
+
@media (forced-colors: active) {
|
|
1016
|
+
forced-color-adjust: none;
|
|
1017
|
+
background-color: Canvas;
|
|
1018
|
+
border-color: CanvasText;
|
|
1019
|
+
transition: none;
|
|
1020
|
+
|
|
1021
|
+
&:checked {
|
|
1022
|
+
background-color: Highlight;
|
|
1023
|
+
border-color: Highlight;
|
|
1024
|
+
|
|
1025
|
+
&::after {
|
|
1026
|
+
background-color: HighlightText;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
663
1030
|
}
|
|
664
1031
|
|
|
665
1032
|
/* A2: every dimension derives from the border width `box` resolved, so the knob
|
|
@@ -715,7 +1082,9 @@
|
|
|
715
1082
|
|
|
716
1083
|
/* The ring, for the reason given on `checkbox`. */
|
|
717
1084
|
&:focus-visible {
|
|
718
|
-
--_shadow:
|
|
1085
|
+
--_shadow:
|
|
1086
|
+
var(--_shadow-parts) var(--_halo-layer,),
|
|
1087
|
+
0 0 0 var(--focus-ring-width) var(--focus-ring, color-mix(in srgb, var(--color-primary) 64%, transparent));
|
|
719
1088
|
}
|
|
720
1089
|
|
|
721
1090
|
&::after {
|
|
@@ -759,6 +1128,43 @@
|
|
|
759
1128
|
transition-duration: 0.01ms;
|
|
760
1129
|
}
|
|
761
1130
|
}
|
|
1131
|
+
|
|
1132
|
+
/* `.ghost.edgeless` would leave the track neither a line nor a plate, so the
|
|
1133
|
+
floor is held up: three classes against the opt-out's two in
|
|
1134
|
+
`text-control`. Published unsupported as a distinct look. */
|
|
1135
|
+
&.ghost.edgeless {
|
|
1136
|
+
--_edge-floor: 100%;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
/* The toggle's cap is its own (`--_fill-cap`), whatever the intent: a
|
|
1140
|
+
neutral fill stops at 20% elsewhere because it is the page's ink, and a
|
|
1141
|
+
neutral checkbox is the common case and has to look like a present,
|
|
1142
|
+
interactive box. In the body so `@apply` carries it; it beats the intent
|
|
1143
|
+
classes from here as it did as a plain rule in `utilities`. */
|
|
1144
|
+
--intent-fill-max: 100%;
|
|
1145
|
+
|
|
1146
|
+
/* Forced colours, carried for an applied toggle. The package's own classes
|
|
1147
|
+
also keep the unlayered copy at the foot of this file, which beats every
|
|
1148
|
+
layered rule. */
|
|
1149
|
+
@media (forced-colors: active) {
|
|
1150
|
+
forced-color-adjust: none;
|
|
1151
|
+
background-color: Canvas;
|
|
1152
|
+
border-color: CanvasText;
|
|
1153
|
+
transition: none;
|
|
1154
|
+
|
|
1155
|
+
&::after {
|
|
1156
|
+
background-color: CanvasText;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
&:checked {
|
|
1160
|
+
background-color: Highlight;
|
|
1161
|
+
border-color: Highlight;
|
|
1162
|
+
|
|
1163
|
+
&::after {
|
|
1164
|
+
background-color: HighlightText;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
762
1168
|
}
|
|
763
1169
|
|
|
764
1170
|
@media (forced-colors: active) {
|
|
@@ -810,4 +1216,11 @@
|
|
|
810
1216
|
outline-offset: 2px;
|
|
811
1217
|
box-shadow: none;
|
|
812
1218
|
}
|
|
1219
|
+
|
|
1220
|
+
/* The group draws the field's ring, so the control inside draws none here
|
|
1221
|
+
either: this block is unlayered, and the ring above beat the group's
|
|
1222
|
+
layered suppression and drew a second ring inside the group's. */
|
|
1223
|
+
.input-group > :is(.ipt, .textarea, .select, .text-control, input, textarea, select):focus-visible {
|
|
1224
|
+
outline: none;
|
|
1225
|
+
}
|
|
813
1226
|
}
|