Skip to main content

marco_core/render/
base_css.rs

1/// Base structural stylesheet for the viewer HTML preview.
2///
3/// This contains ALL HTML element rules and viewer component rules.
4/// It references CSS custom properties (set by the theme token files)
5/// with safe fallback values so it works even if a variable is not defined.
6///
7/// Theme files (`.css` in `assets/themes/html_viever/`) provide ONLY
8/// CSS custom property declarations (`--var: value`) — no structural rules.
9/// This may include descriptive `--theme-*` metadata tokens (name,
10/// author, license, version, description) alongside the colour/font ones —
11/// see [`theme_meta::parse_theme_metadata`](super::theme_meta::parse_theme_metadata)
12/// for how consumers read them back out.
13///
14/// Injection order in the final `<style>` block:
15///   1. `inline_bg_style` — instant background colour flash-prevention
16///   2. `base_css()`       — this file: all structure, via CSS custom properties
17///   3. `css`              — the active theme file: only token overrides
18///   4. `table_resize_css` — separate `<style>` block (interactive table/slider/anchor rules)
19pub fn base_css() -> &'static str {
20    BASE_CSS
21}
22
23const BASE_CSS: &str = r#"
24/* ═══════════════════════════════════════════════════════════════════════════
25   MARCO BASE STYLESHEET
26   All structural CSS for the HTML preview pane. Uses CSS custom properties
27   defined by the active theme token file. Safe fallbacks are provided for
28   every variable so this works standalone.
29   ═══════════════════════════════════════════════════════════════════════════ */
30
31/* ── Color-scheme hints (controls scrollbars, form controls, native UI) ─── */
32html.theme-light { color-scheme: light; }
33html.theme-dark  { color-scheme: dark;  }
34
35/* ── HTML element background (ensures full-page colour in static exports) ── */
36html { background-color: var(--bg-color, #fff); }
37
38/* ── Body ─────────────────────────────────────────────────────────────────── */
39body {
40    font-family: var(--body-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif);
41    font-size: var(--body-font-size, 16px);
42    line-height: var(--body-line-height, 1.6);
43    color: var(--text-color, #333);
44    background-color: var(--bg-color, #fff);
45    max-width: var(--body-max-width, 900px);
46    margin: 0 auto;
47    padding: var(--body-padding, 2rem);
48    transition: background-color 0.2s ease, color 0.2s ease;
49}
50
51body {
52    --mc-task-primary: var(--link-color, #0066cc);
53    --mc-task-accent:  var(--link-hover, #0052a3);
54}
55
56/* ── Headings ─────────────────────────────────────────────────────────────── */
57h1, h2, h3, h4, h5, h6 {
58    font-weight: 600;
59    margin-top: 1.5rem;
60    margin-bottom: 0.75rem;
61    line-height: 1.25;
62    /* Provide a real computed color for child elements (anchor icons, etc.). */
63    color: var(--heading-color, #1a1a1a);
64    /* Gradient: when --heading-gradient-end equals --heading-color the gradient
65       is invisible (solid colour). The viewer theme can set a custom accent. */
66    background: linear-gradient(
67        45deg,
68        var(--heading-color, #1a1a1a),
69        var(--heading-gradient-end, var(--heading-color, #1a1a1a))
70    );
71    -webkit-background-clip: text;
72    -webkit-text-fill-color: transparent;
73    background-clip: text;
74    position: relative;
75}
76
77h1 { font-size: 2rem; }
78h2 { font-size: 1.75rem; }
79h3 { font-size: 1.5rem; }
80h4 { font-size: 1.25rem; }
81h5 { font-size: 1.1rem; }
82h6 { font-size: 1rem; }
83
84/* Optional h1/h2 bottom border (e.g. GitHub theme sets this variable). */
85h1, h2 {
86    border-bottom: var(--h1h2-border-bottom, none);
87    padding-bottom: var(--h1h2-padding-bottom, 0);
88}
89
90/* Fix code/mark/emoji inside headings: restore visible fill. */
91h1 code, h2 code, h3 code, h4 code, h5 code, h6 code,
92h1 mark, h2 mark, h3 mark, h4 mark, h5 mark, h6 mark {
93    -webkit-text-fill-color: initial;
94    color: var(--text-color, #333);
95    background: none;
96    background-clip: unset;
97    -webkit-background-clip: unset;
98}
99
100h1 .marco-emoji, h2 .marco-emoji, h3 .marco-emoji,
101h4 .marco-emoji, h5 .marco-emoji, h6 .marco-emoji {
102    -webkit-text-fill-color: initial;
103    color: initial;
104}
105
106/* ── Paragraphs ───────────────────────────────────────────────────────────── */
107p {
108    margin: 0 0 1rem 0;
109    color: var(--text-color, #333);
110}
111
112/* ── Text formatting ──────────────────────────────────────────────────────── */
113strong, b {
114    font-weight: 700;
115    color: var(--strong-color, var(--text-color, #333));
116}
117
118em, i {
119    font-style: italic;
120    color: var(--text-color, #333);
121}
122
123del, s {
124    text-decoration: line-through;
125    color: var(--text-muted, #888);
126}
127
128mark {
129    background-color: var(--mark-bg, #fff8c5);
130    color: var(--mark-color, #1a1a1a);
131    padding: 0.1em 0.25em;
132    border-radius: 3px;
133}
134
135sup, sub {
136    font-size: 0.8em;
137    line-height: 0;
138    position: relative;
139    vertical-align: baseline;
140}
141
142sup { top: -0.5em; }
143sub { bottom: -0.25em; }
144
145kbd {
146    background-color: var(--bg-code, #f5f5f5);
147    border: 1px solid var(--border-color, #ddd);
148    border-radius: 4px;
149    color: var(--text-color, #333);
150    font-family: var(--code-font, 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace, 'Noto Sans Arabic', 'Noto Sans Hebrew', 'Noto Sans', Arial, sans-serif);
151    font-size: 0.875em;
152    padding: 0.2em 0.4em;
153    vertical-align: baseline;
154}
155
156abbr[title] {
157    border-bottom: 1px dotted var(--border-color, #ddd);
158    cursor: help;
159    text-decoration: none;
160}
161
162/* ── Links ────────────────────────────────────────────────────────────────── */
163/* Basic colour + hover. SVG icon overlays are in the `table_resize_css` block. */
164a {
165    color: var(--link-color, #0066cc);
166    text-decoration: none;
167}
168
169a:hover {
170    color: var(--link-hover, var(--link-color, #0052a3));
171    text-decoration: underline;
172}
173
174a:visited {
175    color: var(--link-color, #0066cc);
176}
177
178/* ── Inline code ──────────────────────────────────────────────────────────── */
179code {
180    font-family: var(--code-font, 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace, 'Noto Sans Arabic', 'Noto Sans Hebrew', 'Noto Sans', Arial, sans-serif);
181    font-size: 0.875em;
182    background-color: var(--bg-code, #f5f5f5);
183    border-radius: 4px;
184    padding: 0.2em 0.4em;
185}
186
187/* ── Code blocks ──────────────────────────────────────────────────────────── */
188pre {
189    background-color: var(--bg-pre, #f8f8f8);
190    border: 1px solid var(--border-color, #ddd);
191    border-radius: 6px;
192    margin: 1rem 0;
193    overflow: hidden;
194    position: relative;
195}
196
197pre[data-language]::before {
198    content: attr(data-language);
199    display: block;
200    background-color: var(--bg-pre, #f8f8f8);
201    color: var(--text-secondary, #666);
202    padding: 0.4rem 0.75rem;
203    font-size: 0.8rem;
204    font-family: var(--body-font, -apple-system, sans-serif);
205    font-weight: 400;
206    border-bottom: 1px solid var(--border-color, #ddd);
207    opacity: 0.8;
208}
209
210pre code {
211    display: block;
212    padding: 1rem;
213    background: transparent;
214    border-radius: 0;
215    font-size: 0.875em;
216    line-height: 1.5;
217    overflow-x: auto;
218    white-space: pre;
219    word-break: normal;
220}
221
222/* ── Nested code blocks (.nested-code-block) ──────────────────────────────── */
223.nested-code-block {
224    border: 1px solid var(--border-color, #ddd);
225    border-left: 4px solid var(--link-color, #0066cc);
226    border-radius: 6px;
227    margin: 1rem 0;
228    overflow: hidden;
229    background-color: var(--bg-pre, #f8f8f8);
230}
231
232.nested-code-block.level-2 { border-left-color: var(--blockquote-border, #ccc); }
233.nested-code-block.level-3 { border-left-color: var(--border-strong, #999); }
234.nested-code-block.level-4,
235.nested-code-block.level-5,
236.nested-code-block.level-6,
237.nested-code-block.level-7,
238.nested-code-block.level-8,
239.nested-code-block.level-9,
240.nested-code-block.level-10 { border-left-color: var(--text-muted, #888); }
241
242.nested-code-block .code-header {
243    background-color: var(--bg-secondary, #f5f5f5);
244    color: var(--text-muted, #888);
245    padding: 0.35rem 0.75rem;
246    font-size: 0.8em;
247    font-family: var(--code-font, monospace, 'Noto Sans Arabic', 'Noto Sans Hebrew', 'Noto Sans', Arial, sans-serif);
248    border-bottom: 1px solid var(--border-color, #ddd);
249}
250
251.nested-code-block .code-content {
252    padding: 0.75rem 1rem;
253    background-color: var(--bg-color, #fff);
254    min-height: 2rem;
255}
256
257.nested-code-block .code-content pre {
258    margin: 0.5rem 0;
259    border: 1px solid var(--border-color, #ddd);
260}
261
262.nested-code-block .code-content pre:before {
263    display: none !important;
264    content: none !important;
265}
266
267.nested-code-block .code-content p {
268    margin: 0.5rem 0;
269}
270
271.nested-code-block .code-content p:first-child { margin-top: 0; }
272.nested-code-block .code-content p:last-child  { margin-bottom: 0; }
273
274/* ── Code copy button ─────────────────────────────────────────────────────── */
275.marco-code-block {
276    position: relative;
277    margin: 1rem 0;
278}
279
280.marco-copy-btn {
281    position: absolute;
282    top: 0.4rem;
283    right: 0.4rem;
284    display: inline-flex;
285    align-items: center;
286    justify-content: center;
287    padding: 0.35rem;
288    border: none;
289    border-radius: 5px;
290    background: transparent;
291    color: var(--text-muted, #888);
292    opacity: 0;
293    cursor: pointer;
294    transition: opacity 0.15s ease, background-color 0.15s ease, color 0.15s ease;
295    z-index: 10;
296}
297
298.marco-code-block:hover .marco-copy-btn {
299    opacity: 1;
300}
301
302.marco-copy-btn svg {
303    width: 1.1em;
304    height: 1.1em;
305    display: block;
306    stroke: currentColor;
307    fill: none;
308}
309
310.marco-copy-btn:hover {
311    background-color: var(--bg-secondary, #f5f5f5);
312    color: var(--link-color, #0066cc);
313    opacity: 1;
314}
315
316.marco-copy-btn:active {
317    background-color: var(--bg-code, #eee);
318}
319
320.marco-copy-btn.copied {
321    color: #1a7f37;
322    background-color: var(--bg-code, #eee);
323    opacity: 1;
324}
325
326/* ── Blockquote ───────────────────────────────────────────────────────────── */
327blockquote {
328    margin: 1rem 0;
329    padding: 0.75rem 1rem;
330    border-left: 4px solid var(--blockquote-border, #ccc);
331    background-color: var(--blockquote-bg, var(--bg-secondary, #f9f9f9));
332    color: var(--blockquote-text, var(--text-secondary, #666));
333    border-radius: 0 4px 4px 0;
334}
335
336blockquote > :first-child { margin-top: 0; }
337blockquote > :last-child  { margin-bottom: 0; }
338
339/* ── Lists ────────────────────────────────────────────────────────────────── */
340ul, ol {
341    margin: 0.5rem 0 1rem 0;
342    padding-left: 2rem;
343}
344
345li {
346    margin-bottom: 0.35rem;
347    color: var(--text-color, #333);
348}
349
350li + li { margin-top: 0.15rem; }
351
352/* ── Task lists ───────────────────────────────────────────────────────────── */
353.marco-task-list-item {
354    list-style-type: none;
355    margin-left: -1.5rem;
356    padding-left: 0;
357    display: flex;
358    align-items: flex-start;
359    gap: 0.4rem;
360}
361
362.marco-task-checkbox,
363.marco-task-list-item .marco-task-checkbox {
364    display: inline-flex;
365    align-items: center;
366    justify-content: center;
367    flex: 0 0 auto;
368    width: 1.15em;
369    height: 1.15em;
370    margin-top: 0.15em;
371    color: currentColor;
372}
373
374.marco-task-checkbox .marco-task-icon,
375.marco-task-list-item .marco-task-checkbox .marco-task-icon {
376    width: 1.15em;
377    height: 1.15em;
378    flex: 0 0 auto;
379}
380
381.marco-task-checkbox.checked,
382.marco-task-list-item .marco-task-checkbox.checked {
383    color: var(--mc-task-primary, var(--link-color, #0066cc));
384}
385
386.marco-task-checkbox.checked .marco-task-check,
387.marco-task-list-item .marco-task-checkbox.checked .marco-task-check {
388    stroke: var(--mc-task-accent, var(--link-hover, #0052a3));
389}
390
391.marco-task-list-item input[type="checkbox"] {
392    margin-right: 0.4rem;
393    accent-color: var(--mc-task-primary, var(--link-color, #0066cc));
394}
395
396/* Content column beside the checkbox icon: grows to fill available width and
397   allows text to wrap. Ensures nested blocks (lists, blockquotes, …) flow
398   below the label rather than appearing as a second flex row-item. */
399.marco-task-content {
400    flex: 1;
401    min-width: 0;
402}
403
404/* ── Definition lists ─────────────────────────────────────────────────────── */
405dl { margin: 1rem 0; }
406
407dt {
408    font-weight: 700;
409    margin-top: 1rem;
410    color: var(--heading-color, #1a1a1a);
411    -webkit-text-fill-color: var(--heading-color, #1a1a1a);
412}
413
414dd {
415    margin-left: 2rem;
416    margin-bottom: 0.5rem;
417    color: var(--text-color, #333);
418}
419
420/* ── Tables ───────────────────────────────────────────────────────────────── */
421table {
422    border-collapse: collapse;
423    width: 100%;
424    margin: 1rem 0;
425    font-size: 0.95em;
426}
427
428th, td {
429    border: 1px solid var(--table-border, #ddd);
430    padding: 0.6rem 0.85rem;
431    text-align: left;
432}
433
434th {
435    background-color: var(--table-header-bg, #f5f5f5);
436    color: var(--table-header-color, var(--heading-color, #333));
437    font-weight: 600;
438}
439
440tr:nth-child(even) {
441    background-color: var(--table-stripe-bg, #fafafa);
442}
443
444tr:hover {
445    background-color: var(--toc-link-hover-bg, var(--bg-secondary, #f5f5f5));
446}
447
448/* Right/centre alignment for GFM auto-align tables */
449.marco-table-auto-align th[align="right"],
450.marco-table-auto-align td[align="right"] { text-align: right; }
451
452.marco-table-auto-align th[align="center"],
453.marco-table-auto-align td[align="center"] { text-align: center; }
454
455/* ── Horizontal rule ──────────────────────────────────────────────────────── */
456hr {
457    border: none;
458    border-top: 1px solid var(--border-color, #ddd);
459    margin: 1.5rem 0;
460}
461
462/* ── Images ───────────────────────────────────────────────────────────────── */
463img {
464    max-width: 100%;
465    height: auto;
466    display: block;
467    border-radius: 4px;
468}
469
470/* Figure caption: italicised <em> directly after an image */
471img + em {
472    display: block;
473    text-align: center;
474    font-style: italic;
475    color: var(--text-muted, #888);
476    margin-top: 0.4rem;
477    font-size: 0.9em;
478}
479
480/* ── Emoji ────────────────────────────────────────────────────────────────── */
481.marco-emoji {
482    font-size: 1.2em;
483    display: inline-block;
484    vertical-align: baseline;
485}
486
487/* ── Footnotes ────────────────────────────────────────────────────────────── */
488.footnote-ref {
489    font-size: 0.8em;
490    vertical-align: super;
491    color: var(--link-color, #0066cc);
492    font-weight: 700;
493    line-height: 0;
494}
495
496.footnote-backref {
497    font-size: 0.85em;
498    color: var(--link-color, #0066cc);
499    text-decoration: none;
500}
501
502.footnotes {
503    border-top: 1px solid var(--border-light, var(--border-color, #ddd));
504    margin-top: 2rem;
505    padding-top: 1rem;
506    font-size: 0.9em;
507    color: var(--text-secondary, #666);
508}
509
510/* ── Inline footnotes ─────────────────────────────────────────────────────── */
511.marco-inline-footnote {
512    font-size: 0.8em;
513    vertical-align: super;
514    color: var(--link-color, #0066cc);
515    cursor: default;
516    border-bottom: 1px dotted var(--link-color, #0066cc);
517    line-height: 0;
518}
519
520/* ── Admonitions ──────────────────────────────────────────────────────────── */
521.admonition {
522    margin: 0.75rem 0;
523    padding: 0.65rem 1rem;
524    border-left: 4px solid var(--admonition-border, var(--border-strong, #ccc));
525    background-color: var(--admonition-bg, var(--bg-secondary, #f9f9f9));
526    border-radius: 0 6px 6px 0;
527}
528
529.admonition p {
530    margin: 0.4rem 0;
531}
532
533.admonition p:first-child { margin-top: 0; }
534.admonition p:last-child  { margin-bottom: 0; }
535
536.admonition .markdown-alert-title {
537    display: flex;
538    align-items: center;
539    gap: 0.5rem;
540    font-weight: 600;
541    line-height: 1.2;
542    margin: 0 0 0.5rem 0;
543}
544
545.admonition .markdown-alert-icon {
546    display: inline-flex;
547    flex: 0 0 auto;
548    align-items: center;
549    justify-content: center;
550    line-height: 0;
551}
552
553.admonition .markdown-alert-icon svg {
554    width: 1.4em;
555    height: 1.4em;
556    display: block;
557    shape-rendering: auto;
558}
559
560.admonition .markdown-alert-emoji {
561    width: 1.4em;
562    height: 1.4em;
563    display: inline-flex;
564    align-items: center;
565    justify-content: center;
566    line-height: 1;
567    font-size: 1.2em;
568}
569
570/* Quote-style admonition (blockquote colours) */
571.admonition-quote {
572    border-left-color: var(--blockquote-border, #ccc);
573    background-color: var(--blockquote-bg, var(--bg-secondary, #f9f9f9));
574    color: var(--blockquote-text, var(--text-secondary, #666));
575}
576
577.admonition-quote .markdown-alert-title {
578    color: var(--link-color, #0066cc);
579}
580
581/* Semantic admonition types — use consistent GitHub-style accent colours */
582.admonition-note { border-left-color: #0969da; background-color: var(--note-bg, var(--admonition-bg, #ebf5fb)); }
583.admonition-note .markdown-alert-title { color: #0969da; }
584
585.admonition-tip  { border-left-color: #1a7f37; background-color: var(--tip-bg, var(--admonition-bg, #eafaf1)); }
586.admonition-tip  .markdown-alert-title { color: #1a7f37; }
587
588.admonition-important { border-left-color: #8250df; background-color: var(--important-bg, var(--admonition-bg, #f5f0ff)); }
589.admonition-important .markdown-alert-title { color: #8250df; }
590
591.admonition-warning { border-left-color: #d97706; background-color: var(--warning-bg, var(--admonition-bg, #fffbeb)); }
592.admonition-warning .markdown-alert-title { color: #d97706; }
593
594.admonition-caution { border-left-color: #cf222e; background-color: var(--caution-bg, var(--admonition-bg, #fef2f2)); }
595.admonition-caution .markdown-alert-title { color: #cf222e; }
596
597/* ── Platform mentions ────────────────────────────────────────────────────── */
598.marco-mention,
599platform-mention {
600    display: inline;
601    color: var(--link-color, #0066cc);
602    font-weight: 500;
603}
604
605.marco-mention:hover,
606platform-mention:hover {
607    color: var(--link-hover, var(--link-color, #0052a3));
608    text-decoration: underline;
609    cursor: pointer;
610}
611
612/* ── GFM autolinks ────────────────────────────────────────────────────────── */
613.marco-autolink {
614    color: var(--link-color, #0066cc);
615    text-decoration: none;
616}
617
618.marco-autolink:hover {
619    color: var(--link-hover, var(--link-color, #0052a3));
620    text-decoration: underline;
621}
622
623/* ── Table of Contents (.toc) ─────────────────────────────────────────────── */
624.toc {
625    margin: 1.5rem 0;
626    padding: 1rem 1.25rem;
627    background-color: var(--toc-bg, var(--bg-secondary, #f9f9f9));
628    border: 1px solid var(--toc-border, var(--border-color, #ddd));
629    border-radius: 6px;
630    box-shadow: 0 2px 6px var(--toc-shadow, rgba(0, 0, 0, 0.08));
631}
632
633.toc h4 {
634    margin: 0 0 0.75rem 0;
635    font-size: 1rem;
636    color: var(--toc-header-color, var(--heading-color, #333));
637    -webkit-text-fill-color: var(--toc-header-color, var(--heading-color, #333));
638    background: none;
639    -webkit-background-clip: unset;
640    background-clip: unset;
641    border-bottom: 1px solid var(--toc-header-border, var(--border-color, #ddd));
642    padding-bottom: 0.5rem;
643    font-weight: 600;
644}
645
646.toc ul {
647    list-style: none;
648    margin: 0;
649    padding-left: 0;
650}
651
652.toc li {
653    margin: 0.15rem 0;
654    line-height: 1.4;
655}
656
657.toc a {
658    display: block;
659    padding: 0.3rem 0.6rem;
660    color: var(--toc-link-color, var(--text-color, #333));
661    text-decoration: none;
662    border-radius: 4px;
663    -webkit-text-fill-color: var(--toc-link-color, var(--text-color, #333));
664    transition: background-color 0.12s ease, color 0.12s ease;
665}
666
667.toc a:hover {
668    background-color: var(--toc-link-hover-bg, var(--bg-secondary, #f0f0f0));
669    color: var(--toc-link-hover-color, var(--link-color, #0066cc));
670    -webkit-text-fill-color: var(--toc-link-hover-color, var(--link-color, #0066cc));
671}
672
673.toc a.active {
674    background-color: var(--toc-link-active-bg, #e0e7ff);
675    color: var(--toc-link-active-color, var(--link-color, #0066cc));
676    -webkit-text-fill-color: var(--toc-link-active-color, var(--link-color, #0066cc));
677    font-weight: 600;
678}
679
680/* Nested TOC levels */
681.toc ul ul {
682    padding-left: 1rem;
683    margin-top: 0.15rem;
684    margin-bottom: 0;
685}
686
687.toc ul ul li { margin: 0.1rem 0; }
688
689.toc ul ul a {
690    font-size: 0.9em;
691    padding: 0.2rem 0.5rem;
692}
693
694/* ── Tab blocks (.marco-tabs) ─────────────────────────────────────────────── */
695.marco-tabs {
696    margin: 1rem 0;
697    border: 1px solid var(--border-color, #ddd);
698    border-radius: 6px;
699    overflow: visible;
700}
701
702/* Keep radios in the accessibility tree while hiding them visually */
703.marco-tabs__radio {
704    position: absolute;
705    opacity: 0;
706    width: 0;
707    height: 0;
708    pointer-events: none;
709}
710
711.marco-tabs__tablist {
712    display: flex;
713    flex-wrap: wrap;
714    gap: 0;
715    border-bottom: 1px solid var(--border-color, #ddd);
716    background-color: var(--bg-secondary, #f9f9f9);
717    border-radius: 6px 6px 0 0;
718    padding: 0 0.25rem;
719}
720
721.marco-tabs__tab {
722    padding: 0.5rem 1rem;
723    cursor: pointer;
724    color: var(--text-secondary, #666);
725    font-size: 0.9em;
726    font-weight: 500;
727    border: none;
728    background: transparent;
729    border-bottom: 2px solid transparent;
730    margin-bottom: -1px;
731    transition: color 0.12s ease, border-color 0.12s ease;
732    user-select: none;
733}
734
735.marco-tabs__tab:hover {
736    color: var(--link-color, #0066cc);
737}
738
739.marco-tabs__panels {
740    border-radius: 0 0 6px 6px;
741}
742
743.marco-tabs__panel {
744    display: none;
745    padding: 1rem;
746}
747
748.marco-tabs__panel > :first-child { margin-top: 0; }
749.marco-tabs__panel > :last-child  { margin-bottom: 0; }
750
751/* Show the selected panel + style the selected tab label (up to 12 tabs) */
752.marco-tabs > input.marco-tabs__radio:nth-of-type(1):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(1),
753.marco-tabs > input.marco-tabs__radio:nth-of-type(2):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(2),
754.marco-tabs > input.marco-tabs__radio:nth-of-type(3):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(3),
755.marco-tabs > input.marco-tabs__radio:nth-of-type(4):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(4),
756.marco-tabs > input.marco-tabs__radio:nth-of-type(5):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(5),
757.marco-tabs > input.marco-tabs__radio:nth-of-type(6):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(6),
758.marco-tabs > input.marco-tabs__radio:nth-of-type(7):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(7),
759.marco-tabs > input.marco-tabs__radio:nth-of-type(8):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(8),
760.marco-tabs > input.marco-tabs__radio:nth-of-type(9):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(9),
761.marco-tabs > input.marco-tabs__radio:nth-of-type(10):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(10),
762.marco-tabs > input.marco-tabs__radio:nth-of-type(11):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(11),
763.marco-tabs > input.marco-tabs__radio:nth-of-type(12):checked ~ .marco-tabs__panels > .marco-tabs__panel:nth-of-type(12) {
764    display: block;
765}
766
767.marco-tabs > input.marco-tabs__radio:nth-of-type(1):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(1),
768.marco-tabs > input.marco-tabs__radio:nth-of-type(2):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(2),
769.marco-tabs > input.marco-tabs__radio:nth-of-type(3):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(3),
770.marco-tabs > input.marco-tabs__radio:nth-of-type(4):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(4),
771.marco-tabs > input.marco-tabs__radio:nth-of-type(5):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(5),
772.marco-tabs > input.marco-tabs__radio:nth-of-type(6):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(6),
773.marco-tabs > input.marco-tabs__radio:nth-of-type(7):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(7),
774.marco-tabs > input.marco-tabs__radio:nth-of-type(8):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(8),
775.marco-tabs > input.marco-tabs__radio:nth-of-type(9):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(9),
776.marco-tabs > input.marco-tabs__radio:nth-of-type(10):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(10),
777.marco-tabs > input.marco-tabs__radio:nth-of-type(11):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(11),
778.marco-tabs > input.marco-tabs__radio:nth-of-type(12):checked ~ .marco-tabs__tablist > .marco-tabs__tab:nth-of-type(12) {
779    color: var(--link-color, #0066cc);
780    border-bottom-color: var(--link-color, #0066cc);
781}
782
783/* ── Paged.js page paper colors ───────────────────────────────────────────── */
784/* Each theme defines --pagedjs-page-bg and --pagedjs-page-color via
785   .theme-light and .theme-dark blocks in its token file.               */
786.pagedjs_page {
787    background-color: var(--pagedjs-page-bg, #ffffff);
788    color: var(--pagedjs-page-color, var(--text-color, #333));
789}
790
791.pagedjs_margin .pagedjs_margin-content {
792    color: var(--text-muted, #888);
793    font-size: 0.8em;
794}
795
796/* ── WebKit scrollbar (HTML preview pane) ─────────────────────────────────── */
797::-webkit-scrollbar { width: 12px; height: 12px; }
798
799::-webkit-scrollbar-track {
800    background: var(--bg-secondary, #f5f5f5);
801}
802
803::-webkit-scrollbar-thumb {
804    background: var(--border-strong, #ccc);
805    border-radius: 0;
806}
807
808::-webkit-scrollbar-thumb:hover { opacity: 0.9; }
809
810/* ── Selection ────────────────────────────────────────────────────────────── */
811::selection {
812    background-color: var(--mark-bg, #b3d9ff);
813    color: var(--mark-color, #1a1a1a);
814}
815"#;
816
817#[cfg(test)]
818mod tests {
819    use super::*;
820
821    #[test]
822    fn smoke_base_css_non_empty() {
823        let css = base_css();
824        assert!(!css.is_empty(), "base_css() must not be empty");
825    }
826
827    #[test]
828    fn smoke_base_css_contains_key_selectors() {
829        let css = base_css();
830        assert!(css.contains("body {"), "body rule missing");
831        assert!(css.contains("blockquote {"), "blockquote rule missing");
832        assert!(css.contains(".admonition"), "admonition rule missing");
833        assert!(css.contains(".marco-tabs"), "tab block rule missing");
834        assert!(css.contains(".toc"), "TOC rule missing");
835        assert!(css.contains(".pagedjs_page"), "paged.js page rule missing");
836        assert!(
837            css.contains("var(--text-color"),
838            "text-color variable missing"
839        );
840        assert!(css.contains("var(--bg-color"), "bg-color variable missing");
841        assert!(
842            css.contains("var(--heading-color"),
843            "heading-color variable missing"
844        );
845    }
846
847    #[test]
848    fn smoke_base_css_no_format_braces() {
849        // The CSS must NOT contain unescaped `{` immediately followed by `{`
850        // (which would indicate accidental format!()-style escaping).
851        let css = base_css();
852        // Valid CSS has single braces; doubled braces are a format! artifact.
853        assert!(
854            !css.contains("{{"),
855            "base_css contains escaped braces ('{{') — remove them"
856        );
857        assert!(
858            !css.contains("}}"),
859            "base_css contains escaped braces ('}}') — remove them"
860        );
861    }
862}