). */}
+
+
+
diff --git a/src/starlightOverrides/Header.astro b/src/starlightOverrides/Header.astro
new file mode 100644
index 0000000..8238e26
--- /dev/null
+++ b/src/starlightOverrides/Header.astro
@@ -0,0 +1,115 @@
+---
+import Search from '@astrojs/starlight/components/Search.astro';
+import SocialIcons from '@astrojs/starlight/components/SocialIcons.astro';
+import SiteTitle from './SiteTitle.astro';
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/starlightOverrides/MarkdownContent.astro b/src/starlightOverrides/MarkdownContent.astro
new file mode 100644
index 0000000..8fdb56c
--- /dev/null
+++ b/src/starlightOverrides/MarkdownContent.astro
@@ -0,0 +1,10 @@
+---
+import "@astrojs/starlight/style/markdown.css";
+---
+
+{/* Identical to Starlight's default MarkdownContent, plus the `content` class:
+ Starlight's TOC scrollspy observes `main .content > *`, but this site's
+ heading-wrapper markup leaves headings with no observable siblings, so
+ without this class `aria-current` only updates when a heading itself
+ crosses the intersection band and goes stale on jump-scrolls. */}
+
diff --git a/src/starlightOverrides/MobileMenuFooter.astro b/src/starlightOverrides/MobileMenuFooter.astro
new file mode 100644
index 0000000..1befb64
--- /dev/null
+++ b/src/starlightOverrides/MobileMenuFooter.astro
@@ -0,0 +1,30 @@
+---
+import SocialIcons from "@astrojs/starlight/components/SocialIcons.astro";
+---
+
+{/* Like Starlight's default, minus the theme select — the site is dark-only. */}
+
+
+
+
+
+
+
diff --git a/src/starlightOverrides/SiteTitle.astro b/src/starlightOverrides/SiteTitle.astro
new file mode 100644
index 0000000..cce6fa3
--- /dev/null
+++ b/src/starlightOverrides/SiteTitle.astro
@@ -0,0 +1,58 @@
+---
+---
+
+
+
+
+
+
+
+
+
diff --git a/src/styles/starlight.css b/src/styles/starlight.css
index c62b8f3..3f818de 100644
--- a/src/styles/starlight.css
+++ b/src/styles/starlight.css
@@ -2,19 +2,29 @@
@layer user.overrides {
:root {
- --sl-font: system-ui, sans-serif;
+ --font-fallback: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
+ Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue",
+ sans-serif;
+ --sl-font: "Inter Variable", var(--font-fallback);
--sl-font-heading: "polymath-display", sans-serif;
+ --sl-font-mono: "dm-mono", ui-monospace, monospace;
--sl-color-text-heading: var(--heading-fill);
- --sl-text-h1: var(--sl-text-6xl);
+
+ /* Heading baseline: one notch smaller than Starlight's wide-viewport
+ scale; the full-size scale only applies at desktop widths (below) */
+ --sl-text-h1: var(--sl-text-5xl);
+ --sl-text-h2: var(--sl-text-2xl);
+ --sl-text-h3: var(--sl-text-xl);
+ --sl-text-h4: var(--sl-text-lg);
--sl-color-accent-hsl: 311 100% 50%;
- --sl-color-accent-low: hsl(var(--sl-color-accent-hsl) / 0.5);
+ --sl-color-accent-low: hsl(var(--sl-color-accent-hsl) / 0.1);
--sl-color-accent: hsl(var(--sl-color-accent-hsl) / 0.9);
--sl-color-accent-high: hsl(var(--sl-color-accent-hsl) / 1);
- --sl-color-bg: var(--container-fill);
- --sl-color-bg-nav: var(--container-fill);
- --sl-color-bg-sidebar: var(--container-fill);
+ --sl-color-bg: var(--background);
+ --sl-color-bg-nav: var(--background);
+ --sl-color-bg-sidebar: var(--background);
--sl-color-bg-inline-code: var(--surface-inner-fill);
--sl-color-bg-accent: var(--sl-color-accent-high);
--sl-color-hairline-light: var(--surface-border-fill);
@@ -22,6 +32,92 @@
--sl-color-hairline-shade: var(--surface-border-fill);
--sl-icon-color: var(--heading-fill);
+
+ /* extra room for the hatched separator strip under the navbar */
+ --hatch-height: 0.75rem;
+ --sl-nav-height: 4.25rem;
+
+ scrollbar-width: thin;
+ scrollbar-gutter: stable;
+ scrollbar-color: hsl(var(--sl-color-accent-hsl)) var(--surface-fill);
+ }
+
+ ::selection {
+ background-color: var(--color-pink-100);
+ color: var(--color-gray-100);
+ }
+
+ /* bomb.sh viewport frame: 8px background strips + 1px grid border, drawn
+ over everything (pointer-events: none) so scrolled content passes
+ "behind" the frame exactly like on the marketing site */
+ body::before {
+ content: "";
+ position: fixed;
+ inset: 0;
+ z-index: 101;
+ pointer-events: none;
+ background-image: /* fill strips */
+ linear-gradient(var(--background), var(--background)),
+ linear-gradient(var(--background), var(--background)),
+ linear-gradient(var(--background), var(--background)),
+ linear-gradient(var(--background), var(--background)),
+ /* border lines */ linear-gradient(var(--c-grid), var(--c-grid)),
+ linear-gradient(var(--c-grid), var(--c-grid)),
+ linear-gradient(var(--c-grid), var(--c-grid)),
+ linear-gradient(var(--c-grid), var(--c-grid));
+ background-size:
+ /* fill: top, bottom, left, right */
+ 100% var(--s-grid-padding),
+ 100% var(--s-grid-padding),
+ var(--s-grid-padding) 100%,
+ var(--s-grid-padding) 100%,
+ /* border: top, bottom, left, right */ 100% var(--s-grid-width),
+ 100% var(--s-grid-width),
+ var(--s-grid-width) 100%,
+ var(--s-grid-width) 100%;
+ background-position:
+ top left,
+ bottom left,
+ top left,
+ top right,
+ 0 var(--s-grid-padding),
+ 0 calc(100% - var(--s-grid-padding)),
+ var(--s-grid-padding) 0,
+ calc(100% - var(--s-grid-padding)) 0;
+ background-repeat: no-repeat;
+ }
+
+ /* bomb.sh hatched separator strip along the bottom of the navbar.
+ Nav content stays centered across the full nav height; the strip
+ overlays the bottom edge like the homepage separator. */
+ header.header::after {
+ content: "";
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ height: var(--hatch-height);
+ border-top: var(--s-grid-width) solid var(--c-grid);
+ --_size: var(--s-grid-width);
+ --_space: 6px;
+ background-image: repeating-linear-gradient(
+ 45deg,
+ transparent,
+ transparent var(--_space),
+ var(--c-grid-muted) var(--_space),
+ var(--c-grid-muted) calc(var(--_space) + var(--_size))
+ );
+ pointer-events: none;
+ }
+
+ /* Full-size heading scale on desktop viewports only */
+ @media (min-width: 72rem) {
+ :root {
+ --sl-text-h1: var(--sl-text-6xl);
+ --sl-text-h2: var(--sl-text-4xl);
+ --sl-text-h3: var(--sl-text-3xl);
+ --sl-text-h4: var(--sl-text-2xl);
+ }
}
:is(h1, h2, h3, h4, h5, h6) {
@@ -55,16 +151,17 @@
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-image: linear-gradient(to right, var(--c-start), var(--c-end));
- letter-spacing: 1px;
+ letter-spacing: 0.1ch;
}
:is(h2, h3, h4, h5, h6) {
--c-start: var(--heading-fill);
- --c-end: var(--heading-muted);
+ --c-end: color-mix(in srgb, var(--heading-fill) 35%, transparent);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-image: linear-gradient(to right, var(--c-start), var(--c-end));
+ letter-spacing: 0.1ch;
}
:is(h1, h2, h3, h4, h5, h6) code {
@@ -86,9 +183,16 @@
color: var(--heading-fill);
}
+ /* Right sidebar (TOC) background gradient */
+ .right-sidebar {
+ background: linear-gradient(
+ to bottom,
+ var(--panel-grad-start) 0%,
+ var(--background) 100%
+ );
+ }
+
starlight-toc nav > ul {
- --c-start: var(--heading-muted);
- --c-end: var(--separator-fill);
border-left: 1px solid transparent;
position: relative;
@@ -99,7 +203,11 @@
bottom: 0;
left: 0;
width: var(--border-050);
- background: linear-gradient(to bottom, var(--c-start), var(--c-end));
+ background: linear-gradient(
+ to bottom,
+ var(--surface-border-highlight),
+ var(--surface-border-fill)
+ );
}
a {
@@ -108,7 +216,32 @@
}
[aria-current] {
- border-left-color: var(--sl-color-accent);
+ border-left-color: hsl(var(--sl-color-accent-hsl) / 0.9);
+ font-weight: 600;
+ color: var(--separator-fill);
+ }
+
+ /* When the animated marker is active, the static per-link border is
+ replaced by a single sliding indicator (injected by Head.astro). */
+ &.has-marker [aria-current] {
+ border-left-color: transparent;
+ }
+
+ .toc-marker {
+ position: absolute;
+ left: 0;
+ width: 2px;
+ background: hsl(var(--sl-color-accent-hsl) / 0.9);
+ transition:
+ top 250ms cubic-bezier(0.23, 1, 0.32, 1),
+ height 250ms cubic-bezier(0.23, 1, 0.32, 1);
+ pointer-events: none;
+ }
+
+ @media (prefers-reduced-motion: reduce) {
+ .toc-marker {
+ transition: none;
+ }
}
}
@@ -121,33 +254,173 @@
sans-serif;
}
+ /* Buttons — match the bomb.sh homepage hero CTAs */
+ .sl-link-button {
+ border-radius: 0.33em;
+ corner-shape: bevel;
+ font-family: var(--sl-font);
+ font-weight: 500;
+ transition:
+ color 120ms cubic-bezier(0.23, 1, 0.32, 1),
+ background-color 120ms cubic-bezier(0.23, 1, 0.32, 1),
+ border-color 120ms cubic-bezier(0.23, 1, 0.32, 1);
+ }
+
.sl-link-button.primary {
- background: linear-gradient(
- to right in oklab,
- var(--color-pink-90),
- var(--color-pink-100)
- );
+ background: var(--color-white-100);
color: var(--color-gray-100);
- border-color: var(--color-pink-100);
- border-radius: 0px;
+ border: var(--s-grid-width) solid var(--c-grid);
+
+ &:is(:hover, :focus-visible) {
+ background: color-mix(in srgb, var(--color-pink-100) 30%, transparent);
+ color: var(--color-pink-100);
+ border-color: var(--color-pink-100);
+ }
+ }
+
+ .sl-link-button:not(.primary) {
+ background: transparent;
+ color: var(--color-gray-40);
+ border: var(--s-grid-width) solid var(--color-gray-40);
+
+ &:is(:hover, :focus-visible) {
+ background: var(--color-gray-80);
+ color: var(--color-white-100);
+ border-color: var(--color-white-100);
+ }
}
.sl-link-button > svg {
- fill: var(--color-gray-100);
+ fill: currentColor;
+ }
+
+ /* Content links — white at rest, topic accent on hover */
+ .sl-markdown-content a:not(:where(.not-content *)) {
+ color: var(--color-white-100);
+ transition: color 120ms cubic-bezier(0.23, 1, 0.32, 1);
+
+ &:is(:hover, :focus-visible) {
+ color: hsl(var(--sl-color-accent-hsl));
+ }
+
+ /* Links wrapping code chips: accent at rest (so the underline matches
+ the chip), flipping to white on hover — the inverse of plain links */
+ &:has(> code) {
+ color: hsl(var(--sl-color-accent-hsl));
+
+ &:is(:hover, :focus-visible) {
+ color: var(--color-white-100);
+
+ & > code {
+ --color: var(--color-white-100);
+ }
+ }
+ }
+ }
+
+ /* Inline code — bomb.sh gradient chip, tinted by the topic accent */
+ .sl-markdown-content code:not(:where(.not-content *)):not(pre *) {
+ --color: hsl(var(--sl-color-accent-hsl));
+ font-family: var(--sl-font-mono);
+ color: var(--color);
+ transition:
+ color 120ms cubic-bezier(0.23, 1, 0.32, 1),
+ background 120ms cubic-bezier(0.23, 1, 0.32, 1);
+ font-size-adjust: 0.5;
+ background: linear-gradient(
+ -45deg,
+ color-mix(in srgb, var(--color) 25%, transparent) 0%,
+ color-mix(in srgb, var(--color) 12%, transparent) 100%
+ );
+ padding-inline: 0.25em;
+ padding-block: 0.1em;
+ border-radius: 4px;
+ }
+
+ /* Search — a full-height section of the nav, delimited by vertical
+ hairline bars, aligned with the main content column */
+ site-search {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ }
+
+ /* Desktop with a TOC column: cap the search at the main content area so
+ its right bar aligns with the content/TOC boundary (measured value from
+ Head.astro; the calc is a close fallback that ignores scrollbar width) */
+ @media (min-width: 72rem) {
+ :root[data-has-toc] site-search {
+ max-width: var(
+ --search-clamp,
+ calc((100vw - 2 * var(--sl-sidebar-width) + var(--sl-content-width)) / 2)
+ );
+ }
+ }
+
+ @media (min-width: 50rem) {
+ site-search button[data-open-modal] {
+ border-radius: 0;
+ max-width: 100%;
+ height: 100%;
+ border-block: none;
+ border-inline: 1px solid var(--surface-border-fill);
+ /* No fill — the nav's hatch strip stays visible through the section */
+ background-color: transparent;
+ /* Stack above the nav's hatch strip so the bars stay unbroken, and
+ nudge 1px left so the left bar overlaps the sidebar border exactly */
+ position: relative;
+ z-index: 1;
+ translate: -1px 0;
+ }
}
.cli-preview {
padding: 1em;
- border: 1px solid #292929;
+ border: 1px solid var(--surface-border-fill);
border-radius: 0.5em;
white-space: pre;
line-height: 1.2em;
- font-family: monospace;
- background-color: #181818;
+ font-family: var(--sl-font-mono);
+ background-color: var(--container-fill);
color: var(--color-white-100);
}
+ /* Code frames — subtle gradient fade on terminal/editor title bars,
+ matching the hatch-and-hairline chrome of the rest of the site */
+ .expressive-code .frame.is-terminal .header,
+ .expressive-code .frame.has-title:not(.is-terminal) .header {
+ background: linear-gradient(
+ to bottom,
+ transparent,
+ color-mix(in srgb, var(--heading-fill) 7%, transparent)
+ );
+ border-bottom: 1px solid var(--surface-border-fill);
+ }
+
+ /* Twoslash hovercards — same panel language as the rest of the chrome */
+ .expressive-code .twoslash-popup-container {
+ border-radius: var(--radius-100);
+ box-shadow: 0 8px 24px color-mix(in srgb, #000 35%, transparent);
+ }
+
+ .expressive-code .twoslash-popup-docs,
+ .expressive-code .twoslash-popup-docs-tags {
+ font-family: var(--sl-font);
+ font-size: var(--sl-text-xs);
+ }
+
+ .expressive-code .twoslash-popup-code {
+ font-family: var(--sl-font-mono);
+ }
+
.sidebar-pane {
+ background: linear-gradient(
+ to bottom,
+ var(--panel-grad-start) 0%,
+ var(--background) 100%
+ );
+
a {
border: 1px solid transparent;
}
@@ -208,14 +481,28 @@
--sl-icon-color: var(--color-gray-100);
- .sl-link-button {
- background-color: var(--color-gray-100);
+ .sl-link-button.primary {
+ background: var(--color-gray-100);
color: var(--color-white-100);
border-color: var(--color-gray-100);
+
+ &:is(:hover, :focus-visible) {
+ background: color-mix(in srgb, var(--color-pink-100) 12%, transparent);
+ color: var(--color-gray-100);
+ border-color: var(--color-pink-100);
+ }
}
- .sl-link-button > svg {
- fill: var(--color-white-100);
+ .sl-link-button:not(.primary) {
+ background: transparent;
+ color: var(--color-gray-70);
+ border-color: var(--color-gray-40);
+
+ &:is(:hover, :focus-visible) {
+ background: var(--color-gray-20);
+ color: var(--color-gray-100);
+ border-color: var(--color-gray-100);
+ }
}
}
@@ -344,3 +631,52 @@ ul.starlight-sidebar-topics
.starlight-sidebar-topics li + li {
margin-top: 0;
}
+
+/* Run the topics separator on the same horizontal line as the divider under
+ the page title, so it reads as one continuous rule across sidebar and
+ content. The min-height mirrors the first content panel's box: mobile-toc
+ bar + panel padding (2 × 1.5rem) + h1 margin (1rem) + one h1 line
+ (--sl-text-6xl × 1.2 line-height), minus the sidebar's own 1rem top
+ padding. Applies wherever the sidebar is visible. */
+@media (min-width: 50rem) {
+ .starlight-sidebar-topics {
+ display: flex;
+ flex-direction: column;
+ /* Measured offset set by Head.astro (no static fallback — it would act
+ as a floor and defeat the natural-height measurement; without JS the
+ two rules are simply compact and unaligned). */
+ min-height: var(--topics-rule-offset, auto);
+ }
+
+ .starlight-sidebar-topics::after {
+ margin-top: auto;
+ }
+
+ /* When the title panel grows to meet a taller topics column, anchor the
+ title to the bottom of the available space, just above the shared rule */
+ main .content-panel:first-of-type {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+
+ /* As a flex item the inner container would otherwise shrink to fit and
+ its auto margins would center it */
+ & > .sl-container {
+ width: 100%;
+ }
+ }
+}
+
+/* Tablet only: drop the title panel's top padding and the h1's default top
+ margin — they only add dead space above the title and force the topics
+ list to stretch further to keep the shared rule aligned. Desktop keeps
+ its larger title spacing. */
+@media (min-width: 50rem) and (max-width: 71.9375rem) {
+ main .content-panel:first-of-type {
+ padding-block-start: 0;
+ }
+
+ main h1#_top {
+ margin-top: 0;
+ }
+}
diff --git a/src/styles/tint.css b/src/styles/tint.css
index 11c32f2..199296a 100644
--- a/src/styles/tint.css
+++ b/src/styles/tint.css
@@ -130,6 +130,14 @@
--space-card-gap: var(--space-400);
--space-card-padding: var(--space-400);
--space-cell-padding: var(--space-150);
+
+ /* bomb.sh page chrome: page background + viewport frame grid */
+ --background: var(--color-white-100);
+ --c-grid: var(--color-gray-30);
+ --c-grid-muted: var(--color-gray-20);
+ --s-grid-width: 1px;
+ --s-grid-padding: 8px;
+ --panel-grad-start: var(--color-gray-20);
}
:root[data-theme=dark] {
@@ -148,6 +156,11 @@
--accent-fill: var(--color-pink-100);
--accent-muted: var(--color-pink-90);
--accent-highlight: var(--color-pink-100);
+
+ --background: #000;
+ --c-grid: var(--color-gray-80);
+ --c-grid-muted: var(--color-gray-90);
+ --panel-grad-start: var(--color-gray-90);
}
:root[data-theme=light] {