metanorma-oiml 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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.adoc +291 -0
  4. data/data/themes/oiml/assets/oiml-logo-full-dark.svg +1 -0
  5. data/data/themes/oiml/assets/oiml-logo-full-light.svg +1 -0
  6. data/data/themes/oiml/assets/oiml-logo-icon-dark.svg +1 -0
  7. data/data/themes/oiml/assets/oiml-logo-icon-light.svg +1 -0
  8. data/data/themes/oiml/assets/oiml-logo.svg +1 -0
  9. data/data/themes/oiml/theme.yaml +56 -0
  10. data/exe/oiml-sts +10 -0
  11. data/lib/metanorma/oiml/document/root.rb +29 -0
  12. data/lib/metanorma/oiml/document.rb +35 -0
  13. data/lib/metanorma/oiml/html/renderer.rb +14 -0
  14. data/lib/metanorma/oiml/html.rb +14 -0
  15. data/lib/metanorma/oiml/sts/cli.rb +89 -0
  16. data/lib/metanorma/oiml/sts/html_renderer/assets/metanorma-icon-dark.svg +1 -0
  17. data/lib/metanorma/oiml/sts/html_renderer/assets/metanorma-icon-light.svg +1 -0
  18. data/lib/metanorma/oiml/sts/html_renderer/assets/oiml-logo-dark.svg +1 -0
  19. data/lib/metanorma/oiml/sts/html_renderer/assets/oiml-logo.svg +1 -0
  20. data/lib/metanorma/oiml/sts/html_renderer/assets/oiml-smart-logo-dark.svg +1 -0
  21. data/lib/metanorma/oiml/sts/html_renderer/assets/oiml-smart-logo.svg +1 -0
  22. data/lib/metanorma/oiml/sts/html_renderer/assets/page.js +145 -0
  23. data/lib/metanorma/oiml/sts/html_renderer/assets/theme.css +509 -0
  24. data/lib/metanorma/oiml/sts/html_renderer/ruby.rb +1071 -0
  25. data/lib/metanorma/oiml/sts/html_renderer/templates/_element.html.liquid +1 -0
  26. data/lib/metanorma/oiml/sts/html_renderer/templates/_footer.html.liquid +21 -0
  27. data/lib/metanorma/oiml/sts/html_renderer/templates/_hero.html.liquid +9 -0
  28. data/lib/metanorma/oiml/sts/html_renderer/templates/_img.html.liquid +1 -0
  29. data/lib/metanorma/oiml/sts/html_renderer/templates/_link.html.liquid +1 -0
  30. data/lib/metanorma/oiml/sts/html_renderer/templates/_meta_header.html.liquid +1 -0
  31. data/lib/metanorma/oiml/sts/html_renderer/templates/document.html.liquid +43 -0
  32. data/lib/metanorma/oiml/sts/html_renderer.rb +19 -0
  33. data/lib/metanorma/oiml/sts/mathml_builder.rb +93 -0
  34. data/lib/metanorma/oiml/sts/parity_validator/normaliser.rb +95 -0
  35. data/lib/metanorma/oiml/sts/parity_validator/report.rb +137 -0
  36. data/lib/metanorma/oiml/sts/parity_validator.rb +23 -0
  37. data/lib/metanorma/oiml/sts/transformer/back_transformer.rb +55 -0
  38. data/lib/metanorma/oiml/sts/transformer/base.rb +71 -0
  39. data/lib/metanorma/oiml/sts/transformer/block_dispatcher.rb +145 -0
  40. data/lib/metanorma/oiml/sts/transformer/body_transformer.rb +23 -0
  41. data/lib/metanorma/oiml/sts/transformer/context.rb +27 -0
  42. data/lib/metanorma/oiml/sts/transformer/dl_transformer.rb +49 -0
  43. data/lib/metanorma/oiml/sts/transformer/document_transformer.rb +65 -0
  44. data/lib/metanorma/oiml/sts/transformer/figure_transformer.rb +49 -0
  45. data/lib/metanorma/oiml/sts/transformer/footnote_collector.rb +33 -0
  46. data/lib/metanorma/oiml/sts/transformer/formula_transformer.rb +45 -0
  47. data/lib/metanorma/oiml/sts/transformer/front_transformer.rb +84 -0
  48. data/lib/metanorma/oiml/sts/transformer/id_generator.rb +39 -0
  49. data/lib/metanorma/oiml/sts/transformer/inline_transformer.rb +14 -0
  50. data/lib/metanorma/oiml/sts/transformer/list_transformer.rb +82 -0
  51. data/lib/metanorma/oiml/sts/transformer/model_builder.rb +322 -0
  52. data/lib/metanorma/oiml/sts/transformer/note_transformer.rb +103 -0
  53. data/lib/metanorma/oiml/sts/transformer/paragraph_transformer.rb +574 -0
  54. data/lib/metanorma/oiml/sts/transformer/reference_transformer.rb +107 -0
  55. data/lib/metanorma/oiml/sts/transformer/rendered_text_extractor.rb +168 -0
  56. data/lib/metanorma/oiml/sts/transformer/section_transformer.rb +233 -0
  57. data/lib/metanorma/oiml/sts/transformer/source_document.rb +246 -0
  58. data/lib/metanorma/oiml/sts/transformer/standard.rb +37 -0
  59. data/lib/metanorma/oiml/sts/transformer/table_transformer.rb +290 -0
  60. data/lib/metanorma/oiml/sts/transformer/term_transformer.rb +236 -0
  61. data/lib/metanorma/oiml/sts/transformer.rb +47 -0
  62. data/lib/metanorma/oiml/sts/validation_report.rb +43 -0
  63. data/lib/metanorma/oiml/sts/validator.rb +126 -0
  64. data/lib/metanorma/oiml/sts/version.rb +9 -0
  65. data/lib/metanorma/oiml/sts.rb +84 -0
  66. data/lib/metanorma-oiml.rb +10 -0
  67. data/schematron/oiml-sts.sch +70 -0
  68. metadata +221 -0
@@ -0,0 +1,509 @@
1
+ @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
2
+
3
+ @theme {
4
+ --color-oiml-blue: #004996;
5
+ --color-oiml-blue-bright: #1a6bcc;
6
+ --color-oiml-blue-dark: #013a78;
7
+ --color-oiml-warm: #d4a017;
8
+ --color-accent: var(--color-oiml-blue);
9
+ --color-accent-soft: #e7eff9;
10
+ --color-accent-strong: #4d97f5;
11
+ --color-nav-bg: #faf6ee;
12
+ --color-nav-border: #e8e0cf;
13
+ --color-nav-text: #4b4137;
14
+ --color-nav-btn-bg: #ffffff;
15
+ --color-nav-btn-border: #ddd2ba;
16
+ --color-ink: #1b2230;
17
+ --color-ink-soft: #4a5568;
18
+ --color-ink-faint: #8a94a6;
19
+ --color-paper: #ffffff;
20
+ --color-paper-soft: #f6f8fb;
21
+ --color-paper-inset: #eef2f7;
22
+ --color-line: #dde3ec;
23
+ --color-line-strong: #c3ccd9;
24
+ --color-link: #0b5ec4;
25
+ --color-link-hover: #084a9e;
26
+ --color-code-bg: #f0f3f8;
27
+ --font-body: "Helvetica Neue", "Segoe UI", Arial, sans-serif;
28
+ --font-mono: "JetBrains Mono", "SFMono-Regular", Menlo, Consolas, monospace;
29
+ }
30
+
31
+ [data-theme="dark"] {
32
+ --color-accent: #4d97f5;
33
+ --color-accent-soft: #16283f;
34
+ --color-nav-bg: #221c14;
35
+ --color-nav-border: #3a3122;
36
+ --color-nav-text: #c9bda6;
37
+ --color-nav-btn-bg: #2b2419;
38
+ --color-nav-btn-border: #4a3f2a;
39
+ --color-ink: #e6eaf2;
40
+ --color-ink-soft: #aeb8c9;
41
+ --color-ink-faint: #76839a;
42
+ --color-paper: #10141c;
43
+ --color-paper-soft: #161c27;
44
+ --color-paper-inset: #1c2431;
45
+ --color-line: #2a3547;
46
+ --color-line-strong: #3a4a63;
47
+ --color-link: #6aa9f7;
48
+ --color-link-hover: #93c2fa;
49
+ --color-code-bg: #1d2736;
50
+ }
51
+
52
+ @media (prefers-color-scheme: dark) {
53
+ :root:not([data-theme="light"]) {
54
+ --color-accent: #4d97f5;
55
+ --color-accent-soft: #16283f;
56
+ --color-nav-bg: #221c14;
57
+ --color-nav-border: #3a3122;
58
+ --color-nav-text: #c9bda6;
59
+ --color-nav-btn-bg: #2b2419;
60
+ --color-nav-btn-border: #4a3f2a;
61
+ --color-ink: #e6eaf2;
62
+ --color-ink-soft: #aeb8c9;
63
+ --color-ink-faint: #76839a;
64
+ --color-paper: #10141c;
65
+ --color-paper-soft: #161c27;
66
+ --color-paper-inset: #1c2431;
67
+ --color-line: #2a3547;
68
+ --color-line-strong: #3a4a63;
69
+ --color-link: #6aa9f7;
70
+ --color-link-hover: #93c2fa;
71
+ --color-code-bg: #1d2736;
72
+ }
73
+ }
74
+
75
+ /* Semantic utilities used by the renderer's element handlers */
76
+ @utility note {
77
+ margin: 1rem 0;
78
+ padding: 0.75rem 1.1rem;
79
+ border-left: 3px solid var(--color-accent);
80
+ background: var(--color-accent-soft);
81
+ border-radius: 0 8px 8px 0;
82
+ box-shadow: 0 1px 2px rgba(16, 42, 84, 0.06);
83
+ & p:first-child { margin-top: 0; }
84
+ & p:last-child { margin-bottom: 0; }
85
+ }
86
+
87
+ @utility example {
88
+ margin: 1rem 0;
89
+ padding: 0.75rem 1.1rem;
90
+ border-left: 3px solid var(--color-oiml-warm);
91
+ background: var(--color-accent-soft);
92
+ border-radius: 0 8px 8px 0;
93
+ box-shadow: 0 1px 2px rgba(16, 42, 84, 0.06);
94
+ & p:first-child { margin-top: 0; }
95
+ & p:last-child { margin-bottom: 0; }
96
+ }
97
+
98
+ @utility table-wrap {
99
+ margin: 1.1rem 0;
100
+ overflow-x: auto;
101
+ border: 1px solid var(--color-line);
102
+ border-radius: 8px;
103
+ box-shadow: 0 1px 2px rgba(16, 42, 84, 0.06);
104
+ }
105
+
106
+ @utility formula {
107
+ margin: 1rem 0;
108
+ padding: 0.6rem 1rem;
109
+ overflow-x: auto;
110
+ background: var(--color-paper-inset);
111
+ border-radius: 8px;
112
+ }
113
+
114
+ @utility label {
115
+ font-weight: 700;
116
+ margin-right: 0.4em;
117
+ }
118
+
119
+ @utility citation { flex: 1; }
120
+
121
+ @utility std {
122
+ display: block;
123
+ margin-top: 0.2em;
124
+ font-size: 0.94em;
125
+ color: var(--color-ink-soft);
126
+ & em { font-style: italic; }
127
+ }
128
+
129
+ @utility std-ref { font-style: italic; }
130
+
131
+ @utility std-ident { color: var(--color-ink-soft); }
132
+
133
+ @utility originator {
134
+ color: var(--color-ink-faint);
135
+ font-size: 0.9em;
136
+ &::before { content: " · "; }
137
+ }
138
+
139
+ @utility copyright { color: var(--color-ink-soft); }
140
+
141
+ @utility footnote {
142
+ font-size: 0.85em;
143
+ vertical-align: super;
144
+ }
145
+
146
+ @utility small-caps { font-variant: small-caps; }
147
+
148
+ @utility h-anchor {
149
+ position: absolute;
150
+ right: 0.35rem;
151
+ top: 50%;
152
+ transform: translateY(-50%);
153
+ padding: 0 0.3em;
154
+ font-size: 0.75em;
155
+ font-weight: 400;
156
+ color: var(--color-ink-faint);
157
+ text-decoration: none;
158
+ opacity: 0;
159
+ transition: opacity 0.15s ease;
160
+ &:hover { color: var(--color-accent); }
161
+ &:focus { opacity: 1; }
162
+ &.copied { color: #0a9d58; opacity: 1; }
163
+ }
164
+
165
+ h2:hover .h-anchor, h3:hover .h-anchor, h4:hover .h-anchor { opacity: 1; }
166
+
167
+ @utility ref-list {
168
+ margin-top: 2.5rem;
169
+ padding-top: 1rem;
170
+ border-top: 1px solid var(--color-line);
171
+ }
172
+
173
+ @utility ref {
174
+ display: flex;
175
+ margin: 0.45rem 0;
176
+ padding: 0.55rem 0.8rem;
177
+ border-radius: 5px;
178
+ background: var(--color-paper-soft);
179
+ border: 1px solid var(--color-line);
180
+ & .label {
181
+ font-family: var(--font-mono);
182
+ font-size: 0.85em;
183
+ color: var(--color-ink-faint);
184
+ margin-right: 0.5em;
185
+ }
186
+ & .citation { flex: 1; }
187
+ }
188
+
189
+ @utility toc-link {
190
+ display: block;
191
+ padding: 0.34rem 0.5rem 0.34rem 1rem;
192
+ border-left: 2px solid transparent;
193
+ color: var(--color-ink-soft);
194
+ text-decoration: none;
195
+ line-height: 1.35;
196
+ border-radius: 0 5px 5px 0;
197
+ &:hover { color: var(--color-accent); background: var(--color-accent-soft); }
198
+ &.active {
199
+ color: var(--color-accent);
200
+ border-left-color: var(--color-accent);
201
+ background: var(--color-accent-soft);
202
+ font-weight: 600;
203
+ }
204
+ }
205
+
206
+ @utility toc-link-d1 {
207
+ padding-left: 1.9rem;
208
+ font-size: 0.94em;
209
+ }
210
+
211
+ @utility toc-link-d2 {
212
+ padding-left: 2.8rem;
213
+ font-size: 0.9em;
214
+ }
215
+
216
+ @utility toc-link-d3 {
217
+ padding-left: 3.7rem;
218
+ font-size: 0.88em;
219
+ }
220
+
221
+ @utility brand-logo-dark { display: none; }
222
+
223
+ [data-theme="dark"] .brand-logo-light { display: none; }
224
+ [data-theme="dark"] .brand-logo-dark { display: block; }
225
+ @media (prefers-color-scheme: dark) {
226
+ :root:not([data-theme="light"]) .brand-logo-light { display: none; }
227
+ :root:not([data-theme="light"]) .brand-logo-dark { display: block; }
228
+ }
229
+
230
+ /* Page chrome that utilities alone can't express */
231
+ html { scroll-padding-top: 68px; }
232
+ body { -webkit-font-smoothing: antialiased; }
233
+
234
+ /* Vertical rhythm (Tailwind preflight zeroes these) */
235
+ main p { margin: 0.85rem 0; }
236
+ main ul, main ol { margin: 0.85rem 0; }
237
+ li { margin: 0.35rem 0; }
238
+ li > p { margin: 0.3rem 0; }
239
+ li > p:first-child { margin-top: 0; }
240
+ li > p:last-child { margin-bottom: 0; }
241
+
242
+ ul, ol { padding-left: 1.6em; }
243
+ li::marker { color: var(--color-accent); }
244
+
245
+ /* Notes and examples carry a kind label */
246
+ .note-label {
247
+ font-weight: 700;
248
+ color: var(--color-accent);
249
+ letter-spacing: 0.04em;
250
+ }
251
+
252
+ /* The TOC panel heading is an h2 for document structure, but must not
253
+ inherit the numbered-section band */
254
+ h2.toc-heading {
255
+ border-left: none;
256
+ background: none;
257
+ padding: 0;
258
+ margin: 0 0 0.5rem 1rem;
259
+ font-size: 0.75rem;
260
+ }
261
+
262
+ /* Reference bodies are paragraphs; the flex ref card resets their rhythm */
263
+ .ref > .ref-body { margin: 0; flex: 1; }
264
+
265
+ /* Section numbers from the source's <label>, prefixed to headings */
266
+ .sec-label {
267
+ font-weight: 750;
268
+ color: var(--color-accent);
269
+ margin-right: 0.35em;
270
+ }
271
+
272
+ /* Lists whose items carry explicit markers from the source */
273
+ .mn-labeled-list { list-style: none; padding-left: 0.2em; }
274
+ .mn-labeled-list > li { position: relative; padding-left: 1.9em; }
275
+ .li-label {
276
+ position: absolute;
277
+ left: 0.2em;
278
+ color: var(--color-ink-soft);
279
+ font-weight: 500;
280
+ }
281
+
282
+ /* Table caption band above the table (tbl-caption, not table-caption:
283
+ Tailwind owns the latter as a display utility) */
284
+ .tbl-caption {
285
+ margin: 0;
286
+ padding: 0.55rem 0.75rem;
287
+ font-size: 0.88rem;
288
+ background: var(--color-paper-soft);
289
+ border-bottom: 1px solid var(--color-line);
290
+ border-radius: 8px 8px 0 0;
291
+ }
292
+ .tc-label { font-weight: 700; color: var(--color-accent); }
293
+ .tc-delim { color: var(--color-ink-faint); }
294
+
295
+ /* Unnumbered front-matter sections (Copyright, Feedback, Foreword,
296
+ Introduction): separated muted cards, no big heading band */
297
+ .frontmatter {
298
+ margin: 0 0 1.1rem;
299
+ padding: 0.9rem 1.2rem;
300
+ background: var(--color-paper-soft);
301
+ border: 1px solid var(--color-line);
302
+ border-radius: 10px;
303
+ font-size: 0.9rem;
304
+ color: var(--color-ink-soft);
305
+ }
306
+ .frontmatter h2 {
307
+ font-size: 0.78rem;
308
+ font-weight: 700;
309
+ letter-spacing: 0.12em;
310
+ text-transform: uppercase;
311
+ padding: 0;
312
+ margin: 0 0 0.5rem;
313
+ border-left: none;
314
+ background: none;
315
+ border-radius: 0;
316
+ color: var(--color-ink-faint);
317
+ }
318
+ .frontmatter p { margin: 0.35rem 0; font-size: inherit; }
319
+ .frontmatter p:last-child { margin-bottom: 0; }
320
+
321
+ dt { margin-top: 0.7rem; font-weight: 650; color: var(--color-accent); }
322
+ dd { margin: 0.15rem 0 0.4rem 1.4rem; }
323
+
324
+ main section { margin-bottom: 1.75rem; }
325
+
326
+ /* Cover hero */
327
+ .hero {
328
+ padding: 2.5rem 1.5rem 2.25rem;
329
+ background: linear-gradient(135deg, var(--color-accent-soft) 0%, transparent 75%);
330
+ border-bottom: 1px solid var(--color-line);
331
+ }
332
+ .hero > * { max-width: 1200px; margin-left: auto; margin-right: auto; }
333
+ .hero-eyebrow {
334
+ margin: 0 0 0.9rem;
335
+ font-family: var(--font-mono);
336
+ font-size: 0.72rem;
337
+ font-weight: 700;
338
+ letter-spacing: 0.16em;
339
+ text-transform: uppercase;
340
+ color: var(--color-accent);
341
+ }
342
+ .hero-title {
343
+ margin: 0 0 1.1rem;
344
+ font-size: 2.1rem;
345
+ font-weight: 800;
346
+ line-height: 1.15;
347
+ letter-spacing: -0.01em;
348
+ color: var(--color-ink);
349
+ max-width: 26ch;
350
+ }
351
+ .hero-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0; }
352
+ .hero-chip {
353
+ font-family: var(--font-mono);
354
+ font-size: 0.75rem;
355
+ font-weight: 600;
356
+ padding: 0.25rem 0.65rem;
357
+ border: 1px solid var(--color-accent);
358
+ border-radius: 999px;
359
+ color: var(--color-accent);
360
+ background: var(--color-paper);
361
+ }
362
+ .hero-chip-primary {
363
+ background: var(--color-accent);
364
+ color: #fff;
365
+ }
366
+ @media (max-width: 640px) {
367
+ .hero { padding: 1.75rem 1rem 1.75rem; }
368
+ .hero-title { font-size: 1.55rem; }
369
+ }
370
+
371
+ /* Footer */
372
+ .footer-grid {
373
+ display: grid;
374
+ grid-template-columns: minmax(0, 1fr) auto;
375
+ gap: 1.5rem;
376
+ max-width: 1200px;
377
+ margin: 0 auto;
378
+ text-align: left;
379
+ }
380
+ .footer-block p { margin: 0.15rem 0; }
381
+ .footer-license { font-weight: 650; color: var(--color-ink); }
382
+ .footer-publisher { font-weight: 600; color: var(--color-ink-soft); }
383
+ .footer-address, .footer-contact { color: var(--color-ink-faint); }
384
+ .footer-meta { text-align: right; white-space: nowrap; }
385
+ .footer-docid {
386
+ display: inline-block;
387
+ font-family: var(--font-mono);
388
+ font-size: 0.78rem;
389
+ font-weight: 700;
390
+ color: var(--color-accent);
391
+ border: 1px solid var(--color-accent);
392
+ border-radius: 999px;
393
+ padding: 0.2rem 0.6rem;
394
+ }
395
+ .footer-generated { color: var(--color-ink-faint); }
396
+ /* The span must NOT set display: the brand-logo-light/dark utility
397
+ decides visibility, and an unlayered display here would override it
398
+ (unlayered CSS beats layered utilities) — showing BOTH metanorma
399
+ icons in light mode. */
400
+ .mn-icon { vertical-align: -2px; margin-right: 0.35rem; }
401
+ .mn-icon svg { height: 15px; width: auto; }
402
+ @media (max-width: 640px) {
403
+ .footer-grid { grid-template-columns: 1fr; gap: 0.75rem; }
404
+ .footer-meta { text-align: left; }
405
+ }
406
+
407
+ h2, h3, h4 { position: relative; line-height: 1.3; }
408
+ h2 {
409
+ font-size: 1.5rem;
410
+ font-weight: 700;
411
+ padding: 0.55rem 0 0.55rem 0.85rem;
412
+ margin: 0 0 0.8rem;
413
+ border-left: 4px solid var(--color-accent);
414
+ background: linear-gradient(90deg, var(--color-accent-soft), transparent 70%);
415
+ border-radius: 0 5px 5px 0;
416
+ }
417
+ h3 { font-size: 1.2rem; font-weight: 650; margin: 1.75rem 0 0.8rem; }
418
+ h4 { font-size: 1.02rem; font-weight: 650; color: var(--color-ink-soft); margin: 1.5rem 0 0.8rem; }
419
+
420
+ table {
421
+ width: 100%;
422
+ border-collapse: collapse;
423
+ font-size: 0.92rem;
424
+ }
425
+ th, td {
426
+ padding: 0.5rem 0.75rem;
427
+ text-align: left;
428
+ vertical-align: top;
429
+ border-bottom: 1px solid var(--color-line);
430
+ }
431
+ th {
432
+ background: var(--color-paper-inset);
433
+ font-weight: 650;
434
+ border-bottom: 2px solid var(--color-accent);
435
+ white-space: nowrap;
436
+ }
437
+ tbody tr:nth-child(even) td { background: var(--color-paper-soft); }
438
+ tbody tr:hover td { background: var(--color-accent-soft); }
439
+ tr:last-child td { border-bottom: none; }
440
+
441
+ code {
442
+ font-family: var(--font-mono);
443
+ font-size: 0.86em;
444
+ background: var(--color-code-bg);
445
+ border-radius: 4px;
446
+ padding: 0.12em 0.34em;
447
+ white-space: nowrap;
448
+ }
449
+
450
+ pre {
451
+ margin: 1rem 0;
452
+ padding: 0.75rem 1rem;
453
+ background: var(--color-code-bg);
454
+ border: 1px solid var(--color-line);
455
+ border-radius: 8px;
456
+ font-family: var(--font-mono);
457
+ font-size: 0.82rem;
458
+ line-height: 1.5;
459
+ overflow-x: auto;
460
+ white-space: pre;
461
+ }
462
+
463
+ a { color: var(--color-link); text-decoration: none; }
464
+ a:hover { color: var(--color-link-hover); text-decoration: underline; }
465
+
466
+ blockquote {
467
+ margin: 1rem 0;
468
+ padding: 0.5rem 1.2rem;
469
+ border-left: 3px solid var(--color-line-strong);
470
+ color: var(--color-ink-soft);
471
+ font-style: italic;
472
+ }
473
+
474
+ figure { margin: 1.2rem 0; text-align: center; }
475
+ figure img { max-width: 100%; height: auto; }
476
+ figcaption { margin-top: 0.4rem; font-size: 0.88rem; color: var(--color-ink-faint); }
477
+
478
+ @media (max-width: 1024px) {
479
+ .toc-panel {
480
+ position: fixed;
481
+ top: 56px;
482
+ left: 0;
483
+ bottom: 0;
484
+ z-index: 46;
485
+ width: min(320px, 84vw);
486
+ max-height: none !important;
487
+ padding: 1rem 1.1rem 1.5rem !important;
488
+ background: var(--color-paper);
489
+ border-right: 1px solid var(--color-line);
490
+ box-shadow: 0 8px 24px rgba(16, 42, 84, 0.10);
491
+ transform: translateX(-105%);
492
+ transition: transform 0.22s ease;
493
+ }
494
+ .toc-panel.open { transform: none; }
495
+ }
496
+
497
+ @media (max-width: 640px) {
498
+ h2 { font-size: 1.3rem; }
499
+ .crumb-current, .crumb-sep { display: none; }
500
+ }
501
+
502
+ @media print {
503
+ .site-nav { position: static; box-shadow: none; }
504
+ .toc-panel, .back-to-top, .site-footer, .nav-actions { display: none !important; }
505
+ .page { display: block !important; padding: 0 !important; }
506
+ main { max-width: none; }
507
+ h2 { break-after: avoid; }
508
+ section { break-inside: avoid-page; }
509
+ }