@cogenta/theme-magazine 1.1.2

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 (117) hide show
  1. package/LICENSE +373 -0
  2. package/dist/src/index.d.ts +21 -0
  3. package/dist/src/index.d.ts.map +1 -0
  4. package/dist/src/index.js +21 -0
  5. package/dist/src/index.js.map +1 -0
  6. package/dist/src/render/blocks/accordion.d.ts +4 -0
  7. package/dist/src/render/blocks/accordion.d.ts.map +1 -0
  8. package/dist/src/render/blocks/accordion.js +20 -0
  9. package/dist/src/render/blocks/accordion.js.map +1 -0
  10. package/dist/src/render/blocks/collection-list.d.ts +5 -0
  11. package/dist/src/render/blocks/collection-list.d.ts.map +1 -0
  12. package/dist/src/render/blocks/collection-list.js +134 -0
  13. package/dist/src/render/blocks/collection-list.js.map +1 -0
  14. package/dist/src/render/blocks/cta.d.ts +10 -0
  15. package/dist/src/render/blocks/cta.d.ts.map +1 -0
  16. package/dist/src/render/blocks/cta.js +16 -0
  17. package/dist/src/render/blocks/cta.js.map +1 -0
  18. package/dist/src/render/blocks/embed.d.ts +4 -0
  19. package/dist/src/render/blocks/embed.d.ts.map +1 -0
  20. package/dist/src/render/blocks/embed.js +76 -0
  21. package/dist/src/render/blocks/embed.js.map +1 -0
  22. package/dist/src/render/blocks/faq.d.ts +4 -0
  23. package/dist/src/render/blocks/faq.d.ts.map +1 -0
  24. package/dist/src/render/blocks/faq.js +18 -0
  25. package/dist/src/render/blocks/faq.js.map +1 -0
  26. package/dist/src/render/blocks/feature-grid.d.ts +4 -0
  27. package/dist/src/render/blocks/feature-grid.d.ts.map +1 -0
  28. package/dist/src/render/blocks/feature-grid.js +27 -0
  29. package/dist/src/render/blocks/feature-grid.js.map +1 -0
  30. package/dist/src/render/blocks/gallery.d.ts +13 -0
  31. package/dist/src/render/blocks/gallery.d.ts.map +1 -0
  32. package/dist/src/render/blocks/gallery.js +26 -0
  33. package/dist/src/render/blocks/gallery.js.map +1 -0
  34. package/dist/src/render/blocks/hero.d.ts +11 -0
  35. package/dist/src/render/blocks/hero.d.ts.map +1 -0
  36. package/dist/src/render/blocks/hero.js +26 -0
  37. package/dist/src/render/blocks/hero.js.map +1 -0
  38. package/dist/src/render/blocks/logo-strip.d.ts +4 -0
  39. package/dist/src/render/blocks/logo-strip.d.ts.map +1 -0
  40. package/dist/src/render/blocks/logo-strip.js +20 -0
  41. package/dist/src/render/blocks/logo-strip.js.map +1 -0
  42. package/dist/src/render/blocks/logos.d.ts +4 -0
  43. package/dist/src/render/blocks/logos.d.ts.map +1 -0
  44. package/dist/src/render/blocks/logos.js +27 -0
  45. package/dist/src/render/blocks/logos.js.map +1 -0
  46. package/dist/src/render/blocks/media-figure.d.ts +15 -0
  47. package/dist/src/render/blocks/media-figure.d.ts.map +1 -0
  48. package/dist/src/render/blocks/media-figure.js +32 -0
  49. package/dist/src/render/blocks/media-figure.js.map +1 -0
  50. package/dist/src/render/blocks/pricing-table.d.ts +4 -0
  51. package/dist/src/render/blocks/pricing-table.d.ts.map +1 -0
  52. package/dist/src/render/blocks/pricing-table.js +32 -0
  53. package/dist/src/render/blocks/pricing-table.js.map +1 -0
  54. package/dist/src/render/blocks/prose.d.ts +16 -0
  55. package/dist/src/render/blocks/prose.d.ts.map +1 -0
  56. package/dist/src/render/blocks/prose.js +17 -0
  57. package/dist/src/render/blocks/prose.js.map +1 -0
  58. package/dist/src/render/blocks/quote.d.ts +16 -0
  59. package/dist/src/render/blocks/quote.d.ts.map +1 -0
  60. package/dist/src/render/blocks/quote.js +29 -0
  61. package/dist/src/render/blocks/quote.js.map +1 -0
  62. package/dist/src/render/blocks/stat-counter.d.ts +4 -0
  63. package/dist/src/render/blocks/stat-counter.d.ts.map +1 -0
  64. package/dist/src/render/blocks/stat-counter.js +17 -0
  65. package/dist/src/render/blocks/stat-counter.js.map +1 -0
  66. package/dist/src/render/blocks/stats.d.ts +4 -0
  67. package/dist/src/render/blocks/stats.d.ts.map +1 -0
  68. package/dist/src/render/blocks/stats.js +19 -0
  69. package/dist/src/render/blocks/stats.js.map +1 -0
  70. package/dist/src/render/blocks/testimonial.d.ts +19 -0
  71. package/dist/src/render/blocks/testimonial.d.ts.map +1 -0
  72. package/dist/src/render/blocks/testimonial.js +28 -0
  73. package/dist/src/render/blocks/testimonial.js.map +1 -0
  74. package/dist/src/render/chrome.d.ts +3 -0
  75. package/dist/src/render/chrome.d.ts.map +1 -0
  76. package/dist/src/render/chrome.js +136 -0
  77. package/dist/src/render/chrome.js.map +1 -0
  78. package/dist/src/render/render-block.d.ts +21 -0
  79. package/dist/src/render/render-block.d.ts.map +1 -0
  80. package/dist/src/render/render-block.js +104 -0
  81. package/dist/src/render/render-block.js.map +1 -0
  82. package/dist/src/render/term-archive.d.ts +13 -0
  83. package/dist/src/render/term-archive.d.ts.map +1 -0
  84. package/dist/src/render/term-archive.js +35 -0
  85. package/dist/src/render/term-archive.js.map +1 -0
  86. package/dist/theme.config.d.ts +12 -0
  87. package/dist/theme.config.d.ts.map +1 -0
  88. package/dist/theme.config.js +42 -0
  89. package/dist/theme.config.js.map +1 -0
  90. package/package.json +57 -0
  91. package/src/index.ts +20 -0
  92. package/src/render/blocks/accordion.ts +51 -0
  93. package/src/render/blocks/collection-list.ts +286 -0
  94. package/src/render/blocks/cta.ts +33 -0
  95. package/src/render/blocks/embed.ts +99 -0
  96. package/src/render/blocks/faq.ts +58 -0
  97. package/src/render/blocks/feature-grid.ts +61 -0
  98. package/src/render/blocks/gallery.ts +46 -0
  99. package/src/render/blocks/hero.ts +54 -0
  100. package/src/render/blocks/logo-strip.ts +35 -0
  101. package/src/render/blocks/logos.ts +57 -0
  102. package/src/render/blocks/media-figure.ts +43 -0
  103. package/src/render/blocks/pricing-table.ts +76 -0
  104. package/src/render/blocks/prose.ts +22 -0
  105. package/src/render/blocks/quote.ts +46 -0
  106. package/src/render/blocks/stat-counter.ts +39 -0
  107. package/src/render/blocks/stats.ts +46 -0
  108. package/src/render/blocks/testimonial.ts +44 -0
  109. package/src/render/chrome.ts +162 -0
  110. package/src/render/render-block.ts +137 -0
  111. package/src/render/term-archive.ts +87 -0
  112. package/src/styles/archive.css +40 -0
  113. package/src/styles/base.css +1037 -0
  114. package/src/styles/blocks.css +1335 -0
  115. package/src/styles/theme.css +18 -0
  116. package/src/styles/tokens.css +308 -0
  117. package/tokens.json +36 -0
@@ -0,0 +1,1037 @@
1
+ /*
2
+ * Document, accessibility floor, the masthead/colophon frame, and the
3
+ * theme's one control (an action link). Everything here reads the design
4
+ * system from `tokens.css`; nothing here reads a `--cogenta-*` token
5
+ * directly.
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-paper);
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
+ font-kerning: normal;
26
+ font-variant-ligatures: common-ligatures;
27
+ text-underline-offset: 0.16em;
28
+ text-decoration-thickness: from-font;
29
+ -webkit-text-size-adjust: 100%;
30
+ }
31
+
32
+ /* The display serif is the theme's whole typographic identity: every
33
+ heading gets it once, here, so no block repeats the family. Blocks only
34
+ ever adjust size, weight and spacing on top of this. */
35
+ h1,
36
+ h2,
37
+ h3,
38
+ h4,
39
+ h5,
40
+ h6 {
41
+ margin: 0;
42
+ font-family: var(--cogenta-font-serif);
43
+ font-weight: var(--cg-weight-bold);
44
+ letter-spacing: var(--cg-tracking-tight);
45
+ line-height: var(--cg-leading-tight);
46
+ text-wrap: balance;
47
+ }
48
+
49
+ ::selection {
50
+ background: var(--cg-accent-tint);
51
+ color: var(--cg-accent-tint-ink);
52
+ }
53
+
54
+ img,
55
+ video,
56
+ iframe {
57
+ max-width: 100%;
58
+ height: auto;
59
+ }
60
+
61
+ img {
62
+ display: block;
63
+ object-fit: cover;
64
+ }
65
+
66
+ :where(a) {
67
+ color: var(--cg-accent);
68
+ text-decoration-color: color-mix(in oklab, var(--cg-accent) 40%, transparent);
69
+ transition:
70
+ color var(--cg-duration-fast) var(--cg-ease),
71
+ text-decoration-color var(--cg-duration-fast) var(--cg-ease);
72
+ }
73
+
74
+ :where(a:hover) {
75
+ color: var(--cg-accent-hover);
76
+ text-decoration-color: currentColor;
77
+ }
78
+
79
+ :where(hr) {
80
+ block-size: 1px;
81
+ border: 0;
82
+ margin-block: var(--cg-s10);
83
+ background: var(--cg-rule);
84
+ }
85
+
86
+ /* `renderSocialLinks` (`@cogenta/theme-kit`) hides each platform's own text
87
+ label behind its icon with this class — the standard clip-to-1px
88
+ technique, kept the accessible name without duplicating it visibly. */
89
+ .cg-visually-hidden {
90
+ position: absolute;
91
+ inline-size: 1px;
92
+ block-size: 1px;
93
+ overflow: hidden;
94
+ clip: rect(0, 0, 0, 0);
95
+ white-space: nowrap;
96
+ }
97
+
98
+ /* --------------------------------------------------------------------------
99
+ Focus, targets, motion
100
+ -------------------------------------------------------------------------- */
101
+
102
+ :where(a, button, summary, [tabindex]):focus-visible {
103
+ outline: 2px solid var(--cg-accent);
104
+ outline-offset: 3px;
105
+ border-radius: var(--cg-radius-sm);
106
+ }
107
+
108
+ :where(.cg-action, .cg-mailbag__question, .cg-press__link, .cg-sidenote__link) {
109
+ min-block-size: 44px;
110
+ min-inline-size: 44px;
111
+ }
112
+
113
+ /*
114
+ * The one entrance the theme allows: a restrained fade, no translate — a
115
+ * magazine reader scrolling a long feature should not feel the page moving
116
+ * under them. Scroll-driven and wrapped in a feature query, since the
117
+ * starting state is `opacity: 0` and a browser without
118
+ * `animation-timeline` must never be left holding an invisible page.
119
+ */
120
+ @supports (animation-timeline: view()) {
121
+ @media (prefers-reduced-motion: no-preference) {
122
+ @keyframes cg-fade-in {
123
+ from {
124
+ opacity: 0;
125
+ }
126
+
127
+ to {
128
+ opacity: 1;
129
+ }
130
+ }
131
+
132
+ .cg-block {
133
+ animation: cg-fade-in linear both;
134
+ animation-timeline: view();
135
+ animation-range: entry 0% cover 18%;
136
+ }
137
+ }
138
+ }
139
+
140
+ @media (prefers-reduced-motion: reduce) {
141
+ *,
142
+ *::before,
143
+ *::after {
144
+ animation-duration: 1ms !important;
145
+ animation-iteration-count: 1 !important;
146
+ transition-duration: 1ms !important;
147
+ scroll-behavior: auto !important;
148
+ }
149
+ }
150
+
151
+ .cg-skip-link {
152
+ position: absolute;
153
+ inset-inline-start: var(--cg-s3);
154
+ inset-block-start: calc(var(--cg-s3) * -8);
155
+ z-index: 10;
156
+ padding: var(--cg-s2) var(--cg-s4);
157
+ background: var(--cg-accent);
158
+ color: var(--cg-accent-ink);
159
+ border-radius: var(--cg-radius-sm);
160
+ box-shadow: var(--cg-elevation-2);
161
+ font-family: var(--cogenta-font-sans);
162
+ font-weight: var(--cg-weight-semibold);
163
+ text-decoration: none;
164
+ transition: inset-block-start var(--cg-duration) var(--cg-ease);
165
+ }
166
+
167
+ .cg-skip-link:focus-visible {
168
+ inset-block-start: var(--cg-s3);
169
+ }
170
+
171
+ /* --------------------------------------------------------------------------
172
+ Page frame
173
+ -------------------------------------------------------------------------- */
174
+
175
+ .cg-main {
176
+ display: flow-root;
177
+ }
178
+
179
+ .cg-block {
180
+ max-inline-size: var(--cg-page);
181
+ margin-inline: auto;
182
+ margin-block: var(--cg-section-y);
183
+ padding-inline: var(--cg-gutter);
184
+ }
185
+
186
+ /* --- per-block visual variant (blocks@2.0, RFC 0002) ----------------------
187
+ `withBlockVariant` (`@cogenta/theme-kit`) stamps one `data-variant-<axis>`
188
+ attribute per axis an author actually set — never all four, never one this
189
+ theme does not resolve. Two attribute selectors give every rule here the
190
+ same specificity, (0,2,0), which is what lets it override `.cg-block`
191
+ above regardless of source order, without `!important` anywhere.
192
+
193
+ `background: 'image'` has no theme mechanism to attach an actual image to
194
+ a block instance (RFC 0002 adds only the semantic token, not a media
195
+ field) — resolved to the same tinted surface as the closest honest
196
+ approximation this theme has, rather than silently doing nothing with a
197
+ stated author intent. "muted" resolves to `--cg-paper-panel`, the boxed-note
198
+ surface this theme already uses for a pull quote's rule background.
199
+ ------------------------------------------------------------------------- */
200
+
201
+ [data-block][data-variant-background="muted"],
202
+ [data-block][data-variant-background="image"] {
203
+ padding-block: var(--cg-s10);
204
+ border-radius: var(--cg-radius-lg);
205
+ }
206
+
207
+ [data-block][data-variant-background="muted"] {
208
+ background: var(--cg-paper-panel);
209
+ }
210
+
211
+ [data-block][data-variant-background="image"] {
212
+ background: var(--cg-paper-tint);
213
+ }
214
+
215
+ [data-block][data-variant-spacing="compact"] {
216
+ margin-block: calc(var(--cg-section-y) / 2);
217
+ }
218
+
219
+ /* No rule for "comfortable": it names this theme's existing default, so an
220
+ author who picks it explicitly gets exactly what an absent `variant`
221
+ already gave them — the whole point of "theme default" being a real,
222
+ selectable option and not only the absence of a choice. */
223
+
224
+ [data-block][data-variant-spacing="spacious"] {
225
+ margin-block: calc(var(--cg-section-y) * 1.6);
226
+ }
227
+
228
+ [data-block][data-variant-align="start"] {
229
+ text-align: start;
230
+ }
231
+
232
+ [data-block][data-variant-align="center"] {
233
+ text-align: center;
234
+ }
235
+
236
+ [data-block][data-variant-align="end"] {
237
+ text-align: end;
238
+ }
239
+
240
+ [data-block][data-variant-width="full"] {
241
+ max-inline-size: none;
242
+ padding-inline: 0;
243
+ }
244
+
245
+ .cg-page__title {
246
+ max-inline-size: var(--cg-page);
247
+ margin-inline: auto;
248
+ margin-block: var(--cg-section-y) var(--cg-s6);
249
+ padding-inline: var(--cg-gutter);
250
+ font-size: var(--cg-text-3xl);
251
+ text-wrap: balance;
252
+ }
253
+
254
+ /* --------------------------------------------------------------------------
255
+ The article header — `renderEntryHeader` (`@cogenta/theme-kit`): a
256
+ classification eyebrow set in the masthead's own journal-red accent, the
257
+ big serif headline, a dek, an editorial meta line (date, byline, reading
258
+ time) between two hairlines, and the cover last, full-bleed.
259
+ -------------------------------------------------------------------------- */
260
+
261
+ .cg-entry-header {
262
+ max-inline-size: var(--cg-page);
263
+ margin-inline: auto;
264
+ margin-block: var(--cg-section-y) var(--cg-s10);
265
+ padding-inline: var(--cg-gutter);
266
+ }
267
+
268
+ .cg-entry-header__terms {
269
+ display: flex;
270
+ flex-wrap: wrap;
271
+ gap: var(--cg-s2) var(--cg-s5);
272
+ margin: 0 0 var(--cg-s3);
273
+ padding: 0;
274
+ list-style: none;
275
+ color: var(--cg-accent);
276
+ font-family: var(--cogenta-font-sans);
277
+ font-size: var(--cg-text-sm);
278
+ font-weight: var(--cg-weight-bold);
279
+ letter-spacing: var(--cg-tracking-wider);
280
+ text-transform: uppercase;
281
+ }
282
+
283
+ .cg-entry-header__terms a {
284
+ color: inherit;
285
+ text-decoration: none;
286
+ }
287
+
288
+ .cg-entry-header__terms a:hover {
289
+ text-decoration: underline;
290
+ }
291
+
292
+ .cg-entry-header__title {
293
+ font-size: var(--cg-text-3xl);
294
+ text-wrap: balance;
295
+ }
296
+
297
+ @media (min-width: 48rem) {
298
+ .cg-entry-header__title {
299
+ font-size: calc(var(--cg-text-3xl) * 1.15);
300
+ }
301
+ }
302
+
303
+ .cg-entry-header__excerpt {
304
+ margin: var(--cg-s5) 0 0;
305
+ max-inline-size: var(--cg-measure);
306
+ color: var(--cg-ink-soft);
307
+ font-family: var(--cogenta-font-serif);
308
+ font-style: italic;
309
+ font-size: var(--cg-text-lg);
310
+ line-height: var(--cg-leading-relaxed);
311
+ text-wrap: pretty;
312
+ }
313
+
314
+ .cg-entry-header__meta {
315
+ display: flex;
316
+ flex-wrap: wrap;
317
+ align-items: center;
318
+ gap: var(--cg-s2) var(--cg-s5);
319
+ margin: var(--cg-s6) 0 0;
320
+ padding-block: var(--cg-s3);
321
+ border-block: 1px solid var(--cg-rule-soft);
322
+ color: var(--cg-ink-faint);
323
+ font-family: var(--cogenta-font-sans);
324
+ font-size: var(--cg-text-sm);
325
+ }
326
+
327
+ .cg-entry-header__author {
328
+ font-weight: var(--cg-weight-semibold);
329
+ color: var(--cg-ink-soft);
330
+ }
331
+
332
+ .cg-entry-header__cover {
333
+ margin: var(--cg-s8) 0 0;
334
+ }
335
+
336
+ .cg-entry-header__cover img {
337
+ inline-size: 100%;
338
+ aspect-ratio: 16 / 9;
339
+ object-fit: cover;
340
+ box-shadow: var(--cg-elevation-2);
341
+ }
342
+
343
+ /* --------------------------------------------------------------------------
344
+ The masthead — a nameplate row, then a quiet rubric row beneath it, the
345
+ way a print front page separates the title from the contents strip.
346
+
347
+ L25 pro pass: the rubric row is a real desktop `<nav>` above `56rem` and a
348
+ CSS-only `<details>` disclosure below it — never one `<details>` forced
349
+ open at width (see `chrome.ts`'s file-level comment for why that fails in
350
+ a real browser).
351
+ -------------------------------------------------------------------------- */
352
+
353
+ .cg-masthead {
354
+ position: sticky;
355
+ inset-block-start: 0;
356
+ z-index: 5;
357
+ border-block-end: 3px double var(--cg-rule-heavy);
358
+ background: var(--cg-paper);
359
+ }
360
+
361
+ .cg-masthead__top {
362
+ position: relative;
363
+ padding-block: var(--cg-s2);
364
+ text-align: center;
365
+ border-block-end: 1px solid var(--cg-rule-soft);
366
+ }
367
+
368
+ .cg-masthead__date {
369
+ font-family: var(--cogenta-font-sans);
370
+ font-size: var(--cg-text-xs);
371
+ font-weight: var(--cg-weight-semibold);
372
+ letter-spacing: var(--cg-tracking-wider);
373
+ text-transform: uppercase;
374
+ color: var(--cg-ink-faint);
375
+ }
376
+
377
+ /* The manual light/dark/system control (`renderThemeToggle`, `@cogenta/
378
+ theme-kit`) — a small outlined icon button pinned to the end of the top
379
+ strip, next to today's date, so it renders on every page regardless of
380
+ whether the rubric row below it has a nav or a header action (see
381
+ `chrome.ts`'s file-level comment). A plain outline, not `.cg-action`'s
382
+ underlined-link style, so it never reads as a navigation item. */
383
+ .cg-theme-toggle {
384
+ position: absolute;
385
+ inset-inline-end: var(--cg-gutter);
386
+ inset-block-start: 50%;
387
+ transform: translateY(-50%);
388
+ display: inline-flex;
389
+ align-items: center;
390
+ justify-content: center;
391
+ inline-size: 1.5rem;
392
+ block-size: 1.5rem;
393
+ border-radius: var(--cg-radius-sm);
394
+ border: 1px solid var(--cg-rule-soft);
395
+ background: transparent;
396
+ color: var(--cg-ink-faint);
397
+ cursor: pointer;
398
+ }
399
+
400
+ .cg-theme-toggle:hover {
401
+ color: var(--cg-accent);
402
+ border-color: var(--cg-accent);
403
+ }
404
+
405
+ .cg-theme-toggle__icon {
406
+ inline-size: 0.85rem;
407
+ block-size: 0.85rem;
408
+ }
409
+
410
+ .cg-theme-toggle__icon--moon {
411
+ display: none;
412
+ }
413
+
414
+ /* Icon reflects the *current* effective appearance — sun while light, moon
415
+ while dark — from the same `[data-theme]`/`prefers-color-scheme` signals
416
+ `tokens.css` already keys the whole palette on. */
417
+ @media (prefers-color-scheme: dark) {
418
+ :where(:root:not([data-theme="light"])) .cg-theme-toggle__icon--sun {
419
+ display: none;
420
+ }
421
+ :where(:root:not([data-theme="light"])) .cg-theme-toggle__icon--moon {
422
+ display: block;
423
+ }
424
+ }
425
+
426
+ :where(:root[data-theme="dark"]) .cg-theme-toggle__icon--sun {
427
+ display: none;
428
+ }
429
+
430
+ :where(:root[data-theme="dark"]) .cg-theme-toggle__icon--moon {
431
+ display: block;
432
+ }
433
+
434
+ .cg-masthead__nameplate {
435
+ display: flex;
436
+ align-items: center;
437
+ justify-content: center;
438
+ gap: var(--cg-s4);
439
+ padding: var(--cg-s4) var(--cg-gutter);
440
+ }
441
+
442
+ .cg-masthead__wordmark {
443
+ display: inline-block;
444
+ color: var(--cg-ink);
445
+ font-family: var(--cogenta-font-serif);
446
+ font-weight: var(--cg-weight-black);
447
+ font-size: var(--cg-text-2xl);
448
+ letter-spacing: var(--cg-tracking-tight);
449
+ line-height: 1;
450
+ text-decoration: none;
451
+ }
452
+
453
+ @media (min-width: 32rem) {
454
+ .cg-masthead__wordmark {
455
+ font-size: var(--cg-text-3xl);
456
+ }
457
+ }
458
+
459
+ /* The uploaded site logo, set at nameplate scale — a masthead's logo is the
460
+ nameplate, so it gets the height the wordmark had rather than a header-bar
461
+ height borrowed from another theme. */
462
+ .cg-masthead__logo {
463
+ display: block;
464
+ block-size: 2.5rem;
465
+ inline-size: auto;
466
+ max-inline-size: min(60vw, 22rem);
467
+ object-fit: contain;
468
+ }
469
+
470
+ @media (min-width: 32rem) {
471
+ .cg-masthead__logo {
472
+ block-size: 3rem;
473
+ }
474
+ }
475
+
476
+ .cg-masthead__wordmark:hover {
477
+ color: var(--cg-accent);
478
+ }
479
+
480
+ .cg-masthead__nav {
481
+ display: none;
482
+ border-block-start: 1px solid var(--cg-rule-soft);
483
+ padding-block: var(--cg-s3);
484
+ }
485
+
486
+ @media (min-width: 56rem) {
487
+ .cg-masthead__nav {
488
+ display: block;
489
+ }
490
+ }
491
+
492
+ .cg-masthead__nav-inner {
493
+ display: flex;
494
+ align-items: center;
495
+ justify-content: center;
496
+ gap: var(--cg-s6);
497
+ max-inline-size: var(--cg-page);
498
+ margin-inline: auto;
499
+ padding-inline: var(--cg-gutter);
500
+ }
501
+
502
+ .cg-masthead__menu {
503
+ display: flex;
504
+ flex-wrap: wrap;
505
+ justify-content: center;
506
+ gap: var(--cg-s6);
507
+ margin: 0;
508
+ padding: 0;
509
+ list-style: none;
510
+ font-family: var(--cogenta-font-sans);
511
+ font-size: var(--cg-text-sm);
512
+ font-weight: var(--cg-weight-semibold);
513
+ letter-spacing: var(--cg-tracking-wide);
514
+ text-transform: uppercase;
515
+ white-space: nowrap;
516
+ }
517
+
518
+ .cg-masthead__menu a,
519
+ .cg-masthead__menu span {
520
+ color: var(--cg-ink-soft);
521
+ text-decoration: none;
522
+ }
523
+
524
+ .cg-masthead__menu a:hover {
525
+ color: var(--cg-accent);
526
+ }
527
+
528
+ /*
529
+ * Higher specificity than the shared `.cg-action[data-emphasis="primary"]`
530
+ * rule below (Actions section, which sets `color: var(--cg-accent)` — a
531
+ * text-forward link on the page's own paper background) is required here,
532
+ * not optional: this button sits on a solid accent fill, so it needs the
533
+ * *foreground* token instead. Without the extra specificity the shared rule
534
+ * wins regardless of source order (both are 0,2,0) — confirmed live: the
535
+ * button rendered as a solid red rectangle with its own "Subscribe" label
536
+ * painted the same red as the fill, and the shared rule's arrow glyph showed
537
+ * through a `content: none` that lost the same tie.
538
+ */
539
+ .cg-masthead__action.cg-action[data-emphasis="primary"] {
540
+ color: var(--cg-accent-ink);
541
+ background: var(--cg-accent);
542
+ padding: var(--cg-s2) var(--cg-s4);
543
+ border-block-end-width: 0;
544
+ }
545
+
546
+ .cg-masthead__action.cg-action::after {
547
+ content: none;
548
+ }
549
+
550
+ .cg-masthead__action.cg-action[data-emphasis="primary"]:hover {
551
+ background: var(--cg-accent-hover);
552
+ color: var(--cg-accent-ink);
553
+ }
554
+
555
+ /* The mobile disclosure — hidden above the desktop breakpoint, shown below it. */
556
+ .cg-masthead__disclosure {
557
+ display: block;
558
+ }
559
+
560
+ @media (min-width: 56rem) {
561
+ .cg-masthead__disclosure {
562
+ display: none;
563
+ }
564
+ }
565
+
566
+ .cg-masthead__toggle {
567
+ display: flex;
568
+ align-items: center;
569
+ justify-content: center;
570
+ inline-size: 44px;
571
+ block-size: 44px;
572
+ border: 1px solid var(--cg-rule);
573
+ border-radius: var(--cg-radius-sm);
574
+ cursor: pointer;
575
+ list-style: none;
576
+ }
577
+
578
+ .cg-masthead__toggle::-webkit-details-marker {
579
+ display: none;
580
+ }
581
+
582
+ .cg-masthead__bars {
583
+ position: relative;
584
+ display: block;
585
+ inline-size: 18px;
586
+ block-size: 2px;
587
+ background: var(--cg-ink);
588
+ }
589
+
590
+ .cg-masthead__bars::before,
591
+ .cg-masthead__bars::after {
592
+ content: "";
593
+ position: absolute;
594
+ inset-inline-start: 0;
595
+ inline-size: 18px;
596
+ block-size: 2px;
597
+ background: var(--cg-ink);
598
+ }
599
+
600
+ .cg-masthead__bars::before {
601
+ inset-block-start: -6px;
602
+ }
603
+
604
+ .cg-masthead__bars::after {
605
+ inset-block-start: 6px;
606
+ }
607
+
608
+ .cg-masthead__panel {
609
+ position: absolute;
610
+ inset-inline: var(--cg-gutter);
611
+ margin-block-start: var(--cg-s3);
612
+ padding: var(--cg-s5);
613
+ background: var(--cg-paper-raised);
614
+ border: 1px solid var(--cg-rule);
615
+ box-shadow: var(--cg-elevation-3);
616
+ border-radius: var(--cg-radius-md);
617
+ }
618
+
619
+ .cg-masthead__panel .cg-masthead__menu {
620
+ flex-direction: column;
621
+ align-items: flex-start;
622
+ gap: var(--cg-s3);
623
+ }
624
+
625
+ .cg-masthead__panel .cg-masthead__action {
626
+ display: inline-flex;
627
+ margin-block-start: var(--cg-s3);
628
+ }
629
+
630
+ /* --------------------------------------------------------------------------
631
+ The colophon — the print magazine's inside-back-cover imprint, in a dense
632
+ four-column layout: brand + tagline, a section index, social icons, and
633
+ a closing note with the branding fragment last, never dropped, never
634
+ restyled beyond the theme's palette.
635
+ -------------------------------------------------------------------------- */
636
+
637
+ .cg-colophon {
638
+ margin-block-start: var(--cg-section-y);
639
+ padding: var(--cg-s16) var(--cg-gutter) var(--cg-s10);
640
+ background: var(--cg-paper-panel);
641
+ color: var(--cg-ink-soft);
642
+ border-block-start: 3px double var(--cg-rule-heavy);
643
+ font-family: var(--cogenta-font-sans);
644
+ font-size: var(--cg-text-sm);
645
+ }
646
+
647
+ .cg-colophon__grid {
648
+ display: grid;
649
+ gap: var(--cg-s10);
650
+ max-inline-size: var(--cg-page);
651
+ margin-inline: auto;
652
+ grid-template-columns: 1fr;
653
+ }
654
+
655
+ @media (min-width: 40rem) {
656
+ .cg-colophon__grid {
657
+ grid-template-columns: 1fr 1fr;
658
+ }
659
+ }
660
+
661
+ @media (min-width: 68rem) {
662
+ .cg-colophon__grid {
663
+ grid-template-columns: 1.3fr 1fr 0.8fr 1fr;
664
+ align-items: start;
665
+ }
666
+ }
667
+
668
+ .cg-colophon__wordmark {
669
+ display: inline-block;
670
+ color: var(--cg-ink);
671
+ font-family: var(--cogenta-font-serif);
672
+ font-weight: var(--cg-weight-bold);
673
+ font-size: var(--cg-text-lg);
674
+ text-decoration: none;
675
+ }
676
+
677
+ .cg-colophon__tagline {
678
+ margin: var(--cg-s3) 0 0;
679
+ max-inline-size: 28ch;
680
+ line-height: var(--cg-leading-relaxed);
681
+ }
682
+
683
+ .cg-colophon__heading {
684
+ margin: 0 0 var(--cg-s3);
685
+ font-family: var(--cogenta-font-sans);
686
+ font-size: var(--cg-text-xs);
687
+ font-weight: var(--cg-weight-bold);
688
+ letter-spacing: var(--cg-tracking-wider);
689
+ text-transform: uppercase;
690
+ color: var(--cg-ink-faint);
691
+ }
692
+
693
+ .cg-colophon__menu {
694
+ margin: 0;
695
+ padding: 0;
696
+ list-style: none;
697
+ }
698
+
699
+ .cg-colophon__menu li {
700
+ margin-block-end: var(--cg-s2);
701
+ }
702
+
703
+ .cg-colophon__menu a,
704
+ .cg-colophon__menu span {
705
+ color: var(--cg-ink-soft);
706
+ text-decoration: none;
707
+ }
708
+
709
+ .cg-colophon__menu a:hover {
710
+ color: var(--cg-accent);
711
+ }
712
+
713
+ /* The social-icon column — `renderSocialLinks` (`@cogenta/theme-kit`) emits
714
+ a bare `<ul>`; this theme styles the icons into a quiet row of circles. */
715
+ .cg-colophon__social {
716
+ display: flex;
717
+ flex-wrap: wrap;
718
+ gap: var(--cg-s3);
719
+ margin: 0;
720
+ padding: 0;
721
+ list-style: none;
722
+ }
723
+
724
+ .cg-colophon__social-item a {
725
+ display: flex;
726
+ align-items: center;
727
+ justify-content: center;
728
+ inline-size: 2.25rem;
729
+ block-size: 2.25rem;
730
+ border: 1px solid var(--cg-rule);
731
+ border-radius: 50%;
732
+ color: var(--cg-ink-soft);
733
+ transition:
734
+ color var(--cg-duration) var(--cg-ease),
735
+ border-color var(--cg-duration) var(--cg-ease);
736
+ }
737
+
738
+ .cg-colophon__social-item a:hover {
739
+ color: var(--cg-accent);
740
+ border-color: var(--cg-accent);
741
+ }
742
+
743
+ .cg-social__icon {
744
+ inline-size: 1.1rem;
745
+ block-size: 1.1rem;
746
+ }
747
+
748
+ .cg-colophon__note {
749
+ margin: 0 0 var(--cg-s4);
750
+ max-inline-size: 32ch;
751
+ line-height: var(--cg-leading-relaxed);
752
+ }
753
+
754
+ .cg-colophon__branding {
755
+ display: flex;
756
+ align-items: flex-start;
757
+ }
758
+
759
+ /* The fixed branding fragment (`cg-site-footer__branding`, emitted by
760
+ `cogenta serve` itself, never by this theme) — restyled to the palette
761
+ without touching its markup. */
762
+ .cg-site-footer__branding a {
763
+ display: flex;
764
+ align-items: center;
765
+ gap: 0.4em;
766
+ color: var(--cg-ink-faint);
767
+ opacity: 0.8;
768
+ transition: opacity var(--cg-duration) var(--cg-ease);
769
+ }
770
+
771
+ .cg-site-footer__branding a:hover,
772
+ .cg-site-footer__branding a:focus-visible {
773
+ opacity: 1;
774
+ }
775
+
776
+ .cg-site-footer__brand-logo {
777
+ display: block;
778
+ /* Explicit pixels, not `em`: relative sizing cascaded from the footer's
779
+ own small font-size and made the credit mark unreadably tiny. */
780
+ block-size: 25px;
781
+ inline-size: auto;
782
+ }
783
+
784
+ .cg-site-footer__version {
785
+ font-variant-numeric: tabular-nums;
786
+ font-size: 0.9em;
787
+ }
788
+
789
+ /* --------------------------------------------------------------------------
790
+ Actions — the theme's only control, a text-forward link rather than a
791
+ filled button, in keeping with a page whose whole vocabulary is type and
792
+ rules rather than UI chrome.
793
+ -------------------------------------------------------------------------- */
794
+
795
+ .cg-actions {
796
+ display: flex;
797
+ flex-wrap: wrap;
798
+ gap: var(--cg-s5);
799
+ margin: var(--cg-s8) 0 0;
800
+ padding: 0;
801
+ list-style: none;
802
+ }
803
+
804
+ .cg-action {
805
+ display: inline-flex;
806
+ align-items: center;
807
+ gap: var(--cg-s2);
808
+ padding-block: var(--cg-s2);
809
+ border: 0;
810
+ border-block-end: 2px solid transparent;
811
+ font-family: var(--cogenta-font-sans);
812
+ font-size: var(--cg-text-sm);
813
+ font-weight: var(--cg-weight-bold);
814
+ letter-spacing: var(--cg-tracking-wide);
815
+ text-transform: uppercase;
816
+ text-decoration: none;
817
+ white-space: nowrap;
818
+ transition:
819
+ color var(--cg-duration) var(--cg-ease),
820
+ border-color var(--cg-duration) var(--cg-ease);
821
+ }
822
+
823
+ .cg-action::after {
824
+ content: "\2192";
825
+ transition: transform var(--cg-duration) var(--cg-ease);
826
+ }
827
+
828
+ .cg-action[data-emphasis="primary"] {
829
+ color: var(--cg-accent);
830
+ border-block-end-color: var(--cg-accent);
831
+ }
832
+
833
+ .cg-action[data-emphasis="secondary"] {
834
+ color: var(--cg-ink);
835
+ border-block-end-color: var(--cg-rule-heavy);
836
+ }
837
+
838
+ .cg-action:hover {
839
+ color: var(--cg-accent-hover);
840
+ border-block-end-color: var(--cg-accent-hover);
841
+ }
842
+
843
+ .cg-action:hover::after {
844
+ transform: translateX(0.2em);
845
+ }
846
+
847
+ /* --------------------------------------------------------------------------
848
+ Search, forms, comments — public utility pages and post-content furniture.
849
+ `/search`, `/forms/{name}` and the comment thread appended after an entry
850
+ page all render real markup with fixed `cg-*` classes from
851
+ `@cogenta/theme-kit`; this theme styles them to the same measure the page
852
+ title uses, rather than leaving them to run edge to edge unstyled.
853
+ -------------------------------------------------------------------------- */
854
+
855
+ .cg-search__form,
856
+ .cg-search__results,
857
+ .cg-search__empty,
858
+ .cg-search__error,
859
+ .cg-form,
860
+ .cg-form__confirmation,
861
+ .cg-comments {
862
+ max-inline-size: var(--cg-page);
863
+ margin-inline: auto;
864
+ padding-inline: var(--cg-gutter);
865
+ }
866
+
867
+ .cg-search__form {
868
+ display: flex;
869
+ flex-wrap: wrap;
870
+ align-items: end;
871
+ gap: var(--cg-s3);
872
+ margin-block-end: var(--cg-s8);
873
+ }
874
+
875
+ .cg-search__form label,
876
+ .cg-form__field label,
877
+ .cg-comment__form label {
878
+ display: block;
879
+ font-family: var(--cogenta-font-sans);
880
+ font-size: var(--cg-text-sm);
881
+ font-weight: var(--cg-weight-semibold);
882
+ margin-block-end: var(--cg-s2);
883
+ }
884
+
885
+ .cg-search__form input[type="search"] {
886
+ flex: 1 1 16rem;
887
+ }
888
+
889
+ .cg-search__results {
890
+ margin: 0 auto;
891
+ display: grid;
892
+ gap: var(--cg-s5);
893
+ padding-block: var(--cg-s5);
894
+ border-block-start: 1px solid var(--cg-rule);
895
+ }
896
+
897
+ .cg-search__empty,
898
+ .cg-comments__empty,
899
+ .cg-comments__closed {
900
+ color: var(--cg-ink-faint);
901
+ font-family: var(--cogenta-font-sans);
902
+ }
903
+
904
+ .cg-search__error,
905
+ .cg-form__error,
906
+ .cg-form__field-error {
907
+ color: var(--cg-ink);
908
+ font-weight: var(--cg-weight-bold);
909
+ }
910
+
911
+ .cg-search__form input,
912
+ .cg-form__field input,
913
+ .cg-form__field select,
914
+ .cg-form__field textarea,
915
+ .cg-comment__form input,
916
+ .cg-comment__form textarea {
917
+ inline-size: 100%;
918
+ padding: var(--cg-s3) var(--cg-s4);
919
+ border: 1px solid var(--cg-rule);
920
+ border-radius: var(--cg-radius-sm);
921
+ background: var(--cg-paper);
922
+ color: var(--cg-ink);
923
+ font: inherit;
924
+ font-family: var(--cogenta-font-sans);
925
+ }
926
+
927
+ .cg-form__field input[aria-invalid="true"],
928
+ .cg-form__field select[aria-invalid="true"],
929
+ .cg-form__field textarea[aria-invalid="true"] {
930
+ border-width: 2px;
931
+ border-color: var(--cg-rule-heavy);
932
+ }
933
+
934
+ .cg-search__form button,
935
+ .cg-form button[type="submit"],
936
+ .cg-comment__form button[type="submit"] {
937
+ padding: var(--cg-s3) var(--cg-s6);
938
+ border: 0;
939
+ border-block-end: 2px solid var(--cg-accent-ink);
940
+ background: var(--cg-accent);
941
+ color: var(--cg-accent-ink);
942
+ font-family: var(--cogenta-font-sans);
943
+ font-weight: var(--cg-weight-bold);
944
+ letter-spacing: var(--cg-tracking-wide);
945
+ text-transform: uppercase;
946
+ cursor: pointer;
947
+ transition: background-color var(--cg-duration) var(--cg-ease);
948
+ }
949
+
950
+ .cg-search__form button:hover,
951
+ .cg-form button[type="submit"]:hover,
952
+ .cg-comment__form button[type="submit"]:hover {
953
+ background: var(--cg-accent-hover);
954
+ }
955
+
956
+ .cg-form__field,
957
+ .cg-comment__form p {
958
+ display: block;
959
+ margin-block-end: var(--cg-s5);
960
+ }
961
+
962
+ .cg-form__help {
963
+ margin: var(--cg-s2) 0 0;
964
+ font-family: var(--cogenta-font-sans);
965
+ font-size: var(--cg-text-sm);
966
+ color: var(--cg-ink-faint);
967
+ }
968
+
969
+ .cg-form__choice {
970
+ display: inline-flex;
971
+ align-items: center;
972
+ gap: var(--cg-s2);
973
+ margin-inline-end: var(--cg-s4);
974
+ font-weight: normal;
975
+ }
976
+
977
+ .cg-form__honeypot,
978
+ .cg-comment__honeypot {
979
+ position: absolute;
980
+ inline-size: 1px;
981
+ block-size: 1px;
982
+ overflow: hidden;
983
+ inset-inline-start: -9999px;
984
+ }
985
+
986
+ .cg-comments {
987
+ margin-block-start: var(--cg-section-y);
988
+ padding-block-start: var(--cg-s8);
989
+ padding-block-end: var(--cg-section-y);
990
+ border-block-start: 3px double var(--cg-rule-heavy);
991
+ font-family: var(--cogenta-font-sans);
992
+ }
993
+
994
+ .cg-comments > h2 {
995
+ font-size: var(--cg-text-xl);
996
+ margin-block-end: var(--cg-s6);
997
+ }
998
+
999
+ .cg-comments__list,
1000
+ .cg-comment__replies {
1001
+ margin: 0;
1002
+ padding: 0;
1003
+ list-style: none;
1004
+ }
1005
+
1006
+ .cg-comment {
1007
+ padding-block: var(--cg-s5);
1008
+ border-block-end: 1px solid var(--cg-rule-soft);
1009
+ }
1010
+
1011
+ .cg-comment__replies {
1012
+ padding-block-start: var(--cg-s5);
1013
+ }
1014
+
1015
+ .cg-comment__replies .cg-comment {
1016
+ padding-inline-start: var(--cg-s6);
1017
+ border-inline-start: 2px solid var(--cg-rule-soft);
1018
+ border-block-end: 0;
1019
+ }
1020
+
1021
+ .cg-comment__meta {
1022
+ display: flex;
1023
+ gap: var(--cg-s3);
1024
+ align-items: baseline;
1025
+ font-size: var(--cg-text-sm);
1026
+ color: var(--cg-ink-faint);
1027
+ margin-block-end: var(--cg-s2);
1028
+ }
1029
+
1030
+ .cg-comment__author {
1031
+ font-weight: var(--cg-weight-semibold);
1032
+ color: var(--cg-ink);
1033
+ }
1034
+
1035
+ .cg-comment__body {
1036
+ margin: 0;
1037
+ }