@cogenta/theme-canonical 0.1.2 → 0.2.1
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/dist/src/render/blocks/collection-list.js +1 -1
- package/dist/src/render/blocks/collection-list.js.map +1 -1
- package/dist/src/render/blocks/cta.d.ts.map +1 -1
- package/dist/src/render/blocks/cta.js +3 -1
- package/dist/src/render/blocks/cta.js.map +1 -1
- package/dist/src/render/blocks/faq.d.ts.map +1 -1
- package/dist/src/render/blocks/faq.js +1 -1
- package/dist/src/render/blocks/faq.js.map +1 -1
- package/dist/src/render/blocks/feature-grid.js +1 -1
- package/dist/src/render/blocks/feature-grid.js.map +1 -1
- package/dist/src/render/blocks/hero.d.ts.map +1 -1
- package/dist/src/render/blocks/hero.js +5 -1
- package/dist/src/render/blocks/hero.js.map +1 -1
- package/dist/src/render/blocks/logos.d.ts.map +1 -1
- package/dist/src/render/blocks/logos.js +1 -1
- package/dist/src/render/blocks/logos.js.map +1 -1
- package/dist/src/render/blocks/media-figure.js +1 -1
- package/dist/src/render/blocks/media-figure.js.map +1 -1
- package/dist/src/render/blocks/quote.d.ts.map +1 -1
- package/dist/src/render/blocks/quote.js +4 -2
- package/dist/src/render/blocks/quote.js.map +1 -1
- package/dist/src/render/blocks/stats.d.ts.map +1 -1
- package/dist/src/render/blocks/stats.js +1 -1
- package/dist/src/render/blocks/stats.js.map +1 -1
- package/dist/src/render/render-block.d.ts.map +1 -1
- package/dist/src/render/render-block.js +34 -1
- package/dist/src/render/render-block.js.map +1 -1
- package/package.json +4 -3
- package/src/render/blocks/collection-list.ts +1 -1
- package/src/render/blocks/cta.ts +8 -2
- package/src/render/blocks/faq.ts +5 -1
- package/src/render/blocks/feature-grid.ts +1 -1
- package/src/render/blocks/hero.ts +7 -3
- package/src/render/blocks/logos.ts +5 -1
- package/src/render/blocks/media-figure.ts +1 -1
- package/src/render/blocks/quote.ts +5 -3
- package/src/render/blocks/stats.ts +5 -1
- package/src/render/render-block.ts +34 -1
- package/src/styles/base.css +341 -0
- package/src/styles/blocks.css +890 -0
- package/src/styles/theme.css +20 -601
- package/src/styles/tokens.css +339 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Document, accessibility floor, page frame and the one control the theme
|
|
3
|
+
* ships (an action link). Everything here reads the design system from
|
|
4
|
+
* `tokens.css`; nothing here reads a `--cogenta-*` token directly, so a value
|
|
5
|
+
* that needs changing is changed in one place.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/* --------------------------------------------------------------------------
|
|
9
|
+
Document
|
|
10
|
+
-------------------------------------------------------------------------- */
|
|
11
|
+
|
|
12
|
+
*,
|
|
13
|
+
*::before,
|
|
14
|
+
*::after {
|
|
15
|
+
box-sizing: border-box;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
body {
|
|
19
|
+
margin: 0;
|
|
20
|
+
background: var(--cg-canvas);
|
|
21
|
+
color: var(--cg-ink);
|
|
22
|
+
font-family: var(--cogenta-font-sans);
|
|
23
|
+
font-size: var(--cg-text-md);
|
|
24
|
+
line-height: var(--cg-leading-normal);
|
|
25
|
+
/* Two opt-in font features rather than a font choice: `kern` is what stops
|
|
26
|
+
display type looking loose, `liga` what stops "fi" breaking apart. Both
|
|
27
|
+
are no-ops on a font that lacks them. */
|
|
28
|
+
font-kerning: normal;
|
|
29
|
+
font-variant-ligatures: common-ligatures;
|
|
30
|
+
text-underline-offset: 0.16em;
|
|
31
|
+
text-decoration-thickness: from-font;
|
|
32
|
+
-webkit-text-size-adjust: 100%;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
::selection {
|
|
36
|
+
background: var(--cg-accent-soft);
|
|
37
|
+
color: var(--cg-accent-soft-fg);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
img,
|
|
41
|
+
video,
|
|
42
|
+
iframe {
|
|
43
|
+
max-width: 100%;
|
|
44
|
+
height: auto;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
img {
|
|
48
|
+
display: block;
|
|
49
|
+
object-fit: cover;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
:where(a) {
|
|
53
|
+
color: var(--cg-accent);
|
|
54
|
+
text-decoration-color: color-mix(in oklab, var(--cg-accent) 45%, transparent);
|
|
55
|
+
transition:
|
|
56
|
+
color var(--cg-duration-fast) var(--cg-ease),
|
|
57
|
+
text-decoration-color var(--cg-duration-fast) var(--cg-ease);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:where(a:hover) {
|
|
61
|
+
color: var(--cg-accent-hover);
|
|
62
|
+
text-decoration-color: currentColor;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
:where(hr) {
|
|
66
|
+
block-size: 1px;
|
|
67
|
+
border: 0;
|
|
68
|
+
margin-block: var(--cg-s10);
|
|
69
|
+
background: var(--cg-line);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* --------------------------------------------------------------------------
|
|
73
|
+
Focus, targets, motion — the three that decide whether AA holds
|
|
74
|
+
-------------------------------------------------------------------------- */
|
|
75
|
+
|
|
76
|
+
:where(a, button, summary, [tabindex]):focus-visible {
|
|
77
|
+
/* Two solid pixels against the page, offset so it never sits on the glyphs.
|
|
78
|
+
`outline`, not `box-shadow`: it survives forced-colors mode. */
|
|
79
|
+
outline: 2px solid var(--cg-accent);
|
|
80
|
+
outline-offset: 3px;
|
|
81
|
+
border-radius: var(--cg-radius-sm);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* WCAG 2.2 asks 24x24 minimum (2.5.8); 44x44 is the comfortable target and
|
|
85
|
+
costs nothing here. Applied to the theme's own controls only — an inline link
|
|
86
|
+
inside a paragraph is exempt, and padding it would break the text flow. */
|
|
87
|
+
:where(.cg-action, .cg-faq__question, .cg-logo__link) {
|
|
88
|
+
min-block-size: 44px;
|
|
89
|
+
min-inline-size: 44px;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* The entrance animation the blocks opt into. Scroll-driven, so it plays as a
|
|
93
|
+
block arrives rather than firing eleven at once on load, and wrapped in a
|
|
94
|
+
feature query because the starting state is `opacity: 0`: a browser without
|
|
95
|
+
`animation-timeline` must never be left holding an invisible page. */
|
|
96
|
+
@supports (animation-timeline: view()) {
|
|
97
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
98
|
+
@keyframes cg-rise {
|
|
99
|
+
from {
|
|
100
|
+
opacity: 0;
|
|
101
|
+
transform: translateY(var(--cg-s4));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
to {
|
|
105
|
+
opacity: 1;
|
|
106
|
+
transform: none;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.cg-block {
|
|
111
|
+
animation: cg-rise linear both;
|
|
112
|
+
animation-timeline: view();
|
|
113
|
+
/* Fully in by the time the block is a fifth of the way up the viewport;
|
|
114
|
+
it never animates back out on the way past. */
|
|
115
|
+
animation-range: entry 0% cover 22%;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@media (prefers-reduced-motion: reduce) {
|
|
121
|
+
/* The `motion.reduced` token says the skin's motion may be removed. Nothing
|
|
122
|
+
in this theme conveys meaning through movement, so removing all of it is
|
|
123
|
+
safe — including the smooth scroll of the carousel, which is the one people
|
|
124
|
+
forget and which triggers vestibular symptoms. */
|
|
125
|
+
*,
|
|
126
|
+
*::before,
|
|
127
|
+
*::after {
|
|
128
|
+
animation-duration: 1ms !important;
|
|
129
|
+
animation-iteration-count: 1 !important;
|
|
130
|
+
transition-duration: 1ms !important;
|
|
131
|
+
scroll-behavior: auto !important;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.cg-skip-link {
|
|
136
|
+
position: absolute;
|
|
137
|
+
inset-inline-start: var(--cg-s3);
|
|
138
|
+
inset-block-start: calc(var(--cg-s3) * -8);
|
|
139
|
+
z-index: 10;
|
|
140
|
+
padding: var(--cg-s2) var(--cg-s4);
|
|
141
|
+
background: var(--cg-accent);
|
|
142
|
+
color: var(--cg-accent-fg);
|
|
143
|
+
border-radius: var(--cg-radius-md);
|
|
144
|
+
box-shadow: var(--cg-elevation-2);
|
|
145
|
+
font-weight: var(--cg-weight-semibold);
|
|
146
|
+
text-decoration: none;
|
|
147
|
+
/* Moved, never hidden: `display:none` would take it out of the tab order,
|
|
148
|
+
which is the whole point of a skip link (WCAG 2.4.1). */
|
|
149
|
+
transition: inset-block-start var(--cg-duration) var(--cg-ease);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.cg-skip-link:focus-visible {
|
|
153
|
+
inset-block-start: var(--cg-s3);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* --------------------------------------------------------------------------
|
|
157
|
+
Page frame
|
|
158
|
+
-------------------------------------------------------------------------- */
|
|
159
|
+
|
|
160
|
+
/* `flow-root`, so the first and last block's own margins stay inside `<main>`
|
|
161
|
+
instead of collapsing through it and pushing the header and footer around.
|
|
162
|
+
That also means no padding is needed here: the last block already carries a
|
|
163
|
+
section's worth of space below itself, and adding more produced a dead band
|
|
164
|
+
three times too tall between the last block and the footer. */
|
|
165
|
+
.cg-main {
|
|
166
|
+
display: flow-root;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* The one measurement every block shares. A block that wants to break out of
|
|
170
|
+
it says so itself (`.cg-figure[data-align="full"]`), so the default stays
|
|
171
|
+
one rule instead of eleven. */
|
|
172
|
+
.cg-block {
|
|
173
|
+
max-inline-size: var(--cg-page);
|
|
174
|
+
margin-inline: auto;
|
|
175
|
+
margin-block: var(--cg-section-y);
|
|
176
|
+
padding-inline: var(--cg-gutter);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.cg-page__title {
|
|
180
|
+
max-inline-size: var(--cg-page);
|
|
181
|
+
margin-inline: auto;
|
|
182
|
+
margin-block: var(--cg-section-y) var(--cg-s6);
|
|
183
|
+
padding-inline: var(--cg-gutter);
|
|
184
|
+
font-size: var(--cg-text-3xl);
|
|
185
|
+
line-height: var(--cg-leading-tight);
|
|
186
|
+
letter-spacing: var(--cg-tracking-tight);
|
|
187
|
+
font-weight: var(--cg-weight-bold);
|
|
188
|
+
text-wrap: balance;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.cg-site-header {
|
|
192
|
+
position: sticky;
|
|
193
|
+
inset-block-start: 0;
|
|
194
|
+
z-index: 5;
|
|
195
|
+
padding: var(--cg-s4) var(--cg-gutter);
|
|
196
|
+
background: color-mix(in oklab, var(--cg-canvas) 82%, transparent);
|
|
197
|
+
border-block-end: 1px solid var(--cg-line-soft);
|
|
198
|
+
/* Progressive: a browser without it simply gets the translucent ground. */
|
|
199
|
+
backdrop-filter: saturate(1.4) blur(12px);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.cg-site-header__inner,
|
|
203
|
+
.cg-site-footer__inner {
|
|
204
|
+
display: flex;
|
|
205
|
+
flex-wrap: wrap;
|
|
206
|
+
align-items: center;
|
|
207
|
+
gap: var(--cg-gap);
|
|
208
|
+
max-inline-size: var(--cg-page);
|
|
209
|
+
margin-inline: auto;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.cg-site-header__home {
|
|
213
|
+
color: var(--cg-ink);
|
|
214
|
+
font-weight: var(--cg-weight-semibold);
|
|
215
|
+
font-size: var(--cg-text-lg);
|
|
216
|
+
letter-spacing: var(--cg-tracking-snug);
|
|
217
|
+
text-decoration: none;
|
|
218
|
+
margin-inline-end: auto;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.cg-site-footer {
|
|
222
|
+
padding: var(--cg-s12) var(--cg-gutter);
|
|
223
|
+
background: var(--cg-surface-sunken);
|
|
224
|
+
color: var(--cg-ink-muted);
|
|
225
|
+
border-block-start: 1px solid var(--cg-line-soft);
|
|
226
|
+
font-size: var(--cg-text-sm);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* --------------------------------------------------------------------------
|
|
230
|
+
Actions — the theme's only control
|
|
231
|
+
-------------------------------------------------------------------------- */
|
|
232
|
+
|
|
233
|
+
.cg-actions {
|
|
234
|
+
display: flex;
|
|
235
|
+
flex-wrap: wrap;
|
|
236
|
+
gap: var(--cg-s3);
|
|
237
|
+
margin: var(--cg-s8) 0 0;
|
|
238
|
+
padding: 0;
|
|
239
|
+
list-style: none;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.cg-action {
|
|
243
|
+
display: inline-flex;
|
|
244
|
+
align-items: center;
|
|
245
|
+
justify-content: center;
|
|
246
|
+
gap: var(--cg-s2);
|
|
247
|
+
padding: var(--cg-s3) var(--cg-s6);
|
|
248
|
+
border: 0;
|
|
249
|
+
border-radius: var(--cg-radius-md);
|
|
250
|
+
font-size: var(--cg-text-sm);
|
|
251
|
+
font-weight: var(--cg-weight-semibold);
|
|
252
|
+
letter-spacing: var(--cg-tracking-snug);
|
|
253
|
+
line-height: var(--cg-leading-snug);
|
|
254
|
+
text-decoration: none;
|
|
255
|
+
white-space: nowrap;
|
|
256
|
+
transition:
|
|
257
|
+
background-color var(--cg-duration) var(--cg-ease),
|
|
258
|
+
color var(--cg-duration) var(--cg-ease),
|
|
259
|
+
box-shadow var(--cg-duration) var(--cg-ease),
|
|
260
|
+
transform var(--cg-duration-fast) var(--cg-ease);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* `emphasis` stays a data attribute, never a class: it is the editor's
|
|
264
|
+
semantic intent, and the skin — not the block — decides what it looks like. */
|
|
265
|
+
.cg-action[data-emphasis="primary"] {
|
|
266
|
+
background: var(--cg-accent);
|
|
267
|
+
color: var(--cg-accent-fg);
|
|
268
|
+
box-shadow: var(--cg-elevation-1);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.cg-action[data-emphasis="primary"]:hover {
|
|
272
|
+
background: var(--cg-accent-hover);
|
|
273
|
+
box-shadow: var(--cg-elevation-2);
|
|
274
|
+
transform: translateY(-1px);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.cg-action[data-emphasis="secondary"] {
|
|
278
|
+
background: var(--cg-surface);
|
|
279
|
+
color: var(--cg-ink);
|
|
280
|
+
box-shadow: var(--cg-ring);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.cg-action[data-emphasis="secondary"]:hover {
|
|
284
|
+
background: var(--cg-accent-soft);
|
|
285
|
+
color: var(--cg-accent-soft-fg);
|
|
286
|
+
box-shadow: var(--cg-ring-accent);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* The press. Without it a hover lift reads as a bug on touch, where there is
|
|
290
|
+
no hover to come back from. */
|
|
291
|
+
.cg-action:active {
|
|
292
|
+
transform: translateY(0);
|
|
293
|
+
box-shadow: var(--cg-elevation-1);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* --------------------------------------------------------------------------
|
|
297
|
+
Shared block furniture
|
|
298
|
+
-------------------------------------------------------------------------- */
|
|
299
|
+
|
|
300
|
+
/* Every block that carries a heading uses the same one, so eleven blocks do
|
|
301
|
+
not drift into eleven title sizes. */
|
|
302
|
+
.cg-features__title,
|
|
303
|
+
.cg-cta__title,
|
|
304
|
+
.cg-faq__title,
|
|
305
|
+
.cg-stats__title,
|
|
306
|
+
.cg-logos__title,
|
|
307
|
+
.cg-collection__title {
|
|
308
|
+
margin: 0 0 var(--cg-s8);
|
|
309
|
+
font-size: var(--cg-text-xl);
|
|
310
|
+
line-height: var(--cg-leading-snug);
|
|
311
|
+
letter-spacing: var(--cg-tracking-tight);
|
|
312
|
+
font-weight: var(--cg-weight-bold);
|
|
313
|
+
text-wrap: balance;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.cg-features__items,
|
|
317
|
+
.cg-logos__items,
|
|
318
|
+
.cg-gallery__items,
|
|
319
|
+
.cg-collection__items,
|
|
320
|
+
.cg-faq__items {
|
|
321
|
+
margin: 0;
|
|
322
|
+
padding: 0;
|
|
323
|
+
list-style: none;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* A scroll-snapping row, used by both `gallery` and `collectionList`. The
|
|
327
|
+
container is focusable and labelled, so it is operable from the keyboard —
|
|
328
|
+
at zero bytes of JavaScript. */
|
|
329
|
+
.cg-gallery__viewport,
|
|
330
|
+
.cg-collection__viewport {
|
|
331
|
+
overflow-x: auto;
|
|
332
|
+
scroll-snap-type: x mandatory;
|
|
333
|
+
scroll-behavior: smooth;
|
|
334
|
+
overscroll-behavior-inline: contain;
|
|
335
|
+
scrollbar-width: thin;
|
|
336
|
+
scrollbar-color: var(--cg-line-strong) transparent;
|
|
337
|
+
/* Room for the focus ring and the hover lift, which would otherwise be
|
|
338
|
+
clipped by the scroll container. */
|
|
339
|
+
padding-block: var(--cg-s2);
|
|
340
|
+
margin-block: calc(var(--cg-s2) * -1);
|
|
341
|
+
}
|