@cogenta/theme-canonical 1.1.2 → 1.3.3

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 (71) hide show
  1. package/dist/src/index.d.ts +1 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +1 -0
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/render/arrow-link.d.ts +11 -0
  6. package/dist/src/render/arrow-link.d.ts.map +1 -0
  7. package/dist/src/render/arrow-link.js +29 -0
  8. package/dist/src/render/arrow-link.js.map +1 -0
  9. package/dist/src/render/blocks/collection-list.d.ts +15 -5
  10. package/dist/src/render/blocks/collection-list.d.ts.map +1 -1
  11. package/dist/src/render/blocks/collection-list.js +36 -13
  12. package/dist/src/render/blocks/collection-list.js.map +1 -1
  13. package/dist/src/render/blocks/embed.d.ts.map +1 -1
  14. package/dist/src/render/blocks/embed.js +3 -2
  15. package/dist/src/render/blocks/embed.js.map +1 -1
  16. package/dist/src/render/blocks/gallery.d.ts.map +1 -1
  17. package/dist/src/render/blocks/gallery.js +4 -1
  18. package/dist/src/render/blocks/gallery.js.map +1 -1
  19. package/dist/src/render/blocks/hero.d.ts.map +1 -1
  20. package/dist/src/render/blocks/hero.js +9 -2
  21. package/dist/src/render/blocks/hero.js.map +1 -1
  22. package/dist/src/render/blocks/pricing-table.d.ts.map +1 -1
  23. package/dist/src/render/blocks/pricing-table.js +17 -4
  24. package/dist/src/render/blocks/pricing-table.js.map +1 -1
  25. package/dist/src/render/chrome.d.ts +40 -1
  26. package/dist/src/render/chrome.d.ts.map +1 -1
  27. package/dist/src/render/chrome.js +103 -71
  28. package/dist/src/render/chrome.js.map +1 -1
  29. package/dist/src/render/dates.d.ts +9 -0
  30. package/dist/src/render/dates.d.ts.map +1 -0
  31. package/dist/src/render/dates.js +16 -0
  32. package/dist/src/render/dates.js.map +1 -0
  33. package/dist/src/render/render-block.d.ts.map +1 -1
  34. package/dist/src/render/render-block.js +7 -1
  35. package/dist/src/render/render-block.js.map +1 -1
  36. package/dist/src/render/strings.d.ts +25 -0
  37. package/dist/src/render/strings.d.ts.map +1 -0
  38. package/dist/src/render/strings.js +26 -0
  39. package/dist/src/render/strings.js.map +1 -0
  40. package/dist/src/render/term-archive.d.ts +5 -5
  41. package/dist/src/render/term-archive.d.ts.map +1 -1
  42. package/dist/src/render/term-archive.js +14 -12
  43. package/dist/src/render/term-archive.js.map +1 -1
  44. package/dist/src/render/widget-areas.d.ts +20 -0
  45. package/dist/src/render/widget-areas.d.ts.map +1 -0
  46. package/dist/src/render/widget-areas.js +40 -0
  47. package/dist/src/render/widget-areas.js.map +1 -0
  48. package/package.json +5 -5
  49. package/src/index.ts +1 -0
  50. package/src/render/arrow-link.ts +27 -0
  51. package/src/render/blocks/collection-list.ts +53 -15
  52. package/src/render/blocks/embed.ts +3 -2
  53. package/src/render/blocks/gallery.ts +4 -1
  54. package/src/render/blocks/hero.ts +9 -2
  55. package/src/render/blocks/pricing-table.ts +22 -4
  56. package/src/render/chrome.ts +156 -70
  57. package/src/render/dates.ts +14 -0
  58. package/src/render/render-block.ts +6 -0
  59. package/src/render/strings.ts +30 -0
  60. package/src/render/term-archive.ts +54 -32
  61. package/src/render/widget-areas.ts +44 -0
  62. package/src/styles/archive.css +66 -20
  63. package/src/styles/base.css +266 -680
  64. package/src/styles/blocks.css +678 -811
  65. package/src/styles/chrome.css +469 -0
  66. package/src/styles/listings.css +183 -0
  67. package/src/styles/theme.css +28 -14
  68. package/src/styles/tokens.css +192 -205
  69. package/src/styles/utility.css +295 -0
  70. package/src/styles/widgets.css +1064 -0
  71. package/tokens.json +15 -15
@@ -1,1013 +1,905 @@
1
1
  /*
2
- * The twelve vocabulary blocks.
2
+ * The vocabulary blocks (contract B), in the contract's order. The
3
+ * collection list lives in `listings.css`, with the term archive's index.
3
4
  *
4
- * One section per block, in the contract-B order. Nothing here declares a
5
- * colour, a size, a radius or a duration of its own: a block composes the
6
- * design system from `tokens.css` and nothing else, which is what keeps a skin
7
- * swap a whole-theme change rather than a per-block one.
5
+ * Every block is a twelve-column grid on the page width (`base.css`), and
6
+ * every one below only says which columns its parts take, at three widths:
7
+ * a phone (one column of content), from 40rem (halves), from 64rem (the full
8
+ * grid). Nothing here casts a shadow, rounds a photograph, moves on hover or
9
+ * fades in on scroll.
8
10
  */
9
11
 
10
12
  /* --- hero ----------------------------------------------------------------
11
- The page's first impression, so it is the one block that gets a decorative
12
- element of its own: a flat solid disc of the skin's accent behind the
13
- media — a geometric accent rather than a wash. It is drawn on a
14
- pseudo-element and sized to stay inside the block's own box — a
15
- decoration that widens the page produces a horizontal scrollbar, which is
16
- the classic way a hero breaks a phone.
13
+ The page's name, set large in the display face, over a wide photograph
14
+ when there is one. Words first and on the page's own ground: never text on
15
+ a picture.
17
16
  ------------------------------------------------------------------------- */
18
17
 
19
18
  .cg-hero {
20
- position: relative;
21
- /* A stacking context of its own, so `z-index: -1` on the disc puts it
22
- behind the hero's content and not behind the page background. */
23
- isolation: isolate;
24
- display: grid;
25
- gap: var(--cg-gap-loose);
26
- align-items: center;
27
- margin-block-start: var(--cg-s10);
28
- }
29
-
30
- .cg-hero::before {
31
- content: "";
32
- position: absolute;
33
- inset-block-start: 0;
34
- inset-inline-end: var(--cg-gutter);
35
- inline-size: min(30rem, 70%);
36
- aspect-ratio: 1;
37
- z-index: -1;
38
- border-radius: 50%;
39
- background: var(--cg-accent-soft);
40
- pointer-events: none;
41
- }
42
-
43
- @media (min-width: 60rem) {
44
- .cg-hero {
45
- /* Not 1fr 1fr: the copy carries the weight, and an even split makes both
46
- halves look accidental. */
47
- grid-template-columns: 1.05fr 0.95fr;
48
- gap: var(--cg-s16);
49
- }
19
+ padding-block-start: calc(var(--cg-section) * 0.6);
50
20
  }
51
21
 
52
- /* A badge, not a line of small text: it is the one label above the h1 and it
53
- has to look deliberate. */
54
22
  .cg-hero__eyebrow {
55
- display: inline-block;
56
- margin: 0 0 var(--cg-s5);
57
- padding: var(--cg-s1) var(--cg-s3);
58
- background: var(--cg-accent-soft);
59
- color: var(--cg-accent-soft-fg);
60
- border-radius: var(--cg-radius-pill);
61
- box-shadow: var(--cg-ring-accent);
62
- font-size: var(--cg-text-xs);
63
- font-weight: var(--cg-weight-semibold);
64
- letter-spacing: var(--cg-tracking-wide);
65
- text-transform: uppercase;
23
+ margin-block-end: var(--cg-s6);
24
+ color: var(--cg-ink-muted);
25
+ font-size: var(--cg-text-sm);
26
+ font-weight: var(--cg-weight-medium);
66
27
  }
67
28
 
68
29
  .cg-hero__title {
69
- margin: 0;
70
- font-size: var(--cg-text-3xl);
71
- line-height: var(--cg-leading-tight);
72
- letter-spacing: var(--cg-tracking-tight);
73
- font-weight: var(--cg-weight-bold);
74
- /* Display type wraps into a shape, not into a ragged column. */
75
- text-wrap: balance;
76
- }
77
-
78
- /* Above 60rem the title is allowed one step larger than the page title — the
79
- hero *is* the page title there, and the extra step is what separates a hero
80
- from a heading with a picture next to it. */
81
- @media (min-width: 60rem) {
82
- .cg-hero__title {
83
- font-size: calc(var(--cg-text-3xl) * 1.15);
84
- }
30
+ font-family: var(--cg-font-display);
31
+ font-size: var(--cg-text-display);
32
+ font-weight: var(--cg-weight-regular);
33
+ line-height: var(--cg-leading-display);
34
+ letter-spacing: var(--cg-tracking-display);
85
35
  }
86
36
 
87
37
  .cg-hero__subtitle {
88
- margin: var(--cg-s5) 0 0;
38
+ margin-block-start: var(--cg-s6);
89
39
  max-inline-size: var(--cg-measure-narrow);
90
- font-size: var(--cg-text-lg);
91
- line-height: var(--cg-leading-relaxed);
92
40
  color: var(--cg-ink-muted);
93
- text-wrap: pretty;
41
+ font-size: var(--cg-text-lg);
42
+ line-height: var(--cg-leading-snug);
94
43
  }
95
44
 
96
- .cg-hero__media img {
97
- inline-size: 100%;
98
- border-radius: var(--cg-radius-xl);
99
- box-shadow: var(--cg-elevation-3), var(--cg-ring);
45
+ .cg-hero .cg-actions {
46
+ margin-block-start: var(--cg-s10);
100
47
  }
101
48
 
102
- /* --- prose --------------------------------------------------------------- */
49
+ .cg-hero__media {
50
+ margin-block-start: var(--cg-s12);
51
+ }
103
52
 
104
- .cg-prose {
105
- max-inline-size: var(--cg-measure);
106
- margin-inline: auto;
107
- /* Body copy is the one place in the theme that reads for minutes rather than
108
- seconds, so it gets the loosest leading of the scale. */
109
- line-height: var(--cg-leading-relaxed);
53
+ .cg-hero__image,
54
+ .cg-hero__media video {
55
+ inline-size: 100%;
56
+ aspect-ratio: 3 / 2;
110
57
  }
111
58
 
112
- /* A block's first and last child must not push the block's own rhythm around:
113
- without these, a prose block that opens on a heading sits a full step lower
114
- than one that opens on a paragraph. */
115
- .cg-prose > :first-child {
116
- margin-block-start: 0;
59
+ @media (min-width: 64rem) {
60
+ .cg-hero__body {
61
+ grid-column: 1 / span 10;
62
+ }
63
+
64
+ .cg-hero__media {
65
+ margin-block-start: var(--cg-s16);
66
+ }
67
+
68
+ .cg-hero__image,
69
+ .cg-hero__media video {
70
+ aspect-ratio: 2 / 1;
71
+ }
117
72
  }
118
73
 
119
- .cg-prose > :last-child {
120
- margin-block-end: 0;
74
+ /* --- prose ----------------------------------------------------------------
75
+ Running text on the first columns, at a reading measure, from the same
76
+ left edge as every title on the page.
77
+ ------------------------------------------------------------------------- */
78
+
79
+ .cg-prose > * {
80
+ max-inline-size: var(--cg-measure);
121
81
  }
122
82
 
123
- .cg-prose h2,
124
- .cg-prose h3,
125
- .cg-prose h4 {
126
- letter-spacing: var(--cg-tracking-snug);
127
- line-height: var(--cg-leading-snug);
128
- font-weight: var(--cg-weight-bold);
129
- text-wrap: balance;
83
+ .cg-prose > * + * {
84
+ margin-block-start: var(--cg-s5);
130
85
  }
131
86
 
132
- /* Asymmetric on purpose: the space above a heading belongs to the section it
133
- opens, so it is much larger than the space below it. */
134
- .cg-prose h2 {
135
- margin-block: var(--cg-s12) var(--cg-s4);
136
- font-size: var(--cg-text-xl);
137
- letter-spacing: var(--cg-tracking-tight);
87
+ .cg-prose > h2 {
88
+ margin-block-start: var(--cg-s12);
89
+ font-size: var(--cg-text-heading);
138
90
  }
139
91
 
140
- .cg-prose h3 {
141
- margin-block: var(--cg-s10) var(--cg-s3);
92
+ .cg-prose > h3 {
93
+ margin-block-start: var(--cg-s10);
142
94
  font-size: var(--cg-text-lg);
143
95
  }
144
96
 
145
- .cg-prose h4 {
146
- margin-block: var(--cg-s8) var(--cg-s2);
97
+ .cg-prose > h4 {
98
+ margin-block-start: var(--cg-s8);
147
99
  font-size: var(--cg-text-md);
148
100
  }
149
101
 
150
- .cg-prose p {
151
- margin-block: var(--cg-s5);
152
- /* Stops the one-word last line, which is the most visible defect in a
153
- justified-looking column and costs nothing to avoid. */
154
- text-wrap: pretty;
102
+ .cg-prose > :is(h2, h3, h4) + * {
103
+ margin-block-start: var(--cg-s3);
155
104
  }
156
105
 
157
- .cg-prose ul,
158
- .cg-prose ol {
159
- margin-block: var(--cg-s5);
160
- padding-inline-start: var(--cg-s6);
106
+ .cg-prose > :first-child {
107
+ margin-block-start: 0;
161
108
  }
162
109
 
163
- .cg-prose li {
164
- margin-block: var(--cg-s2);
165
- padding-inline-start: var(--cg-s1);
110
+ .cg-prose :is(ul, ol) {
111
+ padding-inline-start: 1.25em;
112
+ }
113
+
114
+ .cg-prose li + li,
115
+ .cg-prose li > :is(ul, ol) {
116
+ margin-block-start: var(--cg-s2);
166
117
  }
167
118
 
168
- /* The marker is the only decoration a list gets, so it is the one that carries
169
- the accent. */
170
119
  .cg-prose li::marker {
171
- color: var(--cg-accent);
120
+ color: var(--cg-ink-muted);
172
121
  }
173
122
 
174
123
  .cg-prose strong {
175
124
  font-weight: var(--cg-weight-semibold);
176
- color: var(--cg-ink);
177
125
  }
178
126
 
179
- /* A quoted passage inside an article, not the `quote` block: a panel with a
180
- rule, sized down from the pull quote so the two never compete. */
181
127
  .cg-prose blockquote {
182
- margin-block: var(--cg-s8);
183
- margin-inline: 0;
184
- padding: var(--cg-s5) var(--cg-s6);
185
- border-inline-start: 3px solid var(--cg-accent);
186
- border-start-end-radius: var(--cg-radius-md);
187
- border-end-end-radius: var(--cg-radius-md);
188
- background: var(--cg-surface-sunken);
189
- color: var(--cg-ink-muted);
190
- font-family: var(--cogenta-font-serif);
191
- font-size: var(--cg-text-lg);
192
- line-height: var(--cg-leading-normal);
193
- }
194
-
195
- .cg-prose blockquote > :first-child {
196
- margin-block-start: 0;
128
+ padding-inline-start: var(--cg-s6);
129
+ border-inline-start: var(--cg-rule-strong) solid var(--cg-ink);
130
+ font-family: var(--cg-font-display);
131
+ font-size: var(--cg-text-xl);
132
+ line-height: var(--cg-leading-snug);
197
133
  }
198
134
 
199
- .cg-prose blockquote > :last-child {
200
- margin-block-end: 0;
135
+ .cg-prose blockquote > * + * {
136
+ margin-block-start: var(--cg-s3);
201
137
  }
202
138
 
203
139
  .cg-prose code {
204
- font-family: var(--cogenta-font-mono);
205
- /* `em`, not a scale step: inline code has to match the size of the text it
206
- sits in, and monospace faces read larger at the same nominal size. */
140
+ padding: 0.1em 0.3em;
141
+ border-radius: var(--cg-radius-control);
142
+ background: var(--cg-band);
143
+ font-family: var(--cg-font-mono);
144
+ /* `em`: inline code matches the text it sits in. */
207
145
  font-size: 0.875em;
208
- background: var(--cg-surface-sunken);
209
- border-radius: var(--cg-radius-sm);
210
- box-shadow: var(--cg-ring);
211
- padding: 0.15em 0.4em;
212
146
  }
213
147
 
214
- .cg-prose__figure {
215
- margin-block: var(--cg-s8);
216
- margin-inline: 0;
148
+ .cg-prose > .cg-prose__figure {
149
+ max-inline-size: min(100%, 48rem);
150
+ margin-block: var(--cg-s10);
217
151
  }
218
152
 
219
153
  .cg-prose__figure img {
220
154
  inline-size: 100%;
221
- border-radius: var(--cg-radius-lg);
222
- box-shadow: var(--cg-elevation-2);
223
155
  }
224
156
 
225
157
  .cg-prose__figure figcaption {
226
158
  margin-block-start: var(--cg-s3);
227
- color: var(--cg-ink-subtle);
159
+ max-inline-size: var(--cg-measure);
160
+ color: var(--cg-ink-muted);
228
161
  font-size: var(--cg-text-sm);
229
- line-height: var(--cg-leading-normal);
230
- }
231
-
232
- /* --- mediaFigure --------------------------------------------------------- */
233
-
234
- .cg-figure {
235
- margin-inline: auto;
236
162
  }
237
163
 
238
- .cg-figure[data-align="start"],
239
- .cg-figure[data-align="end"] {
240
- max-inline-size: calc(var(--cg-measure) / 2);
164
+ .cg-prose > .cg-prose__rule {
165
+ margin-block: var(--cg-s12);
241
166
  }
242
167
 
243
- .cg-figure[data-align="start"] {
244
- float: inline-start;
245
- margin-inline-end: var(--cg-s6);
168
+ .cg-prose > .cg-prose__figure + *,
169
+ .cg-prose > .cg-prose__rule + * {
170
+ margin-block-start: 0;
246
171
  }
247
172
 
248
- .cg-figure[data-align="end"] {
249
- float: inline-end;
250
- margin-inline-start: var(--cg-s6);
251
- }
173
+ /* --- mediaFigure ----------------------------------------------------------
174
+ `align` is the editor's intent, mirrored in right-to-left locales. On the
175
+ full grid: `center` takes the reading columns, `wide` the page, `full` the
176
+ window; `start` and `end` set the picture on seven columns and the caption
177
+ beside it, never floated into the text of the next block.
178
+ ------------------------------------------------------------------------- */
252
179
 
253
- .cg-figure[data-align="full"] {
254
- max-inline-size: none;
255
- padding-inline: 0;
180
+ .cg-figure {
181
+ row-gap: var(--cg-s3);
256
182
  }
257
183
 
258
184
  .cg-figure__media {
259
185
  inline-size: 100%;
260
186
  aspect-ratio: var(--cg-ratio, auto);
261
- border-radius: var(--cg-radius-lg);
262
- box-shadow: var(--cg-elevation-2), var(--cg-ring);
263
187
  }
264
188
 
265
- /* Full bleed keeps its corners square: a rounded corner against the viewport
266
- edge reads as a mistake, not as a radius. */
267
- .cg-figure[data-align="full"] .cg-figure__media {
268
- border-radius: 0;
269
- }
270
-
271
- /* An indented caption with a rule, so it reads as annotation rather than as a
272
- stray paragraph that happens to follow a picture. */
273
189
  .cg-figure__caption {
274
- margin-block-start: var(--cg-s4);
275
- padding-inline-start: var(--cg-s4);
276
- border-inline-start: 2px solid var(--cg-line-strong);
277
- color: var(--cg-ink-subtle);
190
+ max-inline-size: var(--cg-measure);
191
+ color: var(--cg-ink-muted);
278
192
  font-size: var(--cg-text-sm);
279
- line-height: var(--cg-leading-normal);
280
- text-wrap: pretty;
281
193
  }
282
194
 
283
- .cg-figure[data-align="full"] .cg-figure__caption {
284
- max-inline-size: var(--cg-measure);
285
- margin-inline: auto;
286
- padding-inline: var(--cg-gutter);
287
- border-inline-start: 0;
195
+ .cg-figure__credit {
196
+ display: block;
288
197
  }
289
198
 
290
- .cg-figure__credit {
291
- color: var(--cg-ink-subtle);
199
+ .cg-figure[data-align="full"] {
200
+ padding-inline: 0;
292
201
  }
293
202
 
294
- .cg-figure__credit::before {
295
- content: " — ";
203
+ .cg-figure[data-align="full"] .cg-figure__caption {
204
+ padding-inline: var(--cg-inset);
205
+ max-inline-size: none;
296
206
  }
297
207
 
298
- /* --- featureGrid --------------------------------------------------------- */
208
+ @media (min-width: 64rem) {
209
+ .cg-figure[data-align="center"] > * {
210
+ grid-column: 1 / span 8;
211
+ }
299
212
 
300
- .cg-features__items {
301
- display: grid;
302
- gap: var(--cg-gap);
303
- grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
304
- }
213
+ .cg-figure[data-align="wide"] .cg-figure__caption {
214
+ grid-column: 1 / span 8;
215
+ }
305
216
 
306
- .cg-feature {
307
- position: relative;
308
- padding: var(--cg-s6);
309
- background: var(--cg-surface-raised);
310
- border-radius: var(--cg-radius-lg);
311
- box-shadow: var(--cg-ring);
312
- transition:
313
- box-shadow var(--cg-duration) var(--cg-ease),
314
- transform var(--cg-duration) var(--cg-ease);
315
- }
217
+ .cg-figure[data-align="start"] .cg-figure__media,
218
+ .cg-figure[data-align="end"] .cg-figure__media {
219
+ grid-row: 1;
220
+ }
316
221
 
317
- .cg-feature:hover {
318
- box-shadow: var(--cg-elevation-2), var(--cg-ring-accent);
319
- transform: translateY(-2px);
320
- }
222
+ .cg-figure[data-align="start"] .cg-figure__media {
223
+ grid-column: 1 / span 7;
224
+ }
321
225
 
322
- /* The whole card becomes the link's hit area, without a second link for a
323
- screen reader to announce: the overlay is drawn from the one anchor the
324
- markup already has, whose accessible name is the feature's title. */
325
- .cg-feature__link::after {
326
- content: "";
327
- position: absolute;
328
- inset: 0;
329
- border-radius: inherit;
226
+ .cg-figure[data-align="start"] .cg-figure__caption {
227
+ grid-column: 9 / -1;
228
+ grid-row: 1;
229
+ align-self: end;
230
+ }
231
+
232
+ .cg-figure[data-align="end"] .cg-figure__media {
233
+ grid-column: 6 / -1;
234
+ }
235
+
236
+ .cg-figure[data-align="end"] .cg-figure__caption {
237
+ grid-column: 1 / span 4;
238
+ grid-row: 1;
239
+ align-self: end;
240
+ }
330
241
  }
331
242
 
332
- .cg-feature__link {
333
- color: inherit;
334
- text-decoration: none;
243
+ /* --- featureGrid ----------------------------------------------------------
244
+ Columns under hairlines, not cards: a feature is a title and a sentence,
245
+ and a frame around each one only repeats itself.
246
+ ------------------------------------------------------------------------- */
247
+
248
+ .cg-features__items {
249
+ display: grid;
250
+ grid-template-columns: subgrid;
251
+ row-gap: var(--cg-s10);
252
+ margin: 0;
253
+ padding: 0;
254
+ list-style: none;
335
255
  }
336
256
 
337
- .cg-feature:hover .cg-feature__link {
338
- color: var(--cg-accent);
257
+ .cg-feature {
258
+ grid-column: span 12;
259
+ padding-block-start: var(--cg-s5);
260
+ border-block-start: var(--cg-rule) solid var(--cg-line);
339
261
  }
340
262
 
341
- /* The vocabulary's `icon` names a symbol — a tinted, ringed square that holds
342
- the space an icon would, whether or not `renderIcon` (`@cogenta/theme-kit`,
343
- L25) recognises the name: an unrecognised one still gets the chip, empty,
344
- exactly the pre-L25 look; a recognised one gets a real glyph, centred and
345
- coloured to the same accent as the ring around it. */
263
+ /* A symbol the editor named: a plain glyph in ink, never a tinted tile. */
346
264
  .cg-feature__icon {
347
- display: flex;
348
- align-items: center;
349
- justify-content: center;
350
- inline-size: var(--cg-s10);
351
- block-size: var(--cg-s10);
265
+ display: block;
266
+ inline-size: 1.5rem;
267
+ block-size: 1.5rem;
352
268
  margin-block-end: var(--cg-s5);
353
- background: var(--cg-accent-soft);
354
- border-radius: var(--cg-radius-md);
355
- box-shadow: var(--cg-ring-accent);
356
- color: var(--cg-accent);
269
+ color: var(--cg-ink);
270
+ }
271
+
272
+ /* A symbol this theme has no glyph for keeps its `data-icon` for the builder
273
+ and takes no room: never an empty square above a title. */
274
+ .cg-feature__icon:empty {
275
+ display: none;
357
276
  }
358
277
 
359
278
  .cg-feature__icon svg {
360
- inline-size: var(--cg-s6);
361
- block-size: var(--cg-s6);
279
+ display: block;
280
+ inline-size: 100%;
281
+ block-size: 100%;
362
282
  }
363
283
 
364
284
  .cg-feature__title {
365
- margin: 0 0 var(--cg-s2);
366
- font-size: var(--cg-text-md);
367
- font-weight: var(--cg-weight-semibold);
368
- line-height: var(--cg-leading-snug);
369
- letter-spacing: var(--cg-tracking-snug);
370
- text-wrap: balance;
285
+ font-size: var(--cg-text-lg);
286
+ }
287
+
288
+ .cg-feature__link {
289
+ color: var(--cg-ink);
290
+ text-decoration-color: var(--cg-underline);
291
+ }
292
+
293
+ .cg-feature__link:hover {
294
+ color: var(--cg-accent);
371
295
  }
372
296
 
373
297
  .cg-feature__text {
374
- margin: 0;
298
+ margin-block-start: var(--cg-s3);
299
+ max-inline-size: var(--cg-measure);
375
300
  color: var(--cg-ink-muted);
376
- line-height: var(--cg-leading-relaxed);
377
- text-wrap: pretty;
378
301
  }
379
302
 
380
- /* --- cta ----------------------------------------------------------------- */
381
-
382
- .cg-cta {
383
- position: relative;
384
- overflow: hidden;
385
- padding: var(--cg-s16) var(--cg-s8);
386
- background: var(--cg-surface-tinted);
387
- border-radius: var(--cg-radius-xl);
388
- box-shadow: var(--cg-ring-accent);
389
- text-align: center;
303
+ @media (min-width: 40rem) {
304
+ .cg-feature {
305
+ grid-column: span 6;
306
+ }
390
307
  }
391
308
 
392
- /* A flat accent bar across the top of the panel — structure instead of a
393
- sheen. `overflow: hidden` on the panel keeps it inside the radius, so it
394
- never leaks past a rounded corner. */
395
- .cg-cta::before {
396
- content: "";
397
- position: absolute;
398
- inset-block-start: 0;
399
- inset-inline: 0;
400
- block-size: var(--cg-s2);
401
- background: var(--cg-accent-soft);
402
- pointer-events: none;
309
+ @media (min-width: 64rem) {
310
+ .cg-feature {
311
+ grid-column: span 4;
312
+ }
313
+
314
+ /* Two or four features take halves, so no row ends on an empty column. */
315
+ .cg-feature:first-child:nth-last-child(2),
316
+ .cg-feature:first-child:nth-last-child(2) ~ .cg-feature,
317
+ .cg-feature:first-child:nth-last-child(4),
318
+ .cg-feature:first-child:nth-last-child(4) ~ .cg-feature {
319
+ grid-column: span 6;
320
+ }
403
321
  }
404
322
 
405
- /* The panel's own children have to sit above that sheen. */
406
- .cg-cta > * {
407
- position: relative;
323
+ /* --- cta -----------------------------------------------------------------
324
+ The one block that asks for something, on a band a step off the page: the
325
+ ask and its reason on the first columns, the actions at the end.
326
+ ------------------------------------------------------------------------- */
327
+
328
+ .cg-cta {
329
+ background: var(--cg-band);
408
330
  }
409
331
 
410
332
  .cg-cta__title {
411
- margin: 0;
412
- /* One step above a section heading: this block asks for something, and the
413
- ask has to outrank the headings around it. */
414
333
  font-size: var(--cg-text-2xl);
415
- line-height: var(--cg-leading-snug);
416
- letter-spacing: var(--cg-tracking-tight);
417
- font-weight: var(--cg-weight-bold);
418
- text-wrap: balance;
334
+ font-family: var(--cg-font-text);
335
+ font-weight: var(--cg-weight-semibold);
336
+ letter-spacing: var(--cg-tracking-heading);
337
+ line-height: var(--cg-leading-heading);
419
338
  }
420
339
 
421
340
  .cg-cta__text {
422
- margin: var(--cg-s4) auto 0;
341
+ margin-block-start: var(--cg-s5);
423
342
  max-inline-size: var(--cg-measure-narrow);
424
343
  color: var(--cg-ink-muted);
425
344
  font-size: var(--cg-text-lg);
426
- line-height: var(--cg-leading-relaxed);
427
- text-wrap: pretty;
345
+ line-height: var(--cg-leading-snug);
428
346
  }
429
347
 
430
- .cg-cta .cg-actions {
431
- justify-content: center;
348
+ @media (min-width: 64rem) {
349
+ .cg-cta__title,
350
+ .cg-cta__text {
351
+ grid-column: 1 / span 7;
352
+ }
353
+
354
+ .cg-cta .cg-actions {
355
+ grid-column: 9 / -1;
356
+ grid-row: 1 / span 2;
357
+ align-self: end;
358
+ margin-block-start: 0;
359
+ }
432
360
  }
433
361
 
434
- /* --- gallery ------------------------------------------------------------- */
362
+ /* --- gallery --------------------------------------------------------------
363
+ Rows of one height, the pictures cropped to fill them: a row of three on a
364
+ desktop, two on a phone, and a last row that shares its width rather than
365
+ leaving an empty place.
366
+ ------------------------------------------------------------------------- */
435
367
 
436
368
  .cg-gallery__items {
437
- display: grid;
438
- gap: var(--cg-gap-tight);
439
- grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
369
+ display: flex;
370
+ flex-wrap: wrap;
371
+ gap: var(--cg-column-gap);
372
+ margin: 0;
373
+ padding: 0;
374
+ list-style: none;
440
375
  }
441
376
 
442
- /* The frame, shared by all three layouts: it is what clips the hover zoom
443
- below, so the picture can grow without the tile growing with it. */
444
377
  .cg-gallery__item {
445
- overflow: hidden;
446
- border-radius: var(--cg-radius-lg);
447
- box-shadow: var(--cg-ring);
378
+ flex: 1 1 calc((100% - var(--cg-column-gap)) / 2);
448
379
  }
449
380
 
450
- .cg-gallery__item img {
381
+ .cg-gallery__image {
451
382
  inline-size: 100%;
452
- block-size: 100%;
453
- transition: transform var(--cg-duration-slow) var(--cg-ease);
383
+ block-size: clamp(9rem, 22vw, 20rem);
454
384
  }
455
385
 
456
- .cg-gallery__item:hover img {
457
- transform: scale(1.04);
458
- }
386
+ @media (min-width: 64rem) {
387
+ .cg-gallery__item {
388
+ flex-basis: calc((100% - 2 * var(--cg-column-gap)) / 3);
389
+ }
459
390
 
460
- /* A grid of pictures needs one shape, or the rows read as an accident. Masonry
461
- is the one layout that opts out, since its whole point is not to. */
462
- .cg-gallery:not([data-layout="masonry"]) .cg-gallery__item img {
463
- aspect-ratio: 4 / 3;
391
+ .cg-gallery__item:first-child:nth-last-child(4),
392
+ .cg-gallery__item:first-child:nth-last-child(4) ~ .cg-gallery__item {
393
+ flex-basis: calc((100% - var(--cg-column-gap)) / 2);
394
+ }
464
395
  }
465
396
 
466
397
  .cg-gallery[data-layout="masonry"] .cg-gallery__items {
467
398
  display: block;
468
- columns: 3 14rem;
469
- column-gap: var(--cg-gap-tight);
399
+ columns: 2;
400
+ column-gap: var(--cg-column-gap);
470
401
  }
471
402
 
472
403
  .cg-gallery[data-layout="masonry"] .cg-gallery__item {
473
404
  break-inside: avoid;
474
- margin-block-end: var(--cg-gap-tight);
405
+ margin-block-end: var(--cg-column-gap);
406
+ }
407
+
408
+ .cg-gallery[data-layout="masonry"] .cg-gallery__image {
409
+ block-size: auto;
410
+ }
411
+
412
+ @media (min-width: 64rem) {
413
+ .cg-gallery[data-layout="masonry"] .cg-gallery__items {
414
+ columns: 3;
415
+ }
416
+ }
417
+
418
+ /* A row the reader scrolls: focusable and labelled (`gallery.ts`), so it is
419
+ operable from the keyboard at zero bytes of script. */
420
+ .cg-gallery__viewport,
421
+ .cg-collection__viewport {
422
+ overflow-x: auto;
423
+ overscroll-behavior-inline: contain;
424
+ scroll-snap-type: x mandatory;
425
+ scrollbar-width: thin;
426
+ scrollbar-color: var(--cg-line-strong) transparent;
427
+ padding-block-end: var(--cg-s4);
475
428
  }
476
429
 
477
430
  .cg-gallery[data-layout="carousel"] .cg-gallery__items {
478
431
  display: grid;
479
432
  grid-auto-flow: column;
480
- grid-auto-columns: minmax(16rem, 40%);
433
+ grid-auto-columns: min(80%, 30rem);
434
+ flex-wrap: nowrap;
481
435
  }
482
436
 
483
437
  .cg-gallery[data-layout="carousel"] .cg-gallery__item {
484
438
  scroll-snap-align: start;
485
439
  }
486
440
 
487
- .cg-collection img {
488
- inline-size: 100%;
489
- border-radius: var(--cg-radius-md);
441
+ .cg-gallery[data-layout="carousel"] .cg-gallery__image {
442
+ block-size: auto;
443
+ aspect-ratio: 3 / 2;
490
444
  }
491
445
 
492
- /* --- quote --------------------------------------------------------------- */
446
+ /* --- quote ----------------------------------------------------------------
447
+ A pull quote in the display face, its opening mark hung into the margin on
448
+ a wide screen so the words keep the left edge.
449
+ ------------------------------------------------------------------------- */
493
450
 
494
- .cg-quote {
495
- max-inline-size: var(--cg-page-narrow);
496
- margin-inline: auto;
497
- text-align: center;
451
+ .cg-quote__text {
452
+ quotes: "\201C" "\201D";
453
+ font-family: var(--cg-font-display);
454
+ font-size: var(--cg-text-title);
455
+ font-weight: var(--cg-weight-regular);
456
+ line-height: var(--cg-leading-heading);
457
+ letter-spacing: var(--cg-tracking-display);
498
458
  }
499
459
 
500
- /* The quotation mark, drawn rather than typed. The `/ ""` gives it an empty
501
- alternative text, so a screen reader that supports it announces nothing —
502
- the mark is decoration, and the `<blockquote>` already says what it means.
503
- A browser without alt-text support reads one quote character, which is
504
- harmless; hiding it with `aria-hidden` is impossible on a pseudo-element. */
505
- .cg-quote::before {
506
- content: "\201C" / "";
507
- display: block;
508
- margin-block-end: calc(var(--cg-s4) * -1);
509
- color: var(--cg-accent-soft);
510
- font-family: var(--cogenta-font-serif);
511
- font-size: calc(var(--cg-text-3xl) * 2);
512
- line-height: 1;
460
+ .cg-quote__text p {
461
+ text-wrap: balance;
513
462
  }
514
463
 
515
- .cg-quote__text {
516
- margin: 0;
517
- font-family: var(--cogenta-font-serif);
518
- /* A pull quote, so it outranks body copy by two steps and sits one below the
519
- hero. Balanced wrap matters more here than anywhere: a centred quote with
520
- a two-word last line looks broken. */
521
- font-size: var(--cg-text-2xl);
522
- line-height: var(--cg-leading-snug);
523
- letter-spacing: var(--cg-tracking-snug);
524
- text-wrap: balance;
464
+ .cg-quote__text p::before {
465
+ content: open-quote;
466
+ }
467
+
468
+ .cg-quote__text p::after {
469
+ content: close-quote;
525
470
  }
526
471
 
527
472
  .cg-quote__attribution {
528
- display: flex;
473
+ display: grid;
474
+ grid-template-columns: auto minmax(0, 1fr);
529
475
  align-items: center;
530
- justify-content: center;
531
- gap: var(--cg-s3);
532
476
  margin-block-start: var(--cg-s8);
533
- color: var(--cg-ink-subtle);
534
477
  font-size: var(--cg-text-sm);
535
478
  }
536
479
 
537
480
  .cg-quote__avatar {
481
+ grid-column: 1;
482
+ grid-row: 1 / span 2;
538
483
  inline-size: var(--cg-s12);
539
484
  block-size: var(--cg-s12);
540
- border-radius: var(--cg-radius-pill);
541
- box-shadow: var(--cg-ring);
485
+ margin-inline-end: var(--cg-s4);
486
+ border-radius: 50%;
542
487
  }
543
488
 
544
489
  .cg-quote__author {
545
- font-weight: var(--cg-weight-semibold);
490
+ grid-column: 2;
546
491
  color: var(--cg-ink);
492
+ font-weight: var(--cg-weight-semibold);
547
493
  }
548
494
 
549
- /* A hairline between name and role, instead of a comma the markup does not
550
- have and the theme has no business inventing. */
551
- .cg-quote__role::before {
552
- content: "";
553
- display: inline-block;
554
- inline-size: var(--cg-s3);
555
- border-block-start: 1px solid var(--cg-line-strong);
556
- vertical-align: middle;
557
- margin-inline-end: var(--cg-s3);
495
+ .cg-quote__role {
496
+ grid-column: 2;
497
+ color: var(--cg-ink-muted);
558
498
  }
559
499
 
560
- /* --- faq ----------------------------------------------------------------- */
500
+ @media (min-width: 64rem) {
501
+ .cg-quote__text {
502
+ grid-column: 1 / span 10;
503
+ }
561
504
 
562
- .cg-faq {
563
- max-inline-size: var(--cg-page-narrow);
564
- margin-inline: auto;
505
+ .cg-quote__text p {
506
+ text-indent: -0.42em;
507
+ }
565
508
  }
566
509
 
567
- .cg-faq__items {
568
- background: var(--cg-surface-raised);
569
- border-radius: var(--cg-radius-lg);
570
- box-shadow: var(--cg-ring);
571
- /* Clips the first and last rows to the container's radius, so the list reads
572
- as one panel rather than as rows that happen to be stacked. */
573
- overflow: hidden;
510
+ /* --- faq ------------------------------------------------------------------
511
+ The title on the first four columns, the questions on the rest, each
512
+ answer opened in place by the browser (`<details>`).
513
+ ------------------------------------------------------------------------- */
514
+
515
+ .cg-faq__items,
516
+ .cg-accordion__items {
517
+ margin: 0;
518
+ padding: 0;
519
+ list-style: none;
520
+ border-block-start: var(--cg-rule) solid var(--cg-ink);
574
521
  }
575
522
 
576
- .cg-faq__item + .cg-faq__item {
577
- border-block-start: 1px solid var(--cg-line-soft);
523
+ .cg-faq__item,
524
+ .cg-accordion__item {
525
+ border-block-end: var(--cg-rule) solid var(--cg-line);
578
526
  }
579
527
 
580
- .cg-faq__question {
528
+ .cg-faq__question,
529
+ .cg-accordion__question {
581
530
  display: flex;
582
- align-items: center;
583
- gap: var(--cg-s4);
584
- padding: var(--cg-s5) var(--cg-s6);
531
+ align-items: baseline;
532
+ gap: var(--cg-s6);
533
+ padding-block: var(--cg-s5);
534
+ color: var(--cg-ink);
535
+ font-size: var(--cg-text-lg);
585
536
  font-weight: var(--cg-weight-semibold);
586
- cursor: pointer;
587
- /* The marker is replaced below; both properties are needed, and the vendor
588
- one still is on WebKit. */
537
+ line-height: var(--cg-leading-snug);
589
538
  list-style: none;
590
- transition: background-color var(--cg-duration) var(--cg-ease);
539
+ cursor: pointer;
540
+ transition: color var(--cg-duration) var(--cg-ease);
591
541
  }
592
542
 
593
- .cg-faq__question::-webkit-details-marker {
543
+ .cg-faq__question::-webkit-details-marker,
544
+ .cg-accordion__question::-webkit-details-marker {
594
545
  display: none;
595
546
  }
596
547
 
597
- .cg-faq__question:hover {
598
- background: var(--cg-accent-soft);
599
- color: var(--cg-accent-soft-fg);
600
- }
601
-
602
- /* A chevron drawn from two borders — no icon set, no glyph that depends on a
603
- font shipping it. It is a pseudo-element on a `<summary>` whose expanded
604
- state the browser already announces, so it stays purely visual. */
605
- .cg-faq__question::after {
606
- content: "";
607
- flex: none;
548
+ /* A plus that turns into a minus: a character, never a drawn shape. */
549
+ .cg-faq__question::after,
550
+ .cg-accordion__question::after {
551
+ content: "+" / "";
608
552
  margin-inline-start: auto;
609
- inline-size: 0.5em;
610
- block-size: 0.5em;
611
- border-inline-end: 2px solid currentColor;
612
- border-block-end: 2px solid currentColor;
613
- transform: translateY(-0.15em) rotate(45deg);
614
- transition: transform var(--cg-duration) var(--cg-ease);
553
+ color: var(--cg-ink-muted);
554
+ font-weight: var(--cg-weight-regular);
615
555
  }
616
556
 
617
- .cg-faq__details[open] .cg-faq__question::after {
618
- transform: translateY(0.1em) rotate(-135deg);
557
+ .cg-faq__details[open] > .cg-faq__question::after,
558
+ .cg-accordion__details[open] > .cg-accordion__question::after {
559
+ content: "\2212" / "";
619
560
  }
620
561
 
621
- .cg-faq__details[open] .cg-faq__question {
562
+ .cg-faq__question:hover,
563
+ .cg-accordion__question:hover {
622
564
  color: var(--cg-accent);
623
565
  }
624
566
 
625
- .cg-faq__answer {
626
- padding: 0 var(--cg-s6) var(--cg-s6);
627
- color: var(--cg-ink-muted);
628
- line-height: var(--cg-leading-relaxed);
567
+ .cg-faq__answer,
568
+ .cg-accordion__answer {
569
+ max-inline-size: var(--cg-measure);
570
+ padding-block-end: var(--cg-s6);
629
571
  }
630
572
 
631
- .cg-faq__answer > :first-child {
632
- margin-block-start: 0;
573
+ .cg-faq__answer > * + *,
574
+ .cg-accordion__answer > * + * {
575
+ margin-block-start: var(--cg-s4);
576
+ }
577
+
578
+ /* Under a title, the title's own rule already opens the list: the first row
579
+ takes a hairline instead of a second rule in ink. */
580
+ .cg-faq__title + .cg-faq__items,
581
+ .cg-accordion__title + .cg-accordion__items {
582
+ border-block-start-color: var(--cg-line);
633
583
  }
634
584
 
635
- .cg-faq__answer > :last-child {
636
- margin-block-end: 0;
585
+ .cg-faq__title {
586
+ margin-block-end: var(--cg-s8);
637
587
  }
638
588
 
639
- /* --- stats --------------------------------------------------------------- */
589
+ @media (min-width: 64rem) {
590
+ .cg-faq__title {
591
+ grid-column: 1 / span 4;
592
+ align-self: start;
593
+ margin-block-end: 0;
594
+ }
595
+
596
+ /* Side by side, the list carries its own rule, level with the title's. */
597
+ .cg-faq__items,
598
+ .cg-faq__title + .cg-faq__items {
599
+ grid-column: 5 / -1;
600
+ border-block-start-color: var(--cg-ink);
601
+ }
602
+
603
+ .cg-faq__items:first-child {
604
+ grid-column: 1 / span 8;
605
+ }
606
+ }
607
+
608
+ /* --- stats ----------------------------------------------------------------
609
+ Figures in a row under hairlines. The markup reads label then figure; the
610
+ paint puts the figure first (`column-reverse` reorders the paint, never
611
+ the `<dl>`), which keeps WCAG 1.3.2.
612
+ ------------------------------------------------------------------------- */
640
613
 
641
- .cg-stats__items {
614
+ .cg-stats__items,
615
+ .cg-stat-counters__items {
642
616
  display: grid;
643
- gap: var(--cg-gap);
644
- grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
617
+ grid-template-columns: subgrid;
618
+ row-gap: var(--cg-s10);
645
619
  margin: 0;
646
620
  }
647
621
 
648
- /* Reading order is label then figure; the stylesheet shows the figure first.
649
- The markup is what a screen reader follows, so the two must not be
650
- conflated — `column-reverse` reorders the paint, never the `<dl>`. */
651
622
  .cg-stat {
623
+ grid-column: span 6;
652
624
  display: flex;
653
625
  flex-direction: column-reverse;
626
+ justify-content: flex-end;
654
627
  gap: var(--cg-s2);
655
- padding: var(--cg-s6);
656
- background: var(--cg-surface-sunken);
657
- border-radius: var(--cg-radius-lg);
658
- box-shadow: var(--cg-ring);
628
+ padding-block-start: var(--cg-s4);
629
+ border-block-start: var(--cg-rule) solid var(--cg-line);
659
630
  }
660
631
 
661
632
  .cg-stat__value {
662
- display: flex;
663
- align-items: baseline;
664
- gap: var(--cg-s1);
665
- margin: 0;
666
- color: var(--cg-accent);
667
- font-size: var(--cg-text-3xl);
668
- font-weight: var(--cg-weight-bold);
669
- line-height: var(--cg-leading-tight);
670
- letter-spacing: var(--cg-tracking-tight);
671
- /* Figures that change between pages must not change width with the digits. */
672
- font-variant-numeric: tabular-nums;
633
+ color: var(--cg-ink);
634
+ font-size: var(--cg-text-figure);
635
+ font-weight: var(--cg-weight-medium);
636
+ line-height: var(--cg-leading-display);
637
+ letter-spacing: var(--cg-tracking-heading);
638
+ font-variant-numeric: tabular-nums lining-nums;
673
639
  }
674
640
 
675
641
  .cg-stat__unit {
676
- font-size: var(--cg-text-lg);
677
- font-weight: var(--cg-weight-medium);
642
+ margin-inline-start: 0.08em;
678
643
  color: var(--cg-ink-muted);
679
- letter-spacing: var(--cg-tracking-normal);
644
+ font-size: 0.6em;
680
645
  }
681
646
 
682
- /* Small caps under a large figure: the label is a caption for the number, and
683
- at body size it competes with it. */
684
647
  .cg-stat__label {
648
+ max-inline-size: 28ch;
685
649
  color: var(--cg-ink-muted);
686
- font-size: var(--cg-text-xs);
687
- font-weight: var(--cg-weight-semibold);
688
- letter-spacing: var(--cg-tracking-wide);
689
- text-transform: uppercase;
690
- }
691
-
692
- /* --- logos --------------------------------------------------------------- */
693
-
694
- /* A grid, not a wrapping row: a flex row leaves the last line ragged, and a
695
- row of logos that does not line up reads as an oversight rather than as a
696
- list of names. */
697
- .cg-logos__items {
698
- display: grid;
699
- grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
700
- gap: var(--cg-gap);
701
- align-items: center;
650
+ font-size: var(--cg-text-sm);
702
651
  }
703
652
 
704
- .cg-logo {
705
- display: flex;
706
- align-items: center;
707
- justify-content: center;
708
- padding: var(--cg-s4);
653
+ /* Two to a row on a phone; an odd last figure takes the whole row rather
654
+ than leaving half of it empty. */
655
+ @media (max-width: 63.99rem) {
656
+ .cg-stat:last-child:nth-child(odd),
657
+ .cg-stat-counter:last-child:nth-child(odd) {
658
+ grid-column: span 12;
659
+ }
709
660
  }
710
661
 
711
- .cg-logo__image {
712
- /* One optical height for every logo, whatever its own proportions: `contain`
713
- keeps a wide wordmark and a square mark at the same weight on the page. */
714
- block-size: var(--cg-s10);
715
- inline-size: auto;
716
- max-inline-size: 100%;
717
- object-fit: contain;
718
- /* Held back so the logos read as a supporting row rather than as eight
719
- competing brands, and brought fully forward on hover. Opacity, not
720
- `grayscale`: a filtered logo is a logo whose owner did not approve it. */
721
- opacity: 0.72;
722
- transition: opacity var(--cg-duration) var(--cg-ease);
723
- }
662
+ @media (min-width: 64rem) {
663
+ .cg-stat {
664
+ grid-column: span 3;
665
+ }
724
666
 
725
- .cg-logo__link {
726
- display: inline-flex;
727
- align-items: center;
728
- justify-content: center;
729
- inline-size: 100%;
730
- border-radius: var(--cg-radius-md);
731
- }
667
+ .cg-stat:first-child:nth-last-child(3),
668
+ .cg-stat:first-child:nth-last-child(3) ~ .cg-stat {
669
+ grid-column: span 4;
670
+ }
732
671
 
733
- .cg-logo:hover .cg-logo__image,
734
- .cg-logo__link:focus-visible .cg-logo__image {
735
- opacity: 1;
672
+ .cg-stat:first-child:nth-last-child(2),
673
+ .cg-stat:first-child:nth-last-child(2) ~ .cg-stat {
674
+ grid-column: span 6;
675
+ }
736
676
  }
737
677
 
738
- /* --- collectionList ------------------------------------------------------ */
678
+ /* --- logos ----------------------------------------------------------------
679
+ Wordmarks on a six-column row, in greyscale so no one mark outshouts the
680
+ others, and turned light on the dark ground.
681
+ ------------------------------------------------------------------------- */
739
682
 
740
- .cg-collection__items {
683
+ .cg-logos__items {
741
684
  display: grid;
742
- gap: var(--cg-gap);
743
- }
744
-
745
- .cg-collection[data-layout="grid"] .cg-collection__items {
746
- grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
747
- }
748
-
749
- .cg-collection[data-layout="carousel"] .cg-collection__items {
750
- grid-auto-flow: column;
751
- grid-auto-columns: minmax(18rem, 45%);
752
- }
753
-
754
- .cg-collection[data-layout="carousel"] .cg-entry {
755
- scroll-snap-align: start;
756
- }
757
-
758
- .cg-entry {
759
- position: relative;
760
- padding: var(--cg-s6);
761
- background: var(--cg-surface-raised);
762
- border-radius: var(--cg-radius-lg);
763
- box-shadow: var(--cg-ring);
764
- transition:
765
- box-shadow var(--cg-duration) var(--cg-ease),
766
- transform var(--cg-duration) var(--cg-ease);
767
- }
768
-
769
- .cg-entry:hover {
770
- box-shadow: var(--cg-elevation-2), var(--cg-ring-accent);
771
- transform: translateY(-2px);
772
- }
773
-
774
- /* Same overlay as `featureGrid`: the card is the hit area, drawn from the one
775
- link the markup has, so nothing extra is announced. */
776
- .cg-entry__link {
777
- color: inherit;
778
- text-decoration: none;
779
- }
780
-
781
- .cg-entry__link::after {
782
- content: "";
783
- position: absolute;
784
- inset: 0;
785
- border-radius: inherit;
685
+ grid-template-columns: subgrid;
686
+ row-gap: var(--cg-s8);
687
+ margin: 0;
688
+ padding: 0;
689
+ list-style: none;
786
690
  }
787
691
 
788
- .cg-entry:hover .cg-entry__link {
789
- color: var(--cg-accent);
692
+ .cg-logo {
693
+ grid-column: span 6;
694
+ display: flex;
695
+ align-items: center;
696
+ min-block-size: 3.5rem;
790
697
  }
791
698
 
792
- /* Date first in the paint, title under it: a list of entries is scanned by
793
- recency, and the markup still reads title then date. */
794
- .cg-entry__body {
699
+ .cg-logo__link {
795
700
  display: flex;
796
- flex-direction: column;
701
+ align-items: center;
702
+ min-block-size: 2.75rem;
703
+ max-inline-size: 100%;
797
704
  }
798
705
 
799
- .cg-entry__title {
800
- order: 2;
801
- margin: 0;
802
- font-size: var(--cg-text-lg);
803
- font-weight: var(--cg-weight-semibold);
804
- line-height: var(--cg-leading-snug);
805
- letter-spacing: var(--cg-tracking-snug);
806
- text-wrap: balance;
706
+ .cg-logo__image,
707
+ .cg-logo-strip__image {
708
+ inline-size: auto;
709
+ max-inline-size: 100%;
710
+ object-fit: contain;
711
+ filter: grayscale(1) invert(var(--cg-mark-invert));
807
712
  }
808
713
 
809
- .cg-entry__date {
810
- order: 1;
811
- margin-block-end: var(--cg-s2);
812
- color: var(--cg-ink-subtle);
813
- font-size: var(--cg-text-xs);
814
- font-weight: var(--cg-weight-semibold);
815
- letter-spacing: var(--cg-tracking-wide);
816
- text-transform: uppercase;
714
+ .cg-logo__image {
715
+ block-size: 3rem;
817
716
  }
818
717
 
819
- .cg-entry__excerpt {
820
- order: 3;
821
- margin: var(--cg-s3) 0 0;
822
- color: var(--cg-ink-muted);
823
- font-size: var(--cg-text-sm);
824
- line-height: var(--cg-leading-relaxed);
825
- /* Three lines, so cards in a row keep their heights close whatever the
826
- editor wrote. Nothing is lost: the entry's own page carries the full text. */
827
- display: -webkit-box;
828
- -webkit-box-orient: vertical;
829
- -webkit-line-clamp: 3;
830
- line-clamp: 3;
831
- overflow: hidden;
718
+ @media (min-width: 40rem) {
719
+ .cg-logo {
720
+ grid-column: span 4;
721
+ }
832
722
  }
833
723
 
834
- .cg-collection__empty {
835
- padding: var(--cg-s8);
836
- background: var(--cg-surface-sunken);
837
- border-radius: var(--cg-radius-lg);
838
- color: var(--cg-ink-subtle);
839
- text-align: center;
840
- }
724
+ @media (min-width: 64rem) {
725
+ .cg-logo {
726
+ grid-column: span 2;
727
+ }
841
728
 
842
- /* --- embed --------------------------------------------------------------- */
729
+ /* Three or four marks share the row instead of stopping short of its end. */
730
+ .cg-logo:first-child:nth-last-child(3),
731
+ .cg-logo:first-child:nth-last-child(3) ~ .cg-logo {
732
+ grid-column: span 4;
733
+ }
843
734
 
844
- .cg-embed {
845
- aspect-ratio: var(--cg-ratio, 16 / 9);
846
- max-inline-size: var(--cg-measure);
847
- margin-inline: auto;
735
+ .cg-logo:first-child:nth-last-child(4),
736
+ .cg-logo:first-child:nth-last-child(4) ~ .cg-logo {
737
+ grid-column: span 3;
738
+ }
848
739
  }
849
740
 
741
+ /* --- embed ----------------------------------------------------------------
742
+ A frame on the reading columns. Before consent, nothing is requested from
743
+ the provider: the placeholder says what would load and links to it.
744
+ ------------------------------------------------------------------------- */
745
+
850
746
  .cg-embed__frame {
851
747
  inline-size: 100%;
852
- block-size: 100%;
748
+ aspect-ratio: var(--cg-ratio, 16 / 9);
853
749
  border: 0;
854
- border-radius: var(--cg-radius-md);
750
+ background: var(--cg-band);
855
751
  }
856
752
 
857
- /* The consent placeholder is a real card, not a grey box: it says what would be
858
- loaded and offers a way out to the source. It requests nothing third-party. */
753
+ /* Not a frame-sized grey box, which reads as a video that failed: a short
754
+ note on a band, with the way out to the source. */
859
755
  .cg-embed__placeholder {
860
756
  display: flex;
861
757
  flex-direction: column;
862
- align-items: center;
863
- justify-content: center;
864
- gap: var(--cg-s5);
865
- block-size: 100%;
866
- padding: var(--cg-s8);
867
- background: var(--cg-surface-sunken);
868
- color: var(--cg-ink-muted);
869
- /* Dashed, and kept dashed: it is the one place in the theme where the border
870
- says "nothing has loaded here yet" rather than "this is a panel". */
871
- border: 1px dashed var(--cg-line-strong);
872
- border-radius: var(--cg-radius-lg);
873
- text-align: center;
758
+ align-items: flex-start;
759
+ gap: var(--cg-s1);
760
+ padding: var(--cg-s6) var(--cg-s6) var(--cg-s4);
761
+ border-block-start: var(--cg-rule) solid var(--cg-ink);
762
+ background: var(--cg-band);
874
763
  }
875
764
 
876
765
  .cg-embed__notice {
877
- margin: 0;
878
- max-inline-size: var(--cg-measure-narrow);
879
- line-height: var(--cg-leading-relaxed);
880
- text-wrap: pretty;
881
- }
882
-
883
- /* The way out is an action, not a sentence with a link in it: this card exists
884
- because the visitor has to choose, and a choice needs something to press. */
885
- .cg-embed__link {
886
- display: inline-flex;
887
- align-items: center;
888
- min-block-size: 44px;
889
- padding: var(--cg-s3) var(--cg-s6);
890
- background: var(--cg-surface-raised);
891
- color: var(--cg-accent);
892
- border-radius: var(--cg-radius-md);
893
- box-shadow: var(--cg-ring-accent);
894
- font-size: var(--cg-text-sm);
895
- font-weight: var(--cg-weight-semibold);
896
- text-decoration: none;
897
- transition:
898
- background-color var(--cg-duration) var(--cg-ease),
899
- color var(--cg-duration) var(--cg-ease);
766
+ max-inline-size: var(--cg-measure);
900
767
  }
901
768
 
902
- .cg-embed__link:hover {
903
- background: var(--cg-accent);
904
- color: var(--cg-accent-fg);
769
+ @media (min-width: 64rem) {
770
+ .cg-embed > * {
771
+ grid-column: 1 / span 8;
772
+ }
905
773
  }
906
774
 
907
- /* --- testimonial (blocks@2.0) --------------------------------------------
908
- Same silhouette as `quote`, left as a distinct rule block for the day the
909
- two diverge visually — a testimonial wall reads differently from a single
910
- pull quote once a theme has more than one on a page.
775
+ /* --- testimonial ----------------------------------------------------------
776
+ A reader's words in the text face, set against a rule in ink: quieter than
777
+ a pull quote, and never a card.
911
778
  ------------------------------------------------------------------------- */
912
779
 
913
- .cg-testimonial {
914
- max-inline-size: var(--cg-page-narrow);
915
- margin-inline: auto;
916
- text-align: center;
780
+ .cg-testimonial__quote,
781
+ .cg-testimonial__attribution {
782
+ padding-inline-start: var(--cg-s6);
783
+ border-inline-start: var(--cg-rule-strong) solid var(--cg-ink);
917
784
  }
918
785
 
919
786
  .cg-testimonial__quote {
920
- margin: 0;
921
- font-family: var(--cogenta-font-serif);
787
+ quotes: "\201C" "\201D";
922
788
  font-size: var(--cg-text-xl);
923
789
  line-height: var(--cg-leading-snug);
924
- text-wrap: balance;
790
+ letter-spacing: var(--cg-tracking-heading);
925
791
  }
926
792
 
927
- .cg-testimonial__quote > :first-child {
928
- margin-block-start: 0;
793
+ .cg-testimonial__quote > * + * {
794
+ margin-block-start: var(--cg-s4);
795
+ }
796
+
797
+ .cg-testimonial__quote > p:first-child::before {
798
+ content: open-quote;
929
799
  }
930
800
 
931
- .cg-testimonial__quote > :last-child {
932
- margin-block-end: 0;
801
+ .cg-testimonial__quote > p:last-child::after {
802
+ content: close-quote;
933
803
  }
934
804
 
935
805
  .cg-testimonial__attribution {
936
806
  display: flex;
937
807
  align-items: center;
938
- justify-content: center;
939
- gap: var(--cg-s3);
940
- margin-block-start: var(--cg-s6);
941
- color: var(--cg-ink-subtle);
808
+ gap: var(--cg-s4);
809
+ padding-block-start: var(--cg-s6);
942
810
  font-size: var(--cg-text-sm);
943
811
  }
944
812
 
945
813
  .cg-testimonial__avatar {
946
814
  inline-size: var(--cg-s12);
947
815
  block-size: var(--cg-s12);
948
- border-radius: var(--cg-radius-pill);
949
- box-shadow: var(--cg-ring);
816
+ border-radius: 50%;
950
817
  }
951
818
 
952
819
  .cg-testimonial__names {
953
820
  display: flex;
954
821
  flex-direction: column;
955
- align-items: flex-start;
956
- line-height: var(--cg-leading-snug);
957
822
  }
958
823
 
959
824
  .cg-testimonial__name {
960
- font-weight: var(--cg-weight-semibold);
961
825
  color: var(--cg-ink);
826
+ font-weight: var(--cg-weight-semibold);
827
+ }
828
+
829
+ .cg-testimonial__role {
830
+ color: var(--cg-ink-muted);
831
+ }
832
+
833
+ @media (min-width: 64rem) {
834
+ .cg-testimonial > * {
835
+ grid-column: 1 / span 8;
836
+ }
962
837
  }
963
838
 
964
- /* --- pricingTable (blocks@2.0) -------------------------------------------
965
- Cards in a row, the highlighted tier lifted and ringed in the accent —
966
- the one place in this theme a card earns a border of its own, because a
967
- pricing table's whole point is telling the tiers apart at a glance.
839
+ /* --- pricingTable ---------------------------------------------------------
840
+ Plans side by side under hairlines, each four rows (name, price, features,
841
+ action) that line up across plans. The recommended plan is marked by a
842
+ heavier rule in ink and a word, never by a tinted card.
968
843
  ------------------------------------------------------------------------- */
969
844
 
970
845
  .cg-pricing__tiers {
971
846
  display: grid;
972
- gap: var(--cg-gap);
973
- grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
974
- align-items: start;
847
+ grid-template-columns: subgrid;
848
+ row-gap: var(--cg-s12);
849
+ margin: 0;
850
+ padding: 0;
851
+ list-style: none;
975
852
  }
976
853
 
977
854
  .cg-pricing__tier {
978
- display: flex;
979
- flex-direction: column;
980
- padding: var(--cg-s8) var(--cg-s6);
981
- background: var(--cg-surface-raised);
982
- border-radius: var(--cg-radius-xl);
983
- box-shadow: var(--cg-ring);
855
+ grid-column: span 12;
856
+ grid-row: span 4;
857
+ display: grid;
858
+ grid-template-rows: subgrid;
859
+ row-gap: 0;
860
+ padding-block-start: var(--cg-s5);
861
+ border-block-start: var(--cg-rule) solid var(--cg-line-strong);
984
862
  }
985
863
 
986
864
  .cg-pricing__tier[data-highlighted="true"] {
987
- background: var(--cg-surface-tinted);
988
- box-shadow: var(--cg-elevation-2), var(--cg-ring-accent);
989
- transform: translateY(calc(var(--cg-s3) * -1));
865
+ padding-block-start: calc(var(--cg-s5) - var(--cg-rule-strong) + var(--cg-rule));
866
+ border-block-start: var(--cg-rule-strong) solid var(--cg-ink);
867
+ }
868
+
869
+ .cg-pricing__head {
870
+ grid-row: 1;
871
+ display: flex;
872
+ flex-wrap: wrap;
873
+ align-items: baseline;
874
+ justify-content: space-between;
875
+ gap: var(--cg-s1) var(--cg-s4);
990
876
  }
991
877
 
992
878
  .cg-pricing__name {
993
- margin: 0;
994
- font-size: var(--cg-text-md);
879
+ font-size: var(--cg-text-lg);
880
+ }
881
+
882
+ .cg-pricing__flag {
883
+ color: var(--cg-ink);
884
+ font-size: var(--cg-text-sm);
995
885
  font-weight: var(--cg-weight-semibold);
996
- letter-spacing: var(--cg-tracking-snug);
997
886
  }
998
887
 
999
888
  .cg-pricing__price {
889
+ grid-row: 2;
1000
890
  display: flex;
891
+ flex-wrap: wrap;
1001
892
  align-items: baseline;
1002
- gap: var(--cg-s1);
1003
- margin: var(--cg-s4) 0 var(--cg-s6);
893
+ gap: var(--cg-s2);
894
+ margin-block-start: var(--cg-s5);
1004
895
  }
1005
896
 
1006
897
  .cg-pricing__amount {
1007
- font-size: var(--cg-text-2xl);
1008
- font-weight: var(--cg-weight-bold);
1009
- letter-spacing: var(--cg-tracking-tight);
1010
- font-variant-numeric: tabular-nums;
898
+ font-size: var(--cg-text-figure);
899
+ font-weight: var(--cg-weight-medium);
900
+ line-height: var(--cg-leading-display);
901
+ letter-spacing: var(--cg-tracking-heading);
902
+ font-variant-numeric: tabular-nums lining-nums;
1011
903
  }
1012
904
 
1013
905
  .cg-pricing__interval {
@@ -1016,205 +908,180 @@
1016
908
  }
1017
909
 
1018
910
  .cg-pricing__features {
1019
- flex: 1;
1020
- margin: 0 0 var(--cg-s6);
911
+ grid-row: 3;
912
+ margin-block-start: var(--cg-s6);
1021
913
  padding: 0;
1022
914
  list-style: none;
1023
- display: flex;
1024
- flex-direction: column;
1025
- gap: var(--cg-s2);
1026
- color: var(--cg-ink-muted);
1027
- line-height: var(--cg-leading-relaxed);
1028
915
  }
1029
916
 
1030
917
  .cg-pricing__features li {
1031
- padding-inline-start: var(--cg-s6);
1032
- position: relative;
1033
- }
1034
-
1035
- /* A drawn checkmark — no icon set, exactly the `faq` chevron's own approach. */
1036
- .cg-pricing__features li::before {
1037
- content: "";
1038
- position: absolute;
1039
- inset-inline-start: 0;
1040
- inset-block-start: 0.4em;
1041
- inline-size: 0.6em;
1042
- block-size: 0.35em;
1043
- border-inline-start: 2px solid var(--cg-accent);
1044
- border-block-end: 2px solid var(--cg-accent);
1045
- transform: rotate(-45deg);
918
+ padding-block: var(--cg-s2);
919
+ border-block-start: var(--cg-rule) solid var(--cg-line);
1046
920
  }
1047
921
 
1048
922
  .cg-pricing__action {
1049
- margin-block-start: auto;
923
+ grid-row: 4;
924
+ align-self: end;
925
+ margin-block-start: var(--cg-s8);
1050
926
  }
1051
927
 
928
+ /* A block-level box, so no line box adds a pixel under the button and the
929
+ filled and outlined controls end up exactly the same height. */
1052
930
  .cg-pricing__action .cg-action {
931
+ display: flex;
1053
932
  inline-size: 100%;
1054
- justify-content: center;
1055
- }
1056
-
1057
- /* --- accordion (blocks@2.0) ----------------------------------------------
1058
- Identical mechanics to `faq`'s panel, kept as its own rule block so the
1059
- two can diverge visually without either one's CSS becoming a conditional.
1060
- ------------------------------------------------------------------------- */
1061
-
1062
- .cg-accordion {
1063
- max-inline-size: var(--cg-page-narrow);
1064
- margin-inline: auto;
1065
- }
1066
-
1067
- .cg-accordion__items {
1068
- background: var(--cg-surface-raised);
1069
- border-radius: var(--cg-radius-lg);
1070
- box-shadow: var(--cg-ring);
1071
- overflow: hidden;
1072
- }
1073
-
1074
- .cg-accordion__item + .cg-accordion__item {
1075
- border-block-start: 1px solid var(--cg-line-soft);
1076
933
  }
1077
934
 
1078
- .cg-accordion__question {
935
+ /* A plan's secondary action is an outlined control of the same size as the
936
+ filled one, so the three plans end on one line of buttons. No arrow: it
937
+ is a control, not a link in running text. */
938
+ .cg-pricing__action .cg-action[data-emphasis="secondary"] {
1079
939
  display: flex;
1080
940
  align-items: center;
1081
- gap: var(--cg-s4);
1082
- padding: var(--cg-s5) var(--cg-s6);
1083
- font-weight: var(--cg-weight-semibold);
1084
- cursor: pointer;
1085
- list-style: none;
1086
- transition: background-color var(--cg-duration) var(--cg-ease);
1087
- }
1088
-
1089
- .cg-accordion__question::-webkit-details-marker {
1090
- display: none;
941
+ justify-content: center;
942
+ min-block-size: 2.75rem;
943
+ padding: var(--cg-s2) var(--cg-s6);
944
+ border: var(--cg-rule) solid var(--cg-ink);
945
+ border-radius: var(--cg-radius-control);
946
+ color: var(--cg-ink);
947
+ line-height: var(--cg-leading-heading);
948
+ text-decoration-line: none;
949
+ white-space: normal;
950
+ transition:
951
+ background-color var(--cg-duration) var(--cg-ease),
952
+ color var(--cg-duration) var(--cg-ease);
1091
953
  }
1092
954
 
1093
- .cg-accordion__question:hover {
1094
- background: var(--cg-accent-soft);
1095
- color: var(--cg-accent-soft-fg);
955
+ .cg-pricing__action .cg-action[data-emphasis="secondary"]::after {
956
+ content: none;
1096
957
  }
1097
958
 
1098
- .cg-accordion__question::after {
1099
- content: "";
1100
- flex: none;
1101
- margin-inline-start: auto;
1102
- inline-size: 0.6em;
1103
- block-size: 0.6em;
1104
- border-radius: var(--cg-radius-pill);
1105
- border: 2px solid currentColor;
1106
- position: relative;
959
+ .cg-pricing__action .cg-action[data-emphasis="secondary"]:hover {
960
+ background: var(--cg-band);
961
+ color: var(--cg-ink);
1107
962
  }
1108
963
 
1109
- /* A plus that becomes a minus, rather than the `faq` chevron — visually
1110
- distinct from its sibling block, on the same zero-JavaScript mechanics. */
1111
- .cg-accordion__question::before {
1112
- content: "";
1113
- position: absolute;
1114
- inset-inline-end: calc(var(--cg-s6) + 0.2em);
1115
- inline-size: 0.32em;
1116
- block-size: 0;
1117
- border-block-start: 2px solid currentColor;
964
+ @media (min-width: 48rem) {
965
+ .cg-pricing__tier {
966
+ grid-column: span 6;
967
+ }
1118
968
  }
1119
969
 
1120
- .cg-accordion__details[open] .cg-accordion__question::before {
1121
- content: none;
1122
- }
970
+ @media (min-width: 64rem) {
971
+ .cg-pricing__tier {
972
+ grid-column: span 4;
973
+ }
1123
974
 
1124
- .cg-accordion__details[open] .cg-accordion__question {
1125
- color: var(--cg-accent);
1126
- }
975
+ .cg-pricing__tier:first-child:nth-last-child(4),
976
+ .cg-pricing__tier:first-child:nth-last-child(4) ~ .cg-pricing__tier {
977
+ grid-column: span 3;
978
+ }
1127
979
 
1128
- .cg-accordion__answer {
1129
- padding: 0 var(--cg-s6) var(--cg-s6);
1130
- color: var(--cg-ink-muted);
1131
- line-height: var(--cg-leading-relaxed);
980
+ .cg-pricing__tier:first-child:nth-last-child(2),
981
+ .cg-pricing__tier:first-child:nth-last-child(2) ~ .cg-pricing__tier {
982
+ grid-column: span 6;
983
+ }
1132
984
  }
1133
985
 
1134
- .cg-accordion__answer > :first-child {
1135
- margin-block-start: 0;
1136
- }
986
+ /* --- accordion ------------------------------------------------------------
987
+ The same mechanics and rows as `faq`, set on the reading columns under its
988
+ title rather than beside it.
989
+ ------------------------------------------------------------------------- */
1137
990
 
1138
- .cg-accordion__answer > :last-child {
1139
- margin-block-end: 0;
991
+ @media (min-width: 64rem) {
992
+ .cg-accordion > * {
993
+ grid-column: 1 / span 8;
994
+ }
1140
995
  }
1141
996
 
1142
- /* --- statCounter (blocks@2.0) ---------------------------------------------
1143
- Same `<dl>` mechanics as `stats`, without a background card: a counter row
1144
- reads as a single strip of figures rather than as `stats`'s set of panels.
997
+ /* --- statCounter ----------------------------------------------------------
998
+ A few large figures in the display face, each with the line that says what
999
+ it counts.
1145
1000
  ------------------------------------------------------------------------- */
1146
1001
 
1147
- .cg-stat-counters__items {
1148
- display: grid;
1149
- gap: var(--cg-gap);
1150
- grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
1151
- margin: 0;
1152
- text-align: center;
1153
- }
1154
-
1155
1002
  .cg-stat-counter {
1003
+ grid-column: span 6;
1156
1004
  display: flex;
1157
1005
  flex-direction: column-reverse;
1158
- gap: var(--cg-s2);
1006
+ justify-content: flex-end;
1007
+ gap: var(--cg-s3);
1159
1008
  }
1160
1009
 
1161
1010
  .cg-stat-counter__value {
1162
- margin: 0;
1163
- color: var(--cg-accent);
1164
- font-size: calc(var(--cg-text-3xl) * 1.15);
1165
- font-weight: var(--cg-weight-bold);
1166
- line-height: var(--cg-leading-tight);
1167
- letter-spacing: var(--cg-tracking-tight);
1168
- font-variant-numeric: tabular-nums;
1011
+ font-family: var(--cg-font-display);
1012
+ font-size: var(--cg-text-display);
1013
+ font-weight: var(--cg-weight-regular);
1014
+ line-height: var(--cg-leading-display);
1015
+ letter-spacing: var(--cg-tracking-display);
1016
+ font-variant-numeric: tabular-nums lining-nums;
1169
1017
  }
1170
1018
 
1171
1019
  .cg-stat-counter__label {
1020
+ max-inline-size: 28ch;
1172
1021
  color: var(--cg-ink-muted);
1173
- font-size: var(--cg-text-xs);
1174
- font-weight: var(--cg-weight-semibold);
1175
- letter-spacing: var(--cg-tracking-wide);
1176
- text-transform: uppercase;
1177
1022
  }
1178
1023
 
1179
- /* --- logoStrip (blocks@2.0) ------------------------------------------------
1180
- The lighter-weight sibling of `logos`: one row, no card, no link — the
1181
- "as seen in" strip rather than the fuller partner grid.
1024
+ @media (min-width: 64rem) {
1025
+ .cg-stat-counter {
1026
+ grid-column: span 4;
1027
+ }
1028
+
1029
+ .cg-stat-counter:first-child:nth-last-child(4),
1030
+ .cg-stat-counter:first-child:nth-last-child(4) ~ .cg-stat-counter {
1031
+ grid-column: span 3;
1032
+ }
1033
+
1034
+ .cg-stat-counter:first-child:nth-last-child(2),
1035
+ .cg-stat-counter:first-child:nth-last-child(2) ~ .cg-stat-counter {
1036
+ grid-column: span 6;
1037
+ }
1038
+ }
1039
+
1040
+ /* --- logoStrip ------------------------------------------------------------
1041
+ One line between hairlines: what the marks are, then the marks.
1182
1042
  ------------------------------------------------------------------------- */
1183
1043
 
1184
1044
  .cg-logo-strip {
1185
- margin-block: 0;
1186
- text-align: center;
1045
+ row-gap: var(--cg-s4);
1046
+ }
1047
+
1048
+ .cg-logo-strip__caption {
1049
+ grid-row: 1;
1050
+ color: var(--cg-ink-muted);
1051
+ font-size: var(--cg-text-sm);
1052
+ font-weight: var(--cg-weight-medium);
1187
1053
  }
1188
1054
 
1189
1055
  .cg-logo-strip__items {
1056
+ grid-row: 2;
1190
1057
  display: flex;
1191
1058
  flex-wrap: wrap;
1192
1059
  align-items: center;
1193
- justify-content: center;
1194
- gap: var(--cg-gap-loose);
1060
+ gap: var(--cg-s5) var(--cg-s10);
1195
1061
  margin: 0;
1196
- padding: 0;
1062
+ padding-block: var(--cg-s6);
1063
+ padding-inline: 0;
1064
+ border-block: var(--cg-rule) solid var(--cg-line);
1197
1065
  list-style: none;
1198
1066
  }
1199
1067
 
1200
- .cg-logo-strip__item {
1201
- display: flex;
1202
- align-items: center;
1203
- }
1204
-
1205
1068
  .cg-logo-strip__image {
1206
- block-size: var(--cg-s8);
1207
- inline-size: auto;
1208
- max-inline-size: 100%;
1209
- object-fit: contain;
1210
- opacity: 0.6;
1069
+ block-size: 2.5rem;
1211
1070
  }
1212
1071
 
1213
- .cg-logo-strip__caption {
1214
- margin-block-start: var(--cg-s4);
1215
- color: var(--cg-ink-subtle);
1216
- font-size: var(--cg-text-xs);
1217
- font-weight: var(--cg-weight-semibold);
1218
- letter-spacing: var(--cg-tracking-wide);
1219
- text-transform: uppercase;
1072
+ @media (min-width: 64rem) {
1073
+ .cg-logo-strip__caption {
1074
+ grid-column: 1 / span 3;
1075
+ grid-row: 1;
1076
+ align-self: stretch;
1077
+ display: flex;
1078
+ align-items: center;
1079
+ border-block: var(--cg-rule) solid var(--cg-line);
1080
+ }
1081
+
1082
+ .cg-logo-strip__items {
1083
+ grid-column: 4 / -1;
1084
+ grid-row: 1;
1085
+ justify-content: space-between;
1086
+ }
1220
1087
  }