@plus234feed/ds 0.3.0 → 0.4.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.md +69 -138
- package/package.json +3 -2
- package/src/components.css +173 -45
package/README.md
CHANGED
|
@@ -1,90 +1,44 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @plus234feed/ds
|
|
2
2
|
|
|
3
|
-
Editorial tokens, a named type scale and the
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
The Plus234Feed design system. Editorial tokens, a named type scale and the
|
|
4
|
+
components a news site needs: newspaper hierarchy, accessible colour in both
|
|
5
|
+
themes, plain CSS.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
No framework, no JavaScript, no build step for consumers. Four stylesheets and
|
|
8
|
+
four font files.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
rules. Each component page says what it is, when to use it, when not to, live
|
|
12
|
-
examples with copyable HTML, and the tokens it reads.
|
|
13
|
-
|
|
14
|
-
## Why this exists
|
|
15
|
-
|
|
16
|
-
The frontend had 252 component files and 40,638 lines of TSX, but only 25
|
|
17
|
-
shared components. Measured on 2026-11-04:
|
|
18
|
-
|
|
19
|
-
| Symptom | Count |
|
|
20
|
-
| --- | --- |
|
|
21
|
-
| `page.tsx` files not using `PageLayout` | 92 (16 do) |
|
|
22
|
-
| Files re-implementing an article card | 47 |
|
|
23
|
-
| `rounded-*` variants in use | 11 |
|
|
24
|
-
| Ad-hoc text sizes in use | 9, dominated by `text-sm` (1,019) and `text-xs` (720) |
|
|
25
|
-
| Hardcoded uses of a single green | 27 |
|
|
26
|
-
| Variables used but defined nowhere | 5 |
|
|
27
|
-
|
|
28
|
-
That last row was a live bug, not a matter of taste. `--text-muted` (42 uses),
|
|
29
|
-
`--border` (36), `--bg-elevated` (13), `--bg-secondary` and `--bg-hover` were
|
|
30
|
-
referenced with no fallback and declared in no stylesheet, concentrated in
|
|
31
|
-
`components/prices/` and the cost of living pages.
|
|
32
|
-
|
|
33
|
-
Reader behaviour pointed the same way. Almost every visitor is new, and
|
|
34
|
-
almost nobody opens a second page. Readers arriving from search spend real
|
|
35
|
-
time on the article, finish it, and leave: the problem is not that they are
|
|
36
|
-
bored, it is that the page offers them nothing to do next.
|
|
10
|
+
Documentation: [ds.plus234feed.com](https://ds.plus234feed.com)
|
|
37
11
|
|
|
38
12
|
## Install
|
|
39
13
|
|
|
40
14
|
```bash
|
|
41
|
-
npm install
|
|
42
|
-
npm run build # tokens + gallery
|
|
43
|
-
npm test # 13 checks
|
|
15
|
+
npm install @plus234feed/ds
|
|
44
16
|
```
|
|
45
17
|
|
|
18
|
+
```css
|
|
19
|
+
@import "@plus234feed/ds/tokens.css"; /* custom properties, both themes */
|
|
20
|
+
@import "@plus234feed/ds/type.css"; /* .p234-headline and friends */
|
|
21
|
+
@import "@plus234feed/ds/components.css"; /* .p234-story and friends */
|
|
22
|
+
@import "@plus234feed/ds/fonts.css"; /* Charter, 64KB, four faces */
|
|
46
23
|
```
|
|
47
|
-
npm run build:tokens tokens/*.json -> build/*.css, build/tokens.json
|
|
48
|
-
npm run build:docs site/pages/** -> docs/**
|
|
49
|
-
npm run check build + test, what CI runs
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Authoring a docs page
|
|
53
24
|
|
|
54
|
-
|
|
55
|
-
|
|
25
|
+
`fonts.css` resolves `./fonts/*.woff2` relative to itself. If your bundler does
|
|
26
|
+
not follow that, copy the faces to a public path and rewrite the four `url()`
|
|
27
|
+
values:
|
|
56
28
|
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
<docs-tokens names="ink,ink-muted"> generated swatches, both themes
|
|
62
|
-
<docs-type roles="display-1,headline"> generated specimens
|
|
63
|
-
<docs-scale group="space"> generated scale table
|
|
64
|
-
<docs-uses>--p234-color-ink, ...</docs-uses> the tokens a component reads
|
|
29
|
+
```bash
|
|
30
|
+
cp node_modules/@plus234feed/ds/src/fonts/*.woff2 public/fonts/
|
|
31
|
+
sed 's|url("./fonts/|url("/fonts/|g' \
|
|
32
|
+
node_modules/@plus234feed/ds/src/fonts.css > app/fonts.css
|
|
65
33
|
```
|
|
66
34
|
|
|
67
|
-
Navigation and the section sidebar are derived from the front matter, so a new
|
|
68
|
-
page appears in both by existing.
|
|
69
|
-
|
|
70
35
|
## Use it
|
|
71
36
|
|
|
72
|
-
```css
|
|
73
|
-
@import "@plus234feed/ds/fonts.css"; /* Charter, self-hosted, 64KB */
|
|
74
|
-
@import "@plus234feed/ds/tokens.css"; /* theme driven by a .dark class */
|
|
75
|
-
@import "@plus234feed/ds/type.css"; /* .p234-headline and friends */
|
|
76
|
-
@import "@plus234feed/ds/components.css";
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Use `tokens-auto.css` instead of `tokens.css` only on standalone pages that
|
|
80
|
-
have no theme toggle. It adds an OS-preference block. The app must not use it:
|
|
81
|
-
a reader who picked light has to get light on a dark laptop.
|
|
82
|
-
|
|
83
37
|
```html
|
|
84
|
-
<a class="p234-story p234-story--lead" href="
|
|
38
|
+
<a class="p234-story p234-story--lead" href="/article/...">
|
|
85
39
|
<span class="p234-kicker" data-section="markets">Market intelligence</span>
|
|
86
|
-
<h3 class="p234-story__headline">Pump prices are running
|
|
87
|
-
<p class="p234-story__standfirst">
|
|
40
|
+
<h3 class="p234-story__headline">Pump prices are running above the last official figure</h3>
|
|
41
|
+
<p class="p234-story__standfirst">The gap between the two is the story.</p>
|
|
88
42
|
<div class="p234-meta">
|
|
89
43
|
<span class="p234-meta__source">Plus234Feed</span>
|
|
90
44
|
<span class="p234-meta__dot">·</span>
|
|
@@ -94,76 +48,53 @@ a reader who picked light has to get light on a dark laptop.
|
|
|
94
48
|
</a>
|
|
95
49
|
```
|
|
96
50
|
|
|
97
|
-
##
|
|
51
|
+
## Themes
|
|
98
52
|
|
|
53
|
+
`tokens.css` is class-driven: add `dark` or `data-theme="dark"` to the root
|
|
54
|
+
element. It never reads the operating system preference, because a reader who
|
|
55
|
+
chose light should get light on a dark laptop.
|
|
56
|
+
|
|
57
|
+
Use `tokens-auto.css` instead only on a standalone page with no theme control.
|
|
58
|
+
|
|
59
|
+
## What is in it
|
|
60
|
+
|
|
61
|
+
| | |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| Tokens | colour, type, space, shape, charts, forms, layering, motion |
|
|
64
|
+
| Type | 17 named roles, serif for reading, tabular sans for figures |
|
|
65
|
+
| Components | story, masthead, footer, prose, chart, map, table, field, and more |
|
|
66
|
+
|
|
67
|
+
Colour is verified rather than eyeballed. Every pair that has to be readable is
|
|
68
|
+
checked in both themes at build time and the build fails on any that is not.
|
|
69
|
+
The chart palette is checked for colour-blind separation using OKLab and the
|
|
70
|
+
Machado simulation, which is also why it stops at the number of series it can
|
|
71
|
+
actually keep distinct instead of inventing more.
|
|
72
|
+
|
|
73
|
+
## Typeface
|
|
74
|
+
|
|
75
|
+
Charter, self-hosted. Bitstream contributed it to the X Consortium in 1992 with
|
|
76
|
+
permission to use, copy, modify, sublicense, sell and redistribute, provided
|
|
77
|
+
the notice stays intact. That notice ships at `src/fonts/LICENSE.charter.txt`.
|
|
78
|
+
BITSTREAM CHARTER is a registered trademark of Bitstream Inc.
|
|
79
|
+
|
|
80
|
+
## Developing
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install
|
|
84
|
+
npm run build # tokens and documentation
|
|
85
|
+
npm test # 33 checks
|
|
86
|
+
npm run check # both, which is what CI runs
|
|
99
87
|
```
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
88
|
+
|
|
89
|
+
Releases publish from CI through an npm trusted publisher, so there is no token
|
|
90
|
+
in the repository:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm version patch # rebuilds the docs, commits, tags
|
|
94
|
+
git push --follow-tags
|
|
107
95
|
```
|
|
108
96
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
44 colour pairs are checked in every theme, 88 checks in all, and the build
|
|
115
|
-
exits non-zero on any failure. This is the point of the pipeline: a combination
|
|
116
|
-
nobody can read cannot reach the site. The first run caught three real
|
|
117
|
-
problems, two of which were dark-theme only.
|
|
118
|
-
|
|
119
|
-
The focus ring is checked differently. It is two colours, `focus` with
|
|
120
|
-
`focus-outer` drawn around it, and neither half clears 3:1 alone. The amber is
|
|
121
|
-
1.64:1 on white and relies on the dark outer ring there; on a dark page the
|
|
122
|
-
outer ring recedes and the amber carries it. So the rule is that at least one
|
|
123
|
-
half must clear 3:1 on every surface. See `checkFocus`.
|
|
124
|
-
|
|
125
|
-
## Rules the tokens cannot enforce
|
|
126
|
-
|
|
127
|
-
1. **Two ad slots on an article, maximum, and no mobile sticky.** The current
|
|
128
|
-
template carries six plus a sticky around a 147-word summary. Mobile is 64
|
|
129
|
-
per cent of search traffic.
|
|
130
|
-
2. **Every article ends with a next step that matches why the reader came.** A
|
|
131
|
-
visa reader gets visa stories, not the general feed. This is the module the
|
|
132
|
-
near-total absence of second pages is asking for.
|
|
133
|
-
3. **No raw hex.** If a colour is missing, add a token.
|
|
134
|
-
4. **No undefined tokens.** A prebuild check fails on any `--p234-` variable
|
|
135
|
-
this package does not declare.
|
|
136
|
-
5. **Pick a type role, never a font size.** Seventeen roles cover the site.
|
|
137
|
-
Reaching past them means a role is missing, which is a conversation.
|
|
138
|
-
6. **Direction is never colour alone.** Gainers and decliners carry an arrow.
|
|
139
|
-
7. **One lead per page.** If two stories both look like the lead, neither is.
|
|
140
|
-
|
|
141
|
-
## Type
|
|
142
|
-
|
|
143
|
-
Roles, not t-shirt sizes. Serif for what a reader reads, sans for what a reader
|
|
144
|
-
operates, tabular sans for every figure.
|
|
145
|
-
|
|
146
|
-
The serif is **Charter**, self-hosted from `src/fonts/`, 64KB for four faces,
|
|
147
|
-
`font-display: swap`. Charter is the face macOS and iOS already carry, which is
|
|
148
|
-
why the gallery looked right before a single font was loaded. Shipping it is
|
|
149
|
-
what gives Android readers, who are most of the audience, the same page
|
|
150
|
-
instead of a Noto Serif fallback.
|
|
151
|
-
|
|
152
|
-
Bitstream contributed Charter to the X Consortium in 1992 with permission to
|
|
153
|
-
use, copy, modify, sublicense, sell and redistribute, provided the notice stays
|
|
154
|
-
intact. That notice is `src/fonts/LICENSE.charter.txt` and ships with the
|
|
155
|
-
files. BITSTREAM CHARTER is a registered trademark of Bitstream Inc.
|
|
156
|
-
|
|
157
|
-
The sans is still the system stack headed by Inter, which the Next app already
|
|
158
|
-
loads. On a machine without Inter it resolves to San Francisco or Roboto. If
|
|
159
|
-
that drift matters it should be self-hosted the same way.
|
|
160
|
-
|
|
161
|
-
Running text never drops below 16px. `caption` and `kicker` are the only roles
|
|
162
|
-
allowed at 12px, and the tests enforce both floors.
|
|
163
|
-
|
|
164
|
-
## Scope
|
|
165
|
-
|
|
166
|
-
Phase 1 is this package plus the site chrome and the article template:
|
|
167
|
-
almost every session starts on an article, and the masthead and footer appear
|
|
168
|
-
on every page, so those are what make the site stop looking like two sites.
|
|
169
|
-
Fronts, data pages, account and forms follow.
|
|
97
|
+
## Licence
|
|
98
|
+
|
|
99
|
+
UNLICENSED. Published so Plus234Feed applications can install it; not offered
|
|
100
|
+
for reuse.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plus234feed/ds",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Plus234Feed design system. Editorial tokens, type scale and components for a news intelligence platform: newspaper hierarchy, accessible colour in both themes, one component per job.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design-system",
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"build:docs": "node scripts/build-docs.mjs",
|
|
45
45
|
"build": "npm run build:tokens && npm run build:docs",
|
|
46
46
|
"test": "node --test test/*.test.js",
|
|
47
|
-
"check": "npm run build && npm test"
|
|
47
|
+
"check": "npm run build && npm test",
|
|
48
|
+
"version": "npm run build && git add build docs"
|
|
48
49
|
},
|
|
49
50
|
"publishConfig": {
|
|
50
51
|
"access": "public"
|
package/src/components.css
CHANGED
|
@@ -590,76 +590,88 @@
|
|
|
590
590
|
}
|
|
591
591
|
|
|
592
592
|
/* --- masthead ----------------------------------------------------------
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
593
|
+
A newspaper masthead, not an app bar. Three rows:
|
|
594
|
+
|
|
595
|
+
utility search, edition links, account
|
|
596
|
+
brand the wordmark, centred, with date and figures flanking it
|
|
597
|
+
sections the section nav, with a full width panel beneath it
|
|
598
|
+
|
|
599
|
+
The centred wordmark is the whole point: it is what makes the top of the
|
|
600
|
+
page read as a paper rather than a product. */
|
|
596
601
|
.p234-masthead {
|
|
597
602
|
position: sticky;
|
|
598
603
|
top: 0;
|
|
599
604
|
z-index: var(--p234-z-sticky);
|
|
600
605
|
background: var(--p234-color-paper);
|
|
601
|
-
border-bottom: var(--p234-border-
|
|
606
|
+
border-bottom: var(--p234-border-hairline) solid var(--p234-color-rule);
|
|
602
607
|
}
|
|
603
|
-
|
|
608
|
+
|
|
609
|
+
/* Row 1: utility. Hidden on phones, where the bar collapses to one row. */
|
|
610
|
+
.p234-masthead__utility {
|
|
611
|
+
display: none;
|
|
612
|
+
border-bottom: var(--p234-border-hairline) solid var(--p234-color-rule);
|
|
613
|
+
}
|
|
614
|
+
@media (min-width: 62rem) { .p234-masthead__utility { display: block; } }
|
|
615
|
+
.p234-masthead__utility-in {
|
|
604
616
|
max-width: var(--p234-layout-container);
|
|
605
617
|
margin: 0 auto;
|
|
606
|
-
padding: var(--p234-space-
|
|
607
|
-
display:
|
|
618
|
+
padding: var(--p234-space-3) var(--p234-layout-gutter-lg);
|
|
619
|
+
display: grid;
|
|
620
|
+
grid-template-columns: 1fr auto 1fr;
|
|
608
621
|
align-items: center;
|
|
609
622
|
gap: var(--p234-space-5);
|
|
610
623
|
}
|
|
611
|
-
|
|
612
|
-
.p234-masthead__bar { padding-inline: var(--p234-layout-gutter-lg); }
|
|
613
|
-
}
|
|
614
|
-
.p234-masthead__brand {
|
|
624
|
+
.p234-masthead__editions {
|
|
615
625
|
display: flex;
|
|
616
|
-
|
|
617
|
-
gap: var(--p234-space-
|
|
626
|
+
justify-content: center;
|
|
627
|
+
gap: var(--p234-space-5);
|
|
628
|
+
}
|
|
629
|
+
.p234-masthead__editions a {
|
|
630
|
+
font-family: var(--p234-type-ui-sm-family);
|
|
631
|
+
font-size: var(--p234-type-ui-sm-size);
|
|
632
|
+
font-weight: 600;
|
|
633
|
+
letter-spacing: 0.04em;
|
|
634
|
+
text-transform: uppercase;
|
|
635
|
+
color: var(--p234-color-ink-muted);
|
|
618
636
|
text-decoration: none;
|
|
619
|
-
|
|
620
|
-
flex-shrink: 0;
|
|
637
|
+
white-space: nowrap;
|
|
621
638
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
639
|
+
.p234-masthead__editions a:hover,
|
|
640
|
+
.p234-masthead__editions a[aria-current] { color: var(--p234-color-ink); }
|
|
641
|
+
|
|
642
|
+
/* Row 2: the wordmark, centred. */
|
|
643
|
+
.p234-masthead__bar {
|
|
644
|
+
max-width: var(--p234-layout-container);
|
|
645
|
+
margin: 0 auto;
|
|
646
|
+
padding: var(--p234-space-4) var(--p234-layout-gutter);
|
|
647
|
+
display: grid;
|
|
648
|
+
grid-template-columns: 1fr auto 1fr;
|
|
649
|
+
align-items: center;
|
|
650
|
+
gap: var(--p234-space-4);
|
|
651
|
+
}
|
|
652
|
+
@media (min-width: 62rem) {
|
|
653
|
+
.p234-masthead__bar { padding: var(--p234-space-5) var(--p234-layout-gutter-lg); }
|
|
654
|
+
}
|
|
655
|
+
.p234-masthead__brand { justify-self: center; display: block; text-decoration: none; }
|
|
625
656
|
.p234-masthead__logo { display: block; height: 1.75rem; width: auto; }
|
|
657
|
+
@media (min-width: 62rem) { .p234-masthead__logo { height: 2.5rem; } }
|
|
626
658
|
.p234-masthead__logo--dark { display: none; }
|
|
627
659
|
.dark .p234-masthead__logo--light,
|
|
628
660
|
[data-theme="dark"] .p234-masthead__logo--light { display: none; }
|
|
629
661
|
.dark .p234-masthead__logo--dark,
|
|
630
662
|
[data-theme="dark"] .p234-masthead__logo--dark { display: block; }
|
|
631
663
|
|
|
632
|
-
|
|
633
|
-
.p234-
|
|
634
|
-
|
|
635
|
-
font-weight: 900;
|
|
636
|
-
font-size: 1.25rem;
|
|
637
|
-
letter-spacing: -0.03em;
|
|
638
|
-
color: var(--p234-color-brand);
|
|
639
|
-
}
|
|
640
|
-
.p234-masthead__tagline {
|
|
641
|
-
font-family: var(--p234-type-caption-family);
|
|
642
|
-
font-size: var(--p234-type-caption-size);
|
|
643
|
-
color: var(--p234-color-ink-muted);
|
|
664
|
+
.p234-masthead__left { display: flex; align-items: center; gap: var(--p234-space-3); }
|
|
665
|
+
.p234-masthead__right { display: flex; align-items: center; justify-content: flex-end; gap: var(--p234-space-3); }
|
|
666
|
+
.p234-masthead__dateline {
|
|
644
667
|
display: none;
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
.p234-masthead__nav { display: none; gap: var(--p234-space-5); margin-left: auto; }
|
|
649
|
-
@media (min-width: 62rem) { .p234-masthead__nav { display: flex; } }
|
|
650
|
-
.p234-masthead__nav a {
|
|
651
|
-
font-family: var(--p234-type-ui-family);
|
|
652
|
-
font-size: var(--p234-type-ui-size);
|
|
653
|
-
font-weight: 600;
|
|
668
|
+
font-family: var(--p234-type-meta-family);
|
|
669
|
+
font-size: var(--p234-type-meta-size);
|
|
654
670
|
color: var(--p234-color-ink-muted);
|
|
655
|
-
|
|
656
|
-
white-space: nowrap;
|
|
671
|
+
line-height: 1.3;
|
|
657
672
|
}
|
|
658
|
-
.p234-
|
|
659
|
-
.p234-masthead__nav a[aria-current] { color: var(--p234-color-ink); }
|
|
673
|
+
@media (min-width: 62rem) { .p234-masthead__dateline { display: block; } }
|
|
660
674
|
|
|
661
|
-
.p234-masthead__actions { display: flex; align-items: center; gap: var(--p234-space-3); margin-left: auto; }
|
|
662
|
-
@media (min-width: 62rem) { .p234-masthead__actions { margin-left: 0; } }
|
|
663
675
|
.p234-masthead__icon {
|
|
664
676
|
display: inline-flex;
|
|
665
677
|
align-items: center;
|
|
@@ -674,6 +686,122 @@
|
|
|
674
686
|
}
|
|
675
687
|
.p234-masthead__icon:hover { background: var(--p234-color-paper-sunk); }
|
|
676
688
|
|
|
689
|
+
/* Phone only: the hamburger and the compact sign in. On desktop the utility
|
|
690
|
+
row carries these, so showing them twice is just clutter. */
|
|
691
|
+
@media (min-width: 62rem) {
|
|
692
|
+
.p234-masthead__menubtn,
|
|
693
|
+
.p234-masthead__compact { display: none !important; }
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/* Row 3: the sections. Centred on desktop, scrolls sideways on a phone. */
|
|
697
|
+
.p234-masthead__sections {
|
|
698
|
+
border-top: var(--p234-border-hairline) solid var(--p234-color-rule);
|
|
699
|
+
overflow-x: auto;
|
|
700
|
+
scrollbar-width: none;
|
|
701
|
+
}
|
|
702
|
+
.p234-masthead__sections::-webkit-scrollbar { display: none; }
|
|
703
|
+
.p234-masthead__sections-in {
|
|
704
|
+
max-width: var(--p234-layout-container);
|
|
705
|
+
margin: 0 auto;
|
|
706
|
+
padding: 0 var(--p234-layout-gutter);
|
|
707
|
+
display: flex;
|
|
708
|
+
gap: var(--p234-space-6);
|
|
709
|
+
}
|
|
710
|
+
@media (min-width: 62rem) {
|
|
711
|
+
.p234-masthead__sections-in { justify-content: center; padding-inline: var(--p234-layout-gutter-lg); }
|
|
712
|
+
}
|
|
713
|
+
.p234-masthead__section {
|
|
714
|
+
display: inline-flex;
|
|
715
|
+
align-items: center;
|
|
716
|
+
gap: var(--p234-space-2);
|
|
717
|
+
flex-shrink: 0;
|
|
718
|
+
background: none;
|
|
719
|
+
border: 0;
|
|
720
|
+
cursor: pointer;
|
|
721
|
+
padding: var(--p234-space-4) 0;
|
|
722
|
+
font-family: var(--p234-type-ui-family);
|
|
723
|
+
font-size: var(--p234-type-ui-size);
|
|
724
|
+
font-weight: 500;
|
|
725
|
+
color: var(--p234-color-ink);
|
|
726
|
+
text-decoration: none;
|
|
727
|
+
white-space: nowrap;
|
|
728
|
+
border-bottom: var(--p234-border-thick) solid transparent;
|
|
729
|
+
margin-bottom: -1px;
|
|
730
|
+
}
|
|
731
|
+
.p234-masthead__section:hover { border-bottom-color: var(--p234-color-rule-strong); }
|
|
732
|
+
.p234-masthead__section[aria-expanded="true"],
|
|
733
|
+
.p234-masthead__section[aria-current] { border-bottom-color: var(--p234-color-ink); }
|
|
734
|
+
|
|
735
|
+
/* The panel. Full width of the viewport, not a box anchored to a button:
|
|
736
|
+
a dropdown pinned under the last nav item runs off the right edge. */
|
|
737
|
+
.p234-megamenu {
|
|
738
|
+
position: absolute;
|
|
739
|
+
left: 0;
|
|
740
|
+
right: 0;
|
|
741
|
+
top: 100%;
|
|
742
|
+
z-index: var(--p234-z-dropdown);
|
|
743
|
+
background: var(--p234-color-paper);
|
|
744
|
+
border-top: var(--p234-border-hairline) solid var(--p234-color-rule);
|
|
745
|
+
border-bottom: var(--p234-border-hairline) solid var(--p234-color-rule);
|
|
746
|
+
box-shadow: var(--p234-shadow-overlay);
|
|
747
|
+
}
|
|
748
|
+
.p234-megamenu__in {
|
|
749
|
+
max-width: var(--p234-layout-container);
|
|
750
|
+
margin: 0 auto;
|
|
751
|
+
padding: var(--p234-space-7) var(--p234-layout-gutter-lg);
|
|
752
|
+
display: grid;
|
|
753
|
+
gap: var(--p234-space-7);
|
|
754
|
+
grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
|
|
755
|
+
}
|
|
756
|
+
.p234-megamenu ul { list-style: none; margin: 0; padding: 0; }
|
|
757
|
+
.p234-megamenu li { margin-bottom: var(--p234-space-4); }
|
|
758
|
+
.p234-megamenu a {
|
|
759
|
+
font-family: var(--p234-type-ui-family);
|
|
760
|
+
font-size: var(--p234-type-ui-size);
|
|
761
|
+
color: var(--p234-color-ink);
|
|
762
|
+
text-decoration: none;
|
|
763
|
+
}
|
|
764
|
+
.p234-megamenu a:hover { text-decoration: underline; text-underline-offset: 2px; }
|
|
765
|
+
|
|
766
|
+
/* The phone drawer: a full screen panel, search first, then the sections as
|
|
767
|
+
accordions. <details> so it works with no JavaScript. */
|
|
768
|
+
.p234-drawer {
|
|
769
|
+
position: fixed;
|
|
770
|
+
inset: 0;
|
|
771
|
+
z-index: var(--p234-z-overlay);
|
|
772
|
+
background: var(--p234-color-paper);
|
|
773
|
+
overflow-y: auto;
|
|
774
|
+
padding: var(--p234-space-5) var(--p234-layout-gutter) var(--p234-space-9);
|
|
775
|
+
}
|
|
776
|
+
.p234-drawer__head { display: flex; justify-content: flex-start; margin-bottom: var(--p234-space-6); }
|
|
777
|
+
.p234-drawer__search { display: flex; gap: var(--p234-space-3); margin-bottom: var(--p234-space-6); }
|
|
778
|
+
.p234-drawer__group { border-top: var(--p234-border-hairline) solid var(--p234-color-rule); }
|
|
779
|
+
.p234-drawer__group > summary {
|
|
780
|
+
list-style: none;
|
|
781
|
+
display: flex;
|
|
782
|
+
align-items: center;
|
|
783
|
+
justify-content: space-between;
|
|
784
|
+
padding: var(--p234-space-5) 0;
|
|
785
|
+
cursor: pointer;
|
|
786
|
+
font-family: var(--p234-type-headline-xs-family);
|
|
787
|
+
font-size: var(--p234-type-headline-xs-size);
|
|
788
|
+
font-weight: var(--p234-type-headline-xs-weight);
|
|
789
|
+
color: var(--p234-color-ink);
|
|
790
|
+
}
|
|
791
|
+
.p234-drawer__group > summary::-webkit-details-marker { display: none; }
|
|
792
|
+
.p234-drawer__links {
|
|
793
|
+
display: grid;
|
|
794
|
+
grid-template-columns: 1fr 1fr;
|
|
795
|
+
gap: var(--p234-space-4);
|
|
796
|
+
padding-bottom: var(--p234-space-5);
|
|
797
|
+
}
|
|
798
|
+
.p234-drawer__links a {
|
|
799
|
+
font-family: var(--p234-type-ui-family);
|
|
800
|
+
font-size: var(--p234-type-ui-size);
|
|
801
|
+
color: var(--p234-color-ink);
|
|
802
|
+
text-decoration: none;
|
|
803
|
+
}
|
|
804
|
+
|
|
677
805
|
/* --- subnav ------------------------------------------------------------
|
|
678
806
|
Section level navigation: the price pages, the account panes. Scrolls
|
|
679
807
|
sideways on a phone rather than wrapping into two rows. */
|