@cogenta/theme-docs 0.3.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 +15 -0
  9. package/dist/src/render/blocks/accordion.js.map +1 -0
  10. package/dist/src/render/blocks/collection-list.d.ts +14 -0
  11. package/dist/src/render/blocks/collection-list.d.ts.map +1 -0
  12. package/dist/src/render/blocks/collection-list.js +77 -0
  13. package/dist/src/render/blocks/collection-list.js.map +1 -0
  14. package/dist/src/render/blocks/cta.d.ts +4 -0
  15. package/dist/src/render/blocks/cta.d.ts.map +1 -0
  16. package/dist/src/render/blocks/cta.js +7 -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 +71 -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 +15 -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 +10 -0
  31. package/dist/src/render/blocks/gallery.d.ts.map +1 -0
  32. package/dist/src/render/blocks/gallery.js +19 -0
  33. package/dist/src/render/blocks/gallery.js.map +1 -0
  34. package/dist/src/render/blocks/hero.d.ts +16 -0
  35. package/dist/src/render/blocks/hero.d.ts.map +1 -0
  36. package/dist/src/render/blocks/hero.js +28 -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 +16 -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 +22 -0
  45. package/dist/src/render/blocks/logos.js.map +1 -0
  46. package/dist/src/render/blocks/media-figure.d.ts +10 -0
  47. package/dist/src/render/blocks/media-figure.d.ts.map +1 -0
  48. package/dist/src/render/blocks/media-figure.js +25 -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 +28 -0
  53. package/dist/src/render/blocks/pricing-table.js.map +1 -0
  54. package/dist/src/render/blocks/prose.d.ts +4 -0
  55. package/dist/src/render/blocks/prose.d.ts.map +1 -0
  56. package/dist/src/render/blocks/prose.js +36 -0
  57. package/dist/src/render/blocks/prose.js.map +1 -0
  58. package/dist/src/render/blocks/quote.d.ts +9 -0
  59. package/dist/src/render/blocks/quote.d.ts.map +1 -0
  60. package/dist/src/render/blocks/quote.js +22 -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 +15 -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 +11 -0
  69. package/dist/src/render/blocks/stats.js.map +1 -0
  70. package/dist/src/render/blocks/testimonial.d.ts +11 -0
  71. package/dist/src/render/blocks/testimonial.d.ts.map +1 -0
  72. package/dist/src/render/blocks/testimonial.js +20 -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 +94 -0
  77. package/dist/src/render/chrome.js.map +1 -0
  78. package/dist/src/render/render-block.d.ts +15 -0
  79. package/dist/src/render/render-block.d.ts.map +1 -0
  80. package/dist/src/render/render-block.js +176 -0
  81. package/dist/src/render/render-block.js.map +1 -0
  82. package/dist/src/render/term-archive.d.ts +10 -0
  83. package/dist/src/render/term-archive.d.ts.map +1 -0
  84. package/dist/src/render/term-archive.js +32 -0
  85. package/dist/src/render/term-archive.js.map +1 -0
  86. package/dist/theme.config.d.ts +16 -0
  87. package/dist/theme.config.d.ts.map +1 -0
  88. package/dist/theme.config.js +46 -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 +170 -0
  94. package/src/render/blocks/cta.ts +25 -0
  95. package/src/render/blocks/embed.ts +94 -0
  96. package/src/render/blocks/faq.ts +46 -0
  97. package/src/render/blocks/feature-grid.ts +67 -0
  98. package/src/render/blocks/gallery.ts +39 -0
  99. package/src/render/blocks/hero.ts +61 -0
  100. package/src/render/blocks/logo-strip.ts +31 -0
  101. package/src/render/blocks/logos.ts +52 -0
  102. package/src/render/blocks/media-figure.ts +36 -0
  103. package/src/render/blocks/pricing-table.ts +72 -0
  104. package/src/render/blocks/prose.ts +49 -0
  105. package/src/render/blocks/quote.ts +35 -0
  106. package/src/render/blocks/stat-counter.ts +37 -0
  107. package/src/render/blocks/stats.ts +38 -0
  108. package/src/render/blocks/testimonial.ts +36 -0
  109. package/src/render/chrome.ts +124 -0
  110. package/src/render/render-block.ts +305 -0
  111. package/src/render/term-archive.ts +78 -0
  112. package/src/styles/archive.css +39 -0
  113. package/src/styles/base.css +1106 -0
  114. package/src/styles/blocks.css +1238 -0
  115. package/src/styles/theme.css +34 -0
  116. package/src/styles/tokens.css +307 -0
  117. package/tokens.json +36 -0
@@ -0,0 +1,305 @@
1
+ import { type BlockRegistry, VOCABULARY_NAMES, type VocabularyBlock } from '@cogenta/blocks'
2
+ import {
3
+ type ContentEntry,
4
+ entryHref,
5
+ entryTitle,
6
+ type FetchedEntries,
7
+ type HtmlElement,
8
+ h,
9
+ type PageContent,
10
+ pageHasOwnHeading,
11
+ type RenderContext,
12
+ renderEntryHeader,
13
+ resolveBlockForRender,
14
+ withBlockKey,
15
+ withBlockVariant,
16
+ } from '@cogenta/theme-kit'
17
+ import { renderAccordion } from './blocks/accordion.js'
18
+ import { renderCollectionList } from './blocks/collection-list.js'
19
+ import { renderCta } from './blocks/cta.js'
20
+ import { renderEmbed } from './blocks/embed.js'
21
+ import { renderFaq } from './blocks/faq.js'
22
+ import { renderFeatureGrid } from './blocks/feature-grid.js'
23
+ import { renderGallery } from './blocks/gallery.js'
24
+ import { renderHero } from './blocks/hero.js'
25
+ import { renderLogoStrip } from './blocks/logo-strip.js'
26
+ import { renderLogos } from './blocks/logos.js'
27
+ import { renderMediaFigure } from './blocks/media-figure.js'
28
+ import { renderPricingTable } from './blocks/pricing-table.js'
29
+ import { renderProse } from './blocks/prose.js'
30
+ import { renderQuote } from './blocks/quote.js'
31
+ import { renderStatCounter } from './blocks/stat-counter.js'
32
+ import { renderStats } from './blocks/stats.js'
33
+ import { renderTestimonial } from './blocks/testimonial.js'
34
+
35
+ export type { FetchedEntries, PageContent }
36
+
37
+ export function renderBlock(
38
+ block: VocabularyBlock,
39
+ ctx: RenderContext,
40
+ entries: FetchedEntries = {},
41
+ registry?: BlockRegistry,
42
+ ): HtmlElement | null {
43
+ const resolved = resolveBlockForRender(block, VOCABULARY_NAMES, registry)
44
+ if (resolved === null) return null
45
+ const known = resolved as unknown as VocabularyBlock
46
+ return withBlockVariant(renderKnownBlock(known, ctx, entries), known.variant)
47
+ }
48
+
49
+ function renderKnownBlock(
50
+ known: VocabularyBlock,
51
+ ctx: RenderContext,
52
+ entries: FetchedEntries,
53
+ ): HtmlElement | null {
54
+ switch (known._type) {
55
+ case 'hero':
56
+ return renderHero(known, ctx)
57
+ case 'prose':
58
+ return renderProse(known, ctx)
59
+ case 'mediaFigure':
60
+ return renderMediaFigure(known, ctx)
61
+ case 'featureGrid':
62
+ return renderFeatureGrid(known, ctx)
63
+ case 'cta':
64
+ return renderCta(known, ctx)
65
+ case 'gallery':
66
+ return renderGallery(known, ctx)
67
+ case 'quote':
68
+ return renderQuote(known, ctx)
69
+ case 'faq':
70
+ return renderFaq(known, ctx)
71
+ case 'stats':
72
+ return renderStats(known, ctx)
73
+ case 'logos':
74
+ return renderLogos(known, ctx)
75
+ case 'collectionList':
76
+ return renderCollectionList(known, ctx, entries[known._key] ?? [])
77
+ case 'embed':
78
+ return renderEmbed(known, ctx)
79
+ case 'testimonial':
80
+ return renderTestimonial(known, ctx)
81
+ case 'pricingTable':
82
+ return renderPricingTable(known, ctx)
83
+ case 'accordion':
84
+ return renderAccordion(known, ctx)
85
+ case 'statCounter':
86
+ return renderStatCounter(known, ctx)
87
+ case 'logoStrip':
88
+ return renderLogoStrip(known, ctx)
89
+ default: {
90
+ const unreachable: never = known
91
+ void unreachable
92
+ return null
93
+ }
94
+ }
95
+ }
96
+
97
+ /**
98
+ * The name every doc page's own blueprint-seeded sidebar `collectionList`
99
+ * targets — checked structurally (first block, this collection) rather than
100
+ * by any flag on the block, because contract B carries no "this is chrome,
101
+ * not content" bit and inventing one would be a contract change for a
102
+ * single theme's layout choice.
103
+ */
104
+ const DOC_PAGE_COLLECTION = 'doc_page'
105
+
106
+ function isDocSidebarBlock(block: VocabularyBlock): boolean {
107
+ return block._type === 'collectionList' && block.collection === DOC_PAGE_COLLECTION
108
+ }
109
+
110
+ /** The sidebar entry whose own link resolves to the page being rendered — the "current page" the brief asks the sidebar to highlight and the breadcrumb to name. */
111
+ function findCurrentEntry(
112
+ entries: readonly ContentEntry[],
113
+ ctx: RenderContext,
114
+ ): ContentEntry | undefined {
115
+ return entries.find((entry) => entryHref(entry, ctx) === ctx.url.pathname)
116
+ }
117
+
118
+ /**
119
+ * The doc-page sidebar — grouped by each entry's own `section` field, in the
120
+ * order the entries were fetched (the blueprint seeds them in `order`
121
+ * within a section already; `collectionList.sort` cannot name `section`/
122
+ * `order`, so an editor who reorders sections relies on the fetch order,
123
+ * exactly like the "All guides" index on the home page does).
124
+ */
125
+ function renderSidebarPanel(
126
+ entries: readonly ContentEntry[],
127
+ ctx: RenderContext,
128
+ currentHref: string,
129
+ ): HtmlElement {
130
+ const groups = new Map<string, ContentEntry[]>()
131
+ for (const entry of entries) {
132
+ const section =
133
+ typeof entry.section === 'string' && entry.section !== ''
134
+ ? entry.section
135
+ : ctx.t('entry.untitled')
136
+ const list = groups.get(section) ?? []
137
+ list.push(entry)
138
+ groups.set(section, list)
139
+ }
140
+
141
+ return h(
142
+ 'nav',
143
+ { class: 'cg-docs__nav-panel', 'aria-label': 'Documentation' },
144
+ [...groups.entries()].map(([section, sectionEntries]) =>
145
+ h(
146
+ 'div',
147
+ { class: 'cg-docs__nav-group' },
148
+ h('p', { class: 'cg-docs__nav-heading' }, section),
149
+ h(
150
+ 'ul',
151
+ { class: 'cg-docs__nav-items' },
152
+ sectionEntries.map((entry) => {
153
+ const href = entryHref(entry, ctx)
154
+ const isCurrent = href === currentHref
155
+ return h(
156
+ 'li',
157
+ {},
158
+ h(
159
+ 'a',
160
+ {
161
+ class: 'cg-docs__nav-link',
162
+ href,
163
+ 'aria-current': isCurrent ? 'page' : undefined,
164
+ },
165
+ entryTitle(entry, ctx),
166
+ ),
167
+ )
168
+ }),
169
+ ),
170
+ ),
171
+ ),
172
+ )
173
+ }
174
+
175
+ /**
176
+ * The sidebar, in two copies — the same zero-JS technique `chrome.ts` already
177
+ * uses for the header's own mobile menu, and for the same reason: Chrome (and
178
+ * every other engine implementing the current HTML rendering rules) hides a
179
+ * closed `<details>`'s non-summary content through its own internal
180
+ * `::details-content` box, not through the plain CSS `display: none` the spec
181
+ * text describes — so a stylesheet rule that sets `display: block` on that
182
+ * content, however specific, does not reliably bring it back while the
183
+ * element itself stays closed. Verified live: a build with a single
184
+ * `<details>` forced open only above the two-column breakpoint rendered an
185
+ * empty sidebar column at 1280px in a real Chrome tab, despite every
186
+ * computed style reporting `display: block`.
187
+ *
188
+ * The fix is the same one already proven for the header: a plain, always-
189
+ * live `<nav>` for the desktop column (nothing to collapse, so nothing for
190
+ * the browser to hide), and a **separate** `<details>` disclosure — a full
191
+ * second copy of the same panel — for narrow viewports. Exactly one of the
192
+ * two is ever `display: block` at a given viewport width (`base.css`), so a
193
+ * screen reader is never offered two "Documentation" navigations at once,
194
+ * matching the header's own accessibility guarantee.
195
+ */
196
+ function renderSidebar(
197
+ entries: readonly ContentEntry[],
198
+ ctx: RenderContext,
199
+ currentHref: string,
200
+ ): HtmlElement {
201
+ return h('div', { class: 'cg-docs__nav-desktop' }, renderSidebarPanel(entries, ctx, currentHref))
202
+ }
203
+
204
+ function renderSidebarMobile(
205
+ entries: readonly ContentEntry[],
206
+ ctx: RenderContext,
207
+ currentHref: string,
208
+ ): HtmlElement {
209
+ return h(
210
+ 'details',
211
+ { class: 'cg-docs__nav-mobile' },
212
+ h('summary', { class: 'cg-docs__nav-toggle' }, 'On this site'),
213
+ renderSidebarPanel(entries, ctx, currentHref),
214
+ )
215
+ }
216
+
217
+ function renderBreadcrumb(section: string | undefined, title: string): HtmlElement {
218
+ return h(
219
+ 'nav',
220
+ { class: 'cg-docs__breadcrumb', 'aria-label': 'Breadcrumb' },
221
+ h(
222
+ 'ol',
223
+ {},
224
+ section === undefined ? null : h('li', {}, section),
225
+ h('li', { 'aria-current': 'page' }, title),
226
+ ),
227
+ )
228
+ }
229
+
230
+ /**
231
+ * A doc page: two columns, CSS-only. The sidebar comes from the page's own
232
+ * *first* block — a `collectionList` on `doc_page` the blueprint seeds on
233
+ * every doc page for exactly this purpose — rendered as navigation rather
234
+ * than as a card list, and dropped from the ordinary block stream so it
235
+ * never also appears as content. The remaining blocks render in the content
236
+ * column, unchanged.
237
+ */
238
+ function renderDocPage(
239
+ page: PageContent,
240
+ ctx: RenderContext,
241
+ sidebarBlock: VocabularyBlock,
242
+ entries: FetchedEntries,
243
+ registry: BlockRegistry | undefined,
244
+ ): HtmlElement {
245
+ const sidebarEntries = entries[sidebarBlock._key] ?? []
246
+ const currentHref = ctx.url.pathname
247
+ const current = findCurrentEntry(sidebarEntries, ctx)
248
+ const section = typeof current?.section === 'string' ? current.section : undefined
249
+ const contentBlocks = page.blocks.slice(1)
250
+ const hasOwnHeading = pageHasOwnHeading(contentBlocks)
251
+ const entryHeader = renderEntryHeader(page, ctx)
252
+
253
+ return h(
254
+ 'main',
255
+ { class: 'cg-main cg-docs', id: 'cg-main' },
256
+ withBlockKey(
257
+ h(
258
+ 'div',
259
+ { class: 'cg-docs__nav' },
260
+ renderSidebar(sidebarEntries, ctx, currentHref),
261
+ renderSidebarMobile(sidebarEntries, ctx, currentHref),
262
+ ),
263
+ sidebarBlock._key,
264
+ ),
265
+ h(
266
+ 'div',
267
+ { class: 'cg-docs__content' },
268
+ renderBreadcrumb(section, page.title),
269
+ entryHeader ?? (hasOwnHeading ? null : h('h1', { class: 'cg-docs__title' }, page.title)),
270
+ contentBlocks.map((block) =>
271
+ withBlockKey(renderBlock(block, ctx, entries, registry), block._key),
272
+ ),
273
+ ),
274
+ )
275
+ }
276
+
277
+ /**
278
+ * `<main id="cg-main">` is mandatory: it is the skip-link's target, written
279
+ * once by `@cogenta/cli`'s own render path.
280
+ *
281
+ * `withBlockKey` stamps every rendered block with its contract-B `_key`, on
282
+ * every page including a doc page's content column — the visual page
283
+ * builder maps a clicked element back to the block that produced it, for
284
+ * this theme exactly as for every other one.
285
+ */
286
+ export function renderPage(
287
+ page: PageContent,
288
+ ctx: RenderContext,
289
+ entries: FetchedEntries = {},
290
+ registry?: BlockRegistry,
291
+ ): HtmlElement {
292
+ const first = page.blocks[0]
293
+ if (first !== undefined && isDocSidebarBlock(first)) {
294
+ return renderDocPage(page, ctx, first, entries, registry)
295
+ }
296
+
297
+ return h(
298
+ 'main',
299
+ { class: 'cg-main', id: 'cg-main' },
300
+ pageHasOwnHeading(page.blocks) ? null : h('h1', { class: 'cg-page__title' }, page.title),
301
+ page.blocks.map((block) =>
302
+ withBlockKey(renderBlock(block, ctx, entries, registry), block._key),
303
+ ),
304
+ )
305
+ }
@@ -0,0 +1,78 @@
1
+ import { type HtmlElement, h, type TermArchiveInput } from '@cogenta/theme-kit'
2
+
3
+ /**
4
+ * The taxonomy-term archive (contract D `theme@1.3`) — a simple titled list,
5
+ * deliberately: a documentation site's own information architecture is the
6
+ * sidebar (`section`/`order`, plain fields), not a taxonomy, so this page is
7
+ * the plain fallback for a term an editor still chooses to classify content
8
+ * under, not a second navigation surface competing with the sidebar.
9
+ */
10
+ export function renderTermArchive(input: TermArchiveInput): HtmlElement {
11
+ const rows = input.entries.map((entry) =>
12
+ h(
13
+ 'li',
14
+ { class: 'cg-list__row' },
15
+ h(
16
+ 'div',
17
+ { class: 'cg-list__body' },
18
+ h(
19
+ 'h2',
20
+ { class: 'cg-list__title' },
21
+ entry.href === null
22
+ ? entry.title
23
+ : h('a', { class: 'cg-list__link', href: entry.href }, entry.title),
24
+ ),
25
+ entry.summary === null ? null : h('p', { class: 'cg-list__excerpt' }, entry.summary),
26
+ ),
27
+ entry.publishedAt === null
28
+ ? null
29
+ : h(
30
+ 'time',
31
+ { class: 'cg-list__date', datetime: entry.publishedAt },
32
+ entry.publishedAt.slice(0, 10),
33
+ ),
34
+ ),
35
+ )
36
+
37
+ return h(
38
+ 'main',
39
+ { class: 'cg-main cg-archive', id: 'cg-main' },
40
+ input.ancestors.length === 0
41
+ ? null
42
+ : h(
43
+ 'nav',
44
+ { class: 'cg-archive__breadcrumb', 'aria-label': input.labels.breadcrumb },
45
+ h(
46
+ 'ol',
47
+ {},
48
+ ...input.ancestors.map((l) => h('li', {}, h('a', { href: l.href }, l.label))),
49
+ ),
50
+ ),
51
+ h('h1', { class: 'cg-page__title' }, input.term.label),
52
+ input.children.length === 0
53
+ ? null
54
+ : h(
55
+ 'ul',
56
+ { class: 'cg-archive__children', 'aria-label': input.labels.subterms },
57
+ ...input.children.map((c) => h('li', {}, h('a', { href: c.href }, c.label))),
58
+ ),
59
+ rows.length === 0
60
+ ? h('p', { class: 'cg-list__empty' }, input.labels.empty)
61
+ : h('ul', { class: 'cg-list__items' }, ...rows),
62
+ pager(input),
63
+ )
64
+ }
65
+
66
+ function pager(input: TermArchiveInput): HtmlElement | null {
67
+ if (input.page.previousHref === null && input.page.nextHref === null) return null
68
+ return h(
69
+ 'nav',
70
+ { class: 'cg-archive__pager', 'aria-label': input.labels.pagination },
71
+ input.page.previousHref === null
72
+ ? null
73
+ : h('a', { rel: 'prev', href: input.page.previousHref }, input.labels.previous),
74
+ input.page.nextHref === null
75
+ ? null
76
+ : h('a', { rel: 'next', href: input.page.nextHref }, input.labels.next),
77
+ )
78
+ }
@@ -0,0 +1,39 @@
1
+ /*
2
+ * The taxonomy-term archive (contract D `theme@1.3`) — a simple titled list.
3
+ *
4
+ * Only the three things an archive adds beyond what `collectionList` already
5
+ * styles — a breadcrumb, a sub-term row, a prev/next pager. The entry list
6
+ * itself reuses `cg-list__items`/`cg-list__row`, on purpose: an archive of
7
+ * entries must look like this theme's own list of entries.
8
+ */
9
+
10
+ .cg-archive {
11
+ max-inline-size: var(--cg-page);
12
+ margin-inline: auto;
13
+ padding: var(--cg-s10) var(--cg-gutter);
14
+ }
15
+
16
+ .cg-archive__breadcrumb ol,
17
+ .cg-archive__children {
18
+ display: flex;
19
+ flex-wrap: wrap;
20
+ gap: var(--cg-s3);
21
+ margin: 0 0 var(--cg-s4);
22
+ padding: 0;
23
+ list-style: none;
24
+ font-size: var(--cg-text-sm);
25
+ }
26
+
27
+ .cg-archive__children {
28
+ margin-block: var(--cg-s4) var(--cg-s8);
29
+ }
30
+
31
+ .cg-archive__pager {
32
+ display: flex;
33
+ justify-content: space-between;
34
+ gap: var(--cg-s4);
35
+ margin-block-start: var(--cg-s10);
36
+ padding-block-start: var(--cg-s5);
37
+ border-block-start: 1px solid var(--cg-line-soft);
38
+ font-weight: var(--cg-weight-semibold);
39
+ }