clairity.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.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +27 -0
- data/.gitignore +66 -0
- data/CHANGELOG.md +423 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +373 -0
- data/README.md +170 -0
- data/Rakefile +12 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/clairity.css.gemspec +51 -0
- data/lib/assets/css/clairity/base.css +951 -0
- data/lib/assets/css/clairity/classes.css +264 -0
- data/lib/assets/css/clairity/components.css +946 -0
- data/lib/assets/css/clairity/cosmetic.css +157 -0
- data/lib/assets/css/clairity/functions.css +46 -0
- data/lib/assets/css/clairity/icons.css +44 -0
- data/lib/assets/css/clairity/normalize.css +239 -0
- data/lib/assets/css/clairity/palette.css +329 -0
- data/lib/assets/css/clairity/shims.css +20 -0
- data/lib/assets/css/clairity/states.css +756 -0
- data/lib/assets/css/clairity/utilities.css +68 -0
- data/lib/assets/css/clairity/variables.css +301 -0
- data/lib/assets/css/clairity.basic.css +28 -0
- data/lib/assets/css/clairity.classless.css +50 -0
- data/lib/assets/css/clairity.css +109 -0
- data/lib/assets/images/input-image.png +0 -0
- data/lib/assets/images/logo.png +0 -0
- data/lib/assets/images/profile-avatar.png +0 -0
- data/lib/assets/js/clairity.css.js +6 -0
- data/lib/assets/media/t-rex_roar.mp3 +0 -0
- data/lib/clairity.css/version.rb +5 -0
- data/lib/clairity.css.rb +10 -0
- data/sig/clairity.css.rbs +4 -0
- data/test/test_clairity_css.rb +17 -0
- data/test/test_helper.rb +5 -0
- metadata +128 -0
@@ -0,0 +1,946 @@
|
|
1
|
+
/******************************************************************************\
|
2
|
+
COMPONENTS - for more complex sites, composable components can provide
|
3
|
+
greater aesthetics and usability.
|
4
|
+
\******************************************************************************/
|
5
|
+
|
6
|
+
|
7
|
+
/* -----------------------------------------------------------------------------
|
8
|
+
// #sectioning #containers
|
9
|
+
// -------------------------------------------------------------------------- */
|
10
|
+
|
11
|
+
/* #body - auto-grid by default - overrides base.css default body definition.
|
12
|
+
set --columns to the number of columns desired */
|
13
|
+
body {
|
14
|
+
display: grid;
|
15
|
+
grid-template-columns: [full-start] var(--padding, var(--m))
|
16
|
+
[padded-start] repeat(var(--columns, auto-fit),
|
17
|
+
minmax(var(--grid), 1fr)) [padded-end]
|
18
|
+
var(--padding, var(--m)) [full-end];
|
19
|
+
column-gap: var(--gap); /* flexible between 400 - 800px */
|
20
|
+
max-width: unset;
|
21
|
+
}
|
22
|
+
|
23
|
+
/* some containers should span full or padded width by default if in the grid */
|
24
|
+
:where(:not(.grid)) > main { grid-column: padded; }
|
25
|
+
nav, header, footer {
|
26
|
+
grid-column: full;
|
27
|
+
}
|
28
|
+
|
29
|
+
/* the top header typically should sit flush to the top of the page and use
|
30
|
+
padding; TODO: this seems to be over-specified */
|
31
|
+
body > header:first-child {
|
32
|
+
margin-top: 0;
|
33
|
+
}
|
34
|
+
|
35
|
+
/* #footer - centered grid by default; this grid overrides base.css definition*/
|
36
|
+
footer {
|
37
|
+
grid-template-columns: [full-start] repeat(auto-fit,
|
38
|
+
minmax(var(--column), 1fr)) [full-end];
|
39
|
+
grid-auto-rows: min-content; /* don't unnecessarily expand rows */
|
40
|
+
column-gap: var(--m);
|
41
|
+
container-type: unset; /* safari doesn't like contain with grid */
|
42
|
+
padding-inline: var(--padding, var(--m)); /* flexible padding */
|
43
|
+
}
|
44
|
+
|
45
|
+
footer > p { grid-column: 1 / -1; } /* take up a whole row in the grid */
|
46
|
+
|
47
|
+
|
48
|
+
/* -----------------------------------------------------------------------------
|
49
|
+
// #headings -
|
50
|
+
// -------------------------------------------------------------------------- */
|
51
|
+
|
52
|
+
header:not(.banner) {
|
53
|
+
display: flex;
|
54
|
+
flex-wrap: wrap;
|
55
|
+
justify-content: space-between;
|
56
|
+
}
|
57
|
+
|
58
|
+
header :where(h1,h2,h3,h4,h5,h6) {
|
59
|
+
}
|
60
|
+
|
61
|
+
header :where(p) {
|
62
|
+
flex: 1 0 100%;
|
63
|
+
}
|
64
|
+
|
65
|
+
|
66
|
+
/* -----------------------------------------------------------------------------
|
67
|
+
// site #footer - typical fat footer; #footer is the singular site footer
|
68
|
+
// -------------------------------------------------------------------------- */
|
69
|
+
|
70
|
+
/* #fat footers are typically distinct and feature a set of columns with links*/
|
71
|
+
.fat, :where(body) > :where(footer):last-of-type { /* [0010] specificity */
|
72
|
+
grid-column: 1 / -1; /* fat footers are full width */
|
73
|
+
max-width: -webkit-fill-available; /* take full width */
|
74
|
+
max-width: -moz-available; /* take full width on firefox */
|
75
|
+
--muted: var(--300, GrayText);
|
76
|
+
color: var(--whitish);
|
77
|
+
background-color: var(--blackish);
|
78
|
+
}
|
79
|
+
|
80
|
+
/* .nav - flex container to group/align columns of <nav>s - [0010] specificity*/
|
81
|
+
.nav {
|
82
|
+
grid-column: 1 / -1; /* break free of the grid, if any */
|
83
|
+
display: flex;
|
84
|
+
flex-wrap: wrap;
|
85
|
+
margin-inline: var(--padding); /* responsive inline, outer margin */
|
86
|
+
column-gap: var(--l); /* fixed inline, inner gap */
|
87
|
+
}
|
88
|
+
|
89
|
+
/* #nav - column-oriented navs - [0001] specificity */
|
90
|
+
:where(.nav) nav {
|
91
|
+
grid-column: unset;
|
92
|
+
flex-direction: column;
|
93
|
+
flex-grow: 1; /* take up the whole role if orphaned */
|
94
|
+
flex-basis: calc((40vw - 100%) * 999);
|
95
|
+
align-items: start; /* some items will float otherwise */
|
96
|
+
row-gap: var(--s); /* add some vertical spacing */
|
97
|
+
justify-content: start;
|
98
|
+
min-width: var(--column); /* 44vw/10rem for narrow screens */
|
99
|
+
}
|
100
|
+
|
101
|
+
/* style headers in the site footer */
|
102
|
+
:where(.fat, body > footer:last-of-type)
|
103
|
+
:is(h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6) {
|
104
|
+
color: var(--muted);
|
105
|
+
font-weight: var(--light);
|
106
|
+
}
|
107
|
+
|
108
|
+
:where(.fat, body > footer:last-of-type) a {
|
109
|
+
font-weight: var(--light);
|
110
|
+
}
|
111
|
+
|
112
|
+
:where(.fat, body > footer:last-of-type) a:not(:hover) {
|
113
|
+
color: var(--whitish);
|
114
|
+
text-decoration: none;
|
115
|
+
}
|
116
|
+
|
117
|
+
|
118
|
+
/* -----------------------------------------------------------------------------
|
119
|
+
// #footnotes
|
120
|
+
// -------------------------------------------------------------------------- */
|
121
|
+
|
122
|
+
/* #footnotes - footnotes/endnotes typically should have the semantic marker of
|
123
|
+
[role="doc-endnote"]; :target doesn't depend on color-scheme here - it's
|
124
|
+
always dark on light. transition to the highlight, to draw the eye to it. */
|
125
|
+
[role="doc-endnotes"] {
|
126
|
+
grid-column: 1 / -1;
|
127
|
+
}
|
128
|
+
|
129
|
+
:where([role="doc-endnote"]):target { /* [0010] specificity */
|
130
|
+
color: var(--blackish);
|
131
|
+
background-color: hsl(var(--yellow), 90%, 75%);
|
132
|
+
transition: color 1s 0.5s, background-color 1s 0.5s;
|
133
|
+
}
|
134
|
+
|
135
|
+
/* ::marker text is outside :target, so match color-scheme text color */
|
136
|
+
:where([role="doc-endnote"]):target::marker { /* [0011] specificity */
|
137
|
+
color: var(--text);
|
138
|
+
}
|
139
|
+
|
140
|
+
|
141
|
+
/* -----------------------------------------------------------------------------
|
142
|
+
// #icons - svg icons
|
143
|
+
// -------------------------------------------------------------------------- */
|
144
|
+
|
145
|
+
i[class^='i-'] {
|
146
|
+
--icon-color: var(--color, currentColor);
|
147
|
+
-webkit-mask: var(--icon) no-repeat center / var(--field-icon);
|
148
|
+
mask: var(--icon) no-repeat center / var(--field-icon);
|
149
|
+
background-color: var(--icon-color);
|
150
|
+
padding: var(--inline-padding);
|
151
|
+
min-height: var(--ml); /* else naked icons collapse into a line */
|
152
|
+
}
|
153
|
+
|
154
|
+
|
155
|
+
/* -----------------------------------------------------------------------------
|
156
|
+
// #banner - header that usually includes a hero image and perhaps a nav
|
157
|
+
// -------------------------------------------------------------------------- */
|
158
|
+
|
159
|
+
.banner {
|
160
|
+
--content-width: 60ch;
|
161
|
+
--banner-height: 50vh;
|
162
|
+
--banner-max-height: 600px;
|
163
|
+
display: grid;
|
164
|
+
grid-template-areas: "banner";
|
165
|
+
place-items: center;
|
166
|
+
align-self: flex-start;
|
167
|
+
height: var(--banner-height);
|
168
|
+
/*max-height: var(--banner-max-height);*/
|
169
|
+
/*background-color: var(--primary-transparent);*/ /* bg color was meant
|
170
|
+
to provide contrast in case an image was missing,
|
171
|
+
but makes banners look weird */
|
172
|
+
overflow: hidden;
|
173
|
+
}
|
174
|
+
|
175
|
+
/* extra margin for banner menu */
|
176
|
+
/*.banner menu { margin-block: var(--ml); }*/
|
177
|
+
|
178
|
+
/* banner #content - constrain content width with a css variable set on parent*/
|
179
|
+
.banner .content { width: var(--content-width); }
|
180
|
+
|
181
|
+
/* banner grid */
|
182
|
+
.banner > * { grid-area: banner; }
|
183
|
+
.banner > nav {
|
184
|
+
place-self: start center;
|
185
|
+
width: var(--line-length);
|
186
|
+
}
|
187
|
+
.banner nav menu { /*flex: auto;*/ }
|
188
|
+
|
189
|
+
.banner > img, .hero {
|
190
|
+
height: min(var(--banner-height), var(--banner-max-height));
|
191
|
+
width: 100%;
|
192
|
+
max-width: none;
|
193
|
+
z-index: -1;
|
194
|
+
}
|
195
|
+
|
196
|
+
.banner figure {
|
197
|
+
--figure-max-height: 10rem;
|
198
|
+
grid-area: unset;
|
199
|
+
max-height: var(--figure-max-height);
|
200
|
+
background-color: unset;
|
201
|
+
border: unset;
|
202
|
+
margin: unset;
|
203
|
+
padding: unset;
|
204
|
+
}
|
205
|
+
|
206
|
+
.banner:has(figure) {
|
207
|
+
margin-bottom: 0;
|
208
|
+
}
|
209
|
+
|
210
|
+
/*remove top margin when the .banner is the first element on the page - [0010]*/
|
211
|
+
:where(body) > :where(main) > :where(.banner):first-of-type {
|
212
|
+
margin-top: 0;
|
213
|
+
}
|
214
|
+
|
215
|
+
/* -----------------------------------------------------------------------------
|
216
|
+
// #alert - the alert flash message box for providing timely info to the user
|
217
|
+
// -------------------------------------------------------------------------- */
|
218
|
+
|
219
|
+
/* #alert - the default alert box is an info box */
|
220
|
+
.alert {
|
221
|
+
color: var(--info);
|
222
|
+
background-color: var(--bg-info);
|
223
|
+
border: var(--solid) var(--info-low);
|
224
|
+
border-radius: var(--radius);
|
225
|
+
max-width: var(--line-length); /* don't just go max-width */
|
226
|
+
margin: var(--m) 0;
|
227
|
+
padding: 0 var(--m);
|
228
|
+
}
|
229
|
+
|
230
|
+
/* #headers - a single header style since alerts only need 1 header typically */
|
231
|
+
.alert :where(h1,h2,h3,h4,h5,h6) {
|
232
|
+
color: var(--info-low);
|
233
|
+
font-size: var(--large);
|
234
|
+
font-weight: var(--bold);
|
235
|
+
margin-top: var(--m);
|
236
|
+
}
|
237
|
+
|
238
|
+
/* #success #warning #error #alert - other alert types get their own colors */
|
239
|
+
.success.alert {
|
240
|
+
color: var(--success);
|
241
|
+
background-color: var(--bg-success);
|
242
|
+
border: var(--solid) var(--success-low);
|
243
|
+
}
|
244
|
+
.warning.alert {
|
245
|
+
color: var(--warning);
|
246
|
+
background-color: var(--bg-warning);
|
247
|
+
border: var(--solid) var(--warning-low);
|
248
|
+
}
|
249
|
+
.error.alert {
|
250
|
+
color: var(--error);
|
251
|
+
background-color: var(--bg-error);
|
252
|
+
border: var(--solid) var(--error-low);
|
253
|
+
}
|
254
|
+
.success.alert :where(h1,h2,h3,h4,h5,h6) { color: var(--success-low); }
|
255
|
+
.warning.alert :where(h1,h2,h3,h4,h5,h6) { color: var(--warning-low); }
|
256
|
+
.error.alert :where(h1,h2,h3,h4,h5,h6) { color: var(--error-low); }
|
257
|
+
|
258
|
+
|
259
|
+
/* -----------------------------------------------------------------------------
|
260
|
+
// main #nav - the body element should only ever have one main header element,
|
261
|
+
// within which, we can assume any nav element is the main nav.
|
262
|
+
// -------------------------------------------------------------------------- */
|
263
|
+
|
264
|
+
body:has(> header > nav) {
|
265
|
+
/*padding-top: 0;*/
|
266
|
+
}
|
267
|
+
|
268
|
+
nav.horizontal {
|
269
|
+
align-items: center; /* vertical alignment */
|
270
|
+
}
|
271
|
+
|
272
|
+
.column {
|
273
|
+
grid-column: unset;
|
274
|
+
flex-direction: column;
|
275
|
+
align-items: start; /* some items will float otherwise */
|
276
|
+
row-gap: var(--s); /* add some vertical spacing */
|
277
|
+
}
|
278
|
+
|
279
|
+
nav > div {
|
280
|
+
display: inline-flex;
|
281
|
+
align-items: center;
|
282
|
+
gap: var(--m);
|
283
|
+
}
|
284
|
+
|
285
|
+
/* both column menus & popup button sub-menus should flex vertically */
|
286
|
+
.column menu, button[aria-haspopup="true"] + menu {
|
287
|
+
flex-direction: column;
|
288
|
+
align-items: start; /* left justify items */
|
289
|
+
/*justify-content: center;*/
|
290
|
+
}
|
291
|
+
|
292
|
+
/* TODO: figure out why both a max-height of var(--height) and an unset
|
293
|
+
max-height results in a vertical shift of #nav #a images */
|
294
|
+
body > nav a, body > header > nav a {
|
295
|
+
max-height: 2.75rem;
|
296
|
+
}
|
297
|
+
/* visited links in the nav menu shouldn't be different colors */
|
298
|
+
:where([aria-label="primary"], nav menu li) a:visited { color: var(--link); }
|
299
|
+
|
300
|
+
/*body > nav a.button, body > header > nav a.button {
|
301
|
+
white-space: nowrap;
|
302
|
+
}*/
|
303
|
+
|
304
|
+
/*body > nav > menu > li, body > header > nav > menu > li {
|
305
|
+
padding: 0 var(--m);
|
306
|
+
}*/
|
307
|
+
|
308
|
+
/* #nav #search - retracting nav search form - the background svg icon is used
|
309
|
+
as the trigger to expand the search box via a :focus transition */
|
310
|
+
:where(nav) [type="search"] { /* [0010] specificity */
|
311
|
+
/*background-color: unset;*/
|
312
|
+
outline: none;
|
313
|
+
border: none;
|
314
|
+
width: var(--height); /* form icons are square */
|
315
|
+
min-width: 0;
|
316
|
+
padding: 0;
|
317
|
+
cursor: pointer; /* unconventional usage for 'clickable' */
|
318
|
+
transition: all var(--transition) ease-out;
|
319
|
+
}
|
320
|
+
/* expanded state of retracting nav search form - [0010] specificity */
|
321
|
+
:where(nav) :where([type="search"]):focus,
|
322
|
+
:where(nav) :where([type="search"]):not(:placeholder-shown) {
|
323
|
+
background-color: revert;
|
324
|
+
border: var(--solid) var(--highlighted);
|
325
|
+
width: auto;
|
326
|
+
padding-left: var(--height);
|
327
|
+
cursor: text;
|
328
|
+
transition: all var(--transition) ease-out;
|
329
|
+
}
|
330
|
+
/* <form>s by default subtract padding from max-width, so reset that */
|
331
|
+
:where(nav) form { max-width: var(--line-length); }
|
332
|
+
|
333
|
+
/*:where(nav) button {
|
334
|
+
min-height: unset;
|
335
|
+
}*/
|
336
|
+
|
337
|
+
/* visually differentiate active page in nav menus */
|
338
|
+
[aria-current="page"] {
|
339
|
+
/*color: var(--primary-900);*/
|
340
|
+
text-decoration: unset;
|
341
|
+
pointer-events: none; /* make link non-clickable */
|
342
|
+
cursor: default;
|
343
|
+
}
|
344
|
+
|
345
|
+
nav [aria-haspopup="true"] + menu > li {
|
346
|
+
display: block;
|
347
|
+
max-width: var(--line-length);
|
348
|
+
}
|
349
|
+
|
350
|
+
nav [aria-haspopup="true"] + menu {
|
351
|
+
position: absolute;
|
352
|
+
visibility: hidden;
|
353
|
+
margin: 0;
|
354
|
+
padding: var(--m);
|
355
|
+
}
|
356
|
+
|
357
|
+
nav.column [aria-haspopup="true"] + menu {
|
358
|
+
width: fit-content;
|
359
|
+
margin-block: 0;
|
360
|
+
}
|
361
|
+
|
362
|
+
nav:not(.column) [aria-haspopup="true"] + menu {
|
363
|
+
background-color: var(--background);
|
364
|
+
border: var(--solid) var(--border);
|
365
|
+
border-radius: var(--radius);
|
366
|
+
}
|
367
|
+
|
368
|
+
nav [aria-haspopup="true"]:focus-within + menu {
|
369
|
+
visibility: visible;
|
370
|
+
transition: visibility position var(--transition);
|
371
|
+
}
|
372
|
+
|
373
|
+
nav.column [aria-haspopup="true"]:focus-within + menu {
|
374
|
+
position: relative;
|
375
|
+
}
|
376
|
+
|
377
|
+
nav [aria-haspopup="true"]:focus + menu {
|
378
|
+
visibility: visible;
|
379
|
+
transition: visibility position var(--transition);
|
380
|
+
}
|
381
|
+
nav.column [aria-haspopup="true"]:focus + menu {
|
382
|
+
position: relative;
|
383
|
+
}
|
384
|
+
|
385
|
+
nav.column menu {
|
386
|
+
width: 100%; /* otherwise menu items might wrap prematurely*/
|
387
|
+
margin-block: var(--m); /* add back vertical spacing */
|
388
|
+
}
|
389
|
+
|
390
|
+
nav.column :where(button, .button):not(.toggle) {
|
391
|
+
width: 100%;
|
392
|
+
}
|
393
|
+
|
394
|
+
/* TODO: this pushes padding into the next column */
|
395
|
+
:not(aside) > nav.column {
|
396
|
+
/*padding: 0 var(--m) var(--m) 0;*/
|
397
|
+
}
|
398
|
+
|
399
|
+
menu > li > button, menu > li > button:hover {
|
400
|
+
/* display: flex;
|
401
|
+
font-size: var(--text);
|
402
|
+
line-height: var(--normal);
|
403
|
+
color: var(--link);
|
404
|
+
background-color: unset;
|
405
|
+
border: none;
|
406
|
+
text-transform: revert;
|
407
|
+
text-decoration: underline;
|
408
|
+
padding: 0;*/
|
409
|
+
}
|
410
|
+
|
411
|
+
|
412
|
+
/* -----------------------------------------------------------------------------
|
413
|
+
// #buttons - button classes to mimic the styles of button types for other
|
414
|
+
elements
|
415
|
+
// -------------------------------------------------------------------------- */
|
416
|
+
|
417
|
+
/* #primary #button - a button class that mirrors the primary button style
|
418
|
+
// .......................................................................... */
|
419
|
+
|
420
|
+
/* TODO: reconcile with button class in base.css; this is one instance where not
|
421
|
+
using SASS/SCSS hurts, but it's a minor pain for less tooling/dependencies.*/
|
422
|
+
.button { /* [0010] specificity */
|
423
|
+
-webkit-appearance: button; /* normalize.css */
|
424
|
+
appearance: button;
|
425
|
+
display: inline-flex; /* allows centering of content */
|
426
|
+
place-items: center; /* does the actual centering */
|
427
|
+
color: var(--action);
|
428
|
+
background-color: var(--foreground); /* inverted style for primary
|
429
|
+
actions - will override for .secondary */
|
430
|
+
font-size: var(--small);
|
431
|
+
font-weight: var(--bold);
|
432
|
+
line-height: 1.15;
|
433
|
+
text-transform: uppercase;
|
434
|
+
text-decoration: none;
|
435
|
+
white-space: nowrap;
|
436
|
+
text-align: center; /* centered text, not left justified */
|
437
|
+
justify-content: center;
|
438
|
+
cursor: pointer; /* controversial for buttons but common */
|
439
|
+
width: fit-content; /* don't grow to container width */
|
440
|
+
height: fit-content; /* don't grow to container height */
|
441
|
+
min-height: var(--height); /* to match input fields */
|
442
|
+
padding: 0 var(--m);
|
443
|
+
border: var(--solid) var(--transparent);
|
444
|
+
border-radius: var(--radius);
|
445
|
+
}
|
446
|
+
|
447
|
+
.button:hover { /* [0020] specificity */
|
448
|
+
color: var(--action); /* needed to override anchor links */
|
449
|
+
background-color: var(--bg-highlight);
|
450
|
+
border-color: var(--transparent);
|
451
|
+
}
|
452
|
+
|
453
|
+
/* #secondary #button - less emphasized than the standard button
|
454
|
+
// .......................................................................... */
|
455
|
+
|
456
|
+
button.secondary, .secondary.button { /* [0011] / [0020] specificity */
|
457
|
+
color: var(--foreground); /* invert foreground/background */
|
458
|
+
background-color: var(--background); /* invert foreground/background */
|
459
|
+
border-color: var(--foreground);
|
460
|
+
}
|
461
|
+
|
462
|
+
:where(button, .button).secondary:hover { /* [0020] specificity */
|
463
|
+
background-color: var(--contrast); /* TODO: make grey in dark mode */
|
464
|
+
}
|
465
|
+
|
466
|
+
/* #tertiary #button - a link-like button
|
467
|
+
// .......................................................................... */
|
468
|
+
|
469
|
+
button.tertiary, .tertiary.button { /* [0011] / [0020] specificity */
|
470
|
+
color: var(--foreground); /* invert foreground/background */
|
471
|
+
background-color: unset; /* border is transparent */
|
472
|
+
padding-inline: var(--xxs);
|
473
|
+
}
|
474
|
+
|
475
|
+
:where(button, .button).tertiary:hover { /* [0020] specificity */
|
476
|
+
text-decoration: underline; /* TODO: make grey in dark mode */
|
477
|
+
border-color: var(--transparent);
|
478
|
+
}
|
479
|
+
|
480
|
+
|
481
|
+
/* #warning - a button for major changes TEMP:
|
482
|
+
// .......................................................................... */
|
483
|
+
|
484
|
+
:where(button, .button).warning {
|
485
|
+
--icon-color: var(--warning-low);
|
486
|
+
color: var(--warning-low);
|
487
|
+
background-color: var(--warning);
|
488
|
+
}
|
489
|
+
|
490
|
+
:where(button, .button).warning:hover {
|
491
|
+
--icon-color: var(--warning);
|
492
|
+
color: var(--warning);
|
493
|
+
background-color: var(--warning-low);
|
494
|
+
border-color: var(--warning);
|
495
|
+
}
|
496
|
+
|
497
|
+
:where(button, .button).secondary.warning {
|
498
|
+
--icon-color: var(--warning);
|
499
|
+
color: var(--warning);
|
500
|
+
background-color: unset;
|
501
|
+
border-color: var(--warning);
|
502
|
+
}
|
503
|
+
|
504
|
+
:where(button, .button).secondary.warning:hover {
|
505
|
+
background-color: var(--warning-low);
|
506
|
+
}
|
507
|
+
|
508
|
+
:where(button, .button).tertiary.warning {
|
509
|
+
--icon-color: var(--warning);
|
510
|
+
color: var(--warning);
|
511
|
+
}
|
512
|
+
|
513
|
+
:where(button, .button).tertiary.warning:hover {
|
514
|
+
background-color: unset;
|
515
|
+
border-color: var(--transparent);
|
516
|
+
}
|
517
|
+
|
518
|
+
|
519
|
+
/* #danger - a button for irrevocable actions TEMP: --secondary should be
|
520
|
+
replaced by --error or perhaps --danger
|
521
|
+
// .......................................................................... */
|
522
|
+
|
523
|
+
.danger {
|
524
|
+
--icon-color: var(--secondary-100);
|
525
|
+
color: var(--secondary-100);
|
526
|
+
background-color: var(--secondary);
|
527
|
+
}
|
528
|
+
|
529
|
+
.danger:hover {
|
530
|
+
--icon-color: var(--secondary);
|
531
|
+
color: var(--secondary);
|
532
|
+
background-color: var(--secondary-100);
|
533
|
+
border-color: var(--secondary);
|
534
|
+
}
|
535
|
+
|
536
|
+
.secondary.danger {
|
537
|
+
--icon-color: var(--secondary);
|
538
|
+
color: var(--secondary);
|
539
|
+
background-color: unset;
|
540
|
+
border-color: var(--secondary);
|
541
|
+
}
|
542
|
+
|
543
|
+
.secondary.danger:hover {
|
544
|
+
background-color: var(--secondary-200);
|
545
|
+
}
|
546
|
+
|
547
|
+
.tertiary.danger {
|
548
|
+
--icon-color: var(--secondary);
|
549
|
+
color: var(--secondary);
|
550
|
+
}
|
551
|
+
|
552
|
+
.tertiary.danger:hover {
|
553
|
+
background-color: unset;
|
554
|
+
border-color: var(--transparent);
|
555
|
+
}
|
556
|
+
|
557
|
+
|
558
|
+
/* #buttons - a flex container for inlining buttons, typically a <div>
|
559
|
+
// .......................................................................... */
|
560
|
+
|
561
|
+
/* TODO: the main form grid should inline elements rather than forcing it here
|
562
|
+
.bottons inlines/wraps multiple buttons where necessary - [0010] specificity*/
|
563
|
+
.buttons {
|
564
|
+
list-style: none;
|
565
|
+
display: flex; /* overwrite display: grid; */
|
566
|
+
flex-wrap: wrap; /* wrap buttons when necessary */
|
567
|
+
/*justify-content: flex-end;*/ /* looks better on narrow screens */
|
568
|
+
gap: var(--s); /* don't let adjacent buttons touch */
|
569
|
+
grid-column: elements; /* put buttons in the inputs grid column */
|
570
|
+
}
|
571
|
+
/* menu buttons can delegate spacing to the parent <menu> - [0011] specificity*/
|
572
|
+
menu.buttons { margin-inline: 0; }
|
573
|
+
/* <p>s take up a whole grid row, so no need to column it - [0012] specificity*/
|
574
|
+
.buttons p :is(button, input) { grid-column: none; }
|
575
|
+
|
576
|
+
form .buttons { max-width: var(--field-max) }
|
577
|
+
|
578
|
+
/*form .buttons.right { padding-right: calc(var(--xl) - var(--s)) }*/
|
579
|
+
|
580
|
+
.roomy.buttons { gap: var(--ml); }
|
581
|
+
|
582
|
+
/* fix buttons floating and getting squished at smaller screen widths */
|
583
|
+
@container (max-width: 28rem) {
|
584
|
+
form { max-width: unset; }
|
585
|
+
form .buttons {
|
586
|
+
max-width: unset;
|
587
|
+
grid-column: -1/1;
|
588
|
+
}
|
589
|
+
label { font-size: var(--small); }
|
590
|
+
}
|
591
|
+
|
592
|
+
/* #popup #button - actuates a popup section - currently for dropdown menu items
|
593
|
+
// .......................................................................... */
|
594
|
+
|
595
|
+
button[aria-haspopup="true"] {
|
596
|
+
all: unset;
|
597
|
+
color: var(--link);
|
598
|
+
font-weight: var(--bold);
|
599
|
+
text-decoration: underline;
|
600
|
+
}
|
601
|
+
|
602
|
+
button[aria-haspopup="true"]::after {
|
603
|
+
display: inline-block; /* negates text-decoration */
|
604
|
+
content: '\00A0\25be'; /* appends inverted triangle */
|
605
|
+
}
|
606
|
+
|
607
|
+
button[aria-haspopup="true"]:hover {
|
608
|
+
color: var(--active);
|
609
|
+
text-decoration: none;
|
610
|
+
cursor: pointer; /* controversial for buttons but common*/
|
611
|
+
}
|
612
|
+
|
613
|
+
/* #toggle - hamburger button for toggling sections of pages
|
614
|
+
// .......................................................................... */
|
615
|
+
.toggle { /* [0010] specifitiy */
|
616
|
+
color: var(--background);
|
617
|
+
padding: 0;
|
618
|
+
aspect-ratio: 1;
|
619
|
+
height: 2.75rem;
|
620
|
+
width: fit-content;
|
621
|
+
}
|
622
|
+
|
623
|
+
.toggle::before { /* [0011] specifitiy */
|
624
|
+
content: '≡'; /* '\2261'; */
|
625
|
+
font-size: 2rem;
|
626
|
+
vertical-align: super;
|
627
|
+
}
|
628
|
+
|
629
|
+
.tertiary.toggle:hover { /* .tertiary has inverted colors so invert the hover */
|
630
|
+
color: var(--active);
|
631
|
+
background-color: unset;
|
632
|
+
text-decoration: none;
|
633
|
+
}
|
634
|
+
|
635
|
+
/* HACK: fixes offset on toggle (hamburger) buttons - [0020] specificity */
|
636
|
+
.toggle.button { display:unset; }
|
637
|
+
|
638
|
+
/* TODO: see if we can use only css to toggle the menu into the burger menu */
|
639
|
+
nav:has(.toggle[aria-expanded]) > menu {
|
640
|
+
/*visibility: visible;*/
|
641
|
+
}
|
642
|
+
|
643
|
+
nav:has(.toggle[aria-expanded=false]) > menu {
|
644
|
+
/*visibility: hidden;*/
|
645
|
+
}
|
646
|
+
|
647
|
+
|
648
|
+
/* TODO: moved from states.css - make sure these get applied correctly */
|
649
|
+
[rel~="external"].button { padding: 0 var(--ms); }
|
650
|
+
[rel~="external"].button::after {
|
651
|
+
padding: var(--button-padding);
|
652
|
+
mask-position-x: right;
|
653
|
+
}
|
654
|
+
[rel~="external"].button:hover::after { background-color: var(--foreground); }
|
655
|
+
|
656
|
+
|
657
|
+
|
658
|
+
/* -----------------------------------------------------------------------------
|
659
|
+
// #selectmenu - Open UI replacement to the standard select element -
|
660
|
+
https://open-ui.org/prototypes/selectmenu
|
661
|
+
// -------------------------------------------------------------------------- */
|
662
|
+
|
663
|
+
selectmenu { }
|
664
|
+
|
665
|
+
selectmenu::part(button) {
|
666
|
+
color: var(--text);
|
667
|
+
background-color: var(--bg-field);
|
668
|
+
min-width: var(--width);
|
669
|
+
height: var(--height);
|
670
|
+
border-radius: var(--radius);
|
671
|
+
}
|
672
|
+
|
673
|
+
selectmenu::part(listbox) {
|
674
|
+
margin-top: var(--m);
|
675
|
+
border: var(--solid) var(--border);
|
676
|
+
border-radius: var(--radius);
|
677
|
+
}
|
678
|
+
|
679
|
+
|
680
|
+
/* -----------------------------------------------------------------------------
|
681
|
+
// #card - general purpose card - cards should appear in a container to get the
|
682
|
+
// benefits of container query-based responsiveness. cards are composed
|
683
|
+
// of an image plus some content. note that content should go in a
|
684
|
+
// content div due to limitations of css grid not allowing content flow
|
685
|
+
// in a grid area: https://github.com/w3c/csswg-drafts/issues/4416
|
686
|
+
// -------------------------------------------------------------------------- */
|
687
|
+
|
688
|
+
/* cards should typically be lists of articles */
|
689
|
+
.cards {
|
690
|
+
display: grid;
|
691
|
+
grid-template-columns: repeat(auto-fit, minmax(var(--container), 1fr));
|
692
|
+
gap: var(--m);
|
693
|
+
|
694
|
+
/* display: flex;
|
695
|
+
flex-wrap: wrap;
|
696
|
+
max-width: var(--line-length);*/
|
697
|
+
column-gap: var(--m); /* gap only for side-by-side placement */
|
698
|
+
}
|
699
|
+
|
700
|
+
/* in most cases .cards should contain a set of articles, otherwise use .card */
|
701
|
+
.card, .cards > article {
|
702
|
+
flex: 1 0 calc((11rem - 100%) * 999);
|
703
|
+
/*display: block;*/
|
704
|
+
display: flex;
|
705
|
+
flex-direction: column;
|
706
|
+
column-gap: var(--m); /* gap only for side-by-side placement */
|
707
|
+
margin: var(--m) 0;
|
708
|
+
}
|
709
|
+
|
710
|
+
.cards .contents {
|
711
|
+
display: flex;
|
712
|
+
flex-direction: column;
|
713
|
+
}
|
714
|
+
|
715
|
+
.cards .meta {
|
716
|
+
margin: 0;
|
717
|
+
}
|
718
|
+
|
719
|
+
:where(.card, .cards) :where(h1,h2,h3,h4,h5,h6):first-child {
|
720
|
+
margin-top: 0;
|
721
|
+
}
|
722
|
+
|
723
|
+
:where(.card) > *, :where(.cards) > article > * {
|
724
|
+
margin-block: var(--ms); /* margin rather than gap for control */
|
725
|
+
}
|
726
|
+
|
727
|
+
.card > .buttons:last-child, .cards > article > .buttons:last-child {
|
728
|
+
margin-top: auto; /* make sure buttons are at the bottom */
|
729
|
+
}
|
730
|
+
|
731
|
+
@container (min-width: 35rem) {
|
732
|
+
/*.card { flex-direction: row; }*/ /* interferes with single-card section */
|
733
|
+
.card > img, .cards > article > img {
|
734
|
+
max-height: var(--width);
|
735
|
+
max-width: var(--width);
|
736
|
+
}
|
737
|
+
/* change orphaned last item to row layout for 3-wide grid */
|
738
|
+
.cards :last-child:nth-child(3n - 2) {
|
739
|
+
grid-column: span 3;
|
740
|
+
flex-direction: row;
|
741
|
+
}
|
742
|
+
}
|
743
|
+
|
744
|
+
/* TEMP: use media queries for browsers that don't support container queries */
|
745
|
+
@supports not (container-type: inline-size) {
|
746
|
+
@media (min-width: 47rem) {
|
747
|
+
/*.card { flex-direction: row; }*/ /* interferes with single-card section */
|
748
|
+
.card > img, .cards > article > img {
|
749
|
+
max-height: var(--width);
|
750
|
+
max-width: var(--width);
|
751
|
+
}
|
752
|
+
.cards :last-child:nth-child(3n - 2) {
|
753
|
+
grid-column-end: span 3;
|
754
|
+
flex-direction: row;
|
755
|
+
}
|
756
|
+
}}
|
757
|
+
|
758
|
+
/* -----------------------------------------------------------------------------
|
759
|
+
// #tags - an inline list of metatags; can be text, links, icons, or other
|
760
|
+
// inline list content.
|
761
|
+
// -------------------------------------------------------------------------- */
|
762
|
+
|
763
|
+
/* .tags should generally be an unordered list. margin/padding get in the way of
|
764
|
+
a compact presentation of tags. */
|
765
|
+
.tags {
|
766
|
+
margin: 0;
|
767
|
+
padding: 0;
|
768
|
+
}
|
769
|
+
|
770
|
+
.tags > li {
|
771
|
+
display: inline-block;
|
772
|
+
color: var(--secondary);
|
773
|
+
font-size: var(--small);
|
774
|
+
font-weight: var(--bold);
|
775
|
+
text-transform: uppercase;
|
776
|
+
letter-spacing: 0.02em;
|
777
|
+
}
|
778
|
+
|
779
|
+
.tags > li + li {
|
780
|
+
margin-left: var(--m);
|
781
|
+
}
|
782
|
+
|
783
|
+
.tags + :where(h1,h2,h3,h4,h5,h6) {
|
784
|
+
margin-top: var(--s);
|
785
|
+
}
|
786
|
+
|
787
|
+
/* .tags should add spacing if inserted elsewhere */
|
788
|
+
.tags:has(+ .buttons) {
|
789
|
+
margin-bottom: var(--m);
|
790
|
+
}
|
791
|
+
|
792
|
+
/* TEMP: add margin-top to buttons for browsers that don't support :has() */
|
793
|
+
@supports not (:has(a)) {
|
794
|
+
.tags + .buttons {
|
795
|
+
margin-top: var(--m);
|
796
|
+
}}
|
797
|
+
|
798
|
+
|
799
|
+
/* -----------------------------------------------------------------------------
|
800
|
+
// #grid - multi-column grid adjustments
|
801
|
+
// -------------------------------------------------------------------------- */
|
802
|
+
|
803
|
+
/* #grid - apply grid with columns of width var(--column) to an element - [0010]
|
804
|
+
// .......................................................................... */
|
805
|
+
.grid {
|
806
|
+
display: grid;
|
807
|
+
grid-template-columns: [full-start] repeat(auto-fit,
|
808
|
+
minmax(var(--column), 1fr)) [full-end];
|
809
|
+
column-gap: var(--m);
|
810
|
+
container-type: none; /* containment clashes with grid on safari */
|
811
|
+
}
|
812
|
+
|
813
|
+
/* for layouts with left & right asides, put main in the middle grid columns */
|
814
|
+
/* grrr, firefox is not forgiving with :has() rules, so this must be separated*/
|
815
|
+
.dual-aside {
|
816
|
+
grid-column: 2 / -2;
|
817
|
+
}
|
818
|
+
|
819
|
+
/*full is a grid area for a row that spans all columns - [0000] specificity */
|
820
|
+
:where(.grid) > :where(header,hgroup,h1,h2,h3,h4,h5,h6,nav:not(.column),footer){
|
821
|
+
grid-column: full;
|
822
|
+
}
|
823
|
+
/* apply default padding/border to .grid asides - [0001] specificity */
|
824
|
+
:where(.grid) > aside {
|
825
|
+
padding: var(--xs) var(--s) var(--s);
|
826
|
+
border-radius: var(--radius);
|
827
|
+
}
|
828
|
+
/* apply default margin to nav menus inside .grid asides - [0001] specificity */
|
829
|
+
:where(.grid) > :where(aside) > :where(nav) > menu {
|
830
|
+
margin: var(--m) 0;
|
831
|
+
}
|
832
|
+
/* put the first aside in the first grid column */
|
833
|
+
:where(.grid:has(> aside)) > :where(aside):first-of-type {/*[0010] specificity*/
|
834
|
+
grid-column: 1;
|
835
|
+
}
|
836
|
+
/* spread main across the remaining grid columns */
|
837
|
+
:where(.grid) > :where(aside) + main, /* [0001] specificity */
|
838
|
+
:where(.grid) :where(aside, nav.column) + :where(main, .main) { /* [0000] */
|
839
|
+
grid-column: 2 / -1;
|
840
|
+
}
|
841
|
+
|
842
|
+
/* TODO: double check this selector for unintended consequences - [0001] */
|
843
|
+
:where(.grid) :where(aside, nav.column) + :where(main, .main) p {
|
844
|
+
margin-top: 0;
|
845
|
+
}
|
846
|
+
|
847
|
+
/* HACK: full-width paragraphs in .grid to ... - [0001] specificity */
|
848
|
+
:where(.grid) > p { grid-column: full; }
|
849
|
+
|
850
|
+
/* remove top margin from the very first heading and no more than that */
|
851
|
+
.grid > :where(main) > :where(header):first-child,
|
852
|
+
.grid > :where(main) > :where(section) > :where(header):first-child,
|
853
|
+
.grid > :where(main) > :where(section) > :where(header) >
|
854
|
+
:where(h1,h2,h3,h4,h5,h6):first-child {
|
855
|
+
margin-top: 0;
|
856
|
+
}
|
857
|
+
|
858
|
+
/* :has() is preferred over using classes, but firefox lacks support so far */
|
859
|
+
@supports selector(:has(*)) {
|
860
|
+
:where(.grid:has(> aside, > main)) > main { /* [0001] specificity */
|
861
|
+
grid-column: 2 / -1;
|
862
|
+
}
|
863
|
+
|
864
|
+
:where(.grid:has(> aside + main + aside)) > main { /* [0001] specificity */
|
865
|
+
grid-column: 2 / -2;
|
866
|
+
}
|
867
|
+
/* [0010] specificity */
|
868
|
+
:where(.grid:has(> aside + main + aside)) > :where(aside):nth-of-type(2n) {
|
869
|
+
grid-column: -2;
|
870
|
+
}
|
871
|
+
}
|
872
|
+
|
873
|
+
/* #form #grid - general purpose 2-column grid, as used on forms by default
|
874
|
+
// .......................................................................... */
|
875
|
+
.form.grid {
|
876
|
+
display: grid;
|
877
|
+
grid-template-columns: [labels full-start] 3fr [elements] 7fr [full-end];
|
878
|
+
gap: var(--m);
|
879
|
+
/*grid-row: auto;*/
|
880
|
+
/*max-width: calc(var(--line-length) - 2 * var(--m));*/
|
881
|
+
}
|
882
|
+
.form.grid :is(h3, p) {
|
883
|
+
grid-column: full;
|
884
|
+
margin: 0;
|
885
|
+
}
|
886
|
+
.form.grid h3 { margin-top: var(--m); }
|
887
|
+
.form.grid label:not(.visually-hidden) { display: contents; }
|
888
|
+
.form.grid :is(meter, progress) { grid-column: elements; }
|
889
|
+
|
890
|
+
/* #label - class to emulate the form label grid style - [0010] specificity
|
891
|
+
// .......................................................................... */
|
892
|
+
.label {
|
893
|
+
display: inline-block;
|
894
|
+
grid-column: labels;
|
895
|
+
text-align: right;
|
896
|
+
}
|
897
|
+
|
898
|
+
/* #input - class to emulate the form input grid style - [0010] specificity
|
899
|
+
// .......................................................................... */
|
900
|
+
.input {
|
901
|
+
display: inline-block;
|
902
|
+
grid-column: elements;
|
903
|
+
}
|
904
|
+
|
905
|
+
|
906
|
+
/* -----------------------------------------------------------------------------
|
907
|
+
// #progressbar - a circular progress bar component - from almond.css
|
908
|
+
// -------------------------------------------------------------------------- */
|
909
|
+
|
910
|
+
[role="progressbar"] {
|
911
|
+
--value: 50;
|
912
|
+
--thick: 50%;
|
913
|
+
--medium: 58%;
|
914
|
+
--thin: 67%;
|
915
|
+
--thickness: var(--medium);
|
916
|
+
aspect-ratio: 1;
|
917
|
+
border-radius: 50%;
|
918
|
+
display: grid;
|
919
|
+
font-size: 2em;
|
920
|
+
overflow: hidden;
|
921
|
+
place-items: center;
|
922
|
+
position: relative;
|
923
|
+
width: 100%;
|
924
|
+
}
|
925
|
+
|
926
|
+
[role="progressbar"]::before {
|
927
|
+
content: "";
|
928
|
+
background: conic-gradient(var(--primary) calc(var(--value) * 1%),
|
929
|
+
#0000 0);
|
930
|
+
background-color: var(--primary-100);
|
931
|
+
height: 100%;
|
932
|
+
left: 0;
|
933
|
+
-webkit-mask: radial-gradient(#0000 var(--thickness), #000 0);
|
934
|
+
mask: radial-gradient(#0000 var(--thickness), #000 0);
|
935
|
+
position: absolute;
|
936
|
+
top: 0;
|
937
|
+
transition: background-color 0.5s;
|
938
|
+
width: 100%;
|
939
|
+
}
|
940
|
+
[role="progressbar"]::after {
|
941
|
+
counter-reset: percentage var(--value);
|
942
|
+
content: counter(percentage) "%";
|
943
|
+
}
|
944
|
+
[role="progressbar"]:hover::before {
|
945
|
+
background-color: var(--primary-300);
|
946
|
+
}
|