@cogenta/theme-entreprise 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 (115) 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/blocks/accordion.d.ts.map +1 -1
  6. package/dist/src/render/blocks/accordion.js +12 -15
  7. package/dist/src/render/blocks/accordion.js.map +1 -1
  8. package/dist/src/render/blocks/collection-list.d.ts +5 -7
  9. package/dist/src/render/blocks/collection-list.d.ts.map +1 -1
  10. package/dist/src/render/blocks/collection-list.js +48 -32
  11. package/dist/src/render/blocks/collection-list.js.map +1 -1
  12. package/dist/src/render/blocks/cta.d.ts +6 -6
  13. package/dist/src/render/blocks/cta.d.ts.map +1 -1
  14. package/dist/src/render/blocks/cta.js +12 -12
  15. package/dist/src/render/blocks/cta.js.map +1 -1
  16. package/dist/src/render/blocks/embed.d.ts.map +1 -1
  17. package/dist/src/render/blocks/embed.js +22 -27
  18. package/dist/src/render/blocks/embed.js.map +1 -1
  19. package/dist/src/render/blocks/faq.d.ts.map +1 -1
  20. package/dist/src/render/blocks/faq.js +13 -16
  21. package/dist/src/render/blocks/faq.js.map +1 -1
  22. package/dist/src/render/blocks/feature-grid.d.ts.map +1 -1
  23. package/dist/src/render/blocks/feature-grid.js +22 -22
  24. package/dist/src/render/blocks/feature-grid.js.map +1 -1
  25. package/dist/src/render/blocks/gallery.d.ts +7 -8
  26. package/dist/src/render/blocks/gallery.d.ts.map +1 -1
  27. package/dist/src/render/blocks/gallery.js +16 -14
  28. package/dist/src/render/blocks/gallery.js.map +1 -1
  29. package/dist/src/render/blocks/hero.d.ts +13 -8
  30. package/dist/src/render/blocks/hero.d.ts.map +1 -1
  31. package/dist/src/render/blocks/hero.js +27 -17
  32. package/dist/src/render/blocks/hero.js.map +1 -1
  33. package/dist/src/render/blocks/logo-strip.d.ts.map +1 -1
  34. package/dist/src/render/blocks/logo-strip.js +14 -11
  35. package/dist/src/render/blocks/logo-strip.js.map +1 -1
  36. package/dist/src/render/blocks/logos.d.ts.map +1 -1
  37. package/dist/src/render/blocks/logos.js +21 -12
  38. package/dist/src/render/blocks/logos.js.map +1 -1
  39. package/dist/src/render/blocks/media-figure.d.ts +10 -6
  40. package/dist/src/render/blocks/media-figure.d.ts.map +1 -1
  41. package/dist/src/render/blocks/media-figure.js +18 -13
  42. package/dist/src/render/blocks/media-figure.js.map +1 -1
  43. package/dist/src/render/blocks/pricing-table.d.ts.map +1 -1
  44. package/dist/src/render/blocks/pricing-table.js +15 -11
  45. package/dist/src/render/blocks/pricing-table.js.map +1 -1
  46. package/dist/src/render/blocks/prose.d.ts +9 -3
  47. package/dist/src/render/blocks/prose.d.ts.map +1 -1
  48. package/dist/src/render/blocks/prose.js +11 -4
  49. package/dist/src/render/blocks/prose.js.map +1 -1
  50. package/dist/src/render/blocks/quote.d.ts +10 -10
  51. package/dist/src/render/blocks/quote.d.ts.map +1 -1
  52. package/dist/src/render/blocks/quote.js +14 -13
  53. package/dist/src/render/blocks/quote.js.map +1 -1
  54. package/dist/src/render/blocks/stat-counter.d.ts.map +1 -1
  55. package/dist/src/render/blocks/stat-counter.js +11 -13
  56. package/dist/src/render/blocks/stat-counter.js.map +1 -1
  57. package/dist/src/render/blocks/stats.d.ts.map +1 -1
  58. package/dist/src/render/blocks/stats.js +12 -13
  59. package/dist/src/render/blocks/stats.js.map +1 -1
  60. package/dist/src/render/blocks/testimonial.d.ts +9 -9
  61. package/dist/src/render/blocks/testimonial.d.ts.map +1 -1
  62. package/dist/src/render/blocks/testimonial.js +15 -14
  63. package/dist/src/render/blocks/testimonial.js.map +1 -1
  64. package/dist/src/render/chrome.d.ts +3 -1
  65. package/dist/src/render/chrome.d.ts.map +1 -1
  66. package/dist/src/render/chrome.js +71 -46
  67. package/dist/src/render/chrome.js.map +1 -1
  68. package/dist/src/render/layout.d.ts +26 -0
  69. package/dist/src/render/layout.d.ts.map +1 -0
  70. package/dist/src/render/layout.js +51 -0
  71. package/dist/src/render/layout.js.map +1 -0
  72. package/dist/src/render/render-block.d.ts.map +1 -1
  73. package/dist/src/render/render-block.js +23 -2
  74. package/dist/src/render/render-block.js.map +1 -1
  75. package/dist/src/render/term-archive.d.ts +8 -6
  76. package/dist/src/render/term-archive.d.ts.map +1 -1
  77. package/dist/src/render/term-archive.js +22 -16
  78. package/dist/src/render/term-archive.js.map +1 -1
  79. package/dist/src/render/widget-areas.d.ts +13 -0
  80. package/dist/src/render/widget-areas.d.ts.map +1 -0
  81. package/dist/src/render/widget-areas.js +20 -0
  82. package/dist/src/render/widget-areas.js.map +1 -0
  83. package/dist/theme.config.js +2 -2
  84. package/dist/theme.config.js.map +1 -1
  85. package/package.json +5 -5
  86. package/src/index.ts +1 -0
  87. package/src/render/blocks/accordion.ts +32 -27
  88. package/src/render/blocks/collection-list.ts +84 -53
  89. package/src/render/blocks/cta.ts +27 -28
  90. package/src/render/blocks/embed.ts +46 -43
  91. package/src/render/blocks/faq.ts +25 -21
  92. package/src/render/blocks/feature-grid.ts +42 -35
  93. package/src/render/blocks/gallery.ts +21 -16
  94. package/src/render/blocks/hero.ts +40 -28
  95. package/src/render/blocks/logo-strip.ts +26 -16
  96. package/src/render/blocks/logos.ts +33 -17
  97. package/src/render/blocks/media-figure.ts +22 -14
  98. package/src/render/blocks/pricing-table.ts +26 -15
  99. package/src/render/blocks/prose.ts +18 -4
  100. package/src/render/blocks/quote.ts +18 -14
  101. package/src/render/blocks/stat-counter.ts +25 -20
  102. package/src/render/blocks/stats.ts +31 -21
  103. package/src/render/blocks/testimonial.ts +22 -18
  104. package/src/render/chrome.ts +84 -49
  105. package/src/render/layout.ts +67 -0
  106. package/src/render/render-block.ts +24 -1
  107. package/src/render/term-archive.ts +54 -50
  108. package/src/render/widget-areas.ts +23 -0
  109. package/src/styles/archive.css +135 -38
  110. package/src/styles/base.css +557 -430
  111. package/src/styles/blocks.css +1192 -1000
  112. package/src/styles/theme.css +18 -24
  113. package/src/styles/tokens.css +162 -192
  114. package/src/styles/widgets.css +913 -0
  115. package/tokens.json +17 -17
@@ -1,8 +1,6 @@
1
1
  /*
2
- * Document, accessibility floor, page frame, chrome (header/footer/nav) and
3
- * the one control the theme ships (an action link). Everything here reads
4
- * the design system from `tokens.css`; nothing here reads a `--cogenta-*`
5
- * token directly.
2
+ * Document, accessibility floor, the grid, the chrome and the one control
3
+ * the theme ships (an action link). Everything reads `tokens.css`.
6
4
  */
7
5
 
8
6
  /* --------------------------------------------------------------------------
@@ -15,207 +13,228 @@
15
13
  box-sizing: border-box;
16
14
  }
17
15
 
16
+ html {
17
+ -webkit-text-size-adjust: 100%;
18
+ text-size-adjust: 100%;
19
+ scroll-padding-block-start: calc(var(--cg-header-height) + var(--cg-s4));
20
+ }
21
+
18
22
  body {
19
23
  margin: 0;
20
24
  background: var(--cg-canvas);
21
25
  color: var(--cg-ink);
22
- font-family: var(--cogenta-font-sans);
26
+ font-family: var(--cg-font-text);
23
27
  font-size: var(--cg-text-md);
24
- line-height: var(--cg-leading-normal);
28
+ font-weight: var(--cg-weight-regular);
29
+ line-height: var(--cg-leading-text);
25
30
  font-kerning: normal;
31
+ font-optical-sizing: auto;
26
32
  font-variant-ligatures: common-ligatures;
27
- text-underline-offset: 0.15em;
28
- text-decoration-thickness: from-font;
29
- -webkit-text-size-adjust: 100%;
33
+ font-synthesis: none;
34
+ text-rendering: optimizeLegibility;
35
+ -webkit-font-smoothing: antialiased;
30
36
  }
31
37
 
32
38
  ::selection {
33
- background: var(--cg-accent-soft);
34
- color: var(--cg-accent-soft-fg);
39
+ background: var(--cg-ink);
40
+ color: var(--cg-canvas);
35
41
  }
36
42
 
37
43
  img,
38
44
  video,
39
45
  iframe {
40
- max-width: 100%;
41
- height: auto;
46
+ display: block;
47
+ max-inline-size: 100%;
48
+ block-size: auto;
42
49
  }
43
50
 
44
51
  img {
45
- display: block;
46
52
  object-fit: cover;
47
53
  }
48
54
 
55
+ :where(h1, h2, h3, h4, h5, h6) {
56
+ font-family: var(--cg-font-display);
57
+ font-weight: var(--cg-weight-regular);
58
+ line-height: var(--cg-leading-heading);
59
+ letter-spacing: var(--cg-tracking-heading);
60
+ text-wrap: balance;
61
+ margin: 0;
62
+ }
63
+
64
+ :where(p, li, dd, figcaption, blockquote) {
65
+ text-wrap: pretty;
66
+ }
67
+
49
68
  :where(a) {
50
69
  color: var(--cg-accent);
51
- text-decoration-color: color-mix(in oklab, var(--cg-accent) 40%, transparent);
70
+ text-decoration-line: underline;
71
+ text-decoration-thickness: var(--cg-rule);
72
+ text-underline-offset: 0.2em;
52
73
  transition:
53
- color var(--cg-duration-fast) var(--cg-ease),
54
- text-decoration-color var(--cg-duration-fast) var(--cg-ease);
74
+ color var(--cg-duration) var(--cg-ease),
75
+ text-decoration-color var(--cg-duration) var(--cg-ease);
55
76
  }
56
77
 
57
78
  :where(a:hover) {
58
79
  color: var(--cg-accent-hover);
59
- text-decoration-color: currentColor;
60
80
  }
61
81
 
62
82
  :where(hr) {
63
- block-size: 1px;
83
+ block-size: var(--cg-rule);
64
84
  border: 0;
65
85
  margin-block: var(--cg-s10);
66
86
  background: var(--cg-line);
67
87
  }
68
88
 
89
+ .cg-visually-hidden {
90
+ position: absolute;
91
+ inline-size: 1px;
92
+ block-size: 1px;
93
+ margin: -1px;
94
+ padding: 0;
95
+ overflow: hidden;
96
+ clip-path: inset(50%);
97
+ white-space: nowrap;
98
+ border: 0;
99
+ }
100
+
101
+ .cg-arrow {
102
+ display: inline-block;
103
+ inline-size: 1em;
104
+ block-size: 1em;
105
+ flex: none;
106
+ vertical-align: -0.12em;
107
+ }
108
+
69
109
  /* --------------------------------------------------------------------------
70
- Focus, targets, motion
110
+ Focus, targets, motion. Motion is a colour or an underline changing, in
111
+ under 150 ms; nothing moves in space, nothing fades in on scroll.
71
112
  -------------------------------------------------------------------------- */
72
113
 
73
- :where(a, button, summary, [tabindex]):focus-visible {
74
- outline: 2px solid var(--cg-accent);
114
+ :where(a, button, summary, input, select, textarea, [tabindex]):focus-visible {
115
+ outline: var(--cg-rule-strong) solid var(--cg-accent);
75
116
  outline-offset: 3px;
76
- border-radius: var(--cg-radius-xs);
77
117
  }
78
118
 
79
- :where(.cg-action, .cg-faq__question, .cg-clients__link, .cg-nav-toggle-label) {
119
+ :where(.cg-action, .cg-nav-toggle-label, .cg-theme-toggle, summary) {
80
120
  min-block-size: 44px;
81
- min-inline-size: 44px;
82
- }
83
-
84
- /* A restrained entrance: blocks settle upward a few pixels as they enter
85
- the viewport, scroll-driven so it plays once per block rather than firing
86
- for all of them on load. Wrapped in a feature query because the starting
87
- state is `opacity: 0` — a browser without `animation-timeline` must never
88
- be left holding an invisible page. */
89
- @supports (animation-timeline: view()) {
90
- @media (prefers-reduced-motion: no-preference) {
91
- @keyframes cg-settle {
92
- from {
93
- opacity: 0;
94
- transform: translateY(var(--cg-s3));
95
- }
96
-
97
- to {
98
- opacity: 1;
99
- transform: none;
100
- }
101
- }
102
-
103
- .cg-block {
104
- animation: cg-settle linear both;
105
- animation-timeline: view();
106
- animation-range: entry 0% cover 20%;
107
- }
108
- }
109
121
  }
110
122
 
123
+ /* Every transition in this theme reads `--cg-duration`, so reduced motion is
124
+ one declaration rather than an `!important` sweep over every element. The
125
+ skin sheet already zeroes `--cogenta-motion-duration` under this query; this
126
+ holds even for a skin that does not. */
111
127
  @media (prefers-reduced-motion: reduce) {
112
- /* The `motion.reduced` token says the skin's motion may be removed.
113
- Nothing here conveys meaning through movement, so removing all of it,
114
- including the smooth scroll of a carousel, is safe. */
115
- *,
116
- *::before,
117
- *::after {
118
- animation-duration: 1ms !important;
119
- animation-iteration-count: 1 !important;
120
- transition-duration: 1ms !important;
121
- scroll-behavior: auto !important;
128
+ :root {
129
+ --cg-duration: 0ms;
122
130
  }
123
131
  }
124
132
 
125
133
  .cg-skip-link {
126
134
  position: absolute;
127
135
  inset-inline-start: var(--cg-s3);
128
- inset-block-start: calc(var(--cg-s3) * -8);
129
- z-index: 10;
136
+ inset-block-start: calc(var(--cg-s16) * -1);
137
+ z-index: 20;
130
138
  padding: var(--cg-s2) var(--cg-s4);
131
- background: var(--cg-ink);
132
- color: var(--cg-canvas);
133
- border-radius: var(--cg-radius-sm);
134
- font-weight: var(--cg-weight-semibold);
139
+ background: var(--cg-action);
140
+ color: var(--cg-action-fg);
141
+ font-size: var(--cg-text-ui);
142
+ font-weight: var(--cg-weight-medium);
135
143
  text-decoration: none;
136
- transition: inset-block-start var(--cg-duration) var(--cg-ease);
137
144
  }
138
145
 
139
146
  .cg-skip-link:focus-visible {
140
147
  inset-block-start: var(--cg-s3);
141
- outline-color: var(--cg-canvas);
148
+ outline-color: var(--cg-accent);
142
149
  }
143
150
 
144
151
  /* --------------------------------------------------------------------------
145
- Page frame
152
+ The grid. Every block is a full-width section around a twelve-column
153
+ container; the section rhythm is one variable, applied to all of them.
146
154
  -------------------------------------------------------------------------- */
147
155
 
148
156
  .cg-main {
149
157
  display: flow-root;
150
- /* A hero's own decorative frame and any full-bleed band can end up a
151
- fraction wider than the viewport on some zoom levels; `clip` — not
152
- `hidden` — cuts that at the edge without turning `<main>` into a scroll
153
- container, so a sticky header inside it keeps behaving normally. */
154
158
  overflow-x: clip;
159
+ padding-block-end: calc(var(--cg-section) / 2);
155
160
  }
156
161
 
157
- .cg-block {
158
- max-inline-size: var(--cg-page);
162
+ .cg-container {
163
+ display: grid;
164
+ grid-template-columns: repeat(var(--cg-columns), minmax(0, 1fr));
165
+ column-gap: var(--cg-col-gap);
166
+ align-items: start;
167
+ inline-size: 100%;
168
+ max-inline-size: calc(var(--cg-page) + var(--cg-gutter) * 2);
159
169
  margin-inline: auto;
160
- margin-block: var(--cg-section-y);
161
170
  padding-inline: var(--cg-gutter);
171
+ container-type: inline-size;
162
172
  }
163
173
 
164
- /* Every block is a page-width, gutter-padded section by default — `:where()`
165
- keeps this at zero specificity so a block that sets its own narrower
166
- measure (`.cg-quote`, `.cg-faq`, `.cg-prose`…) still wins, while a block
167
- that never set one (`.cg-hero`, `.cg-services`) no longer sits flush
168
- against the viewport edge on a wide screen. `data-variant-width="full"`
169
- below opts a block back out. */
170
- :where(.cg-main > [data-block]) {
171
- max-inline-size: var(--cg-page);
172
- margin-inline: auto;
173
- padding-inline: var(--cg-gutter);
174
+ /* Below this width a twelve-column grid only produces slivers: every child
175
+ takes the full row, and the layouts below redistribute from there. */
176
+ .cg-container > * {
177
+ grid-column: 1 / -1;
178
+ min-inline-size: 0;
179
+ }
180
+
181
+ .cg-section {
182
+ padding-block: calc(var(--cg-section) / 2);
174
183
  }
175
184
 
176
- /* --- per-block visual variant (blocks@2.0, RFC 0002) ----------------------
177
- `withBlockVariant` (`@cogenta/theme-kit`) stamps one `data-variant-<axis>`
178
- attribute per axis an author actually set — never all four, never one this
179
- theme does not resolve. Two attribute selectors give every rule here the
180
- same specificity, (0,2,0), which is what lets it override `.cg-block`
181
- above regardless of source order, without `!important` anywhere.
185
+ /* The first block under the header sits closer to it than to a sibling. */
186
+ :is(.cg-main, .cg-sidebar-layout__content) > .cg-section:first-child {
187
+ padding-block-start: calc(var(--cg-section) * 0.4);
188
+ }
182
189
 
183
- `background: 'image'` has no theme mechanism to attach an actual image to
184
- a block instance (RFC 0002 adds only the semantic token, not a media
185
- field) — resolved to the same tinted surface as the closest honest
186
- approximation this theme has, rather than silently doing nothing with a
187
- stated author intent.
188
- ------------------------------------------------------------------------- */
190
+ /* --- section heads ----------------------------------------------------------
191
+ One head for every titled block: a hairline across the full grid, and the
192
+ title set in the display serif under it. `--aside` puts the head in the
193
+ left four columns beside its content instead of above it. */
189
194
 
190
- [data-block][data-variant-background="muted"],
191
- [data-block][data-variant-background="image"] {
192
- padding-block: var(--cg-s10);
193
- border-radius: var(--cg-radius-lg);
195
+ .cg-head {
196
+ padding-block-start: var(--cg-s5);
197
+ border-block-start: var(--cg-rule) solid var(--cg-line);
198
+ margin-block-end: var(--cg-s12);
194
199
  }
195
200
 
196
- [data-block][data-variant-background="muted"] {
197
- background: var(--cg-surface-sunken);
201
+ .cg-head__title {
202
+ max-inline-size: 22ch;
203
+ font-size: var(--cg-size-heading);
204
+ line-height: var(--cg-leading-heading);
205
+ letter-spacing: var(--cg-tracking-heading);
198
206
  }
199
207
 
208
+ @media (min-width: 64rem) {
209
+ .cg-head--aside {
210
+ grid-column: 1 / span 4;
211
+ margin-block-end: 0;
212
+ }
213
+
214
+ .cg-head--aside .cg-head__title {
215
+ max-inline-size: 12ch;
216
+ }
217
+
218
+ .cg-head--sticky {
219
+ position: sticky;
220
+ inset-block-start: calc(var(--cg-header-height) + var(--cg-s6));
221
+ }
222
+ }
223
+
224
+ /* --- per-block variants (blocks@2.0, RFC 0002) --------------------------- */
225
+
226
+ [data-block][data-variant-background="muted"],
200
227
  [data-block][data-variant-background="image"] {
201
- background: var(--cg-surface-tinted);
228
+ background: var(--cg-surface-sunken);
229
+ padding-block: calc(var(--cg-section) * 0.75);
202
230
  }
203
231
 
204
232
  [data-block][data-variant-spacing="compact"] {
205
- margin-block: calc(var(--cg-section-y) / 2);
233
+ padding-block: calc(var(--cg-section) / 4);
206
234
  }
207
235
 
208
- /* No rule for "comfortable": it names this theme's existing default, so an
209
- author who picks it explicitly gets exactly what an absent `variant`
210
- already gave them — the whole point of "theme default" being a real,
211
- selectable option and not only the absence of a choice. */
212
-
213
236
  [data-block][data-variant-spacing="spacious"] {
214
- margin-block: calc(var(--cg-section-y) * 1.6);
215
- }
216
-
217
- [data-block][data-variant-align="start"] {
218
- text-align: start;
237
+ padding-block: calc(var(--cg-section) * 0.8);
219
238
  }
220
239
 
221
240
  [data-block][data-variant-align="center"] {
@@ -226,71 +245,146 @@ img {
226
245
  text-align: end;
227
246
  }
228
247
 
229
- [data-block][data-variant-width="full"] {
248
+ [data-block][data-variant-width="full"] > .cg-container {
230
249
  max-inline-size: none;
231
- padding-inline: 0;
232
250
  }
233
251
 
252
+ /* --- a page with no hero and no entry header ----------------------------- */
253
+
234
254
  .cg-page__title {
235
- max-inline-size: var(--cg-page);
236
- margin-inline: auto;
237
- margin-block: var(--cg-section-y) var(--cg-s6);
238
- padding-inline: var(--cg-gutter);
239
- font-size: var(--cg-text-3xl);
240
- line-height: var(--cg-leading-tight);
241
- letter-spacing: var(--cg-tracking-tight);
242
- font-weight: var(--cg-weight-bold);
243
- text-wrap: balance;
255
+ max-inline-size: calc(var(--cg-page) + var(--cg-gutter) * 2);
256
+ margin: 0 auto;
257
+ padding: calc(var(--cg-section) * 0.4) var(--cg-gutter) 0;
258
+ font-size: var(--cg-size-display);
259
+ line-height: var(--cg-leading-display);
260
+ letter-spacing: var(--cg-tracking-display);
244
261
  }
245
262
 
246
263
  /* --------------------------------------------------------------------------
247
- Chrome — header
264
+ Actions: a filled ink rectangle for the primary intent, an underlined link
265
+ with an arrow for the rest. Square corners, no lift, no shadow.
266
+ -------------------------------------------------------------------------- */
267
+
268
+ .cg-actions {
269
+ display: flex;
270
+ flex-wrap: wrap;
271
+ align-items: center;
272
+ gap: var(--cg-s3) var(--cg-s8);
273
+ margin: 0;
274
+ padding: 0;
275
+ list-style: none;
276
+ }
277
+
278
+ .cg-action {
279
+ display: inline-flex;
280
+ align-items: center;
281
+ gap: var(--cg-s3);
282
+ font-family: var(--cg-font-text);
283
+ font-size: var(--cg-text-ui);
284
+ font-weight: var(--cg-weight-medium);
285
+ line-height: 1.2;
286
+ letter-spacing: 0.005em;
287
+ white-space: nowrap;
288
+ text-decoration: none;
289
+ transition:
290
+ background-color var(--cg-duration) var(--cg-ease),
291
+ color var(--cg-duration) var(--cg-ease),
292
+ border-color var(--cg-duration) var(--cg-ease);
293
+ }
294
+
295
+ .cg-action[data-emphasis="primary"] {
296
+ padding: var(--cg-s3) var(--cg-s6);
297
+ background: var(--cg-action);
298
+ color: var(--cg-action-fg);
299
+ border: var(--cg-rule) solid var(--cg-action);
300
+ border-radius: var(--cg-radius);
301
+ }
302
+
303
+ .cg-action[data-emphasis="primary"]:hover {
304
+ background: var(--cg-action-hover);
305
+ border-color: var(--cg-action-hover);
306
+ color: var(--cg-action-hover-fg);
307
+ }
308
+
309
+ /* A text link with an arrow after it. Not a flex container: in one, the
310
+ words and the arrow are two flex items and each gets its own underline.
311
+ As a block of inline content the words carry one continuous underline,
312
+ and the arrow, an atomic inline box, inherits none (CSS Text Decoration
313
+ §2: decorations are not propagated to inline-blocks). */
314
+ .cg-action[data-emphasis="secondary"] {
315
+ display: inline-block;
316
+ padding-block: var(--cg-s3);
317
+ padding-inline: 0;
318
+ color: var(--cg-ink);
319
+ text-decoration-line: underline;
320
+ text-decoration-thickness: var(--cg-rule);
321
+ text-decoration-color: var(--cg-line-strong);
322
+ text-underline-offset: 0.35em;
323
+ }
324
+
325
+ .cg-action[data-emphasis="secondary"]::after {
326
+ content: "\2192" / "";
327
+ display: inline-block;
328
+ margin-inline-start: 0.45em;
329
+ font-family: var(--cg-font-text);
330
+ }
331
+
332
+ .cg-action[data-emphasis="secondary"]:hover {
333
+ color: var(--cg-accent);
334
+ text-decoration-color: currentColor;
335
+ }
336
+
337
+ /* --------------------------------------------------------------------------
338
+ Header
248
339
  -------------------------------------------------------------------------- */
249
340
 
250
341
  .cg-site-header {
251
342
  position: sticky;
252
343
  inset-block-start: 0;
253
- z-index: 5;
254
- padding: var(--cg-s4) var(--cg-gutter);
255
- /* Flat and fully opaque, not a frosted-glass blur: a plane above the
256
- page, marked off by a hairline rather than a haze. */
344
+ z-index: 10;
257
345
  background: var(--cg-canvas);
258
- border-block-end: 1px solid var(--cg-line-soft);
346
+ border-block-end: var(--cg-rule) solid var(--cg-line);
259
347
  }
260
348
 
261
349
  .cg-site-header__inner {
350
+ position: relative;
262
351
  display: flex;
263
- flex-wrap: wrap;
264
352
  align-items: center;
265
- gap: var(--cg-gap);
266
- max-inline-size: var(--cg-page);
353
+ gap: var(--cg-s6);
354
+ min-block-size: var(--cg-header-height);
355
+ max-inline-size: calc(var(--cg-page) + var(--cg-gutter) * 2);
267
356
  margin-inline: auto;
357
+ padding-inline: var(--cg-gutter);
268
358
  }
269
359
 
270
360
  .cg-site-header__home {
361
+ display: inline-flex;
362
+ align-items: center;
363
+ margin-inline-end: auto;
271
364
  color: var(--cg-ink);
272
- font-weight: var(--cg-weight-bold);
273
- font-size: var(--cg-text-lg);
274
- letter-spacing: var(--cg-tracking-tight);
275
365
  text-decoration: none;
276
- margin-inline-end: auto;
277
366
  }
278
367
 
279
- /* The uploaded corporate logo. Height-constrained so the header bar keeps a
280
- constant height whatever aspect ratio the company's mark has. */
368
+ .cg-site-header__home:hover {
369
+ color: var(--cg-ink);
370
+ }
371
+
372
+ .cg-site-header__name {
373
+ font-family: var(--cg-font-display);
374
+ font-size: var(--cg-text-lg);
375
+ font-weight: var(--cg-weight-medium);
376
+ letter-spacing: -0.01em;
377
+ line-height: 1;
378
+ }
379
+
281
380
  .cg-site-header__logo {
282
381
  display: block;
283
- block-size: 2rem;
382
+ block-size: var(--cg-s8);
284
383
  inline-size: auto;
285
384
  max-inline-size: 14rem;
286
385
  object-fit: contain;
287
386
  }
288
387
 
289
- /* The mobile-menu checkbox: visually hidden the accessible way (still in
290
- the tab order, still Space-operable) rather than `display: none` (which
291
- would remove it from the tab order entirely) or `left: -9999px` (which
292
- some assistive technology and "find in page" treat as content, not
293
- chrome). */
294
388
  .cg-nav-toggle-input {
295
389
  position: absolute;
296
390
  inline-size: 1px;
@@ -304,167 +398,172 @@ img {
304
398
  display: none;
305
399
  flex-direction: column;
306
400
  justify-content: center;
307
- gap: 0.28rem;
308
- inline-size: 2.5rem;
309
- block-size: 2.5rem;
310
- padding: 0.5rem;
311
- margin-inline-start: auto;
312
- border-radius: var(--cg-radius-sm);
401
+ gap: 0.4rem;
402
+ inline-size: 2.75rem;
403
+ padding: 0.7rem;
313
404
  cursor: pointer;
314
405
  }
315
406
 
316
407
  .cg-nav-toggle-input:focus-visible ~ .cg-nav-toggle-label {
317
- outline: 2px solid var(--cg-accent);
408
+ outline: var(--cg-rule-strong) solid var(--cg-accent);
318
409
  outline-offset: 2px;
319
410
  }
320
411
 
321
412
  .cg-nav-toggle-bar {
322
413
  display: block;
323
414
  inline-size: 100%;
324
- block-size: 2px;
415
+ block-size: 1.5px;
325
416
  background: var(--cg-ink);
326
- transition: transform var(--cg-duration) var(--cg-ease);
327
417
  }
328
418
 
329
419
  .cg-site-header__nav {
330
420
  display: flex;
331
421
  align-items: center;
332
- gap: var(--cg-s5);
422
+ gap: var(--cg-s8);
333
423
  }
334
424
 
335
425
  .cg-nav__items {
336
426
  display: flex;
337
427
  flex-wrap: wrap;
338
428
  align-items: center;
339
- gap: var(--cg-s5);
429
+ gap: var(--cg-s2) var(--cg-s8);
340
430
  margin: 0;
341
431
  padding: 0;
342
432
  list-style: none;
343
- font-size: var(--cg-text-sm);
344
- font-weight: var(--cg-weight-medium);
433
+ font-size: var(--cg-text-ui);
345
434
  }
346
435
 
347
436
  .cg-nav__items a,
348
437
  .cg-nav__items span {
349
- color: var(--cg-ink-muted);
350
- text-decoration: none;
438
+ color: var(--cg-ink);
439
+ text-decoration-line: underline;
440
+ text-decoration-color: transparent;
441
+ text-underline-offset: 0.45em;
351
442
  }
352
443
 
353
444
  .cg-nav__items a:hover {
354
445
  color: var(--cg-ink);
446
+ text-decoration-color: var(--cg-ink);
355
447
  }
356
448
 
357
- .cg-site-header__action {
358
- flex: none;
449
+ .cg-site-header__action.cg-action[data-emphasis="primary"] {
450
+ padding-block: var(--cg-s2);
451
+ min-block-size: 40px;
359
452
  }
360
453
 
361
- /* The manual light/dark/system control (`renderThemeToggle`, `@cogenta/
362
- theme-kit`, L26). Sits beside the mobile menu button in `renderChrome`,
363
- outside the `<nav>` it does not control — a visitor must be able to flip
364
- appearance without opening the collapsed mobile panel first. Sized and
365
- squared off like `.cg-nav-toggle-label` right next to it (`--cg-radius-sm`,
366
- this theme's structured register — never the pill canonical uses),
367
- plain-bordered like `.cg-action[data-emphasis="secondary"]`'s own resting
368
- state rather than filled, so it never competes with a real call to action. */
369
454
  .cg-theme-toggle {
370
455
  display: inline-flex;
371
456
  align-items: center;
372
457
  justify-content: center;
373
- flex-shrink: 0;
374
- inline-size: 2.5rem;
375
- block-size: 2.5rem;
376
- border: 1px solid var(--cg-line-soft);
377
- border-radius: var(--cg-radius-sm);
458
+ flex: none;
459
+ inline-size: 2.75rem;
460
+ padding: 0;
461
+ border: 0;
378
462
  background: transparent;
379
- color: var(--cg-ink);
463
+ color: var(--cg-ink-muted);
380
464
  cursor: pointer;
381
- transition: background-color var(--cg-duration) var(--cg-ease);
465
+ transition: color var(--cg-duration) var(--cg-ease);
382
466
  }
383
467
 
384
468
  .cg-theme-toggle:hover {
385
- background: var(--cg-surface-sunken);
386
- }
387
-
388
- .cg-theme-toggle:focus-visible {
389
- outline: 2px solid var(--cg-accent);
390
- outline-offset: 2px;
469
+ color: var(--cg-ink);
391
470
  }
392
471
 
393
472
  .cg-theme-toggle__icon {
394
- inline-size: 1.1rem;
395
- block-size: 1.1rem;
473
+ inline-size: 1.05rem;
474
+ block-size: 1.05rem;
396
475
  }
397
476
 
398
477
  .cg-theme-toggle__icon--moon {
399
478
  display: none;
400
479
  }
401
480
 
402
- /* Icon reflects the *current* effective appearance — sun while light, moon
403
- while dark — from the same `[data-theme]`/`prefers-color-scheme` signals
404
- `tokens.css` already keys the whole palette on. */
405
481
  @media (prefers-color-scheme: dark) {
406
- :where(:root:not([data-theme='light'])) .cg-theme-toggle__icon--sun {
482
+ :where(:root:not([data-theme="light"])) .cg-theme-toggle__icon--sun {
407
483
  display: none;
408
484
  }
409
- :where(:root:not([data-theme='light'])) .cg-theme-toggle__icon--moon {
485
+
486
+ :where(:root:not([data-theme="light"])) .cg-theme-toggle__icon--moon {
410
487
  display: block;
411
488
  }
412
489
  }
413
490
 
414
- :where(:root[data-theme='dark']) .cg-theme-toggle__icon--sun {
491
+ :where(:root[data-theme="dark"]) .cg-theme-toggle__icon--sun {
415
492
  display: none;
416
493
  }
417
494
 
418
- :where(:root[data-theme='dark']) .cg-theme-toggle__icon--moon {
495
+ :where(:root[data-theme="dark"]) .cg-theme-toggle__icon--moon {
419
496
  display: block;
420
497
  }
421
498
 
422
- /* Below the breakpoint: the toggle button appears, and the nav becomes a
423
- panel anchored under the header, shown only while the checkbox is
424
- checked — the whole mechanism is this one selector, no JavaScript. */
425
- @media (max-width: 56rem) {
499
+ /* Below the breakpoint the navigation becomes a panel under the bar, shown
500
+ while the checkbox is checked: the whole mechanism is one selector. */
501
+ @media (max-width: 63.99rem) {
426
502
  .cg-site-header__inner {
427
- position: relative;
503
+ gap: var(--cg-s2);
504
+ }
505
+
506
+ .cg-theme-toggle {
507
+ order: 1;
428
508
  }
429
509
 
430
510
  .cg-nav-toggle-label {
431
511
  display: flex;
512
+ order: 2;
513
+ margin-inline-end: calc(var(--cg-s3) * -1);
432
514
  }
433
515
 
516
+ /* The open panel covers the rest of the viewport, under the header's own
517
+ hairline, so the page never shows through beneath the menu (where its
518
+ own call to action would read as a second copy of the menu's). */
434
519
  .cg-site-header__nav {
435
520
  display: none;
436
521
  position: absolute;
437
522
  inset-inline: 0;
438
- inset-block-start: 100%;
523
+ inset-block-start: calc(100% + var(--cg-rule));
524
+ block-size: calc(100dvh - var(--cg-header-height) - var(--cg-rule));
525
+ overflow-y: auto;
526
+ overscroll-behavior: contain;
439
527
  flex-direction: column;
440
528
  align-items: stretch;
441
- gap: var(--cg-s5);
442
- padding: var(--cg-s6) var(--cg-gutter);
529
+ gap: var(--cg-s8);
530
+ padding: var(--cg-s4) var(--cg-gutter) var(--cg-s10);
443
531
  background: var(--cg-canvas);
444
- border-block-end: 1px solid var(--cg-line-soft);
445
- box-shadow: var(--cogenta-shadow-md);
446
532
  }
447
533
 
448
534
  .cg-nav-toggle-input:checked ~ .cg-site-header__nav {
449
535
  display: flex;
450
536
  }
451
537
 
452
- .cg-nav-toggle-input:checked ~ .cg-nav-toggle-label .cg-nav-toggle-bar:nth-child(1) {
453
- transform: translateY(0.42rem) rotate(45deg);
538
+ /* While the menu is open the page behind it does not scroll. CSS only. */
539
+ :root:has(.cg-nav-toggle-input:checked) {
540
+ overflow: hidden;
454
541
  }
455
542
 
456
- .cg-nav-toggle-input:checked ~ .cg-nav-toggle-label .cg-nav-toggle-bar:nth-child(2) {
457
- opacity: 0;
543
+ .cg-nav-toggle-input:checked ~ .cg-nav-toggle-label .cg-nav-toggle-bar:nth-child(1) {
544
+ transform: translateY(0.3rem) rotate(45deg);
458
545
  }
459
546
 
460
- .cg-nav-toggle-input:checked ~ .cg-nav-toggle-label .cg-nav-toggle-bar:nth-child(3) {
461
- transform: translateY(-0.42rem) rotate(-45deg);
547
+ .cg-nav-toggle-input:checked ~ .cg-nav-toggle-label .cg-nav-toggle-bar:nth-child(2) {
548
+ transform: translateY(-0.3rem) rotate(-45deg);
462
549
  }
463
550
 
464
551
  .cg-site-header__nav .cg-nav__items {
465
552
  flex-direction: column;
466
- align-items: flex-start;
467
- gap: var(--cg-s4);
553
+ align-items: stretch;
554
+ gap: 0;
555
+ font-family: var(--cg-font-display);
556
+ font-size: var(--cg-text-xl);
557
+ }
558
+
559
+ .cg-site-header__nav .cg-nav__items li {
560
+ border-block-end: var(--cg-rule) solid var(--cg-line);
561
+ }
562
+
563
+ .cg-site-header__nav .cg-nav__items a,
564
+ .cg-site-header__nav .cg-nav__items span {
565
+ display: block;
566
+ padding-block: var(--cg-s3);
468
567
  }
469
568
 
470
569
  .cg-site-header__action {
@@ -473,248 +572,198 @@ img {
473
572
  }
474
573
 
475
574
  /* --------------------------------------------------------------------------
476
- Chrome — footer, a real four-column layout
575
+ Footer: a colophon on the twelve-column grid.
477
576
  -------------------------------------------------------------------------- */
478
577
 
479
578
  .cg-site-footer {
480
- padding: var(--cg-s16) var(--cg-gutter) var(--cg-s8);
481
- background: var(--cg-surface-sunken);
579
+ border-block-start: var(--cg-rule) solid var(--cg-line);
580
+ background: var(--cg-canvas);
482
581
  color: var(--cg-ink-muted);
483
- border-block-start: 1px solid var(--cg-line-soft);
484
582
  font-size: var(--cg-text-sm);
583
+ line-height: var(--cg-leading-text);
485
584
  }
486
585
 
487
- .cg-site-footer__grid {
488
- display: grid;
489
- gap: var(--cg-gap-loose);
490
- grid-template-columns: 1fr;
491
- max-inline-size: var(--cg-page);
586
+ .cg-site-footer__inner {
587
+ max-inline-size: calc(var(--cg-page) + var(--cg-gutter) * 2);
492
588
  margin-inline: auto;
493
- padding-block-end: var(--cg-s10);
494
- border-block-end: 1px solid var(--cg-line-soft);
589
+ padding: var(--cg-s16) var(--cg-gutter) var(--cg-s8);
495
590
  }
496
591
 
497
- @media (min-width: 56rem) {
498
- .cg-site-footer__grid {
499
- grid-template-columns: 1.3fr 1fr 0.8fr 1fr;
500
- align-items: start;
501
- }
592
+ .cg-site-footer__top {
593
+ display: grid;
594
+ grid-template-columns: repeat(var(--cg-columns), minmax(0, 1fr));
595
+ column-gap: var(--cg-col-gap);
596
+ row-gap: var(--cg-s10);
597
+ padding-block-end: var(--cg-s16);
502
598
  }
503
599
 
504
- .cg-site-footer__brand a {
505
- color: var(--cg-ink);
506
- font-weight: var(--cg-weight-bold);
507
- font-size: var(--cg-text-lg);
508
- letter-spacing: var(--cg-tracking-tight);
509
- text-decoration: none;
600
+ .cg-site-footer__top > * {
601
+ grid-column: 1 / -1;
510
602
  }
511
603
 
512
- .cg-site-footer__tagline {
513
- margin: var(--cg-s3) 0 0;
514
- max-inline-size: 24ch;
515
- color: var(--cg-ink-muted);
516
- line-height: var(--cg-leading-relaxed);
517
- }
604
+ @media (min-width: 40rem) {
605
+ .cg-site-footer__brand {
606
+ grid-column: 1 / -1;
607
+ }
518
608
 
519
- .cg-site-footer__nav .cg-nav__items {
520
- flex-direction: column;
521
- align-items: flex-start;
522
- gap: var(--cg-s3);
523
- }
609
+ .cg-site-footer__nav {
610
+ grid-column: 1 / span 4;
611
+ }
524
612
 
525
- .cg-site-footer__social {
526
- display: flex;
527
- gap: var(--cg-s3);
528
- margin: 0;
529
- padding: 0;
530
- list-style: none;
613
+ .cg-site-footer__note {
614
+ grid-column: 5 / -1;
615
+ }
616
+
617
+ .cg-site-footer__social-col {
618
+ grid-column: 1 / -1;
619
+ }
531
620
  }
532
621
 
533
- .cg-site-footer__social-item a {
534
- display: inline-flex;
535
- align-items: center;
536
- justify-content: center;
537
- inline-size: 2.25rem;
538
- block-size: 2.25rem;
539
- border: 1px solid var(--cg-line);
540
- border-radius: var(--cg-radius-sm);
541
- color: var(--cg-ink-muted);
542
- transition:
543
- color var(--cg-duration) var(--cg-ease),
544
- border-color var(--cg-duration) var(--cg-ease);
622
+ @media (min-width: 64rem) {
623
+ .cg-site-footer__brand {
624
+ grid-column: 1 / span 3;
625
+ }
626
+
627
+ .cg-site-footer__nav {
628
+ grid-column: 4 / span 2;
629
+ }
630
+
631
+ .cg-site-footer__note {
632
+ grid-column: 6 / span 6;
633
+ }
634
+
635
+ .cg-site-footer__note[data-paragraphs="3"] {
636
+ grid-template-columns: repeat(3, minmax(0, 1fr));
637
+ }
638
+
639
+ .cg-site-footer__note[data-paragraphs="4"] {
640
+ grid-template-columns: repeat(4, minmax(0, 1fr));
641
+ }
642
+
643
+ .cg-site-footer__social-col {
644
+ grid-column: 12 / span 1;
645
+ justify-self: end;
646
+ }
545
647
  }
546
648
 
547
- .cg-site-footer__social-item a:hover {
548
- color: var(--cg-accent);
549
- border-color: var(--cg-accent);
649
+ .cg-site-footer__name {
650
+ font-family: var(--cg-font-display);
651
+ font-size: var(--cg-text-xl);
652
+ font-weight: var(--cg-weight-medium);
653
+ letter-spacing: -0.01em;
654
+ line-height: 1.1;
655
+ color: var(--cg-ink);
656
+ text-decoration: none;
550
657
  }
551
658
 
552
- .cg-social__icon {
553
- inline-size: 1.1rem;
554
- block-size: 1.1rem;
659
+ .cg-site-footer__name:hover {
660
+ color: var(--cg-ink);
555
661
  }
556
662
 
557
- .cg-site-footer__note {
558
- margin: 0 0 var(--cg-s4);
663
+ .cg-site-footer__tagline {
664
+ margin: var(--cg-s3) 0 0;
665
+ max-inline-size: 30ch;
559
666
  color: var(--cg-ink-muted);
560
- line-height: var(--cg-leading-normal);
561
667
  }
562
668
 
563
- .cg-site-footer__meta,
564
- .cg-site-footer__branding {
565
- display: flex;
669
+ .cg-site-footer__nav .cg-nav__items {
566
670
  flex-direction: column;
567
671
  align-items: flex-start;
568
- justify-content: flex-start;
672
+ gap: var(--cg-s2);
673
+ font-size: var(--cg-text-sm);
569
674
  }
570
675
 
571
- @media (min-width: 56rem) {
572
- .cg-site-footer__meta {
573
- align-items: flex-end;
574
- text-align: end;
575
- }
676
+ .cg-site-footer__nav .cg-nav__items a {
677
+ color: var(--cg-ink);
576
678
  }
577
679
 
578
- .cg-site-footer__branding a {
579
- display: flex;
580
- align-items: center;
581
- gap: 0.4em;
582
- opacity: 0.75;
583
- transition: opacity var(--cg-duration) var(--cg-ease);
680
+ .cg-site-footer__note {
681
+ display: grid;
682
+ grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
683
+ gap: var(--cg-s6) var(--cg-col-gap);
684
+ align-content: start;
584
685
  }
585
686
 
586
- .cg-site-footer__branding a:hover,
587
- .cg-site-footer__branding a:focus-visible {
588
- opacity: 1;
687
+ .cg-site-footer__note-text {
688
+ margin: 0;
689
+ color: var(--cg-ink-muted);
589
690
  }
590
691
 
591
- .cg-site-footer__brand-logo {
692
+ .cg-site-footer__note-label {
592
693
  display: block;
593
- /* Explicit pixels, not `em`: relative sizing cascaded from the footer's
594
- own small font-size and made the credit mark unreadably tiny. */
595
- block-size: 25px;
596
- inline-size: auto;
597
- }
598
-
599
- .cg-site-footer__version {
600
- font-variant-numeric: tabular-nums;
601
- font-size: 0.9em;
602
- }
603
-
604
- .cg-site-footer__bottom {
605
- max-inline-size: var(--cg-page);
606
- margin-inline: auto;
607
- padding-block-start: var(--cg-s6);
608
- font-size: var(--cg-text-xs);
609
- letter-spacing: var(--cg-tracking-wide);
610
- text-transform: uppercase;
611
- color: var(--cg-ink-subtle);
694
+ margin-block-end: var(--cg-s1);
695
+ color: var(--cg-ink);
696
+ font-weight: var(--cg-weight-medium);
612
697
  }
613
698
 
614
- /* --------------------------------------------------------------------------
615
- Actions — the theme's only control
616
- -------------------------------------------------------------------------- */
617
-
618
- .cg-actions {
699
+ .cg-site-footer__social {
619
700
  display: flex;
620
- flex-wrap: wrap;
621
- gap: var(--cg-s3);
622
- margin: var(--cg-s8) 0 0;
701
+ gap: var(--cg-s1);
702
+ margin: 0 calc(var(--cg-s2) * -1) 0 0;
623
703
  padding: 0;
624
704
  list-style: none;
625
705
  }
626
706
 
627
- .cg-action {
707
+ .cg-site-footer__social-item a {
628
708
  display: inline-flex;
629
709
  align-items: center;
630
710
  justify-content: center;
631
- gap: var(--cg-s2);
632
- padding: var(--cg-s3) var(--cg-s6);
633
- border: 0;
634
- border-radius: var(--cg-radius-sm);
635
- font-size: var(--cg-text-sm);
636
- font-weight: var(--cg-weight-semibold);
637
- letter-spacing: var(--cg-tracking-snug);
638
- line-height: var(--cg-leading-snug);
639
- text-decoration: none;
640
- white-space: nowrap;
641
- transition:
642
- background-color var(--cg-duration) var(--cg-ease),
643
- color var(--cg-duration) var(--cg-ease),
644
- box-shadow var(--cg-duration) var(--cg-ease),
645
- transform var(--cg-duration-fast) var(--cg-ease);
711
+ inline-size: 2.5rem;
712
+ block-size: 2.5rem;
713
+ color: var(--cg-ink-muted);
714
+ transition: color var(--cg-duration) var(--cg-ease);
646
715
  }
647
716
 
648
- .cg-action[data-emphasis="primary"] {
649
- background: var(--cg-accent);
650
- color: var(--cg-accent-fg);
717
+ .cg-site-footer__social-item a:hover {
718
+ color: var(--cg-ink);
651
719
  }
652
720
 
653
- .cg-action[data-emphasis="primary"]:hover {
654
- background: var(--cg-accent-hover);
655
- box-shadow: var(--cogenta-shadow-sm);
656
- transform: translateY(-1px);
721
+ .cg-social__icon {
722
+ inline-size: 1.15rem;
723
+ block-size: 1.15rem;
657
724
  }
658
725
 
659
- .cg-action[data-emphasis="secondary"] {
660
- background: transparent;
661
- color: var(--cg-ink);
662
- box-shadow: var(--cg-ring-strong);
726
+ .cg-site-footer__bottom {
727
+ display: flex;
728
+ flex-wrap: wrap;
729
+ align-items: center;
730
+ justify-content: space-between;
731
+ gap: var(--cg-s4) var(--cg-s8);
732
+ padding-block-start: var(--cg-s6);
733
+ border-block-start: var(--cg-rule) solid var(--cg-line);
734
+ font-size: var(--cg-text-xs);
735
+ letter-spacing: 0.02em;
663
736
  }
664
737
 
665
- .cg-action[data-emphasis="secondary"]:hover {
666
- color: var(--cg-accent);
667
- box-shadow: var(--cg-ring-accent);
738
+ .cg-site-footer__legal {
739
+ margin: 0;
740
+ font-variant-numeric: lining-nums tabular-nums;
668
741
  }
669
742
 
670
- .cg-action:active {
671
- transform: translateY(0);
672
- box-shadow: none;
743
+ .cg-site-footer__branding a {
744
+ display: inline-flex;
745
+ align-items: center;
746
+ gap: 0.5em;
747
+ color: var(--cg-ink-subtle);
748
+ text-decoration: none;
673
749
  }
674
750
 
675
- /* --------------------------------------------------------------------------
676
- Shared block furniture
677
- -------------------------------------------------------------------------- */
678
-
679
- .cg-services__title,
680
- .cg-banner__title,
681
- .cg-faq__title,
682
- .cg-metrics__title,
683
- .cg-clients__title,
684
- .cg-list__title-heading {
685
- margin: 0 0 var(--cg-s10);
686
- font-size: var(--cg-text-xl);
687
- line-height: var(--cg-leading-snug);
688
- letter-spacing: var(--cg-tracking-tight);
689
- font-weight: var(--cg-weight-bold);
690
- text-wrap: balance;
751
+ .cg-site-footer__branding a:hover {
752
+ color: var(--cg-ink);
691
753
  }
692
754
 
693
- .cg-services__items,
694
- .cg-clients__items,
695
- .cg-gallery__items,
696
- .cg-list__items,
697
- .cg-faq__items {
698
- margin: 0;
699
- padding: 0;
700
- list-style: none;
755
+ .cg-site-footer__brand-logo {
756
+ display: block;
757
+ block-size: 18px;
758
+ inline-size: auto;
701
759
  }
702
760
 
703
- .cg-gallery__viewport,
704
- .cg-list__viewport {
705
- overflow-x: auto;
706
- scroll-snap-type: x mandatory;
707
- scroll-behavior: smooth;
708
- overscroll-behavior-inline: contain;
709
- scrollbar-width: thin;
710
- scrollbar-color: var(--cg-line-strong) transparent;
711
- padding-block: var(--cg-s2);
712
- margin-block: calc(var(--cg-s2) * -1);
761
+ .cg-site-footer__version {
762
+ font-variant-numeric: tabular-nums;
713
763
  }
714
764
 
715
765
  /* --------------------------------------------------------------------------
716
- Search, forms, comments — public utility pages and post-content furniture,
717
- styled with the same restrained, structured language as the seventeen blocks.
766
+ Search, forms, comments: the utility pages, in the same register.
718
767
  -------------------------------------------------------------------------- */
719
768
 
720
769
  .cg-search__form,
@@ -724,7 +773,7 @@ img {
724
773
  .cg-form,
725
774
  .cg-form__confirmation,
726
775
  .cg-comments {
727
- max-inline-size: var(--cg-page);
776
+ max-inline-size: calc(var(--cg-page) + var(--cg-gutter) * 2);
728
777
  margin-inline: auto;
729
778
  padding-inline: var(--cg-gutter);
730
779
  }
@@ -734,31 +783,79 @@ img {
734
783
  flex-wrap: wrap;
735
784
  align-items: end;
736
785
  gap: var(--cg-s3);
737
- margin-block-end: var(--cg-s8);
786
+ margin-block: var(--cg-s10);
738
787
  }
739
788
 
740
- .cg-search__form label {
789
+ .cg-search__form label,
790
+ .cg-form__field label,
791
+ .cg-comment__form label {
741
792
  display: block;
742
- font-size: var(--cg-text-sm);
743
- font-weight: var(--cg-weight-semibold);
744
793
  margin-block-end: var(--cg-s2);
794
+ font-size: var(--cg-text-sm);
795
+ font-weight: var(--cg-weight-medium);
796
+ color: var(--cg-ink);
797
+ }
798
+
799
+ /* The label sits on its own line above the field, as in every other form. */
800
+ .cg-search__form label {
801
+ flex-basis: 100%;
802
+ margin-block-end: calc(var(--cg-s1) * -1);
745
803
  }
746
804
 
747
805
  .cg-search__form input[type="search"] {
748
- flex: 1 1 16rem;
806
+ flex: 1 1 18rem;
749
807
  }
750
808
 
751
809
  .cg-search__results {
752
- margin: 0 auto;
753
- padding-inline-start: var(--cg-gutter);
754
810
  display: grid;
755
- gap: var(--cg-s4);
756
- font-size: var(--cg-text-lg);
811
+ gap: 0;
812
+ margin-block: 0 var(--cg-section);
813
+ list-style: none;
814
+ font-family: var(--cg-font-display);
815
+ font-size: var(--cg-text-xl);
816
+ line-height: 1.25;
817
+ }
818
+
819
+ .cg-search__results > * {
820
+ padding-block: var(--cg-s5);
821
+ border-block-start: var(--cg-rule) solid var(--cg-line);
822
+ }
823
+
824
+ /* A result reads like a row of the sector index: the title in ink, the
825
+ summary in the text face under it. */
826
+ a.cg-search__title {
827
+ color: var(--cg-ink);
828
+ text-decoration-color: transparent;
829
+ text-underline-offset: 0.18em;
830
+ }
831
+
832
+ a.cg-search__title:hover {
833
+ color: var(--cg-accent);
834
+ text-decoration-color: currentColor;
835
+ }
836
+
837
+ .cg-search__excerpt,
838
+ .cg-search__meta,
839
+ .cg-search__count {
840
+ font-family: var(--cg-font-text);
841
+ }
842
+
843
+ .cg-search__count {
844
+ color: var(--cg-ink-muted);
845
+ }
846
+
847
+ .cg-search__excerpt {
848
+ margin: var(--cg-s2) 0 0;
849
+ max-inline-size: 60ch;
850
+ font-size: var(--cg-text-md);
851
+ line-height: 1.55;
852
+ color: var(--cg-ink-muted);
757
853
  }
758
854
 
759
855
  .cg-search__empty,
760
856
  .cg-comments__empty,
761
- .cg-comments__closed {
857
+ .cg-comments__closed,
858
+ .cg-form__help {
762
859
  color: var(--cg-ink-muted);
763
860
  }
764
861
 
@@ -766,7 +863,7 @@ img {
766
863
  .cg-form__error,
767
864
  .cg-form__field-error {
768
865
  color: var(--cg-ink);
769
- font-weight: var(--cg-weight-bold);
866
+ font-weight: var(--cg-weight-semibold);
770
867
  }
771
868
 
772
869
  .cg-search__form input,
@@ -776,9 +873,10 @@ img {
776
873
  .cg-comment__form input,
777
874
  .cg-comment__form textarea {
778
875
  inline-size: 100%;
876
+ min-block-size: 44px;
779
877
  padding: var(--cg-s3) var(--cg-s4);
780
- border: 1px solid var(--cg-line);
781
- border-radius: var(--cg-radius-sm);
878
+ border: var(--cg-rule) solid var(--cg-line-strong);
879
+ border-radius: var(--cg-radius);
782
880
  background: var(--cg-surface);
783
881
  color: var(--cg-ink);
784
882
  font: inherit;
@@ -787,19 +885,22 @@ img {
787
885
  .cg-form__field input[aria-invalid="true"],
788
886
  .cg-form__field select[aria-invalid="true"],
789
887
  .cg-form__field textarea[aria-invalid="true"] {
790
- border-width: 2px;
791
- border-color: var(--cg-line-strong);
888
+ border-width: var(--cg-rule-strong);
889
+ border-color: var(--cg-ink);
792
890
  }
793
891
 
794
892
  .cg-search__form button,
795
893
  .cg-form button[type="submit"],
796
894
  .cg-comment__form button[type="submit"] {
895
+ min-block-size: 44px;
797
896
  padding: var(--cg-s3) var(--cg-s6);
798
- border: 0;
799
- border-radius: var(--cg-radius-sm);
800
- background: var(--cg-accent);
801
- color: var(--cg-accent-fg);
802
- font-weight: var(--cg-weight-semibold);
897
+ border: var(--cg-rule) solid var(--cg-action);
898
+ border-radius: var(--cg-radius);
899
+ background: var(--cg-action);
900
+ color: var(--cg-action-fg);
901
+ font: inherit;
902
+ font-size: var(--cg-text-ui);
903
+ font-weight: var(--cg-weight-medium);
803
904
  cursor: pointer;
804
905
  transition: background-color var(--cg-duration) var(--cg-ease);
805
906
  }
@@ -807,7 +908,9 @@ img {
807
908
  .cg-search__form button:hover,
808
909
  .cg-form button[type="submit"]:hover,
809
910
  .cg-comment__form button[type="submit"]:hover {
810
- background: var(--cg-accent-hover);
911
+ background: var(--cg-action-hover);
912
+ border-color: var(--cg-action-hover);
913
+ color: var(--cg-action-hover-fg);
811
914
  }
812
915
 
813
916
  .cg-form__field,
@@ -816,18 +919,9 @@ img {
816
919
  margin-block-end: var(--cg-s5);
817
920
  }
818
921
 
819
- .cg-form__field label,
820
- .cg-comment__form label {
821
- display: block;
822
- font-size: var(--cg-text-sm);
823
- font-weight: var(--cg-weight-semibold);
824
- margin-block-end: var(--cg-s2);
825
- }
826
-
827
922
  .cg-form__help {
828
923
  margin: var(--cg-s2) 0 0;
829
924
  font-size: var(--cg-text-sm);
830
- color: var(--cg-ink-muted);
831
925
  }
832
926
 
833
927
  .cg-form__choice {
@@ -835,7 +929,7 @@ img {
835
929
  align-items: center;
836
930
  gap: var(--cg-s2);
837
931
  margin-inline-end: var(--cg-s4);
838
- font-weight: normal;
932
+ font-weight: var(--cg-weight-regular);
839
933
  }
840
934
 
841
935
  .cg-form__honeypot,
@@ -847,11 +941,44 @@ img {
847
941
  inset-inline-start: -9999px;
848
942
  }
849
943
 
944
+ /* Comments follow the reading column of the page above them: the heading in
945
+ the left four columns, the thread and the form in the text column, under a
946
+ hairline drawn inside the grid rather than across the gutters. */
850
947
  .cg-comments {
851
- margin-block-start: var(--cg-section-y);
852
- padding-block-start: var(--cg-s8);
853
- padding-block-end: var(--cg-section-y);
854
- border-block-start: 1px solid var(--cg-line-soft);
948
+ display: grid;
949
+ grid-template-columns: repeat(var(--cg-columns), minmax(0, 1fr));
950
+ column-gap: var(--cg-col-gap);
951
+ align-items: start;
952
+ margin-block: calc(var(--cg-section) / 2) var(--cg-section);
953
+ }
954
+
955
+ .cg-comments::before {
956
+ content: "";
957
+ grid-column: 1 / -1;
958
+ block-size: var(--cg-rule);
959
+ margin-block-end: var(--cg-s6);
960
+ background: var(--cg-line);
961
+ }
962
+
963
+ .cg-comments > * {
964
+ grid-column: 1 / -1;
965
+ min-inline-size: 0;
966
+ }
967
+
968
+ .cg-comments > h2 {
969
+ margin-block-end: var(--cg-s6);
970
+ font-size: var(--cg-size-subheading);
971
+ }
972
+
973
+ @media (min-width: 64rem) {
974
+ .cg-comments > h2 {
975
+ grid-column: 1 / span 4;
976
+ grid-row: 2 / span 3;
977
+ }
978
+
979
+ .cg-comments > :not(h2) {
980
+ grid-column: 5 / span 7;
981
+ }
855
982
  }
856
983
 
857
984
  .cg-comments__list,
@@ -863,7 +990,7 @@ img {
863
990
 
864
991
  .cg-comment {
865
992
  padding-block: var(--cg-s5);
866
- border-block-end: 1px solid var(--cg-line-soft);
993
+ border-block-end: var(--cg-rule) solid var(--cg-line-soft);
867
994
  }
868
995
 
869
996
  .cg-comment__replies {
@@ -872,7 +999,7 @@ img {
872
999
 
873
1000
  .cg-comment__replies .cg-comment {
874
1001
  padding-inline-start: var(--cg-s6);
875
- border-inline-start: 2px solid var(--cg-line-soft);
1002
+ border-inline-start: var(--cg-rule) solid var(--cg-line);
876
1003
  border-block-end: 0;
877
1004
  }
878
1005
 
@@ -880,13 +1007,13 @@ img {
880
1007
  display: flex;
881
1008
  gap: var(--cg-s3);
882
1009
  align-items: baseline;
1010
+ margin-block-end: var(--cg-s2);
883
1011
  font-size: var(--cg-text-sm);
884
1012
  color: var(--cg-ink-muted);
885
- margin-block-end: var(--cg-s2);
886
1013
  }
887
1014
 
888
1015
  .cg-comment__author {
889
- font-weight: var(--cg-weight-semibold);
1016
+ font-weight: var(--cg-weight-medium);
890
1017
  color: var(--cg-ink);
891
1018
  }
892
1019