docyard 0.4.0 → 0.6.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +29 -3
  4. data/README.md +37 -12
  5. data/lib/docyard/build/static_generator.rb +1 -1
  6. data/lib/docyard/components/base_processor.rb +6 -0
  7. data/lib/docyard/components/code_block_diff_preprocessor.rb +104 -0
  8. data/lib/docyard/components/code_block_feature_extractor.rb +113 -0
  9. data/lib/docyard/components/code_block_focus_preprocessor.rb +77 -0
  10. data/lib/docyard/components/code_block_icon_detector.rb +40 -0
  11. data/lib/docyard/components/code_block_line_wrapper.rb +46 -0
  12. data/lib/docyard/components/code_block_options_preprocessor.rb +76 -0
  13. data/lib/docyard/components/code_block_patterns.rb +51 -0
  14. data/lib/docyard/components/code_block_processor.rb +135 -14
  15. data/lib/docyard/components/code_line_parser.rb +80 -0
  16. data/lib/docyard/components/code_snippet_import_preprocessor.rb +125 -0
  17. data/lib/docyard/components/heading_anchor_processor.rb +34 -0
  18. data/lib/docyard/components/registry.rb +4 -4
  19. data/lib/docyard/components/table_of_contents_processor.rb +64 -0
  20. data/lib/docyard/components/tabs_parser.rb +135 -4
  21. data/lib/docyard/components/tabs_range_finder.rb +42 -0
  22. data/lib/docyard/config/validator.rb +8 -0
  23. data/lib/docyard/config.rb +18 -0
  24. data/lib/docyard/icons/file_types.rb +0 -13
  25. data/lib/docyard/icons/phosphor.rb +2 -1
  26. data/lib/docyard/markdown.rb +18 -4
  27. data/lib/docyard/prev_next_builder.rb +159 -0
  28. data/lib/docyard/rack_application.rb +25 -3
  29. data/lib/docyard/renderer.rb +20 -8
  30. data/lib/docyard/templates/assets/css/code.css +12 -4
  31. data/lib/docyard/templates/assets/css/components/code-block.css +427 -24
  32. data/lib/docyard/templates/assets/css/components/heading-anchor.css +77 -0
  33. data/lib/docyard/templates/assets/css/components/navigation.css +12 -9
  34. data/lib/docyard/templates/assets/css/components/prev-next.css +114 -0
  35. data/lib/docyard/templates/assets/css/components/table-of-contents.css +269 -0
  36. data/lib/docyard/templates/assets/css/components/tabs.css +50 -44
  37. data/lib/docyard/templates/assets/css/layout.css +58 -1
  38. data/lib/docyard/templates/assets/css/variables.css +45 -0
  39. data/lib/docyard/templates/assets/js/components/heading-anchor.js +90 -0
  40. data/lib/docyard/templates/assets/js/components/navigation.js +6 -2
  41. data/lib/docyard/templates/assets/js/components/table-of-contents.js +301 -0
  42. data/lib/docyard/templates/layouts/default.html.erb +9 -1
  43. data/lib/docyard/templates/partials/_code_block.html.erb +50 -2
  44. data/lib/docyard/templates/partials/_heading_anchor.html.erb +1 -0
  45. data/lib/docyard/templates/partials/_prev_next.html.erb +23 -0
  46. data/lib/docyard/templates/partials/_table_of_contents.html.erb +45 -0
  47. data/lib/docyard/templates/partials/_table_of_contents_toggle.html.erb +8 -0
  48. data/lib/docyard/version.rb +1 -1
  49. metadata +23 -1
@@ -1,4 +1,4 @@
1
- /* Code Block Component with Copy Button */
1
+ /* Code Block Component */
2
2
 
3
3
  .docyard-code-block {
4
4
  position: relative;
@@ -9,17 +9,410 @@
9
9
  margin: 0;
10
10
  }
11
11
 
12
- /* Inside tabs - remove wrapper margin when code block is only child */
13
- .docyard-tabs__panel:has(> [class*="language-"]:only-child) .docyard-code-block {
12
+ /* Titled Code Block Layout */
13
+ .docyard-code-block--titled {
14
+ border: 1px solid var(--color-border);
15
+ border-radius: var(--radius-lg);
16
+ overflow: hidden;
17
+ background-color: var(--color-code-bg);
18
+ }
19
+
20
+ .docyard-code-block--titled .docyard-code-block__body {
21
+ display: block;
22
+ }
23
+
24
+ .docyard-code-block--titled .docyard-code-block__content {
25
+ display: block;
26
+ }
27
+
28
+ .docyard-code-block--titled .highlight {
14
29
  margin: 0;
30
+ border: none;
31
+ border-radius: 0;
32
+ box-shadow: none;
15
33
  }
16
34
 
17
- /* Inside tabs with mixed content - use normal spacing */
18
- .docyard-tabs__panel:not(:has(> [class*="language-"]:only-child)) .docyard-code-block {
19
- margin: var(--space-4) 0;
35
+ .docyard-code-block--titled .highlight pre {
36
+ margin: 0;
37
+ }
38
+
39
+ .docyard-code-block--titled .highlight pre code {
40
+ display: block;
41
+ padding: var(--space-4);
42
+ }
43
+
44
+ /* Code Block Header */
45
+ .docyard-code-block__header {
46
+ display: flex;
47
+ align-items: center;
48
+ gap: var(--space-2);
49
+ padding: var(--space-3) var(--space-4);
50
+ background: var(--color-bg-secondary);
51
+ border-bottom: 1px solid var(--color-border);
52
+ font-size: var(--font-size-sm);
53
+ font-weight: var(--font-weight-semibold);
54
+ color: var(--color-text-secondary);
55
+ }
56
+
57
+ .docyard-code-block__icon {
58
+ display: inline-flex;
59
+ align-items: center;
60
+ flex-shrink: 0;
61
+ }
62
+
63
+ .docyard-code-block__icon .docyard-icon {
64
+ width: 1rem;
65
+ height: 1rem;
66
+ display: inline-flex;
67
+ }
68
+
69
+ .docyard-code-block__icon .docyard-icon svg {
70
+ width: 100%;
71
+ height: 100%;
72
+ }
73
+
74
+ .docyard-code-block__title {
75
+ flex: 1;
76
+ min-width: 0;
77
+ overflow: hidden;
78
+ text-overflow: ellipsis;
79
+ white-space: nowrap;
80
+ }
81
+
82
+ /* Copy button in header */
83
+ .docyard-code-block__header .docyard-code-block__copy {
84
+ position: relative;
85
+ top: auto;
86
+ right: auto;
87
+ flex-shrink: 0;
88
+ }
89
+
90
+ /* Body wrapper for titled blocks */
91
+ .docyard-code-block__body {
92
+ position: relative;
93
+ }
94
+
95
+ /* Line Numbers Layout */
96
+ .docyard-code-block--line-numbers {
97
+ border: 1px solid var(--color-border);
98
+ border-radius: var(--radius-lg);
99
+ background-color: var(--color-code-bg);
100
+ overflow: hidden;
101
+ }
102
+
103
+ .docyard-code-block--line-numbers .docyard-code-block__body {
104
+ display: flex;
105
+ }
106
+
107
+ .docyard-code-block--line-numbers .highlight {
108
+ border: none;
109
+ border-radius: 0;
110
+ flex: 1;
111
+ min-width: 0;
112
+ }
113
+
114
+ .docyard-code-block__lines {
115
+ flex-shrink: 0;
116
+ padding: var(--space-4) 0;
117
+ border-right: 1px solid var(--color-border);
118
+ text-align: right;
119
+ user-select: none;
120
+ color: var(--color-text-tertiary);
121
+ font-family: var(--font-mono);
122
+ font-size: var(--font-size-sm);
123
+ line-height: var(--line-height-relaxed);
124
+ background-color: var(--color-code-bg);
125
+ }
126
+
127
+ .docyard-code-block__lines span {
128
+ display: block;
129
+ padding: 0 var(--space-3);
130
+ min-width: 2.5rem;
131
+ }
132
+
133
+ .docyard-code-block__content {
134
+ flex: 1;
135
+ min-width: 0;
136
+ overflow-x: auto;
137
+ }
138
+
139
+ /* Line Highlighting */
140
+ .docyard-code-line {
141
+ display: block;
142
+ }
143
+
144
+ .docyard-code-line--highlighted {
145
+ background-color: rgba(var(--color-primary-rgb), 0.1);
146
+ border-left: 3px solid var(--color-primary);
147
+ margin-left: calc(-1 * var(--space-4));
148
+ margin-right: calc(-1 * var(--space-4));
149
+ padding-left: calc(var(--space-4) - 3px);
150
+ padding-right: var(--space-4);
151
+ }
152
+
153
+ /* Highlighted line number */
154
+ .docyard-code-block__line--highlighted {
155
+ background-color: rgba(var(--color-primary-rgb), 0.15);
156
+ color: var(--color-primary);
157
+ font-weight: 500;
158
+ }
159
+
160
+ /* Diff line styles */
161
+ .docyard-code-line--diff-add {
162
+ background-color: var(--color-diff-add-bg);
163
+ border-left: 3px solid var(--color-diff-add-border);
164
+ margin-left: calc(-1 * var(--space-4));
165
+ margin-right: calc(-1 * var(--space-4));
166
+ padding-left: calc(var(--space-4) - 3px);
167
+ padding-right: var(--space-4);
168
+ }
169
+
170
+ .docyard-code-line--diff-remove {
171
+ background-color: var(--color-diff-remove-bg);
172
+ border-left: 3px solid var(--color-diff-remove-border);
173
+ margin-left: calc(-1 * var(--space-4));
174
+ margin-right: calc(-1 * var(--space-4));
175
+ padding-left: calc(var(--space-4) - 3px);
176
+ padding-right: var(--space-4);
177
+ }
178
+
179
+ /* Error/Warning line styles */
180
+ .docyard-code-line--error {
181
+ background-color: var(--color-code-error-bg, rgba(239, 68, 68, 0.15));
182
+ border-left: 3px solid var(--color-code-error-border, #ef4444);
183
+ margin-left: calc(-1 * var(--space-4));
184
+ margin-right: calc(-1 * var(--space-4));
185
+ padding-left: calc(var(--space-4) - 3px);
186
+ padding-right: var(--space-4);
187
+ }
188
+
189
+ .docyard-code-line--warning {
190
+ background-color: var(--color-code-warning-bg, rgba(245, 158, 11, 0.15));
191
+ border-left: 3px solid var(--color-code-warning-border, #f59e0b);
192
+ margin-left: calc(-1 * var(--space-4));
193
+ margin-right: calc(-1 * var(--space-4));
194
+ padding-left: calc(var(--space-4) - 3px);
195
+ padding-right: var(--space-4);
196
+ }
197
+
198
+ /* Diff gutter indicators */
199
+ .docyard-code-block__line--diff-add {
200
+ background-color: var(--color-diff-add-gutter-bg);
201
+ color: var(--color-diff-add-indicator);
202
+ font-weight: 500;
203
+ }
204
+
205
+ .docyard-code-block__line--diff-remove {
206
+ background-color: var(--color-diff-remove-gutter-bg);
207
+ color: var(--color-diff-remove-indicator);
208
+ font-weight: 500;
209
+ }
210
+
211
+ /* Error/Warning line number indicators */
212
+ .docyard-code-block__line--error {
213
+ background-color: var(--color-code-error-gutter-bg, rgba(239, 68, 68, 0.2));
214
+ color: var(--color-code-error-indicator, #991b1b);
215
+ font-weight: 500;
216
+ }
217
+
218
+ .docyard-code-block__line--warning {
219
+ background-color: var(--color-code-warning-gutter-bg, rgba(245, 158, 11, 0.2));
220
+ color: var(--color-code-warning-indicator, #78350f);
221
+ font-weight: 500;
222
+ }
223
+
224
+ /* Diff-only gutter */
225
+ .docyard-code-block--diff:not(.docyard-code-block--line-numbers) {
226
+ border: 1px solid var(--color-border);
227
+ border-radius: var(--radius-lg);
228
+ background-color: var(--color-code-bg);
229
+ overflow: hidden;
230
+ }
231
+
232
+ .docyard-code-block--diff:not(.docyard-code-block--line-numbers) .docyard-code-block__body {
233
+ display: flex;
234
+ }
235
+
236
+ .docyard-code-block--diff:not(.docyard-code-block--line-numbers) .highlight {
237
+ border: none;
238
+ border-radius: 0;
239
+ flex: 1;
240
+ min-width: 0;
241
+ }
242
+
243
+ .docyard-code-block__diff-gutter {
244
+ flex-shrink: 0;
245
+ padding: var(--space-4) 0;
246
+ border-right: 1px solid var(--color-border);
247
+ text-align: center;
248
+ user-select: none;
249
+ color: var(--color-text-tertiary);
250
+ font-family: var(--font-mono);
251
+ font-size: var(--font-size-sm);
252
+ line-height: var(--line-height-relaxed);
253
+ background-color: var(--color-code-bg);
254
+ }
255
+
256
+ .docyard-code-block__diff-gutter span {
257
+ display: block;
258
+ padding: 0 var(--space-2);
259
+ min-width: 1.5rem;
20
260
  }
21
261
 
22
- /* Inside callouts - use callout's spacing */
262
+ .docyard-code-block__diff-indicator--add {
263
+ background-color: var(--color-diff-add-gutter-bg);
264
+ color: var(--color-diff-add-indicator);
265
+ font-weight: 600;
266
+ }
267
+
268
+ .docyard-code-block__diff-indicator--remove {
269
+ background-color: var(--color-diff-remove-gutter-bg);
270
+ color: var(--color-diff-remove-indicator);
271
+ font-weight: 600;
272
+ }
273
+
274
+ /* With line numbers - reset margins, they extend via negative margin */
275
+ .docyard-code-block--line-numbers .docyard-code-line {
276
+ margin-left: 0;
277
+ margin-right: 0;
278
+ }
279
+
280
+ .docyard-code-block--line-numbers .docyard-code-line--highlighted,
281
+ .docyard-code-block--line-numbers .docyard-code-line--diff-add,
282
+ .docyard-code-block--line-numbers .docyard-code-line--diff-remove,
283
+ .docyard-code-block--line-numbers .docyard-code-line--error,
284
+ .docyard-code-block--line-numbers .docyard-code-line--warning {
285
+ margin-left: calc(-1 * var(--space-4));
286
+ margin-right: calc(-1 * var(--space-4));
287
+ }
288
+
289
+ /* With diff gutter - reset margins, they extend via negative margin */
290
+ .docyard-code-block--diff:not(.docyard-code-block--line-numbers) .docyard-code-line {
291
+ margin-left: 0;
292
+ margin-right: 0;
293
+ }
294
+
295
+ .docyard-code-block--diff:not(.docyard-code-block--line-numbers) .docyard-code-line--diff-add,
296
+ .docyard-code-block--diff:not(.docyard-code-block--line-numbers) .docyard-code-line--diff-remove {
297
+ margin-left: calc(-1 * var(--space-4));
298
+ margin-right: calc(-1 * var(--space-4));
299
+ }
300
+
301
+ /* Error/Warning blocks without line numbers */
302
+ .docyard-code-block--has-error:not(.docyard-code-block--line-numbers):not(.docyard-code-block--diff),
303
+ .docyard-code-block--has-warning:not(.docyard-code-block--line-numbers):not(.docyard-code-block--diff) {
304
+ border: 1px solid var(--color-border);
305
+ border-radius: var(--radius-lg);
306
+ background-color: var(--color-code-bg);
307
+ overflow: hidden;
308
+ }
309
+
310
+ .docyard-code-block--has-error:not(.docyard-code-block--line-numbers):not(.docyard-code-block--diff) .highlight,
311
+ .docyard-code-block--has-warning:not(.docyard-code-block--line-numbers):not(.docyard-code-block--diff) .highlight {
312
+ border: none;
313
+ border-radius: 0;
314
+ }
315
+
316
+ .docyard-code-block__content .highlight {
317
+ background-color: transparent;
318
+ }
319
+
320
+ /* Focus Effect */
321
+ .docyard-code-block--has-focus .docyard-code-line {
322
+ opacity: 0.4;
323
+ filter: blur(0.5px);
324
+ transition: opacity 0.2s ease, filter 0.2s ease;
325
+ }
326
+
327
+ .docyard-code-block--has-focus .docyard-code-line.docyard-code-line--focus {
328
+ opacity: 1;
329
+ filter: none;
330
+ }
331
+
332
+ /* On hover, reveal all lines */
333
+ .docyard-code-block--has-focus:hover .docyard-code-line {
334
+ opacity: 1;
335
+ filter: none;
336
+ }
337
+
338
+ /* Dark mode line numbers */
339
+ .dark .docyard-code-block--line-numbers {
340
+ background-color: #161b22;
341
+ }
342
+
343
+ .dark .docyard-code-block__lines {
344
+ background-color: #161b22;
345
+ border-right-color: var(--color-border);
346
+ }
347
+
348
+ /* Dark mode diff */
349
+ .dark .docyard-code-block--diff:not(.docyard-code-block--line-numbers) {
350
+ background-color: #161b22;
351
+ }
352
+
353
+ .dark .docyard-code-block__diff-gutter {
354
+ background-color: #161b22;
355
+ border-right-color: var(--color-border);
356
+ }
357
+
358
+ /* Dark mode titled block */
359
+ .dark .docyard-code-block--titled {
360
+ background-color: #161b22;
361
+ }
362
+
363
+ .dark .docyard-code-block__header {
364
+ background-color: rgba(255, 255, 255, 0.03);
365
+ }
366
+
367
+ /* Titled block with line numbers */
368
+ .docyard-code-block--titled.docyard-code-block--line-numbers {
369
+ display: block;
370
+ border: 1px solid var(--color-border);
371
+ }
372
+
373
+ .docyard-code-block--titled.docyard-code-block--line-numbers .docyard-code-block__body {
374
+ display: flex;
375
+ }
376
+
377
+ .docyard-code-block--titled.docyard-code-block--line-numbers .highlight {
378
+ flex: 1;
379
+ min-width: 0;
380
+ }
381
+
382
+ /* Titled block with diff */
383
+ .docyard-code-block--titled.docyard-code-block--diff:not(.docyard-code-block--line-numbers) {
384
+ display: block;
385
+ border: 1px solid var(--color-border);
386
+ }
387
+
388
+ .docyard-code-block--titled.docyard-code-block--diff:not(.docyard-code-block--line-numbers) .docyard-code-block__body {
389
+ display: flex;
390
+ }
391
+
392
+ .docyard-code-block--titled.docyard-code-block--diff:not(.docyard-code-block--line-numbers) .highlight {
393
+ flex: 1;
394
+ min-width: 0;
395
+ }
396
+
397
+ /* Inside tabs - with :has() support */
398
+ @supports selector(:has(*)) {
399
+ .docyard-tabs__panel:has(> [class*="language-"]:only-child) .docyard-code-block {
400
+ margin: 0;
401
+ }
402
+
403
+ .docyard-tabs__panel:not(:has(> [class*="language-"]:only-child)) .docyard-code-block {
404
+ margin: var(--space-4) 0;
405
+ }
406
+ }
407
+
408
+ /* Inside tabs - fallback for browsers without :has() */
409
+ @supports not selector(:has(*)) {
410
+ .docyard-tabs__panel .docyard-code-block {
411
+ margin: var(--space-4) 0;
412
+ }
413
+ }
414
+
415
+ /* Inside callouts */
23
416
  .docyard-callout__body .docyard-code-block {
24
417
  margin: var(--space-4) 0;
25
418
  }
@@ -47,14 +440,7 @@
47
440
  background-color: var(--color-bg);
48
441
  color: var(--color-text-secondary);
49
442
  cursor: pointer;
50
- transition: background-color var(--transition-base), border-color var(--transition-base), color var(--transition-base), opacity var(--transition-base), visibility var(--transition-base);
51
- opacity: 0;
52
- visibility: hidden;
53
- }
54
-
55
- .docyard-code-block:hover .docyard-code-block__copy {
56
- opacity: 1;
57
- visibility: visible;
443
+ transition: background-color var(--transition-base), border-color var(--transition-base), color var(--transition-base);
58
444
  }
59
445
 
60
446
  .docyard-code-block__copy:hover {
@@ -68,8 +454,6 @@
68
454
  }
69
455
 
70
456
  .docyard-code-block__copy:focus-visible {
71
- opacity: 1;
72
- visibility: visible;
73
457
  outline: 2px solid var(--color-primary);
74
458
  outline-offset: 2px;
75
459
  }
@@ -147,11 +531,26 @@
147
531
  color: white;
148
532
  }
149
533
 
150
- /* Mobile: Always show copy button */
151
- @media (max-width: 1024px) {
152
- .docyard-code-block__copy {
153
- opacity: 1;
154
- visibility: visible;
534
+ /* Mobile responsive - header */
535
+ @media (max-width: 640px) {
536
+ .docyard-code-block__header {
537
+ padding: var(--space-2) var(--space-3);
538
+ gap: var(--space-2);
539
+ }
540
+
541
+ .docyard-code-block__icon .docyard-icon {
542
+ width: 0.875rem;
543
+ height: 0.875rem;
544
+ }
545
+
546
+ .docyard-code-block__header .docyard-code-block__copy {
547
+ width: 28px;
548
+ height: 28px;
549
+ }
550
+
551
+ .docyard-code-block__header .docyard-code-block__copy svg {
552
+ width: 14px;
553
+ height: 14px;
155
554
  }
156
555
  }
157
556
 
@@ -166,7 +565,7 @@
166
565
  border-color: var(--color-text-tertiary);
167
566
  }
168
567
 
169
- /* Keep success state using primary colors in dark mode */
568
+ /* Dark mode success state */
170
569
  .dark .docyard-code-block__copy.is-success {
171
570
  background-color: var(--color-primary);
172
571
  border-color: var(--color-primary);
@@ -182,7 +581,7 @@
182
581
  border-color: #ef4444;
183
582
  }
184
583
 
185
- /* Reduced motion support - WCAG accessibility requirement */
584
+ /* Reduced motion */
186
585
  @media (prefers-reduced-motion: reduce) {
187
586
  .docyard-code-block__copy,
188
587
  .docyard-code-block__copy svg {
@@ -193,4 +592,8 @@
193
592
  .docyard-code-block__copy:active {
194
593
  transform: none;
195
594
  }
595
+
596
+ .docyard-code-block--has-focus .docyard-code-line {
597
+ transition: none;
598
+ }
196
599
  }
@@ -0,0 +1,77 @@
1
+ .content h2[id],
2
+ .content h3[id],
3
+ .content h4[id],
4
+ .content h5[id],
5
+ .content h6[id] {
6
+ position: relative;
7
+ scroll-margin-top: 100px;
8
+ }
9
+
10
+ /* Tablet: Account for both primary + secondary header */
11
+ @media (max-width: 1280px) and (min-width: 1025px) {
12
+ .content h2[id],
13
+ .content h3[id],
14
+ .content h4[id],
15
+ .content h5[id],
16
+ .content h6[id] {
17
+ scroll-margin-top: calc(var(--header-height) + 3rem + var(--space-4));
18
+ }
19
+ }
20
+
21
+ .heading-anchor {
22
+ float: left;
23
+ margin-left: -0.75em;
24
+ padding-right: 0.25em;
25
+ font-weight: var(--font-weight-normal);
26
+ color: var(--color-primary);
27
+ text-decoration: none !important;
28
+ opacity: 0;
29
+ transition: opacity var(--transition-fast);
30
+ cursor: pointer;
31
+ user-select: none;
32
+ }
33
+
34
+ .heading-anchor:hover,
35
+ .heading-anchor:focus {
36
+ opacity: 1;
37
+ text-decoration: none !important;
38
+ }
39
+
40
+ .heading-anchor:active,
41
+ .heading-anchor:visited {
42
+ text-decoration: none !important;
43
+ }
44
+
45
+ .heading-anchor:focus {
46
+ outline: 2px solid var(--color-primary);
47
+ outline-offset: 2px;
48
+ border-radius: 4px;
49
+ }
50
+
51
+ .content h2[id]:hover .heading-anchor,
52
+ .content h3[id]:hover .heading-anchor,
53
+ .content h4[id]:hover .heading-anchor,
54
+ .content h5[id]:hover .heading-anchor,
55
+ .content h6[id]:hover .heading-anchor {
56
+ opacity: 1;
57
+ }
58
+
59
+ @media (max-width: 1024px) {
60
+ .heading-anchor {
61
+ position: static;
62
+ margin-left: var(--space-2);
63
+ float: none;
64
+ opacity: 0.6;
65
+ }
66
+
67
+ .heading-anchor:hover,
68
+ .heading-anchor:focus {
69
+ opacity: 1;
70
+ }
71
+ }
72
+
73
+ @media (prefers-reduced-motion: reduce) {
74
+ .heading-anchor {
75
+ transition: none;
76
+ }
77
+ }
@@ -99,15 +99,18 @@
99
99
  position: relative;
100
100
  }
101
101
 
102
- .sidebar nav ul ul li:has(> a.active)::before {
103
- content: '';
104
- position: absolute;
105
- left: calc(-1 * var(--space-4));
106
- top: 0;
107
- bottom: 0;
108
- width: 2px;
109
- background-color: var(--color-primary);
110
- z-index: 1;
102
+ /* Active indicator with :has() support */
103
+ @supports selector(:has(*)) {
104
+ .sidebar nav ul ul li:has(> a.active)::before {
105
+ content: '';
106
+ position: absolute;
107
+ left: calc(-1 * var(--space-4));
108
+ top: 0;
109
+ bottom: 0;
110
+ width: 2px;
111
+ background-color: var(--color-primary);
112
+ z-index: 1;
113
+ }
111
114
  }
112
115
 
113
116
  .sidebar nav ul ul a {
@@ -0,0 +1,114 @@
1
+ /* Previous/Next Navigation Footer */
2
+
3
+ .doc-footer {
4
+ margin-top: 48px;
5
+ padding-top: 24px;
6
+ border-top: 1px solid var(--color-border);
7
+ }
8
+
9
+ .pager {
10
+ display: grid;
11
+ grid-template-columns: repeat(2, 1fr);
12
+ gap: 8px;
13
+ }
14
+
15
+ .pager-link {
16
+ display: block;
17
+ padding: 16px;
18
+ border: 1px solid var(--color-border);
19
+ border-radius: 8px;
20
+ text-decoration: none !important;
21
+ transition: border-color 0.25s ease, background-color 0.25s ease;
22
+ outline: none;
23
+ background-color: transparent;
24
+ }
25
+
26
+ .pager-link:hover {
27
+ border-color: var(--color-primary);
28
+ background-color: var(--color-background-soft);
29
+ }
30
+
31
+ .pager-link:focus-visible {
32
+ outline: 2px solid var(--color-primary);
33
+ outline-offset: 2px;
34
+ border-radius: 8px;
35
+ }
36
+
37
+ .pager-link.prev {
38
+ text-align: left;
39
+ }
40
+
41
+ .pager-link.next {
42
+ text-align: right;
43
+ }
44
+
45
+ .pager-label {
46
+ display: block;
47
+ font-size: 13px;
48
+ font-weight: 500;
49
+ color: var(--color-text-secondary);
50
+ margin-bottom: 0px;
51
+ text-decoration: none !important;
52
+ }
53
+
54
+ .pager-title {
55
+ display: block;
56
+ font-size: 14px;
57
+ font-weight: 500;
58
+ color: var(--color-text-primary);
59
+ overflow: hidden;
60
+ text-overflow: ellipsis;
61
+ white-space: nowrap;
62
+ text-decoration: none !important;
63
+ }
64
+
65
+ /* Mobile responsive */
66
+ @media (max-width: 640px) {
67
+ .doc-footer {
68
+ margin-top: 48px;
69
+ }
70
+
71
+ .pager {
72
+ grid-template-columns: 1fr;
73
+ }
74
+
75
+ .pager-link.next {
76
+ margin-left: 0;
77
+ }
78
+
79
+ .pager-link {
80
+ width: 100%;
81
+ }
82
+
83
+ .pager-title {
84
+ white-space: normal;
85
+ word-break: break-word;
86
+ }
87
+ }
88
+
89
+ /* Reduced motion accessibility */
90
+ @media (prefers-reduced-motion: reduce) {
91
+ .pager-link {
92
+ transition: none;
93
+ }
94
+ }
95
+
96
+ /* Print: hide navigation */
97
+ @media print {
98
+ .doc-footer {
99
+ display: none;
100
+ }
101
+ }
102
+
103
+ /* Visually hidden utility (for screen readers) */
104
+ .visually-hidden {
105
+ position: absolute;
106
+ width: 1px;
107
+ height: 1px;
108
+ padding: 0;
109
+ margin: -1px;
110
+ overflow: hidden;
111
+ clip: rect(0, 0, 0, 0);
112
+ white-space: nowrap;
113
+ border-width: 0;
114
+ }