@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.
Files changed (42) hide show
  1. package/dist/src/render/blocks/collection-list.js +1 -1
  2. package/dist/src/render/blocks/collection-list.js.map +1 -1
  3. package/dist/src/render/blocks/cta.d.ts.map +1 -1
  4. package/dist/src/render/blocks/cta.js +3 -1
  5. package/dist/src/render/blocks/cta.js.map +1 -1
  6. package/dist/src/render/blocks/faq.d.ts.map +1 -1
  7. package/dist/src/render/blocks/faq.js +1 -1
  8. package/dist/src/render/blocks/faq.js.map +1 -1
  9. package/dist/src/render/blocks/feature-grid.js +1 -1
  10. package/dist/src/render/blocks/feature-grid.js.map +1 -1
  11. package/dist/src/render/blocks/hero.d.ts.map +1 -1
  12. package/dist/src/render/blocks/hero.js +5 -1
  13. package/dist/src/render/blocks/hero.js.map +1 -1
  14. package/dist/src/render/blocks/logos.d.ts.map +1 -1
  15. package/dist/src/render/blocks/logos.js +1 -1
  16. package/dist/src/render/blocks/logos.js.map +1 -1
  17. package/dist/src/render/blocks/media-figure.js +1 -1
  18. package/dist/src/render/blocks/media-figure.js.map +1 -1
  19. package/dist/src/render/blocks/quote.d.ts.map +1 -1
  20. package/dist/src/render/blocks/quote.js +4 -2
  21. package/dist/src/render/blocks/quote.js.map +1 -1
  22. package/dist/src/render/blocks/stats.d.ts.map +1 -1
  23. package/dist/src/render/blocks/stats.js +1 -1
  24. package/dist/src/render/blocks/stats.js.map +1 -1
  25. package/dist/src/render/render-block.d.ts.map +1 -1
  26. package/dist/src/render/render-block.js +34 -1
  27. package/dist/src/render/render-block.js.map +1 -1
  28. package/package.json +4 -3
  29. package/src/render/blocks/collection-list.ts +1 -1
  30. package/src/render/blocks/cta.ts +8 -2
  31. package/src/render/blocks/faq.ts +5 -1
  32. package/src/render/blocks/feature-grid.ts +1 -1
  33. package/src/render/blocks/hero.ts +7 -3
  34. package/src/render/blocks/logos.ts +5 -1
  35. package/src/render/blocks/media-figure.ts +1 -1
  36. package/src/render/blocks/quote.ts +5 -3
  37. package/src/render/blocks/stats.ts +5 -1
  38. package/src/render/render-block.ts +34 -1
  39. package/src/styles/base.css +341 -0
  40. package/src/styles/blocks.css +890 -0
  41. package/src/styles/theme.css +20 -601
  42. 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
+ }