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
@@ -0,0 +1,57 @@
1
+ // ── Modern reset ─────────────────────────────────────────────
2
+ *, *::before, *::after { box-sizing: border-box; }
3
+ * { margin: 0; }
4
+
5
+ html {
6
+ font-size: var(--fs-root);
7
+ -webkit-text-size-adjust: 100%;
8
+ scroll-behavior: smooth;
9
+ scroll-padding-top: calc(var(--nav-h) + var(--sp-4));
10
+ }
11
+
12
+ body {
13
+ min-height: 100vh;
14
+ font-family: var(--font-sans);
15
+ font-size: var(--fs-base);
16
+ line-height: var(--lh-body);
17
+ color: var(--text);
18
+ background: var(--bg);
19
+ -webkit-font-smoothing: antialiased;
20
+ -moz-osx-font-smoothing: grayscale;
21
+ font-synthesis-weight: none;
22
+ text-rendering: optimizeLegibility;
23
+ }
24
+
25
+ img, picture, svg, video, canvas { display: block; max-width: 100%; height: auto; }
26
+ input, button, textarea, select { font: inherit; color: inherit; }
27
+ button { background: none; border: 0; cursor: pointer; }
28
+ a { color: var(--link); text-decoration: none; }
29
+ a:hover { text-decoration: underline; }
30
+
31
+ ul[class], ol[class] { list-style: none; padding: 0; }
32
+
33
+ :target { scroll-margin-top: calc(var(--nav-h) + var(--sp-5)); }
34
+
35
+ ::selection { background: var(--selection); }
36
+
37
+ :focus-visible {
38
+ outline: none;
39
+ box-shadow: var(--focus-ring);
40
+ border-radius: var(--r-sm);
41
+ }
42
+
43
+ .skip-link {
44
+ position: fixed;
45
+ top: var(--sp-2);
46
+ left: var(--sp-2);
47
+ z-index: 200;
48
+ padding: var(--sp-2) var(--sp-4);
49
+ background: var(--brand);
50
+ color: var(--brand-contrast);
51
+ border-radius: var(--r-sm);
52
+ transform: translateY(-160%);
53
+ transition: transform var(--dur) var(--ease);
54
+ }
55
+ .skip-link:focus { transform: translateY(0); text-decoration: none; }
56
+
57
+ [hidden] { display: none !important; }
@@ -0,0 +1,31 @@
1
+ // ── Extra responsive polish ─────────────────────────────────
2
+ @media (max-width: 1400px) {
3
+ :root { --sidebar-w: 264px; --toc-w: 220px; }
4
+ }
5
+
6
+ @media (max-width: 1180px) {
7
+ :root { --content-max: 76ch; }
8
+ }
9
+
10
+ @media (max-width: 960px) {
11
+ :root { --content-max: 100%; --measure: 100%; }
12
+ .home { padding-inline: var(--sp-4); }
13
+ }
14
+
15
+ @media (max-width: 560px) {
16
+ :root { --sp-9: 72px; --sp-8: 48px; }
17
+ }
18
+
19
+ @media (max-width: 480px) {
20
+ :root { --fs-root: 15.5px; }
21
+ .page-main { padding-inline: var(--sp-4); }
22
+ .hero__actions .btn { width: 100%; }
23
+ .to-top { right: var(--sp-3); bottom: var(--sp-3); }
24
+ .code-wrap__bar { padding-left: var(--sp-3); }
25
+ .prose pre { padding-inline: var(--sp-4); }
26
+ }
27
+
28
+ // Large screens: let content breathe without going past a readable measure
29
+ @media (min-width: 1600px) {
30
+ :root { --content-max: 80ch; }
31
+ }
@@ -0,0 +1,98 @@
1
+ // ── Live search modal ───────────────────────────────────────
2
+ .search-modal {
3
+ position: fixed;
4
+ inset: 0;
5
+ z-index: 120;
6
+ display: none;
7
+ padding: clamp(var(--sp-4), 10vh, 120px) var(--sp-4) var(--sp-4);
8
+ }
9
+ .search-modal.is-open { display: block; }
10
+ .search-modal__backdrop {
11
+ position: absolute;
12
+ inset: 0;
13
+ background: hsl(220 40% 6% / .55);
14
+ backdrop-filter: blur(3px);
15
+ animation: fade .16s var(--ease);
16
+ }
17
+ .search-modal__panel {
18
+ position: relative;
19
+ max-width: 620px;
20
+ margin-inline: auto;
21
+ background: var(--bg-elev);
22
+ border: 1px solid var(--border);
23
+ border-radius: var(--r-lg);
24
+ box-shadow: var(--shadow-lg);
25
+ overflow: hidden;
26
+ animation: pop .16s var(--ease);
27
+ }
28
+ @keyframes fade { from { opacity: 0; } }
29
+ @keyframes pop { from { opacity: 0; transform: translateY(-8px) scale(.98); } }
30
+
31
+ .search-modal__bar {
32
+ display: flex;
33
+ align-items: center;
34
+ gap: var(--sp-3);
35
+ padding: var(--sp-4) var(--sp-5);
36
+ border-bottom: 1px solid var(--border);
37
+ }
38
+ .search-modal__bar > i { color: var(--text-faint); }
39
+ .search-modal__input {
40
+ flex: 1;
41
+ border: 0;
42
+ background: none;
43
+ font-size: 1rem;
44
+ outline: none;
45
+ }
46
+ .search-modal__input::placeholder { color: var(--text-faint); }
47
+ .search-modal__esc { color: var(--text-faint); }
48
+
49
+ .search-modal__body { max-height: min(60vh, 520px); overflow-y: auto; padding: var(--sp-2); }
50
+
51
+ .search-results { display: grid; gap: 2px; }
52
+ .search-result {
53
+ display: block;
54
+ padding: var(--sp-3) var(--sp-4);
55
+ border-radius: var(--r-md);
56
+ color: var(--text);
57
+ }
58
+ .search-result:hover, .search-result.is-active {
59
+ background: var(--brand-soft);
60
+ text-decoration: none;
61
+ }
62
+ .search-result__crumb {
63
+ font-size: .72rem;
64
+ font-weight: 600;
65
+ text-transform: uppercase;
66
+ letter-spacing: .04em;
67
+ color: var(--brand);
68
+ }
69
+ .search-result__title { font-weight: 600; margin-top: 2px; }
70
+ .search-result__excerpt {
71
+ margin-top: 3px;
72
+ font-size: .84rem;
73
+ color: var(--text-soft);
74
+ display: -webkit-box;
75
+ -webkit-line-clamp: 2;
76
+ -webkit-box-orient: vertical;
77
+ overflow: hidden;
78
+ }
79
+ .search-result mark {
80
+ background: hsl(var(--brand-h) var(--brand-s) 55% / .22);
81
+ color: inherit;
82
+ border-radius: 3px;
83
+ padding: 0 1px;
84
+ }
85
+
86
+ .search-modal__empty, .search-modal__hint {
87
+ padding: var(--sp-4) var(--sp-5);
88
+ font-size: .84rem;
89
+ color: var(--text-faint);
90
+ text-align: center;
91
+ }
92
+ .search-modal__hint kbd { margin: 0 2px; }
93
+
94
+ @media (max-width: 520px) {
95
+ .search-modal { padding-top: 0; }
96
+ .search-modal__panel { border-radius: 0; min-height: 100%; }
97
+ .search-modal__body { max-height: calc(100vh - 66px); }
98
+ }
@@ -0,0 +1,159 @@
1
+ // ── Left sidebar ─────────────────────────────────────────────
2
+ .sidebar {
3
+ border-right: 1px solid var(--border);
4
+ background: var(--bg);
5
+ // .page-shell is align-items:start, which would shrink this grid item to its
6
+ // content height — leaving the sticky __inner no room to travel, so sticky
7
+ // would silently do nothing. Stretching to the full row gives it that room
8
+ // (and runs the border the whole height of the page, which looks better).
9
+ align-self: stretch;
10
+ }
11
+ .sidebar.is-sticky .sidebar__inner {
12
+ position: sticky;
13
+ top: var(--nav-h);
14
+ max-height: calc(100vh - var(--nav-h));
15
+ overflow-y: auto;
16
+ overscroll-behavior: contain;
17
+ }
18
+ .sidebar__inner {
19
+ padding: var(--sp-5) var(--sp-4) var(--sp-8);
20
+ scrollbar-width: thin;
21
+ scrollbar-color: var(--border-strong) transparent;
22
+ }
23
+ .sidebar__inner::-webkit-scrollbar { width: 10px; }
24
+ .sidebar__inner::-webkit-scrollbar-track { background: transparent; }
25
+ .sidebar__inner::-webkit-scrollbar-thumb {
26
+ background: var(--border-strong);
27
+ border: 3px solid var(--bg);
28
+ border-radius: 5px;
29
+ }
30
+
31
+ // ── Search trigger ───────────────────────────────────────────
32
+ .sidebar__search {
33
+ display: flex;
34
+ align-items: center;
35
+ gap: var(--sp-3);
36
+ width: 100%;
37
+ height: 38px;
38
+ margin-bottom: var(--sp-6);
39
+ padding-inline: var(--sp-3);
40
+ border: 1px solid var(--border);
41
+ border-radius: var(--r-md);
42
+ background: var(--bg-sunken);
43
+ color: var(--text-faint);
44
+ font-size: var(--fs-sm);
45
+ text-align: left;
46
+ transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease),
47
+ background var(--dur) var(--ease);
48
+ }
49
+ .sidebar__search:hover {
50
+ border-color: var(--border-strong);
51
+ color: var(--text-soft);
52
+ background: var(--bg-elev);
53
+ }
54
+ .sidebar__search i { font-size: .85em; }
55
+
56
+ // ── Groups ───────────────────────────────────────────────────
57
+ .sidebar__nav { display: grid; gap: var(--sp-1); }
58
+
59
+ .sidebar__group + .sidebar__group { margin-top: var(--sp-4); }
60
+
61
+ .sidebar__group-title {
62
+ display: flex;
63
+ align-items: center;
64
+ gap: var(--sp-2);
65
+ width: 100%;
66
+ padding: var(--sp-2) var(--sp-3);
67
+ border-radius: var(--r-sm);
68
+ font-size: var(--fs-xs);
69
+ font-weight: 650;
70
+ text-transform: uppercase;
71
+ letter-spacing: var(--tr-wide);
72
+ color: var(--text-faint);
73
+ text-align: left;
74
+ transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
75
+ }
76
+ .sidebar__group-title:hover { color: var(--text-soft); background: var(--surface-2); }
77
+ .sidebar__group-title > i:first-child { font-size: .95em; color: var(--brand); opacity: .85; }
78
+ .sidebar__group-title > span { flex: 1; }
79
+ .sidebar__chev {
80
+ font-size: .62rem;
81
+ opacity: .6;
82
+ transition: transform var(--dur) var(--ease);
83
+ }
84
+ .sidebar__group:not(.is-collapsed) .sidebar__chev { transform: rotate(90deg); }
85
+
86
+ // ── Links ────────────────────────────────────────────────────
87
+ .sidebar__list {
88
+ display: grid;
89
+ gap: 1px;
90
+ margin-top: var(--sp-1);
91
+ margin-left: calc(var(--sp-3) + 7px);
92
+ padding-left: var(--sp-3);
93
+ border-left: 1px solid var(--border);
94
+ }
95
+ .sidebar__group.is-collapsed .sidebar__list { display: none; }
96
+
97
+ .sidebar__link {
98
+ position: relative;
99
+ display: flex;
100
+ align-items: center;
101
+ gap: var(--sp-2);
102
+ min-height: 32px;
103
+ padding: 5px var(--sp-3);
104
+ border-radius: var(--r-sm);
105
+ font-size: var(--fs-sm);
106
+ line-height: 1.4;
107
+ color: var(--text-soft);
108
+ transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
109
+ }
110
+ .sidebar__link:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
111
+ .sidebar__link.is-active {
112
+ color: var(--brand);
113
+ background: var(--brand-soft);
114
+ font-weight: 600;
115
+ }
116
+ // The active marker sits on the group's rail, not inside the pill
117
+ .sidebar__link.is-active::before {
118
+ content: "";
119
+ position: absolute;
120
+ left: calc((var(--sp-3) + 1px) * -1);
121
+ top: 6px; bottom: 6px;
122
+ width: 2px;
123
+ border-radius: 2px;
124
+ background: var(--brand);
125
+ }
126
+ .sidebar__link .badge { margin-left: auto; }
127
+
128
+ .sidebar__coffee {
129
+ margin-top: var(--sp-7);
130
+ padding-top: var(--sp-5);
131
+ border-top: 1px solid var(--border);
132
+ }
133
+
134
+ // ── Mobile drawer ────────────────────────────────────────────
135
+ .sidebar-scrim {
136
+ position: fixed;
137
+ inset: 0;
138
+ z-index: 88;
139
+ background: hsl(220 30% 6% / .5);
140
+ backdrop-filter: blur(2px);
141
+ animation: fade .16s var(--ease);
142
+ }
143
+
144
+ @media (max-width: 960px) {
145
+ .sidebar {
146
+ position: fixed;
147
+ top: 0; bottom: 0; left: 0;
148
+ z-index: 89;
149
+ width: min(88vw, var(--sidebar-w));
150
+ background: var(--bg-elev);
151
+ transform: translateX(-100%);
152
+ transition: transform var(--dur-lg) var(--ease-out);
153
+ box-shadow: var(--shadow-lg);
154
+ }
155
+ .sidebar.is-open { transform: translateX(0); }
156
+ .sidebar.is-sticky .sidebar__inner { position: static; max-height: none; }
157
+ .sidebar__inner { padding-top: calc(var(--nav-h) + var(--sp-4)); height: 100%; }
158
+ .sidebar__link { min-height: 38px; }
159
+ }
@@ -0,0 +1,193 @@
1
+ @use "sass:list";
2
+ @use "sass:map";
3
+
4
+ // ── Colour skins ─────────────────────────────────────────────
5
+ // Six curated palettes. Pick one in _config.yml:
6
+ // docsteer: { skin: aqua|violet|mint|ember|graphite|clay }
7
+ //
8
+ // Every value below becomes a CSS custom property, so nothing else in
9
+ // the codebase references a raw colour — edit a map, restyle the theme.
10
+ //
11
+ // aqua azure → cyan the safe default: product & API docs
12
+ // violet violet → fuchsia creative, design-system & SDK docs
13
+ // mint teal → spring fresh and technical: developer docs
14
+ // ember rose → amber warm: help centres & support portals
15
+ // graphite monochrome ink minimal and premium: internal wikis
16
+ // clay warm paper + terracotta editorial, long-form reading
17
+ //
18
+ // Contrast: every `brand` clears 4.5:1 against its own `bg`, so links
19
+ // in body copy are AA-legible. Keep that in mind if you retune one.
20
+
21
+ $skins: (
22
+ // ───────────── AQUA — azure → cyan ─────────────
23
+ aqua: (
24
+ ring: (218, 92%),
25
+ light: (
26
+ bg:#ffffff, bg-elev:#ffffff, bg-sunken:#f6f8fb, surface-2:#eef2f7,
27
+ text:#101828, text-soft:#51607a, text-faint:#7b8798,
28
+ border:#e6ebf2, border-strong:#d3dbe6,
29
+ brand:#1668f0, brand-strong:#0d51cc, brand-contrast:#ffffff, brand-soft:#e8f0fe,
30
+ link:#1668f0, accent:#00b4d8,
31
+ code-bg:#f7f9fc, shadow-color:218 45% 20%, selection:#cfe0ff,
32
+ ),
33
+ dark: (
34
+ bg:#0b0f16, bg-elev:#111722, bg-sunken:#080b11, surface-2:#17202e,
35
+ text:#e8eef7, text-soft:#a0adbe, text-faint:#6f7d90,
36
+ border:#1e2735, border-strong:#2c3746,
37
+ brand:#5fa3ff, brand-strong:#85baff, brand-contrast:#071022, brand-soft:#10243f,
38
+ link:#5fa3ff, accent:#3ad2ea,
39
+ code-bg:#0e141d, shadow-color:216 70% 2%, selection:#1c4a86,
40
+ ),
41
+ ),
42
+
43
+ // ───────────── VIOLET — violet → fuchsia ─────────────
44
+ violet: (
45
+ ring: (258, 90%),
46
+ light: (
47
+ bg:#ffffff, bg-elev:#ffffff, bg-sunken:#f8f6fd, surface-2:#f1ecfb,
48
+ text:#191428, text-soft:#565070, text-faint:#8a83a3,
49
+ border:#ebe5f7, border-strong:#dbd2ef,
50
+ brand:#6d3bf5, brand-strong:#5726df, brand-contrast:#ffffff, brand-soft:#efe9fe,
51
+ link:#6d3bf5, accent:#d946ef,
52
+ code-bg:#f8f6fd, shadow-color:258 45% 24%, selection:#ddd0ff,
53
+ ),
54
+ dark: (
55
+ bg:#100d1a, bg-elev:#171327, bg-sunken:#0b0914, surface-2:#201a33,
56
+ text:#ece8f8, text-soft:#aba3c6, text-faint:#7c7399,
57
+ border:#272040, border-strong:#362d55,
58
+ brand:#a98bff, brand-strong:#c0a8ff, brand-contrast:#120b26, brand-soft:#241b40,
59
+ link:#a98bff, accent:#e879f9,
60
+ code-bg:#151124, shadow-color:258 65% 3%, selection:#45308f,
61
+ ),
62
+ ),
63
+
64
+ // ───────────── MINT — teal → spring ─────────────
65
+ mint: (
66
+ ring: (170, 82%),
67
+ light: (
68
+ bg:#ffffff, bg-elev:#ffffff, bg-sunken:#f3faf8, surface-2:#e7f5f1,
69
+ text:#0e201c, text-soft:#46605a, text-faint:#7a938c,
70
+ border:#dcefe9, border-strong:#c5e3da,
71
+ brand:#0b8069, brand-strong:#086355, brand-contrast:#ffffff, brand-soft:#e0f5f0,
72
+ link:#0b8069, accent:#21c8a8,
73
+ code-bg:#f5faf9, shadow-color:170 40% 18%, selection:#b9ece1,
74
+ ),
75
+ dark: (
76
+ bg:#08130f, bg-elev:#0e1c18, bg-sunken:#050d0a, surface-2:#13251f,
77
+ text:#e0f2ec, text-soft:#9ab5ad, text-faint:#67827a,
78
+ border:#1a2d27, border-strong:#274038,
79
+ brand:#34e0bb, brand-strong:#5cebcb, brand-contrast:#04150f, brand-soft:#0c2e27,
80
+ link:#34e0bb, accent:#22d3ee,
81
+ code-bg:#0b1814, shadow-color:170 65% 2%, selection:#14584a,
82
+ ),
83
+ ),
84
+
85
+ // ───────────── EMBER — rose → amber ─────────────
86
+ ember: (
87
+ ring: (346, 82%),
88
+ light: (
89
+ bg:#ffffff, bg-elev:#ffffff, bg-sunken:#fdf6f5, surface-2:#fbeceb,
90
+ text:#26161a, text-soft:#6a5057, text-faint:#9c7d85,
91
+ border:#f5e3e2, border-strong:#eed0ce,
92
+ brand:#d81b45, brand-strong:#b41339, brand-contrast:#ffffff, brand-soft:#fde8ec,
93
+ link:#d81b45, accent:#f59e0b,
94
+ code-bg:#fdf7f6, shadow-color:346 45% 22%, selection:#ffd3dc,
95
+ ),
96
+ dark: (
97
+ bg:#150e11, bg-elev:#1e1418, bg-sunken:#0e090b, surface-2:#281b20,
98
+ text:#f6e9ec, text-soft:#c3a6ad, text-faint:#8f757c,
99
+ border:#2e2027, border-strong:#432f37,
100
+ brand:#ff6b8a, brand-strong:#ff90a6, brand-contrast:#1a0710, brand-soft:#3a1723,
101
+ link:#ff6b8a, accent:#fbbf24,
102
+ code-bg:#1a1216, shadow-color:346 60% 3%, selection:#7d2440,
103
+ ),
104
+ ),
105
+
106
+ // ───────────── GRAPHITE — monochrome ink ─────────────
107
+ graphite: (
108
+ ring: (215, 16%),
109
+ light: (
110
+ bg:#ffffff, bg-elev:#ffffff, bg-sunken:#f6f7f9, surface-2:#eef0f3,
111
+ text:#0c0f14, text-soft:#4d5560, text-faint:#7d8593,
112
+ border:#e4e7ec, border-strong:#d0d5dd,
113
+ brand:#0c0f14, brand-strong:#000000, brand-contrast:#ffffff, brand-soft:#e8ebf0,
114
+ link:#0c0f14, accent:#64748b,
115
+ code-bg:#f6f7f9, shadow-color:215 25% 16%, selection:#dfe3e9,
116
+ ),
117
+ dark: (
118
+ bg:#0a0b0d, bg-elev:#101215, bg-sunken:#070809, surface-2:#181b20,
119
+ text:#f2f4f7, text-soft:#a2aab6, text-faint:#6f7783,
120
+ border:#1e2126, border-strong:#2c3138,
121
+ brand:#f2f4f7, brand-strong:#ffffff, brand-contrast:#0a0b0d, brand-soft:#1c2026,
122
+ link:#f2f4f7, accent:#94a3b8,
123
+ code-bg:#0e1013, shadow-color:215 30% 1%, selection:#2b3138,
124
+ ),
125
+ ),
126
+
127
+ // ───────────── CLAY — warm paper + terracotta ─────────────
128
+ clay: (
129
+ ring: (18, 62%),
130
+ light: (
131
+ bg:#fdfaf6, bg-elev:#ffffff, bg-sunken:#f5efe7, surface-2:#efe7dc,
132
+ text:#1f1a15, text-soft:#5f5449, text-faint:#8d8175,
133
+ border:#ece3d8, border-strong:#ddd0c0,
134
+ brand:#b04a26, brand-strong:#8f3a1c, brand-contrast:#ffffff, brand-soft:#f8ebe2,
135
+ link:#b04a26, accent:#c98a3f,
136
+ code-bg:#f7f1e9, shadow-color:26 35% 20%, selection:#f2d9c4,
137
+ ),
138
+ dark: (
139
+ bg:#14100d, bg-elev:#1c1713, bg-sunken:#0d0a08, surface-2:#261f19,
140
+ text:#f2ebe2, text-soft:#b9aa9a, text-faint:#8a7b6c,
141
+ border:#2b2219, border-strong:#3e3227,
142
+ brand:#e0865c, brand-strong:#eda37e, brand-contrast:#180c06, brand-soft:#332015,
143
+ link:#e0865c, accent:#d9a55f,
144
+ code-bg:#191410, shadow-color:26 55% 2%, selection:#6b3a1f,
145
+ ),
146
+ ),
147
+ );
148
+
149
+ // Shared status colours (same across skins, tuned for contrast)
150
+ :root {
151
+ --success:#15803d; --success-bg:#eaf6ee;
152
+ --warning:#a16207; --warning-bg:#fdf4e3;
153
+ --danger:#c02626; --danger-bg:#fdecec;
154
+ --info:#1d4ed8; --info-bg:#eaf0fd;
155
+ }
156
+ :root[data-mode="dark"], :root:not([data-mode="light"]) {
157
+ @media (prefers-color-scheme: dark) {
158
+ --success:#4ade80; --success-bg:#0f2016;
159
+ --warning:#fbbf24; --warning-bg:#221a0c;
160
+ --danger:#fb7185; --danger-bg:#241014;
161
+ --info:#7dabff; --info-bg:#101c33;
162
+ }
163
+ }
164
+ :root[data-mode="dark"] {
165
+ --success:#4ade80; --success-bg:#0f2016;
166
+ --warning:#fbbf24; --warning-bg:#221a0c;
167
+ --danger:#fb7185; --danger-bg:#241014;
168
+ --info:#7dabff; --info-bg:#101c33;
169
+ }
170
+
171
+ @mixin emit-vars($map) {
172
+ @each $key, $val in $map {
173
+ --#{$key}: #{$val};
174
+ }
175
+ }
176
+
177
+ @each $name, $data in $skins {
178
+ $ring: map.get($data, ring);
179
+ $light: map.get($data, light);
180
+ $dark: map.get($data, dark);
181
+ $sel: "" + $name;
182
+
183
+ [data-skin="#{$sel}"] {
184
+ @include emit-vars($light);
185
+ --brand-h: #{list.nth($ring, 1)};
186
+ --brand-s: #{list.nth($ring, 2)};
187
+
188
+ @media (prefers-color-scheme: dark) {
189
+ &:not([data-mode="light"]) { @include emit-vars($dark); }
190
+ }
191
+ &[data-mode="dark"] { @include emit-vars($dark); }
192
+ }
193
+ }
@@ -0,0 +1,72 @@
1
+ // ── Rouge syntax highlighting (theme-aware) ──────────────────
2
+ :root {
3
+ --tok-comment:#8a919c;
4
+ --tok-keyword:#cf222e;
5
+ --tok-string:#0a7d33;
6
+ --tok-number:#0550ae;
7
+ --tok-function:#8250df;
8
+ --tok-variable:#953800;
9
+ --tok-type:#0550ae;
10
+ --tok-tag:#116329;
11
+ --tok-attr:#0550ae;
12
+ --tok-operator:#0f172a;
13
+ --tok-deleted-bg:#fbe9e7;
14
+ --tok-inserted-bg:#e6ffec;
15
+ }
16
+ :root[data-mode="dark"], :root:not([data-mode="light"]) {
17
+ @media (prefers-color-scheme: dark) {
18
+ --tok-comment:#7a828e;
19
+ --tok-keyword:#ff7b72;
20
+ --tok-string:#7ee787;
21
+ --tok-number:#79c0ff;
22
+ --tok-function:#d2a8ff;
23
+ --tok-variable:#ffa657;
24
+ --tok-type:#79c0ff;
25
+ --tok-tag:#7ee787;
26
+ --tok-attr:#79c0ff;
27
+ --tok-operator:#e6edf3;
28
+ --tok-deleted-bg:#3c1618;
29
+ --tok-inserted-bg:#12261e;
30
+ }
31
+ }
32
+ :root[data-mode="dark"] {
33
+ --tok-comment:#7a828e;
34
+ --tok-keyword:#ff7b72;
35
+ --tok-string:#7ee787;
36
+ --tok-number:#79c0ff;
37
+ --tok-function:#d2a8ff;
38
+ --tok-variable:#ffa657;
39
+ --tok-type:#79c0ff;
40
+ --tok-tag:#7ee787;
41
+ --tok-attr:#79c0ff;
42
+ --tok-operator:#e6edf3;
43
+ --tok-deleted-bg:#3c1618;
44
+ --tok-inserted-bg:#12261e;
45
+ }
46
+
47
+ .highlight, .highlight code { color: var(--text); background: transparent; }
48
+ .highlight .c, .highlight .c1, .highlight .cm, .highlight .cp, .highlight .cs { color: var(--tok-comment); font-style: italic; }
49
+ .highlight .k, .highlight .kd, .highlight .kn, .highlight .kp, .highlight .kr, .highlight .kt, .highlight .kc { color: var(--tok-keyword); }
50
+ .highlight .s, .highlight .s1, .highlight .s2, .highlight .sb, .highlight .sc, .highlight .sd, .highlight .se, .highlight .sh, .highlight .si, .highlight .sx, .highlight .sr, .highlight .ss { color: var(--tok-string); }
51
+ .highlight .m, .highlight .mf, .highlight .mh, .highlight .mi, .highlight .mo, .highlight .il { color: var(--tok-number); }
52
+ .highlight .nf, .highlight .fm { color: var(--tok-function); }
53
+ .highlight .nb, .highlight .bp { color: var(--tok-function); }
54
+ .highlight .nv, .highlight .vc, .highlight .vg, .highlight .vi { color: var(--tok-variable); }
55
+ .highlight .nc, .highlight .nn, .highlight .no { color: var(--tok-type); }
56
+ .highlight .nt { color: var(--tok-tag); }
57
+ .highlight .na { color: var(--tok-attr); }
58
+ .highlight .o, .highlight .ow, .highlight .p { color: var(--tok-operator); }
59
+ .highlight .gd { background: var(--tok-deleted-bg); }
60
+ .highlight .gi { background: var(--tok-inserted-bg); }
61
+ .highlight .gh, .highlight .gu { color: var(--tok-number); font-weight: 700; }
62
+ .highlight .err { color: var(--danger); }
63
+
64
+ // Rouge line-numbers table
65
+ .highlight .lineno {
66
+ color: var(--text-faint);
67
+ user-select: none;
68
+ -webkit-user-select: none;
69
+ padding-right: var(--sp-4);
70
+ border-right: 1px solid var(--border);
71
+ margin-right: var(--sp-4);
72
+ }
@@ -0,0 +1,46 @@
1
+ // ── Right "On this page" TOC ─────────────────────────────────
2
+ .toc {
3
+ position: sticky;
4
+ top: calc(var(--nav-h) + var(--sp-6));
5
+ align-self: start;
6
+ max-height: calc(100vh - var(--nav-h) - var(--sp-8));
7
+ overflow-y: auto;
8
+ font-size: var(--fs-sm);
9
+ scrollbar-width: thin;
10
+ scrollbar-color: var(--border-strong) transparent;
11
+ }
12
+ .toc::-webkit-scrollbar { width: 6px; }
13
+ .toc::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; }
14
+
15
+ .toc__title {
16
+ display: flex;
17
+ align-items: center;
18
+ gap: var(--sp-2);
19
+ margin-bottom: var(--sp-3);
20
+ padding-left: var(--sp-3);
21
+ font-size: var(--fs-xs);
22
+ font-weight: 650;
23
+ text-transform: uppercase;
24
+ letter-spacing: var(--tr-wide);
25
+ color: var(--text-faint);
26
+ }
27
+ .toc__title i { font-size: .9em; opacity: .7; }
28
+
29
+ .toc__nav { display: grid; }
30
+ .toc__nav a {
31
+ display: block;
32
+ padding: 5px var(--sp-3);
33
+ border-left: 2px solid var(--border);
34
+ color: var(--text-soft);
35
+ line-height: 1.45;
36
+ text-wrap: pretty;
37
+ transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
38
+ }
39
+ .toc__nav a:hover { color: var(--text); border-left-color: var(--border-strong); text-decoration: none; }
40
+ .toc__nav a.lvl-3 { padding-left: var(--sp-6); font-size: .95em; }
41
+ .toc__nav a.is-active {
42
+ color: var(--brand);
43
+ border-left-color: var(--brand);
44
+ font-weight: 600;
45
+ }
46
+ .toc__coffee { margin-top: var(--sp-6); padding-left: var(--sp-3); }