blume 0.0.0 → 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 (263) hide show
  1. package/bin/blume.mjs +18 -0
  2. package/dist/cli/index.js +11989 -0
  3. package/dist/cli/index.js.map +141 -0
  4. package/docs/01-quickstart.mdx +99 -0
  5. package/docs/02-deployment.mdx +129 -0
  6. package/docs/advanced/api-reference.mdx +114 -0
  7. package/docs/advanced/blog.mdx +121 -0
  8. package/docs/advanced/changelog.mdx +113 -0
  9. package/docs/advanced/custom-pages.mdx +187 -0
  10. package/docs/advanced/meta.ts +7 -0
  11. package/docs/changelog/v0-1-0.mdx +12 -0
  12. package/docs/changelog/v0-2-0.mdx +16 -0
  13. package/docs/configuration/ai.mdx +228 -0
  14. package/docs/configuration/analytics.mdx +98 -0
  15. package/docs/configuration/customization.mdx +91 -0
  16. package/docs/configuration/export.mdx +70 -0
  17. package/docs/configuration/index.mdx +271 -0
  18. package/docs/configuration/meta.ts +15 -0
  19. package/docs/configuration/search.mdx +172 -0
  20. package/docs/configuration/seo.mdx +196 -0
  21. package/docs/configuration/theming.mdx +178 -0
  22. package/docs/content/components.mdx +565 -0
  23. package/docs/content/i18n.mdx +205 -0
  24. package/docs/content/index.mdx +161 -0
  25. package/docs/content/islands.mdx +94 -0
  26. package/docs/content/meta.mdx +119 -0
  27. package/docs/content/meta.ts +15 -0
  28. package/docs/content/navigation.mdx +168 -0
  29. package/docs/content/sources.mdx +216 -0
  30. package/docs/content/syntax.mdx +445 -0
  31. package/docs/index.mdx +112 -0
  32. package/docs/reference/cli.mdx +43 -0
  33. package/docs/reference/frontmatter.mdx +74 -0
  34. package/docs/reference/meta.ts +7 -0
  35. package/package.json +140 -6
  36. package/src/ai/ask.ts +93 -0
  37. package/src/ai/llms.ts +65 -0
  38. package/src/ai/markdown.ts +31 -0
  39. package/src/ai/mcp/data.ts +74 -0
  40. package/src/ai/mcp/discovery.ts +49 -0
  41. package/src/ai/mcp/server.ts +225 -0
  42. package/src/ai/mcp/tools.ts +47 -0
  43. package/src/assets/icon.png +0 -0
  44. package/src/astro/generate.ts +878 -0
  45. package/src/astro/index.ts +4 -0
  46. package/src/astro/integration.ts +74 -0
  47. package/src/astro/islands.ts +131 -0
  48. package/src/astro/markdown-negotiation.ts +68 -0
  49. package/src/astro/pages.ts +28 -0
  50. package/src/astro/templates.ts +1199 -0
  51. package/src/cli/commands/add.ts +81 -0
  52. package/src/cli/commands/build.ts +103 -0
  53. package/src/cli/commands/dev.ts +108 -0
  54. package/src/cli/commands/doctor.ts +74 -0
  55. package/src/cli/commands/eject.ts +57 -0
  56. package/src/cli/commands/init.ts +98 -0
  57. package/src/cli/commands/migrate.ts +39 -0
  58. package/src/cli/commands/preview.ts +39 -0
  59. package/src/cli/commands/sync.ts +52 -0
  60. package/src/cli/commands/validate.ts +60 -0
  61. package/src/cli/index.ts +35 -0
  62. package/src/cli/log.ts +37 -0
  63. package/src/cli/prepare.ts +80 -0
  64. package/src/components/Icon.astro +99 -0
  65. package/src/components/content/Accordion.astro +8 -0
  66. package/src/components/content/AccordionItem.astro +121 -0
  67. package/src/components/content/AutoTypeTable.astro +51 -0
  68. package/src/components/content/Badge.astro +124 -0
  69. package/src/components/content/Callout.astro +73 -0
  70. package/src/components/content/Card.astro +104 -0
  71. package/src/components/content/CardGroup.astro +14 -0
  72. package/src/components/content/CodeGroup.astro +13 -0
  73. package/src/components/content/Color.astro +15 -0
  74. package/src/components/content/ColorItem.astro +87 -0
  75. package/src/components/content/ColorRow.astro +10 -0
  76. package/src/components/content/Column.astro +6 -0
  77. package/src/components/content/Columns.astro +9 -0
  78. package/src/components/content/Expandable.astro +11 -0
  79. package/src/components/content/FileTree.astro +8 -0
  80. package/src/components/content/Frame.astro +70 -0
  81. package/src/components/content/GithubInfo.astro +110 -0
  82. package/src/components/content/Math.astro +24 -0
  83. package/src/components/content/Panel.astro +20 -0
  84. package/src/components/content/Prompt.astro +129 -0
  85. package/src/components/content/Step.astro +34 -0
  86. package/src/components/content/Steps.astro +20 -0
  87. package/src/components/content/Tab.astro +40 -0
  88. package/src/components/content/Tabs.astro +273 -0
  89. package/src/components/content/Tile.astro +42 -0
  90. package/src/components/content/Tooltip.astro +68 -0
  91. package/src/components/content/Tree.astro +300 -0
  92. package/src/components/content/TreeFile.astro +15 -0
  93. package/src/components/content/TreeFolder.astro +62 -0
  94. package/src/components/content/TypeTable.astro +106 -0
  95. package/src/components/content/Update.astro +66 -0
  96. package/src/components/content/Visibility.astro +12 -0
  97. package/src/components/content/Warning.astro +9 -0
  98. package/src/components/content/auto-type-table.ts +141 -0
  99. package/src/components/content/github-info.ts +79 -0
  100. package/src/components/content/mermaid-element.ts +68 -0
  101. package/src/components/github-mark.ts +9 -0
  102. package/src/components/index.ts +14 -0
  103. package/src/components/islands/AskAI.astro +12 -0
  104. package/src/components/islands/ask-ai.tsx +156 -0
  105. package/src/components/layout/Analytics.astro +63 -0
  106. package/src/components/layout/Banner.astro +50 -0
  107. package/src/components/layout/Breadcrumbs.astro +31 -0
  108. package/src/components/layout/Favicon.astro +15 -0
  109. package/src/components/layout/Fonts.astro +14 -0
  110. package/src/components/layout/Header.astro +188 -0
  111. package/src/components/layout/LanguageSwitcher.astro +56 -0
  112. package/src/components/layout/NavTree.astro +462 -0
  113. package/src/components/layout/PageActions.astro +438 -0
  114. package/src/components/layout/PageFeedback.astro +58 -0
  115. package/src/components/layout/Pagination.astro +56 -0
  116. package/src/components/layout/ReferenceLayout.astro +102 -0
  117. package/src/components/layout/RootLayout.astro +533 -0
  118. package/src/components/layout/Search.astro +608 -0
  119. package/src/components/layout/TableOfContents.astro +68 -0
  120. package/src/components/layout/analytics-client.ts +38 -0
  121. package/src/components/layout/nav-utils.ts +87 -0
  122. package/src/components/layout/overrides.ts +32 -0
  123. package/src/components/layout/search/algolia.ts +43 -0
  124. package/src/components/layout/search/endpoint.ts +22 -0
  125. package/src/components/layout/search/flexsearch.ts +52 -0
  126. package/src/components/layout/search/orama-cloud.ts +41 -0
  127. package/src/components/layout/search/orama.ts +26 -0
  128. package/src/components/layout/search/pagefind.ts +43 -0
  129. package/src/components/layout/search/types.ts +163 -0
  130. package/src/components/layout/search/typesense.ts +60 -0
  131. package/src/components/layout/toc-element.ts +108 -0
  132. package/src/core/bridge.ts +92 -0
  133. package/src/core/config.ts +112 -0
  134. package/src/core/content.ts +50 -0
  135. package/src/core/define-components.ts +34 -0
  136. package/src/core/define-meta.ts +20 -0
  137. package/src/core/deployment-env.ts +73 -0
  138. package/src/core/diagnostics.ts +104 -0
  139. package/src/core/graph.ts +128 -0
  140. package/src/core/i18n-ui.ts +171 -0
  141. package/src/core/i18n.ts +169 -0
  142. package/src/core/last-modified.ts +88 -0
  143. package/src/core/links.ts +336 -0
  144. package/src/core/load-module.ts +15 -0
  145. package/src/core/manifest.ts +126 -0
  146. package/src/core/meta.ts +97 -0
  147. package/src/core/navigation.ts +392 -0
  148. package/src/core/package-root.ts +37 -0
  149. package/src/core/project-graph.ts +153 -0
  150. package/src/core/project.ts +56 -0
  151. package/src/core/schema.ts +1057 -0
  152. package/src/core/server-features.ts +23 -0
  153. package/src/core/sources/assets.ts +77 -0
  154. package/src/core/sources/cache.ts +122 -0
  155. package/src/core/sources/filesystem.ts +99 -0
  156. package/src/core/sources/mdx-remote.ts +216 -0
  157. package/src/core/sources/mintlify.ts +161 -0
  158. package/src/core/sources/normalize.ts +227 -0
  159. package/src/core/sources/notion.ts +440 -0
  160. package/src/core/sources/portable-text.ts +143 -0
  161. package/src/core/sources/read.ts +36 -0
  162. package/src/core/sources/resolve.ts +158 -0
  163. package/src/core/sources/sanity.ts +218 -0
  164. package/src/core/sources/types.ts +105 -0
  165. package/src/core/types.ts +261 -0
  166. package/src/core/ui-packs/ar.ts +47 -0
  167. package/src/core/ui-packs/bg.ts +47 -0
  168. package/src/core/ui-packs/bn.ts +47 -0
  169. package/src/core/ui-packs/ca.ts +47 -0
  170. package/src/core/ui-packs/cs.ts +47 -0
  171. package/src/core/ui-packs/da.ts +47 -0
  172. package/src/core/ui-packs/de.ts +47 -0
  173. package/src/core/ui-packs/el.ts +47 -0
  174. package/src/core/ui-packs/es.ts +47 -0
  175. package/src/core/ui-packs/fa.ts +47 -0
  176. package/src/core/ui-packs/fi.ts +47 -0
  177. package/src/core/ui-packs/fr.ts +47 -0
  178. package/src/core/ui-packs/he.ts +47 -0
  179. package/src/core/ui-packs/hi.ts +47 -0
  180. package/src/core/ui-packs/hr.ts +47 -0
  181. package/src/core/ui-packs/hu.ts +47 -0
  182. package/src/core/ui-packs/id.ts +47 -0
  183. package/src/core/ui-packs/index.ts +87 -0
  184. package/src/core/ui-packs/it.ts +47 -0
  185. package/src/core/ui-packs/ja.ts +47 -0
  186. package/src/core/ui-packs/ko.ts +47 -0
  187. package/src/core/ui-packs/nl.ts +47 -0
  188. package/src/core/ui-packs/no.ts +47 -0
  189. package/src/core/ui-packs/pl.ts +47 -0
  190. package/src/core/ui-packs/pt-br.ts +47 -0
  191. package/src/core/ui-packs/pt.ts +47 -0
  192. package/src/core/ui-packs/ro.ts +47 -0
  193. package/src/core/ui-packs/ru.ts +47 -0
  194. package/src/core/ui-packs/sk.ts +47 -0
  195. package/src/core/ui-packs/sr.ts +47 -0
  196. package/src/core/ui-packs/sv.ts +47 -0
  197. package/src/core/ui-packs/th.ts +47 -0
  198. package/src/core/ui-packs/tr.ts +47 -0
  199. package/src/core/ui-packs/uk.ts +47 -0
  200. package/src/core/ui-packs/vi.ts +47 -0
  201. package/src/core/ui-packs/zh-tw.ts +47 -0
  202. package/src/core/ui-packs/zh.ts +47 -0
  203. package/src/core/version.ts +23 -0
  204. package/src/deploy/robots.ts +20 -0
  205. package/src/deploy/rss.ts +128 -0
  206. package/src/deploy/sitemap.ts +28 -0
  207. package/src/index.ts +27 -0
  208. package/src/markdown/code-title.ts +71 -0
  209. package/src/markdown/directives.ts +83 -0
  210. package/src/markdown/heading-anchors.ts +137 -0
  211. package/src/markdown/index.ts +159 -0
  212. package/src/markdown/inline-code.ts +108 -0
  213. package/src/markdown/language-icon.ts +172 -0
  214. package/src/markdown/math.ts +32 -0
  215. package/src/markdown/mdast.ts +48 -0
  216. package/src/markdown/mermaid.ts +37 -0
  217. package/src/markdown/package-commands.ts +159 -0
  218. package/src/markdown/package-install.ts +40 -0
  219. package/src/migrate/fumadocs/config.ts +106 -0
  220. package/src/migrate/fumadocs/content.ts +365 -0
  221. package/src/migrate/fumadocs/frontmatter.ts +18 -0
  222. package/src/migrate/fumadocs/index.ts +252 -0
  223. package/src/migrate/fumadocs/meta.ts +114 -0
  224. package/src/migrate/migrate.ts +53 -0
  225. package/src/migrate/mintlify/config.ts +1040 -0
  226. package/src/migrate/mintlify/content.ts +98 -0
  227. package/src/migrate/mintlify/frontmatter.ts +126 -0
  228. package/src/migrate/mintlify/i18n.ts +51 -0
  229. package/src/migrate/mintlify/icons.ts +128 -0
  230. package/src/migrate/mintlify/index.ts +266 -0
  231. package/src/migrate/mintlify/snippets.ts +305 -0
  232. package/src/migrate/mintlify/transform.ts +81 -0
  233. package/src/migrate/nextra/content.ts +46 -0
  234. package/src/migrate/nextra/frontmatter.ts +40 -0
  235. package/src/migrate/nextra/index.ts +374 -0
  236. package/src/migrate/nextra/meta.ts +266 -0
  237. package/src/migrate/shared.ts +623 -0
  238. package/src/migrate/starlight/config.ts +459 -0
  239. package/src/migrate/starlight/content.ts +78 -0
  240. package/src/migrate/starlight/frontmatter.ts +111 -0
  241. package/src/migrate/starlight/i18n.ts +54 -0
  242. package/src/migrate/starlight/index.ts +131 -0
  243. package/src/og/card.ts +92 -0
  244. package/src/og/index.ts +2 -0
  245. package/src/openapi/scalar.ts +246 -0
  246. package/src/registry/eject.ts +263 -0
  247. package/src/registry/registry.ts +100 -0
  248. package/src/registry/rewrite-imports.ts +39 -0
  249. package/src/runtime/index.ts +14 -0
  250. package/src/search/build.ts +23 -0
  251. package/src/search/documents.ts +165 -0
  252. package/src/search/orama-index.ts +66 -0
  253. package/src/search/providers.ts +91 -0
  254. package/src/search/sync/algolia.ts +30 -0
  255. package/src/search/sync/index.ts +50 -0
  256. package/src/search/sync/orama-cloud.ts +40 -0
  257. package/src/search/sync/typesense.ts +65 -0
  258. package/src/seo/jsonld.ts +113 -0
  259. package/src/theme/entry.ts +608 -0
  260. package/src/theme/fonts.ts +198 -0
  261. package/src/theme/icons.ts +184 -0
  262. package/src/theme/palette.ts +143 -0
  263. package/src/theme/twoslash.ts +81 -0
@@ -0,0 +1,608 @@
1
+ interface TailwindEntryOptions {
2
+ /**
3
+ * Globs to scan for utility classes. Typically the Blume package source and
4
+ * the user's project (node_modules is skipped automatically).
5
+ */
6
+ sources: string[];
7
+ /** Config-derived token overrides (`:root { --blume-accent: ... }`). */
8
+ configTokens: string;
9
+ /** Raw contents of the user's theme.css, if any. */
10
+ userTheme: string;
11
+ /** Twoslash rich-renderer styles (for fences with the `twoslash` meta). */
12
+ twoslashCss?: string;
13
+ }
14
+
15
+ /**
16
+ * Build the single Tailwind v4 entry stylesheet for the generated runtime.
17
+ *
18
+ * Everything flows through one Tailwind-processed file so utilities are
19
+ * generated and design tokens cascade deterministically:
20
+ * base defaults -> config tokens -> user theme.css.
21
+ */
22
+ export const tailwindEntryTemplate = (options: TailwindEntryOptions): string =>
23
+ `/* Generated by Blume. Do not edit. */
24
+ @import "tailwindcss";
25
+ @plugin "@tailwindcss/typography";
26
+
27
+ /* Scan Blume's components and the user's project for utility classes. */
28
+ ${options.sources.map((source) => `@source "${source}";`).join("\n")}
29
+
30
+ /* Dark mode is driven by data-theme on the <html> element. */
31
+ @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
32
+
33
+ :root {
34
+ --blume-background: oklch(1 0 0);
35
+ --blume-background-decoration: none;
36
+ --blume-background-decoration-repeat: no-repeat;
37
+ --blume-background-decoration-size: auto;
38
+ --blume-background-image: none;
39
+ --blume-background-image-repeat: no-repeat;
40
+ --blume-background-image-size: cover;
41
+ --blume-foreground: oklch(0.145 0 0);
42
+ --blume-muted: oklch(0.965 0 0);
43
+ --blume-muted-foreground: oklch(0.54 0 0);
44
+ --blume-border: oklch(0.88 0.006 260 / 0.72);
45
+ --blume-accent: oklch(0.145 0 0);
46
+ --blume-accent-foreground: oklch(1 0 0);
47
+ --blume-action: var(--blume-accent);
48
+ --blume-action-foreground: var(--blume-accent-foreground);
49
+ --blume-code-background: oklch(0.99 0 0);
50
+ /* Shiki notation transformers: line/word highlight, diff add/remove. */
51
+ --blume-code-highlight: oklch(0.55 0.16 255 / 0.1);
52
+ --blume-code-highlight-border: oklch(0.55 0.16 255 / 0.55);
53
+ --blume-code-add: oklch(0.72 0.16 150 / 0.16);
54
+ --blume-code-add-border: oklch(0.52 0.15 150 / 0.7);
55
+ --blume-code-remove: oklch(0.66 0.21 22 / 0.16);
56
+ --blume-code-remove-border: oklch(0.55 0.2 22 / 0.7);
57
+ --blume-code-word: oklch(0.55 0.16 255 / 0.16);
58
+ --blume-code-word-border: oklch(0.55 0.16 255 / 0.5);
59
+ --blume-radius: 0.75rem;
60
+
61
+ /*
62
+ * Font tokens resolve through optional src variables that Astro's Fonts API
63
+ * populates (via theme.fonts). When unset they fall back to the system
64
+ * stacks, so the default look is unchanged. The display font defaults to the
65
+ * body font.
66
+ */
67
+ --blume-font-body: var(
68
+ --blume-font-body-src,
69
+ ui-sans-serif,
70
+ system-ui,
71
+ -apple-system,
72
+ "Segoe UI",
73
+ Roboto,
74
+ Helvetica,
75
+ Arial,
76
+ sans-serif
77
+ );
78
+ --blume-font-mono: var(
79
+ --blume-font-mono-src,
80
+ ui-monospace,
81
+ "SF Mono",
82
+ "Cascadia Code",
83
+ "Source Code Pro",
84
+ Menlo,
85
+ Consolas,
86
+ monospace
87
+ );
88
+ --blume-font-display: var(--blume-font-display-src, var(--blume-font-body));
89
+ }
90
+
91
+ :root[data-theme="dark"] {
92
+ --blume-background: oklch(0.085 0 0);
93
+ --blume-background-decoration: none;
94
+ --blume-background-decoration-repeat: no-repeat;
95
+ --blume-background-decoration-size: auto;
96
+ --blume-background-image: none;
97
+ --blume-background-image-repeat: no-repeat;
98
+ --blume-background-image-size: cover;
99
+ --blume-foreground: oklch(0.96 0 0);
100
+ --blume-muted: oklch(0.16 0 0);
101
+ --blume-muted-foreground: oklch(0.68 0 0);
102
+ --blume-border: oklch(0.24 0 0 / 0.8);
103
+ --blume-accent: oklch(0.96 0 0);
104
+ --blume-accent-foreground: oklch(0.085 0 0);
105
+ --blume-action: var(--blume-accent);
106
+ --blume-action-foreground: var(--blume-accent-foreground);
107
+ --blume-code-background: oklch(0.12 0 0);
108
+ /* Brighter tints read better over the dark code surface. */
109
+ --blume-code-highlight: oklch(0.7 0.14 255 / 0.16);
110
+ --blume-code-highlight-border: oklch(0.7 0.14 255 / 0.6);
111
+ --blume-code-add: oklch(0.78 0.17 150 / 0.2);
112
+ --blume-code-add-border: oklch(0.72 0.16 150 / 0.7);
113
+ --blume-code-remove: oklch(0.72 0.21 22 / 0.22);
114
+ --blume-code-remove-border: oklch(0.7 0.2 22 / 0.7);
115
+ --blume-code-word: oklch(0.7 0.14 255 / 0.22);
116
+ --blume-code-word-border: oklch(0.7 0.14 255 / 0.55);
117
+ }
118
+
119
+ @theme inline {
120
+ --color-background: var(--blume-background);
121
+ --color-foreground: var(--blume-foreground);
122
+ --color-muted: var(--blume-muted);
123
+ --color-muted-foreground: var(--blume-muted-foreground);
124
+ --color-border: var(--blume-border);
125
+ --color-accent: var(--blume-accent);
126
+ --color-accent-foreground: var(--blume-accent-foreground);
127
+ --color-action: var(--blume-action);
128
+ --color-action-foreground: var(--blume-action-foreground);
129
+ --color-code: var(--blume-code-background);
130
+ --radius-blume: var(--blume-radius);
131
+ --font-sans: var(--blume-font-body);
132
+ --font-mono: var(--blume-font-mono);
133
+ --font-display: var(--blume-font-display);
134
+ }
135
+
136
+ @layer base {
137
+ html {
138
+ scroll-behavior: smooth;
139
+ scroll-padding-top: 4.5rem;
140
+ }
141
+ /* Headings use the display font (defaults to the body font when unset). */
142
+ h1,
143
+ h2,
144
+ h3,
145
+ h4,
146
+ h5,
147
+ h6 {
148
+ font-family: var(--font-display);
149
+ }
150
+ :focus-visible {
151
+ outline: 2px solid var(--blume-accent);
152
+ outline-offset: 2px;
153
+ border-radius: 2px;
154
+ }
155
+ body {
156
+ background-attachment: fixed, fixed;
157
+ background-image:
158
+ var(--blume-background-image), var(--blume-background-decoration);
159
+ background-position: center top, top center;
160
+ background-repeat:
161
+ var(--blume-background-image-repeat),
162
+ var(--blume-background-decoration-repeat);
163
+ background-size:
164
+ var(--blume-background-image-size),
165
+ var(--blume-background-decoration-size);
166
+ }
167
+ @media (prefers-reduced-motion: reduce) {
168
+ html {
169
+ scroll-behavior: auto;
170
+ }
171
+ }
172
+ }
173
+
174
+ /* Code reads left-to-right regardless of page direction; only the surrounding
175
+ chrome mirrors for RTL. Inline code is isolated so LTR identifiers don't
176
+ disturb the bidi flow of right-to-left prose. */
177
+ [dir="rtl"] pre,
178
+ [dir="rtl"] .prose pre {
179
+ direction: ltr;
180
+ text-align: left;
181
+ }
182
+ [dir="rtl"] :not(pre) > code {
183
+ unicode-bidi: isolate;
184
+ }
185
+
186
+ /* Theme Tailwind Typography (prose) with Blume tokens. */
187
+ .prose {
188
+ --tw-prose-body: var(--blume-foreground);
189
+ --tw-prose-headings: var(--blume-foreground);
190
+ --tw-prose-lead: var(--blume-muted-foreground);
191
+ --tw-prose-links: var(--blume-foreground);
192
+ --tw-prose-bold: var(--blume-foreground);
193
+ --tw-prose-counters: var(--blume-muted-foreground);
194
+ --tw-prose-bullets: var(--blume-border);
195
+ --tw-prose-hr: var(--blume-border);
196
+ --tw-prose-quotes: var(--blume-muted-foreground);
197
+ --tw-prose-quote-borders: var(--blume-border);
198
+ --tw-prose-captions: var(--blume-muted-foreground);
199
+ --tw-prose-code: var(--blume-foreground);
200
+ --tw-prose-pre-code: var(--blume-foreground);
201
+ --tw-prose-pre-bg: var(--blume-code-background);
202
+ --tw-prose-th-borders: var(--blume-border);
203
+ --tw-prose-td-borders: var(--blume-border);
204
+ color: var(--blume-muted-foreground);
205
+ font-size: 0.875rem;
206
+ line-height: 1.7;
207
+ }
208
+
209
+ .prose :where(h1, h2, h3, h4) {
210
+ font-weight: 500;
211
+ letter-spacing: 0;
212
+ }
213
+
214
+ .prose :where(h1) {
215
+ font-size: 3rem;
216
+ line-height: 1.1;
217
+ margin: 0 0 1rem;
218
+ }
219
+
220
+ .prose :where(h2) {
221
+ font-size: 1.875rem;
222
+ line-height: 1.2;
223
+ margin-top: 3rem;
224
+ }
225
+
226
+ .prose :where(h3) {
227
+ font-size: 1.25rem;
228
+ line-height: 1.35;
229
+ }
230
+
231
+ .prose :where(h4) {
232
+ color: var(--blume-muted-foreground);
233
+ font-size: 0.875rem;
234
+ line-height: 1.4;
235
+ }
236
+
237
+ .prose :where(h1, h2, h3, h4, h5, h6) a {
238
+ color: inherit;
239
+ font-weight: inherit;
240
+ text-decoration: none;
241
+ }
242
+
243
+ /* Auto-generated heading permalinks (markdown.headingAnchors): the whole
244
+ heading links to its own id, with a muted “#” revealed on hover or keyboard
245
+ focus so the link is discoverable without cluttering the heading at rest. */
246
+ .prose :where(h2, h3, h4, h5, h6) a.blume-heading-anchor::after {
247
+ content: "#";
248
+ color: var(--blume-muted-foreground);
249
+ margin-inline-start: 0.35em;
250
+ opacity: 0;
251
+ transition: opacity 0.15s ease;
252
+ }
253
+ .prose :where(h2, h3, h4, h5, h6) a.blume-heading-anchor:hover::after,
254
+ .prose :where(h2, h3, h4, h5, h6) a.blume-heading-anchor:focus-visible::after {
255
+ opacity: 1;
256
+ }
257
+
258
+ .prose :where(h2:first-child) {
259
+ border-top: 0;
260
+ padding-top: 0;
261
+ }
262
+
263
+ .prose :where(p, ul, ol) {
264
+ margin-top: 1rem;
265
+ margin-bottom: 1rem;
266
+ }
267
+
268
+ .prose :where(strong) {
269
+ font-weight: 600;
270
+ }
271
+
272
+ .prose :where(a) {
273
+ color: var(--blume-foreground);
274
+ font-weight: 500;
275
+ text-decoration-line: underline;
276
+ text-decoration-style: dotted;
277
+ text-decoration-thickness: 1px;
278
+ text-underline-offset: 0.2em;
279
+ }
280
+
281
+ .prose :where(a[data-blume-card]) {
282
+ color: inherit;
283
+ font-weight: inherit;
284
+ text-decoration: none;
285
+ }
286
+
287
+ .prose :where(hr) {
288
+ margin: 2.5rem 0;
289
+ }
290
+
291
+ .prose :where(pre) {
292
+ background: transparent;
293
+ border: 1px solid var(--blume-border);
294
+ border-radius: var(--blume-radius);
295
+ color: var(--blume-foreground);
296
+ font-family: var(--font-mono);
297
+ font-size: 0.8125rem;
298
+ line-height: 1.55;
299
+ margin: 1.5rem 0;
300
+ overflow-x: auto;
301
+ padding: 1rem 1.25rem;
302
+ position: relative;
303
+ }
304
+
305
+ .prose :where(pre.astro-code) {
306
+ background: transparent !important;
307
+ color: var(--shiki-light, var(--blume-foreground)) !important;
308
+ }
309
+
310
+ :root[data-theme="dark"] .prose :where(pre.astro-code) {
311
+ color: var(--shiki-dark, var(--blume-foreground)) !important;
312
+ }
313
+
314
+ .prose :where(pre.astro-code span) {
315
+ background: transparent !important;
316
+ color: var(--shiki-light, inherit);
317
+ font-style: var(--shiki-light-font-style, inherit);
318
+ font-weight: var(--shiki-light-font-weight, inherit);
319
+ text-decoration: var(--shiki-light-text-decoration, inherit);
320
+ }
321
+
322
+ :root[data-theme="dark"] .prose :where(pre.astro-code span) {
323
+ color: var(--shiki-dark, inherit);
324
+ font-style: var(--shiki-dark-font-style, inherit);
325
+ font-weight: var(--shiki-dark-font-weight, inherit);
326
+ text-decoration: var(--shiki-dark-text-decoration, inherit);
327
+ }
328
+
329
+ .prose :where(pre[data-language]) {
330
+ padding-top: 3.75rem;
331
+ }
332
+
333
+ .prose :where(pre[data-language])::before {
334
+ align-items: center;
335
+ border-bottom: 1px solid var(--blume-border);
336
+ color: var(--blume-muted-foreground);
337
+ content: attr(data-language);
338
+ display: flex;
339
+ font-family: var(--font-sans);
340
+ font-size: 0.75rem;
341
+ font-weight: 500;
342
+ height: 2.75rem;
343
+ left: 0;
344
+ padding: 0 3.25rem 0 1rem;
345
+ position: absolute;
346
+ right: 0;
347
+ top: 0;
348
+ }
349
+
350
+ .prose :where(pre[data-title])::before {
351
+ content: attr(data-title);
352
+ }
353
+
354
+ /* Language icon (simple-icons) sits at the header's left edge; the label shifts
355
+ right to make room. Injected at build time by the language-icon transformer.
356
+ Shown only for top-level prose blocks, which have a header — flush code in
357
+ tabs and API panels is nested deeper, so the child combinator skips it. */
358
+ .blume-lang-icon {
359
+ display: none;
360
+ }
361
+
362
+ .prose > :where(pre[data-icon]) > .blume-lang-icon {
363
+ color: var(--blume-muted-foreground);
364
+ display: block;
365
+ height: 0.875rem;
366
+ left: 1rem;
367
+ position: absolute;
368
+ top: 0.875rem;
369
+ width: 0.875rem;
370
+ }
371
+
372
+ .prose > :where(pre[data-icon])::before {
373
+ padding-left: 2.5rem;
374
+ }
375
+
376
+ .prose :where(pre code) {
377
+ background: transparent;
378
+ border-radius: 0;
379
+ color: inherit;
380
+ font-size: inherit;
381
+ font-weight: 400;
382
+ padding: 0;
383
+ }
384
+
385
+ /* Word wrap (markdown.code.wrap): long lines wrap instead of scrolling. The
386
+ attribute is set on <body> from config; default code keeps \`white-space: pre\`. */
387
+ [data-blume-code-wrap] pre,
388
+ [data-blume-code-wrap] pre code {
389
+ overflow-wrap: break-word;
390
+ white-space: pre-wrap;
391
+ }
392
+
393
+ .prose :where(table) {
394
+ font-size: 0.8125rem;
395
+ }
396
+
397
+ blume-tabs pre,
398
+ .not-prose > div > pre {
399
+ background: var(--blume-code-background);
400
+ }
401
+
402
+ /* Code blocks inside tabs sit flush; the tab container owns the frame. These
403
+ rules are unlayered like the base \`pre\` styles, so they win over Tailwind's
404
+ layered utilities (which a class on the panel cannot). The second selector
405
+ covers <CodeGroup>, where each code block IS the panel (a direct child of the
406
+ tab content wrapper) rather than a <pre> nested inside a <Tab>. */
407
+ blume-tabs [data-blume-tab-panel] > pre,
408
+ blume-tabs [data-blume-tab-content] > pre {
409
+ /* Important to beat the astro-code background rule above; the tab container
410
+ owns the surface, so the code sits directly on it. */
411
+ background: transparent !important;
412
+ border: 0;
413
+ border-radius: 0;
414
+ margin: 0;
415
+ }
416
+
417
+ blume-tabs pre[data-language],
418
+ .not-prose pre[data-language] {
419
+ padding-top: 1rem;
420
+ }
421
+
422
+ blume-tabs pre[data-language]::before,
423
+ .not-prose pre[data-language]::before {
424
+ content: none;
425
+ }
426
+
427
+ /* Pre-hydration layout-shift guard. The horizontal trigger row and
428
+ single-panel visibility are built by the <blume-tabs> custom element's JS:
429
+ until it upgrades, the trigger row is empty and every panel is in normal flow,
430
+ so the browser paints all panels stacked vertically (e.g. all four
431
+ package-manager commands at once) before JS hides them. While the element is
432
+ :not(:defined), show only the first panel and reserve the trigger row's height
433
+ so nothing jumps when JS takes over. The child selector covers both <Tab>
434
+ panels and <CodeGroup> raw code blocks (which only gain
435
+ [data-blume-tab-panel] from JS). */
436
+ blume-tabs:not(:defined) [data-blume-tab-content] > *:nth-child(n + 2) {
437
+ display: none;
438
+ }
439
+
440
+ blume-tabs:not(:defined) [data-blume-tablist] {
441
+ /* Matches a trigger's height: py-2.5 + text-xs line-height + border-b-2. */
442
+ min-height: 2.375rem;
443
+ }
444
+
445
+ blume-tabs:not(:defined)[data-dropdown="true"] [data-blume-tablist] {
446
+ /* Dropdown variant: p-3 padding around a select (py-2 + text-sm + border). */
447
+ min-height: 3.875rem;
448
+ }
449
+
450
+ /* Code blocks inside request/response example panels sit flush; the panel owns
451
+ the frame. Unlayered (like the tab rules) so they beat the base \`pre\` styles
452
+ that a class on the panel cannot. */
453
+ [data-blume-code-panel] pre {
454
+ background: transparent !important;
455
+ border: 0;
456
+ border-radius: 0;
457
+ margin: 0;
458
+ }
459
+
460
+ /* Opt-in line numbers (\`\`\`ts file.ts lineNumbers): a counter-driven gutter that
461
+ works in prose and flush (tab / API panel) code blocks alike. */
462
+ pre[data-line-numbers] code {
463
+ counter-reset: line;
464
+ }
465
+
466
+ pre[data-line-numbers] .line::before {
467
+ color: var(--blume-muted-foreground);
468
+ content: counter(line);
469
+ counter-increment: line;
470
+ display: inline-block;
471
+ margin-right: 1.25rem;
472
+ text-align: right;
473
+ user-select: none;
474
+ width: 1.25rem;
475
+ }
476
+
477
+ /* Shiki notation transformers (on by default). The notation comments are
478
+ stripped from the output; these style the classes they leave behind. A styled
479
+ line becomes a full-width inline-block so its background fills the row; plain
480
+ lines are left untouched, so blocks without notations render as before. */
481
+ .line.highlighted,
482
+ .line.diff {
483
+ display: inline-block;
484
+ width: 100%;
485
+ }
486
+
487
+ /* The backgrounds need !important to beat the \`pre.astro-code span\` rule above,
488
+ which forces token spans transparent; these line/word spans are exceptions. */
489
+ .line.highlighted {
490
+ background-color: var(--blume-code-highlight) !important;
491
+ box-shadow: inset 2px 0 0 0 var(--blume-code-highlight-border);
492
+ }
493
+
494
+ .line.diff.add {
495
+ background-color: var(--blume-code-add) !important;
496
+ box-shadow: inset 2px 0 0 0 var(--blume-code-add-border);
497
+ }
498
+
499
+ .line.diff.remove {
500
+ background-color: var(--blume-code-remove) !important;
501
+ box-shadow: inset 2px 0 0 0 var(--blume-code-remove-border);
502
+ }
503
+
504
+ /* Word highlight (\`// [!code word:x]\`) wraps matches in an inline span. The
505
+ element selector keeps it ahead of the transparent token-span rule. */
506
+ span.highlighted-word {
507
+ background-color: var(--blume-code-word) !important;
508
+ border-radius: 0.25rem;
509
+ box-shadow: 0 0 0 1px var(--blume-code-word-border);
510
+ padding: 0.1em 0.2em;
511
+ }
512
+
513
+ /* Focus (\`// [!code focus]\`): dim and blur the rest; reveal on hover. */
514
+ pre:has(.line.focused) .line:not(.focused) {
515
+ filter: blur(0.085rem);
516
+ opacity: 0.5;
517
+ transition:
518
+ filter 0.2s ease,
519
+ opacity 0.2s ease;
520
+ }
521
+
522
+ pre:has(.line.focused):hover .line:not(.focused) {
523
+ filter: none;
524
+ opacity: 1;
525
+ }
526
+
527
+ @media (prefers-reduced-motion: reduce) {
528
+ pre:has(.line.focused) .line:not(.focused) {
529
+ transition: none;
530
+ }
531
+ }
532
+
533
+ @media (max-width: 640px) {
534
+ .prose :where(h1) {
535
+ font-size: 2.25rem;
536
+ }
537
+
538
+ .prose :where(h2) {
539
+ font-size: 1.625rem;
540
+ }
541
+ }
542
+
543
+ .prose :not(pre) > code {
544
+ background: var(--blume-code-background);
545
+ padding: 0.15em 0.35em;
546
+ border-radius: 0.3rem;
547
+ font-family: var(--font-mono);
548
+ font-weight: 500;
549
+ }
550
+
551
+ .prose :not(pre) > code::before,
552
+ .prose :not(pre) > code::after {
553
+ content: none;
554
+ }
555
+
556
+ /* Inline code highlighting (markdown.code.inline): Shiki colors the tokens of a
557
+ \`code\`{:lang} snippet via the same dual-theme CSS variables as fenced blocks,
558
+ keeping the inline pill background. */
559
+ .prose code.blume-inline-code span {
560
+ color: var(--shiki-light);
561
+ }
562
+
563
+ :root[data-theme="dark"] .prose code.blume-inline-code span {
564
+ color: var(--shiki-dark);
565
+ }
566
+
567
+ /* Print / "Save as PDF" (the page-actions Export → PDF runs window.print()).
568
+ Strip the surrounding chrome so the printout is just the article. */
569
+ @media print {
570
+ [data-blume-banner],
571
+ header,
572
+ aside,
573
+ [data-blume-page-actions],
574
+ #blume-content > nav,
575
+ #blume-content > details {
576
+ display: none !important;
577
+ }
578
+
579
+ #blume-content {
580
+ padding: 0 !important;
581
+ }
582
+
583
+ .prose {
584
+ margin: 0 !important;
585
+ max-width: none !important;
586
+ }
587
+
588
+ /* Reveal collapsed tab panels so their content isn't dropped from the print. */
589
+ blume-tabs [data-blume-tab-panel] {
590
+ display: block !important;
591
+ }
592
+
593
+ /* Keep code/callout backgrounds (subject to the dialog's "Background graphics"
594
+ toggle). */
595
+ pre,
596
+ .prose :not(pre) > code {
597
+ -webkit-print-color-adjust: exact;
598
+ print-color-adjust: exact;
599
+ }
600
+ }
601
+
602
+ /* Twoslash rich-renderer styles (used by fences with the \`twoslash\` meta). */
603
+ ${options.twoslashCss ?? ""}
604
+
605
+ /* Token overrides: config first, then the user's theme.css (highest priority). */
606
+ ${options.configTokens}
607
+ ${options.userTheme}
608
+ `;