@dsbasko/cookbook-engine 0.1.0

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.

Potentially problematic release.


This version of @dsbasko/cookbook-engine might be problematic. Click here for more details.

Files changed (137) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +232 -0
  3. package/assets/fonts/jetbrains-mono/JetBrainsMono-Bold.woff2 +0 -0
  4. package/assets/fonts/jetbrains-mono/JetBrainsMono-BoldItalic.woff2 +0 -0
  5. package/assets/fonts/jetbrains-mono/JetBrainsMono-Italic.woff2 +0 -0
  6. package/assets/fonts/jetbrains-mono/JetBrainsMono-Medium.woff2 +0 -0
  7. package/assets/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2 +0 -0
  8. package/assets/fonts/jetbrains-mono/JetBrainsMono-SemiBold.woff2 +0 -0
  9. package/package.json +92 -0
  10. package/scripts/check-course-coverage.mts +32 -0
  11. package/scripts/fix-static-image-extensions.mjs +78 -0
  12. package/scripts/generate-readme-toc.mts +32 -0
  13. package/scripts/resolve-course-paths.mjs +28 -0
  14. package/scripts/sync-images.mjs +88 -0
  15. package/src/components/AppShell/AppShell.module.css +40 -0
  16. package/src/components/AppShell/AppShell.tsx +135 -0
  17. package/src/components/AppShell/index.ts +1 -0
  18. package/src/components/Callout/Callout.module.css +68 -0
  19. package/src/components/Callout/Callout.tsx +83 -0
  20. package/src/components/Callout/index.ts +1 -0
  21. package/src/components/CodeBlock/CodeBlock.module.css +68 -0
  22. package/src/components/CodeBlock/CodeBlock.tsx +65 -0
  23. package/src/components/CodeBlock/index.ts +1 -0
  24. package/src/components/GateProvider/GateProvider.tsx +207 -0
  25. package/src/components/GateProvider/index.ts +1 -0
  26. package/src/components/Header/Breadcrumbs.tsx +50 -0
  27. package/src/components/Header/Header.module.css +131 -0
  28. package/src/components/Header/Header.tsx +26 -0
  29. package/src/components/Header/HeaderLessonNav.tsx +118 -0
  30. package/src/components/Header/index.ts +1 -0
  31. package/src/components/HomePage/HomePage.module.css +538 -0
  32. package/src/components/HomePage/HomePage.tsx +295 -0
  33. package/src/components/HomePage/index.ts +1 -0
  34. package/src/components/LessonAwareLink/LessonAwareLink.module.css +12 -0
  35. package/src/components/LessonAwareLink/LessonAwareLink.tsx +86 -0
  36. package/src/components/LessonAwareLink/index.ts +1 -0
  37. package/src/components/LessonLayout/LessonLayout.module.css +35 -0
  38. package/src/components/LessonLayout/LessonLayout.tsx +18 -0
  39. package/src/components/LessonLayout/index.ts +1 -0
  40. package/src/components/LessonLockedInterstitial/LessonLockedInterstitial.module.css +367 -0
  41. package/src/components/LessonLockedInterstitial/LessonLockedInterstitial.tsx +256 -0
  42. package/src/components/LessonLockedInterstitial/index.ts +1 -0
  43. package/src/components/LessonNav/LessonNav.module.css +84 -0
  44. package/src/components/LessonNav/LessonNav.tsx +64 -0
  45. package/src/components/LessonNav/index.ts +1 -0
  46. package/src/components/LessonPageLayout/LessonPageLayout.module.css +118 -0
  47. package/src/components/LessonPageLayout/LessonPageLayout.tsx +46 -0
  48. package/src/components/LessonPageLayout/index.ts +1 -0
  49. package/src/components/LessonSideMeta/LessonSideMeta.module.css +68 -0
  50. package/src/components/LessonSideMeta/LessonSideMeta.tsx +87 -0
  51. package/src/components/LessonSideMeta/index.ts +1 -0
  52. package/src/components/ModulePage/ModulePage.module.css +693 -0
  53. package/src/components/ModulePage/ModulePage.tsx +301 -0
  54. package/src/components/ModulePage/index.ts +1 -0
  55. package/src/components/ProgramDrawer/LockIcon.tsx +19 -0
  56. package/src/components/ProgramDrawer/ProgramDrawer.module.css +563 -0
  57. package/src/components/ProgramDrawer/ProgramDrawer.tsx +481 -0
  58. package/src/components/ProgramDrawer/index.ts +1 -0
  59. package/src/components/ProgressBar/ProgressBar.module.css +46 -0
  60. package/src/components/ProgressBar/ProgressBar.tsx +45 -0
  61. package/src/components/ProgressBar/index.ts +1 -0
  62. package/src/components/ProgressModeProvider/ProgressModeProvider.tsx +87 -0
  63. package/src/components/ProgressModeProvider/index.ts +1 -0
  64. package/src/components/ReadingPrefsProvider/ReadingPrefsProvider.tsx +100 -0
  65. package/src/components/ReadingPrefsProvider/index.ts +1 -0
  66. package/src/components/ReadingProgress/ReadingProgress.module.css +19 -0
  67. package/src/components/ReadingProgress/ReadingProgress.tsx +53 -0
  68. package/src/components/ReadingProgress/index.ts +1 -0
  69. package/src/components/SettingsToggle/SettingsToggle.module.css +888 -0
  70. package/src/components/SettingsToggle/SettingsToggle.tsx +688 -0
  71. package/src/components/SettingsToggle/index.ts +1 -0
  72. package/src/components/Sidebar/Sidebar.module.css +157 -0
  73. package/src/components/Sidebar/Sidebar.tsx +63 -0
  74. package/src/components/Sidebar/icons/GitHubIcon.tsx +17 -0
  75. package/src/components/Sidebar/icons/HomeIcon.tsx +22 -0
  76. package/src/components/Sidebar/icons/LanguageIcon.tsx +24 -0
  77. package/src/components/Sidebar/icons/ProgramIcon.tsx +23 -0
  78. package/src/components/Sidebar/icons/SettingsIcon.tsx +26 -0
  79. package/src/components/Sidebar/icons/ThemeIcon.tsx +22 -0
  80. package/src/components/Sidebar/icons/index.ts +6 -0
  81. package/src/components/Sidebar/index.ts +1 -0
  82. package/src/components/ThemeProvider/ThemeProvider.tsx +68 -0
  83. package/src/components/ThemeProvider/index.ts +1 -0
  84. package/src/components/Toc/Toc.module.css +78 -0
  85. package/src/components/Toc/Toc.tsx +92 -0
  86. package/src/components/Toc/index.ts +1 -0
  87. package/src/components/TranslationBanner/TranslationBanner.module.css +32 -0
  88. package/src/components/TranslationBanner/TranslationBanner.tsx +40 -0
  89. package/src/components/TranslationBanner/index.ts +1 -0
  90. package/src/config.d.mts +12 -0
  91. package/src/config.mjs +110 -0
  92. package/src/index.ts +62 -0
  93. package/src/layout/lang.tsx +44 -0
  94. package/src/layout/root.tsx +223 -0
  95. package/src/lib/course-loader.ts +33 -0
  96. package/src/lib/course.ts +429 -0
  97. package/src/lib/coverage.ts +141 -0
  98. package/src/lib/description.ts +43 -0
  99. package/src/lib/extract-toc.ts +59 -0
  100. package/src/lib/format.ts +55 -0
  101. package/src/lib/frontier-link.ts +37 -0
  102. package/src/lib/gate-init-script.ts +40 -0
  103. package/src/lib/gate-mark-script.ts +324 -0
  104. package/src/lib/i18n.ts +474 -0
  105. package/src/lib/lang.ts +90 -0
  106. package/src/lib/lesson-gate.ts +79 -0
  107. package/src/lib/lesson.ts +66 -0
  108. package/src/lib/markdown-components.tsx +51 -0
  109. package/src/lib/markdown.ts +180 -0
  110. package/src/lib/mdx-plugins/rehype-callout.ts +80 -0
  111. package/src/lib/mdx-plugins/remark-lesson-images.ts +109 -0
  112. package/src/lib/mdx-plugins/remark-link-rewrite.ts +231 -0
  113. package/src/lib/paths.ts +36 -0
  114. package/src/lib/program-drawer.ts +8 -0
  115. package/src/lib/progress-mode.ts +69 -0
  116. package/src/lib/progress.ts +182 -0
  117. package/src/lib/reading-prefs.ts +127 -0
  118. package/src/lib/readme-toc.ts +69 -0
  119. package/src/lib/site-url.ts +33 -0
  120. package/src/lib/sitemap.ts +112 -0
  121. package/src/lib/slug.ts +15 -0
  122. package/src/lib/theme.ts +78 -0
  123. package/src/lib/use-i18n.ts +25 -0
  124. package/src/og/icon.tsx +40 -0
  125. package/src/og/opengraph-image.tsx +126 -0
  126. package/src/pages/home.tsx +66 -0
  127. package/src/pages/lesson.tsx +260 -0
  128. package/src/pages/module.tsx +80 -0
  129. package/src/pages/not-found-lang.tsx +51 -0
  130. package/src/pages/not-found-root.tsx +48 -0
  131. package/src/pages/root.tsx +44 -0
  132. package/src/seo/robots.ts +16 -0
  133. package/src/seo/sitemap.ts +10 -0
  134. package/src/styles/globals.css +139 -0
  135. package/src/styles/markdown.css +265 -0
  136. package/src/styles/reset.css +89 -0
  137. package/src/styles/tokens.css +270 -0
@@ -0,0 +1,563 @@
1
+ /* Program drawer — slide-in accordion of modules and lessons. Sits to the
2
+ right of the 64px sidebar so the navigation rail stays visible while the
3
+ drawer is open. */
4
+
5
+ .overlay {
6
+ position: fixed;
7
+ inset: 0;
8
+ background: rgba(20, 16, 8, 0.32);
9
+ backdrop-filter: blur(2px);
10
+ -webkit-backdrop-filter: blur(2px);
11
+ z-index: var(--z-overlay);
12
+ opacity: 0;
13
+ pointer-events: none;
14
+ transition: opacity 180ms ease;
15
+ }
16
+
17
+ [data-theme='dark'] .overlay {
18
+ background: rgba(0, 0, 0, 0.55);
19
+ }
20
+
21
+ .overlay[data-open='true'] {
22
+ opacity: 1;
23
+ pointer-events: auto;
24
+ }
25
+
26
+ .drawer {
27
+ position: fixed;
28
+ top: 0;
29
+ left: var(--layout-sidebar-width);
30
+ bottom: 0;
31
+ width: 480px;
32
+ max-width: calc(100vw - var(--layout-sidebar-width));
33
+ z-index: var(--z-drawer);
34
+ background-color: var(--bg-default);
35
+ border-right: 1px solid var(--bg-stroke-strong);
36
+ box-shadow: var(--shadow-md);
37
+ display: flex;
38
+ flex-direction: column;
39
+ overflow: hidden;
40
+ transform: translateX(-12px);
41
+ opacity: 0;
42
+ pointer-events: none;
43
+ transition: transform 220ms cubic-bezier(0.2, 0.7, 0.2, 1), opacity 180ms ease;
44
+ }
45
+
46
+ .drawer[data-open='true'] {
47
+ transform: translateX(0);
48
+ opacity: 1;
49
+ pointer-events: auto;
50
+ }
51
+
52
+ /* ---------- Header ---------- */
53
+
54
+ .header {
55
+ display: flex;
56
+ align-items: flex-end;
57
+ justify-content: space-between;
58
+ padding: var(--space-6) var(--space-6) var(--space-5);
59
+ border-bottom: 1px solid var(--bg-stroke);
60
+ flex: 0 0 auto;
61
+ }
62
+
63
+ .eyebrow {
64
+ font-family: var(--font-mono);
65
+ font-size: 12px;
66
+ color: var(--content-tertiary);
67
+ text-transform: uppercase;
68
+ letter-spacing: 0.08em;
69
+ margin-bottom: var(--space-2);
70
+ }
71
+
72
+ .title {
73
+ margin: 0;
74
+ font-size: 22px;
75
+ font-weight: var(--font-weight-semibold);
76
+ letter-spacing: -0.015em;
77
+ color: var(--content-primary);
78
+ }
79
+
80
+ .close {
81
+ width: 32px;
82
+ height: 32px;
83
+ display: grid;
84
+ place-items: center;
85
+ border: 1px solid transparent;
86
+ background: transparent;
87
+ border-radius: var(--radius-sm);
88
+ color: var(--content-secondary);
89
+ cursor: pointer;
90
+ transition:
91
+ background-color 120ms ease,
92
+ color 120ms ease;
93
+ }
94
+
95
+ .close:hover {
96
+ background-color: var(--bg-subtle);
97
+ color: var(--content-primary);
98
+ }
99
+
100
+ .close:focus-visible {
101
+ outline: 2px solid var(--accent-main);
102
+ outline-offset: 2px;
103
+ }
104
+
105
+ /* ---------- Body ---------- */
106
+
107
+ .body {
108
+ flex: 1 1 auto;
109
+ overflow-y: auto;
110
+ padding: var(--space-3) 0 var(--space-8);
111
+ }
112
+
113
+ .modules {
114
+ list-style: none;
115
+ margin: 0;
116
+ padding: 0;
117
+ display: flex;
118
+ flex-direction: column;
119
+ }
120
+
121
+ .module {
122
+ list-style: none;
123
+ border-bottom: 1px solid var(--bg-stroke);
124
+ }
125
+
126
+ .module:last-child {
127
+ border-bottom: 0;
128
+ }
129
+
130
+ .moduleHead {
131
+ display: grid;
132
+ grid-template-columns: 40px 1fr auto 24px;
133
+ align-items: center;
134
+ gap: var(--space-3);
135
+ width: 100%;
136
+ padding: var(--space-4) var(--space-6);
137
+ background: transparent;
138
+ border: 0;
139
+ text-align: left;
140
+ color: var(--content-primary);
141
+ font: inherit;
142
+ font-size: 15px;
143
+ cursor: pointer;
144
+ transition: background-color 120ms ease;
145
+ }
146
+
147
+ .moduleHead:hover {
148
+ background-color: var(--bg-subtle);
149
+ }
150
+
151
+ .moduleHead:focus-visible {
152
+ outline: 2px solid var(--accent-main);
153
+ outline-offset: -2px;
154
+ }
155
+
156
+ .moduleNum {
157
+ font-family: var(--font-mono);
158
+ font-size: 12px;
159
+ color: var(--content-tertiary);
160
+ letter-spacing: 0.04em;
161
+ }
162
+
163
+ .moduleTitle {
164
+ font-weight: var(--font-weight-semibold);
165
+ font-size: 15px;
166
+ color: var(--content-primary);
167
+ }
168
+
169
+ /* Done/total pill — flips green once the whole module is completed. */
170
+ .moduleBadge {
171
+ font-family: var(--font-mono);
172
+ font-size: 12px;
173
+ color: var(--content-secondary);
174
+ padding: 2px 6px;
175
+ background: var(--bg-subtle);
176
+ border-radius: 2px;
177
+ }
178
+
179
+ .moduleBadge[data-complete='true'] {
180
+ color: var(--content-inverse);
181
+ background: var(--accent-success);
182
+ }
183
+
184
+ .moduleChevron {
185
+ font-family: var(--font-mono);
186
+ font-size: 16px;
187
+ color: var(--content-tertiary);
188
+ text-align: center;
189
+ line-height: 1;
190
+ }
191
+
192
+ /* ---------- Lessons ---------- */
193
+
194
+ .lessons {
195
+ list-style: none;
196
+ margin: 0;
197
+ padding: 0 var(--space-6) var(--space-4);
198
+ border-top: 1px solid var(--bg-stroke);
199
+ background: var(--bg-subtle);
200
+ display: flex;
201
+ flex-direction: column;
202
+ }
203
+
204
+ .lesson {
205
+ list-style: none;
206
+ }
207
+
208
+ .lessonLink {
209
+ display: grid;
210
+ grid-template-columns: 32px 1fr auto;
211
+ align-items: center;
212
+ gap: var(--space-3);
213
+ padding: var(--space-3);
214
+ border-radius: var(--radius-sm);
215
+ font-size: 13px;
216
+ color: var(--content-secondary);
217
+ text-decoration: none;
218
+ position: relative;
219
+ transition:
220
+ background-color 120ms ease,
221
+ color 120ms ease;
222
+ }
223
+
224
+ .lessonLink:hover {
225
+ background-color: var(--bg-surface);
226
+ color: var(--content-primary);
227
+ }
228
+
229
+ .lessonLink:focus-visible {
230
+ outline: 2px solid var(--accent-main);
231
+ outline-offset: -2px;
232
+ }
233
+
234
+ .lessonNum {
235
+ font-family: var(--font-mono);
236
+ font-size: 12px;
237
+ color: var(--content-tertiary);
238
+ }
239
+
240
+ .lessonTitle {
241
+ line-height: 1.4;
242
+ }
243
+
244
+ .lessonMeta {
245
+ font-family: var(--font-mono);
246
+ font-size: 12px;
247
+ color: var(--content-tertiary);
248
+ }
249
+
250
+ .lessonCheck {
251
+ color: var(--accent-success);
252
+ font-weight: var(--font-weight-bold);
253
+ }
254
+
255
+ /* Completed: dim the link, strike-through the title — same treatment as
256
+ the reference, signals "you've been here" without hiding the entry. */
257
+ .lessonLink[data-completed='true'] {
258
+ color: var(--content-tertiary);
259
+ }
260
+
261
+ .lessonLink[data-completed='true'] .lessonTitle {
262
+ text-decoration: line-through;
263
+ text-decoration-color: var(--content-tertiary);
264
+ }
265
+
266
+ /* Active lesson — surface up with bg-surface, accent vertical strip on the
267
+ left edge via inset shadow (avoids re-flowing the grid). */
268
+ .lessonLink[data-current='true'] {
269
+ background-color: var(--bg-surface);
270
+ color: var(--content-primary);
271
+ font-weight: var(--font-weight-semibold);
272
+ box-shadow: inset 2px 0 0 var(--accent-main);
273
+ }
274
+
275
+ .lessonLink[data-current='true']:hover {
276
+ background-color: var(--bg-surface);
277
+ }
278
+
279
+ /* Gate-managed lock state. JSX always renders the open shape; the inline
280
+ gate-mark script flips data-locked on this link before first paint, and
281
+ CSS swaps the meta cell (duration/✓ → lock icon) and dims the row.
282
+ Avoids the React-driven re-render that previously caused a flash. */
283
+ .lessonLink[data-locked='true'] {
284
+ cursor: not-allowed;
285
+ color: var(--content-tertiary);
286
+ }
287
+
288
+ .lessonLink[data-locked='true']:hover {
289
+ background-color: transparent;
290
+ color: var(--content-tertiary);
291
+ }
292
+
293
+ .lessonLink[data-locked='true'] .lessonTitle,
294
+ .lessonLink[data-locked='true'] .lessonNum,
295
+ .lessonLink[data-locked='true'] .lessonMeta {
296
+ color: var(--content-tertiary);
297
+ }
298
+
299
+ .lessonMeta .metaLocked {
300
+ display: none;
301
+ align-items: center;
302
+ }
303
+
304
+ .lessonLink[data-locked='true'] .metaOpen {
305
+ display: none;
306
+ }
307
+
308
+ .lessonLink[data-locked='true'] .metaLocked {
309
+ display: inline-flex;
310
+ }
311
+
312
+ /* ---------- Mobile context strip (progress + prev/next + home/github) ---- */
313
+
314
+ /* Default = desktop: the breadcrumb header carries progress and prev/next,
315
+ the bottom sidebar carries home and github, so suppress these inside the
316
+ drawer to avoid duplication. The mobile breakpoint below re-enables them. */
317
+ .contextProgress,
318
+ .contextNav,
319
+ .contextFooter {
320
+ display: none;
321
+ }
322
+
323
+ @media (max-width: 720px) {
324
+ .drawer {
325
+ width: 100vw;
326
+ left: var(--layout-sidebar-width);
327
+ }
328
+ }
329
+
330
+ @media (max-width: 1023px) {
331
+ /* Drawer covers the entire viewport on mobile — the user explicitly asked
332
+ for a fullscreen overlay (no peeking content behind, no slide-in width
333
+ guess). The drawer is the only command surface on this breakpoint. */
334
+ .drawer {
335
+ left: 0;
336
+ right: 0;
337
+ top: 0;
338
+ bottom: 0;
339
+ width: 100vw;
340
+ width: 100dvw;
341
+ max-width: 100vw;
342
+ border: 0;
343
+ box-shadow: none;
344
+ }
345
+
346
+ /* Sticky frosted header so the eyebrow + title persist under the iOS
347
+ status bar as the user scrolls the module list. Matches the design's
348
+ drawer-head treatment (color-mix(bg 94%) + 16px backdrop blur). */
349
+ .header {
350
+ position: sticky;
351
+ top: 0;
352
+ z-index: 5;
353
+ padding: max(env(safe-area-inset-top), var(--space-4)) var(--space-5)
354
+ var(--space-4);
355
+ background-color: color-mix(in srgb, var(--bg-default) 94%, transparent);
356
+ backdrop-filter: blur(16px);
357
+ -webkit-backdrop-filter: blur(16px);
358
+ }
359
+
360
+ .contextProgress {
361
+ display: flex;
362
+ align-items: center;
363
+ padding: var(--space-3) var(--space-5);
364
+ border-bottom: 1px solid var(--bg-stroke);
365
+ flex: 0 0 auto;
366
+ }
367
+
368
+ /* The ProgressBar uses min-width:14ch on its label and a fixed-width track;
369
+ on a mobile sheet we want it to span the full width — left-align label,
370
+ stretch track to fill remaining space. */
371
+ .contextProgress > :global(*) {
372
+ width: 100%;
373
+ }
374
+
375
+ /* Lesson-nav context block: current card on top, prev/next 2-up below. */
376
+ .contextNav {
377
+ display: flex;
378
+ flex-direction: column;
379
+ gap: var(--space-3);
380
+ padding: var(--space-4) var(--space-5);
381
+ border-bottom: 1px solid var(--bg-stroke);
382
+ flex: 0 0 auto;
383
+ }
384
+
385
+ .currentCard {
386
+ padding: var(--space-3) var(--space-4);
387
+ border: 1px solid var(--bg-stroke);
388
+ border-radius: var(--radius-md);
389
+ background-color: var(--bg-surface);
390
+ }
391
+
392
+ .currentEyebrow {
393
+ font-family: var(--font-mono);
394
+ font-size: 10px;
395
+ color: var(--content-tertiary);
396
+ letter-spacing: 0.05em;
397
+ text-transform: lowercase;
398
+ }
399
+
400
+ .currentTitle {
401
+ margin-top: 4px;
402
+ font-size: 17px;
403
+ font-weight: var(--font-weight-semibold);
404
+ line-height: 1.25;
405
+ color: var(--content-primary);
406
+ }
407
+
408
+ .currentMeta {
409
+ margin-top: 6px;
410
+ font-family: var(--font-mono);
411
+ font-size: 11px;
412
+ color: var(--content-tertiary);
413
+ }
414
+
415
+ .navRow {
416
+ display: grid;
417
+ grid-template-columns: 1fr 1fr;
418
+ gap: var(--space-2);
419
+ }
420
+
421
+ .navCard {
422
+ display: flex;
423
+ align-items: center;
424
+ gap: var(--space-3);
425
+ padding: var(--space-3) var(--space-4);
426
+ border: 1px solid var(--bg-stroke);
427
+ border-radius: var(--radius-md);
428
+ background-color: var(--bg-default);
429
+ text-decoration: none;
430
+ color: inherit;
431
+ min-height: 56px;
432
+ transition:
433
+ background-color 120ms ease,
434
+ border-color 120ms ease;
435
+ }
436
+
437
+ .navCard:hover,
438
+ .navCard:focus-visible {
439
+ border-color: var(--bg-stroke-strong);
440
+ background-color: var(--bg-subtle);
441
+ }
442
+
443
+ .navCard:focus-visible {
444
+ outline: 2px solid var(--accent-main);
445
+ outline-offset: 2px;
446
+ }
447
+
448
+ .navNext {
449
+ flex-direction: row;
450
+ text-align: right;
451
+ }
452
+
453
+ .navNext .navMeta {
454
+ align-items: flex-end;
455
+ }
456
+
457
+ .navPrev {
458
+ text-align: left;
459
+ }
460
+
461
+ .navDisabled {
462
+ opacity: 0.4;
463
+ cursor: not-allowed;
464
+ }
465
+
466
+ .navChevron {
467
+ display: flex;
468
+ align-items: center;
469
+ justify-content: center;
470
+ width: 28px;
471
+ height: 28px;
472
+ flex: 0 0 28px;
473
+ border-radius: 50%;
474
+ background-color: var(--bg-surface);
475
+ border: 1px solid var(--bg-stroke);
476
+ color: var(--content-secondary);
477
+ transition:
478
+ background-color 120ms ease,
479
+ color 120ms ease,
480
+ border-color 120ms ease;
481
+ }
482
+
483
+ .navCard:hover .navChevron,
484
+ .navCard:focus-visible .navChevron {
485
+ background-color: var(--content-primary);
486
+ color: var(--bg-default);
487
+ border-color: var(--content-primary);
488
+ }
489
+
490
+ .navMeta {
491
+ display: flex;
492
+ flex-direction: column;
493
+ gap: 2px;
494
+ min-width: 0;
495
+ flex: 1 1 auto;
496
+ }
497
+
498
+ .navLabel {
499
+ font-family: var(--font-mono);
500
+ font-size: 10px;
501
+ color: var(--content-tertiary);
502
+ text-transform: lowercase;
503
+ letter-spacing: 0.02em;
504
+ }
505
+
506
+ .navTitle {
507
+ font-size: 13px;
508
+ font-weight: var(--font-weight-medium);
509
+ color: var(--content-primary);
510
+ line-height: 1.25;
511
+ overflow: hidden;
512
+ text-overflow: ellipsis;
513
+ display: -webkit-box;
514
+ -webkit-line-clamp: 2;
515
+ -webkit-box-orient: vertical;
516
+ }
517
+
518
+ .contextFooter {
519
+ display: grid;
520
+ grid-template-columns: 1fr 1fr;
521
+ gap: var(--space-3);
522
+ padding: var(--space-4) var(--space-5)
523
+ calc(var(--space-4) + env(safe-area-inset-bottom));
524
+ border-top: 1px solid var(--bg-stroke);
525
+ flex: 0 0 auto;
526
+ background-color: var(--bg-default);
527
+ }
528
+
529
+ .footerLink {
530
+ display: inline-flex;
531
+ align-items: center;
532
+ justify-content: center;
533
+ gap: var(--space-2);
534
+ padding: var(--space-3) var(--space-4);
535
+ border: 1px solid var(--bg-stroke);
536
+ border-radius: var(--radius-md);
537
+ background-color: var(--bg-surface);
538
+ color: var(--content-primary);
539
+ font-size: 14px;
540
+ font-weight: var(--font-weight-medium);
541
+ text-decoration: none;
542
+ transition:
543
+ background-color 120ms ease,
544
+ border-color 120ms ease;
545
+ }
546
+
547
+ .footerLink:hover,
548
+ .footerLink:focus-visible {
549
+ border-color: var(--accent-main);
550
+ background-color: var(--bg-subtle);
551
+ }
552
+
553
+ .footerLink:focus-visible {
554
+ outline: 2px solid var(--accent-main);
555
+ outline-offset: 2px;
556
+ }
557
+
558
+ .footerLink svg {
559
+ width: 18px;
560
+ height: 18px;
561
+ color: var(--content-secondary);
562
+ }
563
+ }