diff --git a/site/astro.config.mjs b/site/astro.config.mjs
index 355e4bb..4798542 100644
--- a/site/astro.config.mjs
+++ b/site/astro.config.mjs
@@ -83,7 +83,20 @@ export default defineConfig({
markdown: { rehypePlugins: [rehypeRepoLinks, rehypeLinkNames] },
integrations: [
starlight({
- customCss: ["./src/styles/custom.css"],
+ components: {
+ SiteTitle: "./src/components/SiteTitle.astro",
+ ThemeSelect: "./src/components/ThemeSelect.astro",
+ SocialIcons: "./src/components/SocialIcons.astro",
+ },
+ customCss: [
+ "@fontsource/dm-sans/400.css",
+ "@fontsource/dm-sans/500.css",
+ "@fontsource/dm-sans/600.css",
+ "@fontsource/dm-sans/700.css",
+ "@fontsource/jetbrains-mono/400.css",
+ "@fontsource/jetbrains-mono/600.css",
+ "./src/styles/custom.css",
+ ],
plugins: [starlightLinksValidator()],
favicon: "/favicon.svg",
title: "LemmaScript",
diff --git a/site/package-lock.json b/site/package-lock.json
index 83ad772..60c6def 100644
--- a/site/package-lock.json
+++ b/site/package-lock.json
@@ -7,6 +7,8 @@
"name": "lemmascript-site",
"dependencies": {
"@astrojs/starlight": "^0.39.2",
+ "@fontsource/dm-sans": "^5.2.8",
+ "@fontsource/jetbrains-mono": "^5.2.8",
"astro": "^6.3.7",
"sharp": "^0.34.5"
},
@@ -729,6 +731,24 @@
"@expressive-code/core": "^0.42.0"
}
},
+ "node_modules/@fontsource/dm-sans": {
+ "version": "5.2.8",
+ "resolved": "https://registry.npmjs.org/@fontsource/dm-sans/-/dm-sans-5.2.8.tgz",
+ "integrity": "sha512-tlovG42m9ESG28WiHpLq3F5umAlm64rv0RkqTbYowRn70e9OlRr5a3yTJhrhrY+k5lftR/OFJjPzOLQzk8EfCA==",
+ "license": "OFL-1.1",
+ "funding": {
+ "url": "https://github.com/sponsors/ayuhito"
+ }
+ },
+ "node_modules/@fontsource/jetbrains-mono": {
+ "version": "5.2.8",
+ "resolved": "https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-5.2.8.tgz",
+ "integrity": "sha512-6w8/SG4kqvIMu7xd7wt6x3idn1Qux3p9N62s6G3rfldOUYHpWcc2FKrqf+Vo44jRvqWj2oAtTHrZXEP23oSKwQ==",
+ "license": "OFL-1.1",
+ "funding": {
+ "url": "https://github.com/sponsors/ayuhito"
+ }
+ },
"node_modules/@img/colour": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
diff --git a/site/package.json b/site/package.json
index 66ab8c3..2090a5f 100644
--- a/site/package.json
+++ b/site/package.json
@@ -12,6 +12,8 @@
},
"dependencies": {
"@astrojs/starlight": "^0.39.2",
+ "@fontsource/dm-sans": "^5.2.8",
+ "@fontsource/jetbrains-mono": "^5.2.8",
"astro": "^6.3.7",
"sharp": "^0.34.5"
},
diff --git a/site/src/components/SiteTitle.astro b/site/src/components/SiteTitle.astro
new file mode 100644
index 0000000..dee7df1
--- /dev/null
+++ b/site/src/components/SiteTitle.astro
@@ -0,0 +1,31 @@
+---
+// Starlight SiteTitle override: brand wordmark split like the landing site —
+// "Lemma" in text color, "Script" in the brand green.
+---
+
+LemmaScriptDOCS
+
+
diff --git a/site/src/components/SocialIcons.astro b/site/src/components/SocialIcons.astro
new file mode 100644
index 0000000..6474514
--- /dev/null
+++ b/site/src/components/SocialIcons.astro
@@ -0,0 +1,84 @@
+---
+// Starlight SocialIcons override: the landing site's GitHub pill — logo,
+// label, and best-effort star count fetched at build time.
+let stars: number | null = null
+try {
+ const res = await fetch("https://api.github.com/repos/midspiral/LemmaScript", {
+ headers: { Accept: "application/vnd.github+json" },
+ })
+ if (res.ok) {
+ const data = await res.json()
+ stars = typeof data.stargazers_count === "number" ? data.stargazers_count : null
+ }
+} catch {
+ stars = null
+}
+const starLabel =
+ stars == null ? null : stars >= 1000 ? (stars / 1000).toFixed(1).replace(/\.0$/, "") + "k" : String(stars)
+---
+
+
+
+ GitHub
+ {starLabel && (
+
+
+ {starLabel}
+
+ )}
+
+
+
+
+ npm
+
+
+
diff --git a/site/src/components/ThemeSelect.astro b/site/src/components/ThemeSelect.astro
new file mode 100644
index 0000000..e625c43
--- /dev/null
+++ b/site/src/components/ThemeSelect.astro
@@ -0,0 +1,90 @@
+---
+// Starlight ThemeSelect override:
+// - replaces the theme dropdown with the toolchain version, read mechanically
+// from the repo root package.json at build time (cannot drift)
+// - moves theme switching to a floating bottom-right toggle, same icons and
+// behavior as the landing site's ThemeToggle
+import { readFileSync } from "node:fs"
+import { resolve } from "node:path"
+
+// Builds always run from site/ (npm scripts), so the toolchain package.json is
+// one level up. cwd-anchored because import.meta.url moves after bundling.
+const pkg = JSON.parse(readFileSync(resolve(process.cwd(), "..", "package.json"), "utf8"))
+if (!pkg.version) throw new Error("ThemeSelect: could not read toolchain version from ../package.json")
+const version = `v${pkg.version}`
+---
+
+{version}
+
+
+
+
+
+
diff --git a/site/src/styles/custom.css b/site/src/styles/custom.css
index 1c1caa2..0907ecd 100644
--- a/site/src/styles/custom.css
+++ b/site/src/styles/custom.css
@@ -1,3 +1,58 @@
+/* ============================================================
+ LemmaScript brand theme — mirrors lemmascript-landing's tokens
+ (src/styles/tokens.css there). Twin-sync: if the landing accent
+ or grays change, update these to match.
+ ============================================================ */
+
+/* Fonts: same faces as the landing site */
+:root {
+ --sl-font: "DM Sans", ui-sans-serif, system-ui, sans-serif;
+ --sl-font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
+}
+
+/* Dark theme — landing dark: bg #0A0E14, text #E6EDF3, accent #2DD4A7 */
+:root {
+ --ls-brand-accent: #2dd4a7; /* landing --accent (dark) */
+ --ls-star: #f5c451; /* landing --state-pending (dark) */
+ --sl-color-accent-low: #0f3a2e;
+ --sl-color-accent: #1b8a6e;
+ --sl-color-accent-high: #2dd4a7;
+ --sl-color-white: #e6edf3;
+ --sl-color-gray-1: #d3dbe3;
+ --sl-color-gray-2: #b3bdc9;
+ --sl-color-gray-3: #8b98a7;
+ --sl-color-gray-4: #55606e;
+ --sl-color-gray-5: #2b3442;
+ --sl-color-gray-6: #141a23;
+ --sl-color-black: #0a0e14;
+}
+
+/* Light theme — landing light: bg #F6F7F9, text #10151C, accent #0D805D */
+:root[data-theme="light"] {
+ --ls-brand-accent: #0d805d; /* landing --accent (light) */
+ --ls-star: #8a6100; /* landing --state-pending (light) */
+ --sl-color-accent-low: #d2ede2;
+ --sl-color-accent: #0d805d;
+ --sl-color-accent-high: #0a5c43;
+ --sl-color-white: #10151c;
+ --sl-color-gray-1: #1e2632;
+ --sl-color-gray-2: #333e4e;
+ --sl-color-gray-3: #55606e;
+ --sl-color-gray-4: #8b98a7;
+ --sl-color-gray-5: #d5dae1;
+ --sl-color-gray-6: #eceef2;
+ --sl-color-gray-7: #f6f7f9;
+ --sl-color-black: #ffffff;
+}
+
+/* Landing-style touches */
+.site-title {
+ font-weight: 700;
+}
+.sidebar-content a[aria-current="page"] {
+ font-weight: 600;
+}
+
/* Compact code blocks — no window chrome, no copy button, no language badge */
.expressive-code .frame {
box-shadow: none !important;