@getvitops/generator 8.2.0-alpha.0 → 8.3.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +550 -25
- package/assets/css/index.css +7 -0
- package/assets/css/patterns/banner.css +20 -0
- package/assets/css/patterns/callout.css +39 -0
- package/assets/css/patterns/copy.css +5 -0
- package/assets/css/patterns/embed.css +39 -0
- package/assets/css/patterns/forms.css +19 -0
- package/assets/css/patterns/logos.css +45 -0
- package/assets/css/patterns/marquee.css +16 -0
- package/assets/css/patterns/section.css +53 -0
- package/assets/css/patterns/sitenav.css +262 -0
- package/assets/css/patterns/splitter.css +11 -0
- package/assets/css/patterns/stats.css +61 -0
- package/assets/css/patterns/steps.css +98 -0
- package/assets/css/patterns/table.css +10 -0
- package/assets/css/patterns/tone.css +38 -0
- package/assets/js/consent.js +1 -1
- package/assets/js/elements.js +5 -5
- package/assets/js/polyfills/adoptedStyleSheets.js +1 -1
- package/assets/js/polyfills/css-anchor-positioning-fn.js +2 -2
- package/assets/js/polyfills/popover.js +2 -2
- package/config.schema.json +257 -120
- package/dist/config-BfcWKH-5.mjs +1743 -0
- package/dist/config-BfcWKH-5.mjs.map +1 -0
- package/dist/{config-DvbYx3Gi.mjs → config-Bhg3Xv3D.mjs} +10 -207
- package/dist/config-Bhg3Xv3D.mjs.map +1 -0
- package/dist/config-D5xuz8--.mjs +1807 -0
- package/dist/config-D5xuz8--.mjs.map +1 -0
- package/dist/config.d.mts +157 -211
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +1 -1
- package/dist/{icons-sprite-Bf_KmKeX.d.mts → icons-sprite-CQ5Zj4go.d.mts} +4 -6
- package/dist/icons-sprite-CQ5Zj4go.d.mts.map +1 -0
- package/dist/icons-sprite.d.mts +1 -1
- package/dist/icons-sprite.mjs +1 -2
- package/dist/index.d.mts +49 -35
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +607 -75
- package/dist/index.mjs.map +1 -1
- package/dist/{schema-Dmq1J7S3.d.mts → schema-BV2n2phj.d.mts} +2 -3
- package/dist/{schema-Dmq1J7S3.d.mts.map → schema-BV2n2phj.d.mts.map} +1 -1
- package/dist/schema-C-P9dF9F.d.mts +337 -0
- package/dist/schema-C-P9dF9F.d.mts.map +1 -0
- package/dist/{tokens-8SXMDAd1.d.mts → tokens-BzBbTeTi.d.mts} +2 -6
- package/dist/tokens-BzBbTeTi.d.mts.map +1 -0
- package/dist/{tokens-zi594IZ3.mjs → tokens-C1RJwFeG.mjs} +3 -5
- package/dist/{tokens-zi594IZ3.mjs.map → tokens-C1RJwFeG.mjs.map} +1 -1
- package/dist/tokens-CaIGQQLk.mjs +740 -0
- package/dist/tokens-CaIGQQLk.mjs.map +1 -0
- package/dist/tokens-DH5cpvKd.d.mts +242 -0
- package/dist/tokens-DH5cpvKd.d.mts.map +1 -0
- package/dist/tokens.d.mts +1 -1
- package/dist/tokens.mjs +1 -1
- package/package.json +6 -5
- package/schema.json +95 -5
- package/dist/config-DvbYx3Gi.mjs.map +0 -1
- package/dist/icons-sprite-Bf_KmKeX.d.mts.map +0 -1
- package/dist/tokens-8SXMDAd1.d.mts.map +0 -1
package/assets/css/index.css
CHANGED
|
@@ -72,6 +72,13 @@
|
|
|
72
72
|
@import './patterns/text-effects.css';
|
|
73
73
|
@import './patterns/svg.css';
|
|
74
74
|
@import './patterns/marquee.css';
|
|
75
|
+
@import './patterns/tone.css';
|
|
76
|
+
@import './patterns/section.css';
|
|
77
|
+
@import './patterns/steps.css';
|
|
78
|
+
@import './patterns/stats.css';
|
|
79
|
+
@import './patterns/callout.css';
|
|
80
|
+
@import './patterns/logos.css';
|
|
81
|
+
@import './patterns/embed.css';
|
|
75
82
|
@import './patterns/counter.css';
|
|
76
83
|
@import './patterns/nav.css';
|
|
77
84
|
@import './patterns/carousel.css';
|
|
@@ -69,3 +69,23 @@
|
|
|
69
69
|
.banner[hidden] {
|
|
70
70
|
display: none;
|
|
71
71
|
}
|
|
72
|
+
|
|
73
|
+
/*
|
|
74
|
+
* `<wc-dismissable>` wraps a banner or notification — block content — and animates its own
|
|
75
|
+
* opacity/scale on dismiss, so it needs a box of its own: `display: contents` would drop
|
|
76
|
+
* that animation. Pre-upgrade it would otherwise be an inline box around a block child.
|
|
77
|
+
*/
|
|
78
|
+
:where(wc-dismissable) {
|
|
79
|
+
display: block;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
* A dismiss button does nothing until `<wc-dismissable>` upgrades — an inert control that
|
|
84
|
+
* looks live is worse than none. `:not(:defined)` is true with no JS (and until elements.js
|
|
85
|
+
* has run), so the close affordance only appears once something can act on it. The banner
|
|
86
|
+
* itself stays fully readable. Markup that puts a `[data-dismiss]` button inside the element
|
|
87
|
+
* gets the same treatment, whatever its class.
|
|
88
|
+
*/
|
|
89
|
+
wc-dismissable:not(:defined) :is(.banner__close, .notification__close, [data-dismiss]) {
|
|
90
|
+
display: none;
|
|
91
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Callout — a call-to-action band: a short message and the action it points at, set
|
|
3
|
+
* apart from the page. Not a banner: `banner` is a dismissible announcement; this is
|
|
4
|
+
* content that stays.
|
|
5
|
+
*
|
|
6
|
+
* Message left and actions right when there is room, stacked when there is not. Colour
|
|
7
|
+
* is `.tone` (tone.css); `--center` stacks and centres at every width.
|
|
8
|
+
*/
|
|
9
|
+
.callout {
|
|
10
|
+
display: grid;
|
|
11
|
+
gap: var(--callout-gap, 1rem 2rem);
|
|
12
|
+
align-items: center;
|
|
13
|
+
padding: var(--callout-padding, clamp(1.25rem, 4cqi, 2.5rem));
|
|
14
|
+
border: var(--b-card, var(--b-card-group, var(--b-default)));
|
|
15
|
+
border-radius: var(--br-card, var(--br-card-group, var(--br-default)));
|
|
16
|
+
|
|
17
|
+
.callout__body {
|
|
18
|
+
display: grid;
|
|
19
|
+
gap: 0.5rem;
|
|
20
|
+
min-inline-size: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.callout__title,
|
|
24
|
+
.callout__text,
|
|
25
|
+
.callout__actions {
|
|
26
|
+
margin: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.callout--center {
|
|
30
|
+
text-align: center;
|
|
31
|
+
justify-items: center;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@container (min-width: 48rem) {
|
|
36
|
+
.callout:not(.callout--center) {
|
|
37
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embed — a third-party iframe (map, video) held at a fixed aspect ratio, behind consent.
|
|
3
|
+
*
|
|
4
|
+
* The iframe ships with NO `src`: the address rides on `data-consent-src`, and the consent
|
|
5
|
+
* runtime assigns it only once the visitor has granted the category. Until then the
|
|
6
|
+
* `.embed__placeholder` — a real link to the same content, so it is useful with no JS — is
|
|
7
|
+
* what the page shows; `[data-vitops-activated]` on the iframe (set by the runtime) hides
|
|
8
|
+
* it. No third-party request is made before consent.
|
|
9
|
+
*/
|
|
10
|
+
.embed {
|
|
11
|
+
position: relative;
|
|
12
|
+
aspect-ratio: var(--embed-ratio, 16 / 9);
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
border: var(--b-card, var(--b-card-group, var(--b-default)));
|
|
15
|
+
border-radius: var(--br-card, var(--br-card-group, var(--br-default)));
|
|
16
|
+
|
|
17
|
+
.embed__frame {
|
|
18
|
+
position: absolute;
|
|
19
|
+
inset: 0;
|
|
20
|
+
inline-size: 100%;
|
|
21
|
+
block-size: 100%;
|
|
22
|
+
border: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.embed__placeholder {
|
|
26
|
+
position: absolute;
|
|
27
|
+
inset: 0;
|
|
28
|
+
display: grid;
|
|
29
|
+
place-content: center;
|
|
30
|
+
gap: 0.5rem;
|
|
31
|
+
padding: 1rem;
|
|
32
|
+
text-align: center;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Once the runtime has loaded the frame, the placeholder has nothing left to say. */
|
|
36
|
+
.embed__frame[data-vitops-activated] ~ .embed__placeholder {
|
|
37
|
+
display: none;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -364,3 +364,22 @@ select.custom-select {
|
|
|
364
364
|
outline-offset: 2px;
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
|
+
|
|
368
|
+
/* `<wc-multi-field>` is a group of controls, a block. Its shadow `:host` declares no display. */
|
|
369
|
+
:where(wc-multi-field) {
|
|
370
|
+
display: block;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* `<wc-turnstile>` wraps a fallback paragraph and the widget box, both blocks (light DOM, no `:host`). */
|
|
374
|
+
:where(wc-turnstile) {
|
|
375
|
+
display: block;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/*
|
|
379
|
+
* A message shown only when the URL fragment names it. A prerendered page cannot know whether a
|
|
380
|
+
* no-JS post succeeded, so a form's success and error notices are always in the markup and the
|
|
381
|
+
* endpoint's redirect (`#form-sent` / `#form-error`) reveals one.
|
|
382
|
+
*/
|
|
383
|
+
.form-notice--target:not(:target) {
|
|
384
|
+
display: none;
|
|
385
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logos — a static grid of partner/client marks. `marquee` is the scrolling version;
|
|
3
|
+
* this one holds still, which is what most "key partners" rows should do (nothing to
|
|
4
|
+
* pause, nothing to track, no motion to opt out of).
|
|
5
|
+
*
|
|
6
|
+
* Each item is a plain image, or a link around one. Marks are normalised to a common
|
|
7
|
+
* height rather than a common width, because logos vary far more in aspect ratio than
|
|
8
|
+
* in how tall they should read. `--grayscale` quiets them until hover or focus.
|
|
9
|
+
*/
|
|
10
|
+
.logos {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-wrap: wrap;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: var(--logos-justify, center);
|
|
15
|
+
gap: var(--logos-gap, 1.5rem 2.5rem);
|
|
16
|
+
margin: 0;
|
|
17
|
+
padding: 0;
|
|
18
|
+
list-style: none;
|
|
19
|
+
|
|
20
|
+
.logos__item {
|
|
21
|
+
display: grid;
|
|
22
|
+
place-items: center;
|
|
23
|
+
margin: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.logos__item img {
|
|
27
|
+
block-size: var(--logos-height, 2.5rem);
|
|
28
|
+
inline-size: auto;
|
|
29
|
+
max-inline-size: 100%;
|
|
30
|
+
object-fit: contain;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&.logos--grayscale .logos__item img {
|
|
34
|
+
filter: grayscale(1);
|
|
35
|
+
opacity: 0.7;
|
|
36
|
+
transition:
|
|
37
|
+
filter 0.2s,
|
|
38
|
+
opacity 0.2s;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&.logos--grayscale .logos__item:is(:hover, :focus-within) img {
|
|
42
|
+
filter: none;
|
|
43
|
+
opacity: 1;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -56,6 +56,13 @@
|
|
|
56
56
|
animation-play-state: paused;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/* Keyboard users can't hover; focusing anything inside (a link in an item) also pauses, and
|
|
60
|
+
`<wc-marquee>`'s pause button sets `data-paused` (WCAG 2.2.2). */
|
|
61
|
+
&:focus-within .marquee__content,
|
|
62
|
+
&[data-paused] .marquee__content {
|
|
63
|
+
animation-play-state: paused;
|
|
64
|
+
}
|
|
65
|
+
|
|
59
66
|
&.marquee--reverse {
|
|
60
67
|
--_marquee-direction: reverse;
|
|
61
68
|
}
|
|
@@ -100,3 +107,12 @@
|
|
|
100
107
|
translate: 0 calc(-1 * var(--_marquee-distance, calc(100% + var(--marquee-gap, 1rem))));
|
|
101
108
|
}
|
|
102
109
|
}
|
|
110
|
+
|
|
111
|
+
/*
|
|
112
|
+
* The `.marquee` class carries `display: flex` when present (the Astro component always sets
|
|
113
|
+
* it). This is the fallback for a hand-written `<wc-marquee>` without the class, and it is
|
|
114
|
+
* zero specificity so `.marquee` still wins.
|
|
115
|
+
*/
|
|
116
|
+
:where(wc-marquee) {
|
|
117
|
+
display: block;
|
|
118
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section — the editorial wrapper most pages are made of: an optional kicker, a heading,
|
|
3
|
+
* a lead-in line, then a body of other blocks.
|
|
4
|
+
*
|
|
5
|
+
* Composed from the layout primitives rather than reinventing them: the outer element
|
|
6
|
+
* is `.region` (vertical rhythm) and the content sits on `.centered`'s tracks, so this
|
|
7
|
+
* partial only adds what neither has — the head's own rhythm and the `--split` layout,
|
|
8
|
+
* which puts the head beside the body (heading-left) above the container breakpoint.
|
|
9
|
+
* Backdrop and colour come from `.tone` (tone.css), never from here.
|
|
10
|
+
*/
|
|
11
|
+
.section {
|
|
12
|
+
.section__head {
|
|
13
|
+
display: grid;
|
|
14
|
+
gap: var(--section-head-gap, 0.75rem);
|
|
15
|
+
align-content: start;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.section__kicker,
|
|
19
|
+
.section__title {
|
|
20
|
+
margin: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.section__sub {
|
|
24
|
+
margin: 0;
|
|
25
|
+
max-inline-size: var(--width-measure, 65ch);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.section__body {
|
|
29
|
+
display: grid;
|
|
30
|
+
gap: var(--section-body-gap, 1.5rem);
|
|
31
|
+
min-inline-size: 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Head and body stack until there is room for two columns (below). */
|
|
35
|
+
&.section--split .section__inner {
|
|
36
|
+
display: grid;
|
|
37
|
+
gap: var(--section-split-gap, clamp(1.5rem, 4cqi, 3rem));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&.section--center .section__head {
|
|
41
|
+
text-align: center;
|
|
42
|
+
justify-items: center;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@container (min-width: 48rem) {
|
|
47
|
+
.section.section--split .section__inner {
|
|
48
|
+
grid-template-columns:
|
|
49
|
+
minmax(0, var(--section-split-head, 1fr))
|
|
50
|
+
minmax(0, var(--section-split-body, 2fr));
|
|
51
|
+
align-items: start;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -425,3 +425,265 @@
|
|
|
425
425
|
display: none;
|
|
426
426
|
}
|
|
427
427
|
}
|
|
428
|
+
|
|
429
|
+
/* ── Tiers (`<SiteNav>`'s optional `primary-mobile` / `primary-mega` menus) ──────
|
|
430
|
+
Each tier is its own `<nav>` in a `.sitenav-tier` wrapper, and a wrapper is
|
|
431
|
+
`display: none` outside its container-width window — so exactly one tier is ever
|
|
432
|
+
in the accessibility tree. Same container as the `--bp-*` flag above (the nearest
|
|
433
|
+
ancestor `container-type`, `body` per layout.css), so the hand-over width and the
|
|
434
|
+
drawer→navbar flip can never disagree. One pair per breakpoint; `sitenav.ts`'s
|
|
435
|
+
`VISIBILITY_CLASSES` lists them and `sitenav.test.ts` checks each is defined here. */
|
|
436
|
+
@container (width < 30rem) {
|
|
437
|
+
.sitenav-tier--from-sm {
|
|
438
|
+
display: none;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
@container (width >= 30rem) {
|
|
442
|
+
.sitenav-tier--below-sm {
|
|
443
|
+
display: none;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
@container (width < 48rem) {
|
|
447
|
+
.sitenav-tier--from-md {
|
|
448
|
+
display: none;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
@container (width >= 48rem) {
|
|
452
|
+
.sitenav-tier--below-md {
|
|
453
|
+
display: none;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
@container (width < 64rem) {
|
|
457
|
+
.sitenav-tier--from-lg {
|
|
458
|
+
display: none;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
@container (width >= 64rem) {
|
|
462
|
+
.sitenav-tier--below-lg {
|
|
463
|
+
display: none;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
@container (width < 80rem) {
|
|
467
|
+
.sitenav-tier--from-xl {
|
|
468
|
+
display: none;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
@container (width >= 80rem) {
|
|
472
|
+
.sitenav-tier--below-xl {
|
|
473
|
+
display: none;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/* ── Item description (EmDash `titleAttr` convention — see SiteNav.astro) ───── */
|
|
478
|
+
.sitenav__link--described {
|
|
479
|
+
flex-direction: column;
|
|
480
|
+
align-items: flex-start;
|
|
481
|
+
gap: 0.125rem;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.sitenav__desc {
|
|
485
|
+
font-size: 0.875em;
|
|
486
|
+
opacity: 0.75;
|
|
487
|
+
font-weight: normal;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/* The current page. Text-weight + a non-colour cue, so it survives forced-colors. */
|
|
491
|
+
.sitenav__link[aria-current='page'] {
|
|
492
|
+
font-weight: 600;
|
|
493
|
+
text-decoration: underline;
|
|
494
|
+
text-underline-offset: 0.25em;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/* ── Mega variant — WIDE ONLY ───────────────────────────────────────────────
|
|
498
|
+
Top-level submenus become full-width panels of columns under the nav row. The
|
|
499
|
+
branch item stops being the positioning context so the panel anchors to
|
|
500
|
+
`.sitenav--mega` instead. Inside the wide branch, with the same reasoning as the
|
|
501
|
+
rest of the file: a rule here competes at its bare selector weight. */
|
|
502
|
+
@container style(--_sitenav-wide: 1) {
|
|
503
|
+
.sitenav--mega {
|
|
504
|
+
position: relative;
|
|
505
|
+
}
|
|
506
|
+
.sitenav--mega .sitenav__list > .sitenav__item--branch {
|
|
507
|
+
position: static;
|
|
508
|
+
}
|
|
509
|
+
.sitenav--mega .sitenav__list > .sitenav__item--branch > .sitenav__submenu {
|
|
510
|
+
inset-inline: 0;
|
|
511
|
+
inline-size: 100%;
|
|
512
|
+
flex-direction: row;
|
|
513
|
+
flex-wrap: wrap;
|
|
514
|
+
align-items: flex-start;
|
|
515
|
+
gap: 1.5rem;
|
|
516
|
+
padding: 1.5rem;
|
|
517
|
+
}
|
|
518
|
+
/* Third level is a column inside the panel, not a fly-out. */
|
|
519
|
+
.sitenav--mega .sitenav__submenu .sitenav__item--branch {
|
|
520
|
+
position: static;
|
|
521
|
+
display: block;
|
|
522
|
+
}
|
|
523
|
+
.sitenav--mega .sitenav__submenu .sitenav__item--branch > .sitenav__submenu {
|
|
524
|
+
position: static;
|
|
525
|
+
opacity: 1;
|
|
526
|
+
visibility: visible;
|
|
527
|
+
pointer-events: auto;
|
|
528
|
+
translate: none;
|
|
529
|
+
box-shadow: none;
|
|
530
|
+
border: none;
|
|
531
|
+
padding: 0.25rem 0 0;
|
|
532
|
+
min-inline-size: 0;
|
|
533
|
+
}
|
|
534
|
+
.sitenav--mega .sitenav__submenu .sitenav__disclosure {
|
|
535
|
+
display: none;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/* ── In-page menu (`vitops.nav` block) ─────────────────────────────────────────
|
|
540
|
+
*
|
|
541
|
+
* A menu read in the body of a page — a site map, a section's links, footer-style columns —
|
|
542
|
+
* as plain nested lists. No disclosure and no drawer: that is the header's job (`.sitenav`).
|
|
543
|
+
*
|
|
544
|
+
* <nav aria-label="Services"><ul class="navlist navlist--columns">
|
|
545
|
+
* <li class="navlist__item"><a class="navlist__link">…</a><ul class="navlist__sub">…</ul></li>
|
|
546
|
+
*
|
|
547
|
+
* Modifiers: `--inline` (one wrapping row) and `--columns` (an auto-fit grid, each top-level
|
|
548
|
+
* item a column with its sub-links beneath it). */
|
|
549
|
+
.navlist,
|
|
550
|
+
.navlist__sub {
|
|
551
|
+
list-style: none;
|
|
552
|
+
margin: 0;
|
|
553
|
+
padding: 0;
|
|
554
|
+
display: flex;
|
|
555
|
+
flex-direction: column;
|
|
556
|
+
gap: 0.25rem;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/* The rhythm utility's `li + li` margin is the flow's job; the list's own gap does it here. */
|
|
560
|
+
.navlist__item {
|
|
561
|
+
margin: 0;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
.navlist__sub {
|
|
565
|
+
margin-block-start: 0.25rem;
|
|
566
|
+
padding-inline-start: 1rem;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.navlist__link {
|
|
570
|
+
color: inherit;
|
|
571
|
+
text-decoration: underline;
|
|
572
|
+
text-underline-offset: 0.2em;
|
|
573
|
+
padding-block: 0.25rem;
|
|
574
|
+
border-radius: var(--br-control, 0.25rem);
|
|
575
|
+
|
|
576
|
+
&:focus-visible {
|
|
577
|
+
outline: 2px solid var(--sitenav-focus-color, var(--color-border-focus));
|
|
578
|
+
outline-offset: 2px;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
&[aria-current='page'] {
|
|
582
|
+
font-weight: 600;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.navlist__label {
|
|
587
|
+
font-weight: 600;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.navlist--inline {
|
|
591
|
+
flex-direction: row;
|
|
592
|
+
flex-wrap: wrap;
|
|
593
|
+
gap: 0.25rem 1.25rem;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
.navlist--columns {
|
|
597
|
+
display: grid;
|
|
598
|
+
grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
|
|
599
|
+
gap: 1.5rem;
|
|
600
|
+
|
|
601
|
+
> .navlist__item > :is(.navlist__link, .navlist__label) {
|
|
602
|
+
font-weight: 600;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
> .navlist__item > .navlist__sub {
|
|
606
|
+
padding-inline-start: 0;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
@media (forced-colors: active) {
|
|
611
|
+
.navlist__link:focus-visible {
|
|
612
|
+
outline-color: Highlight;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/* ── Footer (`<SiteFooter>`) ───────────────────────────────────────────────── */
|
|
617
|
+
.sitefooter {
|
|
618
|
+
margin-block-start: var(--space-2xl, 3rem);
|
|
619
|
+
display: flex;
|
|
620
|
+
flex-direction: column;
|
|
621
|
+
gap: 1rem;
|
|
622
|
+
padding-block: var(--space-l, 2rem);
|
|
623
|
+
border-block-start: 1px solid var(--color-border-neutral, currentColor);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.sitefooter__nav {
|
|
627
|
+
display: flex;
|
|
628
|
+
flex-wrap: wrap;
|
|
629
|
+
gap: 1rem 3rem;
|
|
630
|
+
justify-content: space-between;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.sitefooter__list {
|
|
634
|
+
list-style: none;
|
|
635
|
+
margin: 0;
|
|
636
|
+
padding: 0;
|
|
637
|
+
display: flex;
|
|
638
|
+
flex-wrap: wrap;
|
|
639
|
+
gap: 0.25rem 1.25rem;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.sitefooter__link {
|
|
643
|
+
color: inherit;
|
|
644
|
+
text-decoration: underline;
|
|
645
|
+
text-underline-offset: 0.2em;
|
|
646
|
+
padding-block: 0.25rem;
|
|
647
|
+
border-radius: var(--br-control, 0.25rem);
|
|
648
|
+
|
|
649
|
+
&:focus-visible {
|
|
650
|
+
outline: 2px solid var(--sitenav-focus-color, var(--color-border-focus));
|
|
651
|
+
outline-offset: 2px;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
&[aria-current='page'] {
|
|
655
|
+
font-weight: 600;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
.sitefooter__copy {
|
|
660
|
+
margin: 0;
|
|
661
|
+
font-size: 0.875em;
|
|
662
|
+
opacity: 0.8;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/* ── Motion + forced colours (both site-nav and footer) ────────────────────── */
|
|
666
|
+
@media (prefers-reduced-motion: reduce) {
|
|
667
|
+
.sitenav__panel,
|
|
668
|
+
.sitenav__panel::backdrop,
|
|
669
|
+
.sitenav__submenu,
|
|
670
|
+
.sitenav__item--branch {
|
|
671
|
+
transition: none;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
@media (forced-colors: active) {
|
|
676
|
+
.sitenav__link:focus-visible,
|
|
677
|
+
.sitenav__toggle:focus-visible,
|
|
678
|
+
.sitenav__close:focus-visible,
|
|
679
|
+
.sitefooter__link:focus-visible {
|
|
680
|
+
outline-color: Highlight;
|
|
681
|
+
}
|
|
682
|
+
.sitenav__panel,
|
|
683
|
+
.sitenav__submenu {
|
|
684
|
+
border: 1px solid CanvasText;
|
|
685
|
+
}
|
|
686
|
+
.sitenav__link[aria-current='page'] {
|
|
687
|
+
text-decoration-thickness: 2px;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
@@ -210,3 +210,14 @@
|
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
|
+
|
|
214
|
+
/*
|
|
215
|
+
* Pre-upgrade display for the two elements that live in this partial — see the note on
|
|
216
|
+
* `wc-entries` in table.css. Both are a framed block of content (two panes; two images),
|
|
217
|
+
* and `wc-image-compare`'s upgraded `:host` is already `display: block`, so declaring it
|
|
218
|
+
* here removes the layout shift when it registers. `wc-split-panel` has no `:host` display
|
|
219
|
+
* at all, so this also fixes it after upgrade.
|
|
220
|
+
*/
|
|
221
|
+
:where(wc-split-panel, wc-image-compare) {
|
|
222
|
+
display: block;
|
|
223
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stats — a row of headline figures ("11 hrs/week", "82%") and, as `.stats--tiles`, a
|
|
3
|
+
* grid of labelled tiles with a group, a delta and a state (the generic kernel of a
|
|
4
|
+
* dashboard mock: "Open jobs 24 +3 this week").
|
|
5
|
+
*
|
|
6
|
+
* The figure is the `.counter` pattern, so the count-up is `<wc-counter>`'s; this
|
|
7
|
+
* partial only lays the figures out. With no JS and no CSS each figure is plain text
|
|
8
|
+
* beside its label.
|
|
9
|
+
*
|
|
10
|
+
* `data-state` on a tile (`up` / `down`) drives the delta's colour through the semantic
|
|
11
|
+
* roles, so "good" and "bad" follow the site's own success/danger rather than a hard-coded
|
|
12
|
+
* green and red. The delta's words stay in the text: colour is never the only carrier.
|
|
13
|
+
*/
|
|
14
|
+
.stats {
|
|
15
|
+
display: grid;
|
|
16
|
+
gap: var(--stats-gap, 1.5rem);
|
|
17
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--stats-min, 12rem)), 1fr));
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
list-style: none;
|
|
21
|
+
|
|
22
|
+
.stats__item {
|
|
23
|
+
display: grid;
|
|
24
|
+
gap: 0.25rem;
|
|
25
|
+
align-content: start;
|
|
26
|
+
margin: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.stats__figure,
|
|
30
|
+
.stats__label,
|
|
31
|
+
.stats__group,
|
|
32
|
+
.stats__delta {
|
|
33
|
+
margin: 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.stats__figure {
|
|
37
|
+
color: var(--tone-fg, inherit);
|
|
38
|
+
font-variant-numeric: tabular-nums;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.stats__group {
|
|
42
|
+
text-transform: uppercase;
|
|
43
|
+
letter-spacing: 0.05em;
|
|
44
|
+
opacity: 0.8;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.stats__item[data-state='up'] .stats__delta {
|
|
48
|
+
color: var(--color-text-success, inherit);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.stats__item[data-state='down'] .stats__delta {
|
|
52
|
+
color: var(--color-text-danger, inherit);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&.stats--tiles .stats__item {
|
|
56
|
+
padding: var(--stats-tile-padding, 1rem 1.25rem);
|
|
57
|
+
border: var(--b-card, var(--b-card-group, var(--b-default)));
|
|
58
|
+
border-radius: var(--br-card, var(--br-card-group, var(--br-default)));
|
|
59
|
+
background-color: var(--tone-bg, transparent);
|
|
60
|
+
}
|
|
61
|
+
}
|