jekyll-theme-docsteer 1.0.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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +107 -0
  4. data/_data/navigation.yml +44 -0
  5. data/_includes/buy-me-a-coffee.html +10 -0
  6. data/_includes/doc-footer.html +38 -0
  7. data/_includes/faq-list.html +52 -0
  8. data/_includes/footer.html +43 -0
  9. data/_includes/head-custom.html +4 -0
  10. data/_includes/head.html +61 -0
  11. data/_includes/navbar.html +70 -0
  12. data/_includes/scripts.html +22 -0
  13. data/_includes/search-modal.html +24 -0
  14. data/_includes/sidebar.html +48 -0
  15. data/_includes/toc.html +11 -0
  16. data/_layouts/default.html +45 -0
  17. data/_layouts/doc.html +37 -0
  18. data/_layouts/faq.html +51 -0
  19. data/_layouts/home.html +74 -0
  20. data/_layouts/page.html +13 -0
  21. data/_sass/docsteer/_base.scss +56 -0
  22. data/_sass/docsteer/_components.scss +166 -0
  23. data/_sass/docsteer/_content.scss +300 -0
  24. data/_sass/docsteer/_faq.scss +140 -0
  25. data/_sass/docsteer/_footer.scss +51 -0
  26. data/_sass/docsteer/_home.scss +184 -0
  27. data/_sass/docsteer/_layout.scss +52 -0
  28. data/_sass/docsteer/_lightbox.scss +73 -0
  29. data/_sass/docsteer/_navbar.scss +169 -0
  30. data/_sass/docsteer/_print.scss +13 -0
  31. data/_sass/docsteer/_reset.scss +57 -0
  32. data/_sass/docsteer/_responsive.scss +31 -0
  33. data/_sass/docsteer/_search.scss +98 -0
  34. data/_sass/docsteer/_sidebar.scss +159 -0
  35. data/_sass/docsteer/_skins.scss +193 -0
  36. data/_sass/docsteer/_syntax.scss +72 -0
  37. data/_sass/docsteer/_toc.scss +46 -0
  38. data/_sass/docsteer/_tokens.scss +96 -0
  39. data/_sass/docsteer/_utilities.scss +18 -0
  40. data/_sass/docsteer.scss +22 -0
  41. data/assets/css/main.scss +4 -0
  42. data/assets/images/favicon.svg +14 -0
  43. data/assets/images/logo.svg +14 -0
  44. data/assets/js/lightbox.js +96 -0
  45. data/assets/js/main.js +275 -0
  46. data/assets/js/search.js +186 -0
  47. data/assets/vendor/fontawesome/NOTICE.md +18 -0
  48. data/assets/vendor/fontawesome/css/all.min.css +9 -0
  49. data/assets/vendor/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  50. data/assets/vendor/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  51. data/assets/vendor/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  52. data/assets/vendor/fontawesome/webfonts/fa-v4compatibility.woff2 +0 -0
  53. metadata +190 -0
data/_layouts/doc.html ADDED
@@ -0,0 +1,37 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+ {%- assign cfg = site.docsteer -%}
5
+ <div class="doc-grid{% if cfg.toc.enabled and page.toc != false %} has-toc{% endif %}">
6
+ <article class="prose doc-content" id="doc-content">
7
+ <header class="doc-head">
8
+ {% if page.category %}<p class="doc-head__eyebrow">{{ page.category }}</p>{% endif %}
9
+ <h1>{{ page.title }}</h1>
10
+ {% if page.description %}<p class="doc-head__lead">{{ page.description }}</p>{% endif %}
11
+
12
+ <div class="doc-head__meta">
13
+ {% if page.updated or page.date %}
14
+ <span><i class="fa-regular fa-clock" aria-hidden="true"></i>
15
+ Updated {{ page.updated | default: page.date | date: "%b %-d, %Y" }}</span>
16
+ {% endif %}
17
+ {% if page.read_time %}
18
+ <span><i class="fa-regular fa-file-lines" aria-hidden="true"></i> {{ page.read_time }} min read</span>
19
+ {% endif %}
20
+ {% if cfg.edit_page.enabled and cfg.edit_page.repo %}
21
+ {%- assign edit_url = cfg.edit_page.repo | append: "/edit/" | append: cfg.edit_page.branch | append: "/" | append: cfg.edit_page.path | append: page.path -%}
22
+ <a class="doc-head__edit" href="{{ edit_url }}" rel="noopener">
23
+ <i class="fa-solid fa-pen-to-square" aria-hidden="true"></i> Edit this page
24
+ </a>
25
+ {% endif %}
26
+ </div>
27
+ </header>
28
+
29
+ {{ content }}
30
+
31
+ {% include doc-footer.html %}
32
+ </article>
33
+
34
+ {% if cfg.toc.enabled and page.toc != false %}
35
+ {% include toc.html %}
36
+ {% endif %}
37
+ </div>
data/_layouts/faq.html ADDED
@@ -0,0 +1,51 @@
1
+ ---
2
+ layout: doc
3
+ ---
4
+ {%- comment -%}
5
+ DocSteer — FAQ layout.
6
+
7
+ Inherits everything from `doc` (sidebar, TOC, edit link, doc footer) and adds
8
+ the accordion plus FAQPage structured data.
9
+
10
+ Questions come from the page front matter:
11
+
12
+ layout: faq
13
+ faq:
14
+ - section: Billing # optional grouping
15
+ q: Is it free?
16
+ a: |
17
+ Markdown **is** allowed here.
18
+
19
+ …or from a shared data file, with `faq_data: faq` reading `_data/faq.yml`.
20
+ {%- endcomment -%}
21
+ {%- assign cfg = site.docsteer.faq -%}
22
+ {%- if page.faq_data -%}
23
+ {%- assign faq_items = site.data[page.faq_data] -%}
24
+ {%- else -%}
25
+ {%- assign faq_items = page.faq -%}
26
+ {%- endif -%}
27
+
28
+ {{ content }}
29
+
30
+ {%- if cfg.enabled != false -%}
31
+ {% include faq-list.html items=faq_items %}
32
+
33
+ {%- if cfg.schema and faq_items and faq_items.size > 0 %}
34
+ <script type="application/ld+json">
35
+ {
36
+ "@context": "https://schema.org",
37
+ "@type": "FAQPage",
38
+ "mainEntity": [{% for item in faq_items %}
39
+ {
40
+ "@type": "Question",
41
+ "name": {{ item.q | strip_html | normalize_whitespace | jsonify }},
42
+ "acceptedAnswer": {
43
+ "@type": "Answer",
44
+ "text": {{ item.a | markdownify | strip_html | normalize_whitespace | jsonify }}
45
+ }
46
+ }{% unless forloop.last %},{% endunless %}{% endfor %}
47
+ ]
48
+ }
49
+ </script>
50
+ {%- endif -%}
51
+ {%- endif -%}
@@ -0,0 +1,74 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+ {%- assign cfg = site.docsteer -%}
5
+ <div class="home">
6
+
7
+ <section class="hero">
8
+ <div class="hero__inner">
9
+ {% if page.hero.eyebrow %}<p class="hero__eyebrow">{{ page.hero.eyebrow }}</p>{% endif %}
10
+ <h1 class="hero__title">{{ page.hero.title | default: site.title }}</h1>
11
+ <p class="hero__lead">{{ page.hero.lead | default: site.tagline }}</p>
12
+
13
+ <div class="hero__actions">
14
+ {% for btn in page.hero.buttons %}
15
+ <a class="btn {{ btn.style | default: 'btn--primary' }}" href="{{ btn.url | relative_url }}">
16
+ {% if btn.icon %}<i class="{{ btn.icon }}" aria-hidden="true"></i>{% endif %}
17
+ {{ btn.label }}
18
+ </a>
19
+ {% endfor %}
20
+ </div>
21
+
22
+ {% if site.docsteer.search.enabled %}
23
+ <button class="hero__search" data-search-open type="button">
24
+ <i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i>
25
+ <span>{{ cfg.search.placeholder | default: "Search the docs…" }}</span>
26
+ {% if cfg.search.hotkey %}<kbd>/</kbd>{% endif %}
27
+ </button>
28
+ {% endif %}
29
+ </div>
30
+ <div class="hero__glow" aria-hidden="true"></div>
31
+ </section>
32
+
33
+ {% if page.features %}
34
+ <section class="features">
35
+ <div class="features__grid">
36
+ {% for f in page.features %}
37
+ <article class="feature-card">
38
+ <span class="feature-card__icon"><i class="{{ f.icon }}" aria-hidden="true"></i></span>
39
+ <h3>{{ f.title }}</h3>
40
+ <p>{{ f.text }}</p>
41
+ {% if f.url %}<a class="feature-card__link" href="{{ f.url | relative_url }}">Learn more <i class="fa-solid fa-arrow-right" aria-hidden="true"></i></a>{% endif %}
42
+ </article>
43
+ {% endfor %}
44
+ </div>
45
+ </section>
46
+ {% endif %}
47
+
48
+ {% if page.sections %}
49
+ {% for s in page.sections %}
50
+ <section class="link-section">
51
+ <div class="link-section__head">
52
+ <h2>{{ s.title }}</h2>
53
+ {% if s.text %}<p>{{ s.text }}</p>{% endif %}
54
+ </div>
55
+ <div class="link-section__grid">
56
+ {% for l in s.links %}
57
+ <a class="link-tile" href="{{ l.url | relative_url }}">
58
+ {% if l.icon %}<i class="{{ l.icon }}" aria-hidden="true"></i>{% endif %}
59
+ <span class="link-tile__title">{{ l.label }}</span>
60
+ {% if l.text %}<span class="link-tile__text">{{ l.text }}</span>{% endif %}
61
+ </a>
62
+ {% endfor %}
63
+ </div>
64
+ </section>
65
+ {% endfor %}
66
+ {% endif %}
67
+
68
+ {% if page.content != "" %}
69
+ <section class="home__prose prose">
70
+ {{ content }}
71
+ </section>
72
+ {% endif %}
73
+
74
+ </div>
@@ -0,0 +1,13 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+ <article class="prose doc-content{% if page.wide %} is-wide{% endif %}">
5
+ {% if page.title %}
6
+ <header class="page-head">
7
+ <h1>{{ page.title }}</h1>
8
+ {% if page.description %}<p class="page-head__lead">{{ page.description }}</p>{% endif %}
9
+ </header>
10
+ {% endif %}
11
+
12
+ {{ content }}
13
+ </article>
@@ -0,0 +1,56 @@
1
+ // ── Base typography ──────────────────────────────────────────
2
+ h1, h2, h3, h4, h5, h6 {
3
+ font-family: var(--font-display);
4
+ line-height: var(--lh-tight);
5
+ font-weight: 650;
6
+ color: var(--text);
7
+ text-wrap: balance;
8
+ scroll-margin-top: calc(var(--nav-h) + var(--sp-5));
9
+ }
10
+ h1 { font-size: var(--fs-h1); letter-spacing: var(--tr-tight); font-weight: 700; }
11
+ h2 { font-size: var(--fs-h2); letter-spacing: var(--tr-tight); }
12
+ h3 { font-size: var(--fs-h3); letter-spacing: var(--tr-snug); }
13
+ h4 { font-size: var(--fs-h4); letter-spacing: var(--tr-snug); }
14
+ h5, h6 { font-size: var(--fs-base); letter-spacing: 0; }
15
+
16
+ p { text-wrap: pretty; }
17
+
18
+ p, ul, ol, dl, blockquote, pre, table, figure { margin-block: 0 var(--sp-4); }
19
+
20
+ strong, b { font-weight: 650; color: var(--text); }
21
+ small { font-size: var(--fs-sm); color: var(--text-soft); }
22
+
23
+ hr {
24
+ border: 0;
25
+ height: 1px;
26
+ background: var(--border);
27
+ margin-block: var(--sp-7);
28
+ }
29
+
30
+ code, kbd, samp {
31
+ font-family: var(--font-mono);
32
+ font-size: .875em;
33
+ font-feature-settings: "liga" 0;
34
+ }
35
+
36
+ kbd {
37
+ display: inline-block;
38
+ min-width: 1.6em;
39
+ padding: 2px 6px;
40
+ font-size: .75em;
41
+ line-height: 1.4;
42
+ text-align: center;
43
+ color: var(--text-soft);
44
+ background: var(--bg-elev);
45
+ border: 1px solid var(--border-strong);
46
+ border-bottom-width: 2px;
47
+ border-radius: var(--r-sm);
48
+ white-space: nowrap;
49
+ }
50
+
51
+ .container {
52
+ width: 100%;
53
+ max-width: var(--shell-max);
54
+ margin-inline: auto;
55
+ padding-inline: var(--sp-5);
56
+ }
@@ -0,0 +1,166 @@
1
+ // ── Reusable components ──────────────────────────────────────
2
+
3
+ // ── Buttons ──────────────────────────────────────────────────
4
+ .btn {
5
+ display: inline-flex;
6
+ align-items: center;
7
+ justify-content: center;
8
+ gap: var(--sp-2);
9
+ min-height: 42px;
10
+ padding: 0 var(--sp-5);
11
+ border-radius: var(--r-md);
12
+ font-weight: 600;
13
+ font-size: var(--fs-base);
14
+ letter-spacing: var(--tr-snug);
15
+ line-height: 1;
16
+ border: 1px solid transparent;
17
+ white-space: nowrap;
18
+ transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
19
+ background var(--dur) var(--ease), border-color var(--dur) var(--ease);
20
+ }
21
+ .btn:hover { text-decoration: none; }
22
+ .btn:active { transform: translateY(1px); }
23
+
24
+ .btn--primary {
25
+ color: var(--brand-contrast);
26
+ background: var(--brand);
27
+ box-shadow: var(--shadow-sm);
28
+ }
29
+ .btn--primary:hover { background: var(--brand-strong); box-shadow: var(--shadow-md); }
30
+
31
+ .btn--ghost {
32
+ color: var(--text);
33
+ background: var(--bg-elev);
34
+ border-color: var(--border-strong);
35
+ }
36
+ .btn--ghost:hover { border-color: var(--text-faint); background: var(--bg-sunken); }
37
+
38
+ .btn--soft { color: var(--brand); background: var(--brand-soft); }
39
+ .btn--soft:hover { background: var(--surface-2); }
40
+
41
+ // ── Badges ───────────────────────────────────────────────────
42
+ .badge {
43
+ display: inline-block;
44
+ padding: 1px 7px;
45
+ font-size: var(--fs-xs);
46
+ font-weight: 650;
47
+ line-height: 1.5;
48
+ border-radius: var(--r-pill);
49
+ color: var(--brand-contrast);
50
+ background: var(--brand);
51
+ }
52
+ .badge--soft {
53
+ color: var(--brand);
54
+ background: var(--brand-soft);
55
+ border: 1px solid hsl(var(--brand-h) var(--brand-s) 55% / .18);
56
+ }
57
+
58
+ // ── Callouts / admonitions ───────────────────────────────────
59
+ .callout {
60
+ --callout-tint: var(--info);
61
+ --callout-bg: var(--info-bg);
62
+ display: grid;
63
+ grid-template-columns: auto 1fr;
64
+ gap: var(--sp-3);
65
+ padding: var(--sp-4) var(--sp-5);
66
+ margin-block: var(--sp-5);
67
+ border: 1px solid hsl(0 0% 0% / 0);
68
+ border-left: 3px solid var(--callout-tint);
69
+ border-radius: var(--r-sm) var(--r-md) var(--r-md) var(--r-sm);
70
+ background: var(--callout-bg);
71
+ font-size: var(--fs-sm);
72
+ line-height: 1.65;
73
+ }
74
+ .callout__icon {
75
+ display: grid;
76
+ place-items: center;
77
+ width: 1.6em;
78
+ height: 1.6em;
79
+ margin-top: .05em;
80
+ font-size: var(--fs-base);
81
+ color: var(--callout-tint);
82
+ }
83
+ .callout > div > :last-child { margin-bottom: 0; }
84
+ .callout > div > :first-child { margin-top: 0; }
85
+ .callout__title {
86
+ font-weight: 650;
87
+ color: var(--text);
88
+ margin-bottom: var(--sp-1);
89
+ letter-spacing: var(--tr-snug);
90
+ }
91
+ .callout p { max-width: none; }
92
+ .callout--note { --callout-tint: var(--info); --callout-bg: var(--info-bg); }
93
+ .callout--tip { --callout-tint: var(--success); --callout-bg: var(--success-bg); }
94
+ .callout--warning { --callout-tint: var(--warning); --callout-bg: var(--warning-bg); }
95
+ .callout--danger { --callout-tint: var(--danger); --callout-bg: var(--danger-bg); }
96
+
97
+ // ── Cards ────────────────────────────────────────────────────
98
+ .card {
99
+ padding: var(--sp-5);
100
+ background: var(--bg-elev);
101
+ border: 1px solid var(--border);
102
+ border-radius: var(--r-lg);
103
+ transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
104
+ border-color var(--dur) var(--ease);
105
+ }
106
+ .card:hover {
107
+ transform: translateY(-2px);
108
+ box-shadow: var(--shadow-md);
109
+ border-color: var(--border-strong);
110
+ text-decoration: none;
111
+ }
112
+
113
+ // ── Buy me a coffee ──────────────────────────────────────────
114
+ .bmc {
115
+ display: inline-flex;
116
+ align-items: center;
117
+ gap: var(--sp-2);
118
+ height: 36px;
119
+ padding: 0 var(--sp-4);
120
+ border-radius: var(--r-pill);
121
+ font-size: var(--fs-sm);
122
+ font-weight: 650;
123
+ color: #17202a;
124
+ background: #ffdd57;
125
+ border: 1px solid hsl(46 90% 46%);
126
+ white-space: nowrap;
127
+ transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
128
+ background var(--dur) var(--ease);
129
+ }
130
+ .bmc:hover {
131
+ text-decoration: none;
132
+ background: #ffe375;
133
+ transform: translateY(-1px);
134
+ box-shadow: 0 4px 14px hsl(46 90% 45% / .35);
135
+ }
136
+ .bmc--compact { width: 36px; padding: 0; justify-content: center; }
137
+
138
+ // ── Back to top ──────────────────────────────────────────────
139
+ .to-top {
140
+ position: fixed;
141
+ right: var(--sp-5);
142
+ bottom: var(--sp-5);
143
+ z-index: 70;
144
+ width: 42px; height: 42px;
145
+ display: grid; place-items: center;
146
+ border-radius: 50%;
147
+ color: var(--text-soft);
148
+ background: var(--bg-elev);
149
+ border: 1px solid var(--border-strong);
150
+ box-shadow: var(--shadow-md);
151
+ opacity: 0;
152
+ transform: translateY(10px);
153
+ transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
154
+ color var(--dur) var(--ease), border-color var(--dur) var(--ease);
155
+ }
156
+ .to-top:hover { color: var(--brand); border-color: var(--brand); }
157
+ .to-top.is-visible { opacity: 1; transform: translateY(0); }
158
+
159
+ // ── Loading shimmer ──────────────────────────────────────────
160
+ .skeleton {
161
+ background: linear-gradient(90deg, var(--surface-2) 25%, var(--bg-sunken) 37%, var(--surface-2) 63%);
162
+ background-size: 400% 100%;
163
+ animation: shimmer 1.4s ease infinite;
164
+ border-radius: var(--r-sm);
165
+ }
166
+ @keyframes shimmer { to { background-position: -200% 0; } }
@@ -0,0 +1,300 @@
1
+ // ── Doc / page content ───────────────────────────────────────
2
+
3
+ // Page & doc headers
4
+ .doc-head { margin-bottom: var(--sp-7); }
5
+ .doc-head__eyebrow {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ margin-bottom: var(--sp-3);
9
+ font-size: var(--fs-xs);
10
+ font-weight: 650;
11
+ text-transform: uppercase;
12
+ letter-spacing: var(--tr-wide);
13
+ color: var(--brand);
14
+ }
15
+ .doc-head h1, .page-head h1 { margin-bottom: var(--sp-3); }
16
+ .doc-head__lead, .page-head__lead {
17
+ font-size: var(--fs-lg);
18
+ line-height: 1.55;
19
+ color: var(--text-soft);
20
+ max-width: 60ch;
21
+ text-wrap: pretty;
22
+ }
23
+ .doc-head__meta {
24
+ display: flex;
25
+ flex-wrap: wrap;
26
+ align-items: center;
27
+ gap: var(--sp-2) var(--sp-5);
28
+ margin-top: var(--sp-5);
29
+ padding-top: var(--sp-4);
30
+ border-top: 1px solid var(--border);
31
+ font-size: var(--fs-sm);
32
+ color: var(--text-faint);
33
+ }
34
+ .doc-head__meta i { margin-right: 6px; }
35
+ .doc-head__edit { margin-left: auto; color: var(--text-soft); font-weight: 500; }
36
+ .doc-head__edit:hover { color: var(--brand); }
37
+
38
+ .page-head { margin-bottom: var(--sp-7); }
39
+
40
+ // ── Prose rhythm ─────────────────────────────────────────────
41
+ .prose > * + * { margin-top: var(--sp-4); }
42
+ .prose > h2 {
43
+ margin-top: var(--sp-8);
44
+ padding-top: var(--sp-5);
45
+ border-top: 1px solid var(--border);
46
+ }
47
+ .prose > h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
48
+ .prose > h3 { margin-top: var(--sp-7); }
49
+ .prose > h4 { margin-top: var(--sp-5); }
50
+ .prose > h2 + *, .prose > h3 + *, .prose > h4 + * { margin-top: var(--sp-3); }
51
+
52
+ .prose p, .prose li { overflow-wrap: break-word; }
53
+ .prose > p { max-width: var(--measure); }
54
+
55
+ .prose ul { list-style: none; padding-left: 0; }
56
+ .prose ul > li { position: relative; padding-left: 1.5em; }
57
+ .prose ul > li::before {
58
+ content: "";
59
+ position: absolute;
60
+ left: .45em;
61
+ top: .68em;
62
+ width: 5px; height: 5px;
63
+ border-radius: 50%;
64
+ background: var(--border-strong);
65
+ }
66
+ .prose ol { list-style: none; counter-reset: li; padding-left: 0; }
67
+ .prose ol > li { position: relative; counter-increment: li; padding-left: 1.9em; }
68
+ .prose ol > li::before {
69
+ content: counter(li);
70
+ position: absolute;
71
+ left: 0;
72
+ top: .1em;
73
+ width: 1.4em;
74
+ font-size: var(--fs-sm);
75
+ font-weight: 650;
76
+ font-variant-numeric: tabular-nums;
77
+ color: var(--brand);
78
+ }
79
+ .prose li + li { margin-top: var(--sp-2); }
80
+ .prose li > ul, .prose li > ol { margin-top: var(--sp-2); }
81
+ .prose li > p { margin-bottom: var(--sp-2); }
82
+
83
+ // Icon-only affordances (heading anchors, FAQ permalinks) opt out of the
84
+ // underlined body-link treatment.
85
+ .prose a:not(.btn):not(.heading-anchor):not(.faq-item__permalink) {
86
+ color: var(--link);
87
+ font-weight: 500;
88
+ text-decoration: underline;
89
+ text-underline-offset: 3px;
90
+ text-decoration-thickness: 1px;
91
+ text-decoration-color: hsl(var(--brand-h) var(--brand-s) 55% / .35);
92
+ transition: text-decoration-color var(--dur) var(--ease);
93
+ }
94
+ .prose a:not(.btn):not(.heading-anchor):not(.faq-item__permalink):hover { text-decoration-color: currentColor; }
95
+
96
+ // Heading anchors (added by JS)
97
+ .heading-anchor {
98
+ margin-left: .4em;
99
+ font-size: .62em;
100
+ color: var(--text-faint);
101
+ opacity: 0;
102
+ text-decoration: none;
103
+ vertical-align: middle;
104
+ transition: opacity var(--dur) var(--ease), color var(--dur) var(--ease);
105
+ }
106
+ .heading-anchor:hover { color: var(--brand); }
107
+ h2:hover > .heading-anchor, h3:hover > .heading-anchor,
108
+ h4:hover > .heading-anchor, .heading-anchor:focus-visible { opacity: 1; }
109
+
110
+ // Blockquote — quieter than a callout, deliberately
111
+ .prose blockquote {
112
+ padding-left: var(--sp-5);
113
+ border-left: 2px solid var(--border-strong);
114
+ color: var(--text-soft);
115
+ font-style: normal;
116
+ }
117
+ .prose blockquote > :last-child { margin-bottom: 0; }
118
+
119
+ // Inline code
120
+ .prose :not(pre) > code {
121
+ padding: .12em .38em;
122
+ background: var(--bg-sunken);
123
+ border: 1px solid var(--border);
124
+ border-radius: var(--r-sm);
125
+ color: var(--text);
126
+ white-space: nowrap;
127
+ }
128
+ .prose a :not(pre) > code, .prose a > code { color: inherit; }
129
+
130
+ // ── Code blocks ──────────────────────────────────────────────
131
+ // main.js wraps each Rouge block in .code-wrap and adds a header bar
132
+ // with the language name and an always-visible copy button.
133
+ .code-wrap {
134
+ margin-block: var(--sp-5);
135
+ border: 1px solid var(--border);
136
+ border-radius: var(--r-md);
137
+ background: var(--code-bg);
138
+ overflow: hidden;
139
+ }
140
+ .code-wrap__bar {
141
+ display: flex;
142
+ align-items: center;
143
+ gap: var(--sp-3);
144
+ padding: 6px 6px 6px var(--sp-4);
145
+ background: var(--bg-sunken);
146
+ border-bottom: 1px solid var(--border);
147
+ }
148
+ .code-wrap__lang {
149
+ font-family: var(--font-mono);
150
+ font-size: var(--fs-xs);
151
+ font-weight: 600;
152
+ letter-spacing: .04em;
153
+ text-transform: uppercase;
154
+ color: var(--text-faint);
155
+ }
156
+ .code-copy {
157
+ display: inline-flex;
158
+ align-items: center;
159
+ gap: 6px;
160
+ margin-left: auto;
161
+ padding: 5px 10px;
162
+ font-size: var(--fs-xs);
163
+ font-weight: 600;
164
+ color: var(--text-soft);
165
+ background: transparent;
166
+ border: 1px solid transparent;
167
+ border-radius: var(--r-sm);
168
+ transition: color var(--dur) var(--ease), background var(--dur) var(--ease),
169
+ border-color var(--dur) var(--ease);
170
+ }
171
+ .code-copy:hover { color: var(--brand); background: var(--bg-elev); border-color: var(--border); }
172
+ .code-copy.is-done { color: var(--success); }
173
+
174
+ // Rouge output inside the wrapper: strip its own chrome so only the
175
+ // wrapper draws a border and only <pre> carries padding.
176
+ .code-wrap .highlighter-rouge,
177
+ .code-wrap .highlight,
178
+ .code-wrap figure.highlight {
179
+ margin: 0;
180
+ padding: 0;
181
+ background: transparent;
182
+ border: 0;
183
+ border-radius: 0;
184
+ }
185
+
186
+ .prose pre {
187
+ margin: 0;
188
+ padding: var(--sp-4) var(--sp-5);
189
+ background: var(--code-bg);
190
+ overflow-x: auto;
191
+ font-size: var(--fs-sm);
192
+ line-height: 1.65;
193
+ tab-size: 2;
194
+ -webkit-overflow-scrolling: touch;
195
+ }
196
+ // Standalone <pre> (not wrapped by JS) keeps a border of its own
197
+ .prose > pre:not(.highlight) {
198
+ border: 1px solid var(--border);
199
+ border-radius: var(--r-md);
200
+ margin-block: var(--sp-5);
201
+ }
202
+ .prose pre code {
203
+ background: none;
204
+ border: 0;
205
+ padding: 0;
206
+ font-size: inherit;
207
+ white-space: pre;
208
+ }
209
+ .prose pre::-webkit-scrollbar { height: 8px; }
210
+ .prose pre::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
211
+
212
+ // ── Tables ───────────────────────────────────────────────────
213
+ .table-scroll { overflow-x: auto; margin-block: var(--sp-5); -webkit-overflow-scrolling: touch; }
214
+ .prose table {
215
+ width: 100%;
216
+ // Scroll inside .table-scroll on narrow screens instead of squeezing
217
+ min-width: 34rem;
218
+ border-collapse: separate;
219
+ border-spacing: 0;
220
+ font-size: var(--fs-sm);
221
+ border: 1px solid var(--border);
222
+ border-radius: var(--r-md);
223
+ overflow: hidden;
224
+ }
225
+ .prose th, .prose td {
226
+ padding: var(--sp-3) var(--sp-4);
227
+ text-align: left;
228
+ vertical-align: top;
229
+ border-bottom: 1px solid var(--border);
230
+ }
231
+ .prose thead th {
232
+ background: var(--bg-sunken);
233
+ font-weight: 650;
234
+ font-size: var(--fs-xs);
235
+ text-transform: uppercase;
236
+ letter-spacing: .04em;
237
+ color: var(--text-soft);
238
+ white-space: nowrap;
239
+ }
240
+ .prose tbody tr:last-child td { border-bottom: 0; }
241
+ .prose tbody tr:hover { background: var(--bg-sunken); }
242
+ .prose td code { white-space: nowrap; }
243
+
244
+ // ── Figures / images ─────────────────────────────────────────
245
+ .prose img {
246
+ border-radius: var(--r-md);
247
+ border: 1px solid var(--border);
248
+ }
249
+ .prose figure { margin-block: var(--sp-5); }
250
+ .prose figcaption {
251
+ margin-top: var(--sp-3);
252
+ font-size: var(--fs-sm);
253
+ color: var(--text-faint);
254
+ text-align: center;
255
+ }
256
+ .prose .lightbox-trigger { cursor: zoom-in; transition: opacity var(--dur) var(--ease); }
257
+ .prose .lightbox-trigger:hover { opacity: .92; }
258
+
259
+ // ── Doc pager ────────────────────────────────────────────────
260
+ .doc-pager {
261
+ display: grid;
262
+ grid-template-columns: 1fr 1fr;
263
+ gap: var(--sp-4);
264
+ margin-top: var(--sp-8);
265
+ padding-top: var(--sp-6);
266
+ border-top: 1px solid var(--border);
267
+ }
268
+ .doc-pager__link {
269
+ display: grid;
270
+ gap: var(--sp-1);
271
+ padding: var(--sp-4) var(--sp-5);
272
+ border: 1px solid var(--border);
273
+ border-radius: var(--r-md);
274
+ color: var(--text);
275
+ background: var(--bg-elev);
276
+ transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
277
+ transform var(--dur) var(--ease);
278
+ }
279
+ .doc-pager__link:hover {
280
+ border-color: var(--border-strong);
281
+ box-shadow: var(--shadow-md);
282
+ transform: translateY(-1px);
283
+ text-decoration: none;
284
+ }
285
+ .doc-pager__next { text-align: right; }
286
+ .doc-pager__dir {
287
+ font-size: var(--fs-xs);
288
+ color: var(--text-faint);
289
+ font-weight: 600;
290
+ text-transform: uppercase;
291
+ letter-spacing: var(--tr-wide);
292
+ }
293
+ .doc-pager__title { font-weight: 600; color: var(--brand); line-height: 1.4; }
294
+
295
+ .doc-tags { margin-top: var(--sp-6); display: flex; flex-wrap: wrap; gap: var(--sp-2); }
296
+
297
+ @media (max-width: 560px) {
298
+ .doc-pager { grid-template-columns: 1fr; }
299
+ .doc-head__edit { margin-left: 0; }
300
+ }