@import "tailwindcss"; @import "fumadocs-ui/css/neutral.css"; @import "fumadocs-ui/css/preset.css"; /* ------------------------------------------------------------------ */ /* Theme tokens */ /* - Fonts: Inter (UI/body) + Instrument Serif (display). */ /* - Layout width. */ /* - Zero out every Tailwind radius token → square corners everywhere. */ /* - Light-mode color tokens (full Fumadocs set). */ /* ------------------------------------------------------------------ */ @theme { --font-sans: var(--font-sans), "Geist", ui-sans-serif, system-ui, sans-serif; --font-heading: var(--font-heading), "Space Grotesk", "Inter", ui-sans-serif, system-ui, sans-serif; --fd-layout-width: 90rem; --site-shell-max-width: 1400px; --site-shell-pad-x: 32px; --site-shell-pad-x-mobile: 20px; --radius-xs: 0px; --radius-sm: 0px; --radius-md: 0px; --radius-lg: 0px; --radius-xl: 0px; --radius-2xl: 0px; --radius-3xl: 0px; --radius-4xl: 0px; /* Foundation — warm off-white */ --color-fd-background: hsl(40, 25%, 97%); --color-bg-inverse: #000000; --color-fd-foreground: hsl(0, 0%, 9%); --color-fd-muted: hsl(40, 15%, 94%); --color-fd-muted-foreground: hsl(0, 0%, 52%); --color-fd-popover: hsl(0, 0%, 100%); --color-fd-popover-foreground: hsl(0, 0%, 12%); --color-fd-card: hsl(0, 0%, 100%); --color-fd-card-foreground: hsl(0, 0%, 9%); --color-fd-border: hsla(35, 12%, 65%, 0.4); --color-fd-secondary: hsl(40, 15%, 92%); --color-fd-secondary-foreground: hsl(0, 0%, 9%); --color-fd-accent: hsla(35, 12%, 80%, 0.45); --color-fd-accent-foreground: hsl(0, 0%, 9%); /* Primary = neutral foreground. Violet is gone entirely. */ --color-fd-primary: hsl(0, 0%, 9%); --color-fd-primary-foreground: hsl(0, 0%, 100%); --color-fd-ring: hsl(0, 0%, 9%); /* Prose body copy — in between foreground (9%) and muted (52%). */ --color-prose: hsl(0, 0%, 30%); /* Prose surface — slightly whiter than the page off-white so the * MDX article reads as a distinct "paper" on top of the canvas. */ --color-prose-bg: hsl(40, 30%, 99%); } /* Dark mode — neutral foundation, no accent color */ .dark { --color-fd-background: hsl(0, 0%, 7%); --color-bg-inverse: #ffffff; --color-fd-foreground: hsl(0, 0%, 92%); --color-fd-muted: hsl(0, 0%, 13%); --color-fd-muted-foreground: hsla(0, 0%, 78%, 0.8); --color-fd-popover: hsl(0, 0%, 11%); --color-fd-popover-foreground: hsl(0, 0%, 87%); --color-fd-card: hsl(0, 0%, 10%); --color-fd-card-foreground: hsl(0, 0%, 98%); --color-fd-border: hsla(0, 0%, 40%, 0.2); --color-fd-secondary: hsl(0, 0%, 13%); --color-fd-secondary-foreground: hsl(0, 0%, 92%); --color-fd-accent: hsla(0, 0%, 41%, 0.3); --color-fd-accent-foreground: hsl(0, 0%, 90%); --color-fd-primary: hsl(0, 0%, 92%); --color-fd-primary-foreground: hsl(0, 0%, 9%); --color-fd-ring: hsl(0, 0%, 92%); /* Prose body copy — in between foreground (92%) and muted (78%). */ --color-prose: hsl(0, 0%, 84%); /* Prose surface — one notch brighter than the page background so the * article still reads as a lifted "paper" in dark mode. */ --color-prose-bg: hsl(0, 0%, 12%); } :root { --color-bg-inverse: #000000; } .dark { --color-bg-inverse: #ffffff; } /* MDX content — cap each child block and center it inside the page * column. Notebook's container uses flex-col + `*:max-w` which * left-aligns by default; `margin-inline: auto` centers it. */ :is(#nd-page, .docs-page-surface) > * { max-width: 650px; margin-left: auto; margin-right: auto; width: 100%; } /* (fix: remove or correct the invalid selector) */ /* The selector `* >` is invalid and will throw a CSS error. If the intention is to add a border for debugging, use a valid selector like `*` or a more specific one. */ /* * { border: 1px solid red !important; } */ /* ------------------------------------------------------------------ */ /* Reusable utility: engineering grid background */ /* */ /* Apply the `.bg-grid` class to any element to paint a layered grid */ /* behind its content — large cells framing smaller subcells, like */ /* engineering graph paper. Override the locally-scoped CSS variables */ /* to change cell size / line color / strength per instance, e.g.: */ /* */ /* ... */ /* */ /* Defaults are deliberately strong-ish so the utility looks right */ /* when used on standalone blocks (hero, cards). The MDX article */ /* column turns the strength way down below — see `#nd-page`. */ /* ------------------------------------------------------------------ */ .bg-grid { --grid-cell: 80px; --grid-subcell: 16px; --grid-line: var(--color-fd-border); --grid-subline: color-mix(in oklab, var(--color-fd-border) 40%, transparent); --grid-line-width: 1px; background-image: linear-gradient( to right, var(--grid-line) var(--grid-line-width), transparent var(--grid-line-width) ), linear-gradient( to bottom, var(--grid-line) var(--grid-line-width), transparent var(--grid-line-width) ), linear-gradient( to right, var(--grid-subline) var(--grid-line-width), transparent var(--grid-line-width) ), linear-gradient( to bottom, var(--grid-subline) var(--grid-line-width), transparent var(--grid-line-width) ); background-size: var(--grid-cell) var(--grid-cell), var(--grid-cell) var(--grid-cell), var(--grid-subcell) var(--grid-subcell), var(--grid-subcell) var(--grid-subcell); background-position: 0 0; } /* Reusable prose "paper" surface. * * The grid sits on a ::before layer (not the element directly) so we can * inset it away from container edges. The inset leaves a clean gutter of * prose-bg between the grid and vertical borders, avoiding doubled lines. */ #nd-page, .paper-grid-surface { position: relative; isolation: isolate; background-color: var(--color-prose-bg); } #nd-page::before, .paper-grid-surface::before { content: ""; position: absolute; /* Gutter on left/right only — tops/bottoms don't collide with anything, * so letting the grid run edge-to-edge vertically is fine. */ inset: 0 2px; z-index: -1; pointer-events: none; /* Note: --color-fd-border is already translucent (~0.4 alpha), so the * color-mix percentage multiplies into that. Anything under ~15% * falls below the visible threshold on the off-white surface. */ --grid-line: color-mix(in oklab, var(--color-fd-border) 20%, transparent); --grid-subline: color-mix(in oklab, var(--color-fd-border) 10%, transparent); background-image: linear-gradient( to right, var(--grid-line) 1px, transparent 1px ), linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px), linear-gradient(to right, var(--grid-subline) 1px, transparent 1px), linear-gradient(to bottom, var(--grid-subline) 1px, transparent 1px); background-size: 80px 80px, 80px 80px, 16px 16px, 16px 16px; background-position: 0 0; } /* Sidebar — smaller font + tight row padding. * Fumadocs items render as / with `p-2` (0.5rem) and the * aside is `text-sm` (14px). We drop to ~13px, zero the viewport's * inline padding so section separator rules span the full width, * and let each item / heading own its own inline padding. */ #nd-sidebar, #nd-sidebar-mobile { font-size: 13px; /* Fumadocs' banner wrapper (`> div:first-child`) previously sat * empty (tabs are hidden on desktop, nav title lives in the top * nav) and took up `p-4 pb-2` of dead space. It now hosts the * search trigger (see `SidebarSearch` + `sidebar.banner` in * `lib/section.tsx`). A hairline underneath separates it from * the first section heading ("Getting Started"), mirroring the * `p ~ p` rule that already divides subsequent sections. * * Padding is forced to a uniform 0.5rem (overriding Fumadocs' * `p-4 pb-2`) so the search trigger sits tight against the * sidebar's vertical rules on both sides and hugs the divider * above/below — matches the visual density of the section * headings directly below, which also use 0.5rem horizontal * padding. */ > div:first-child { padding: 0.5rem; border-bottom: 1px solid var(--color-fd-border); } [data-radix-scroll-area-viewport] { padding: 0.5rem 0 0.25rem; } a, button { padding-top: 0.125rem; padding-bottom: 0.125rem; padding-right: 0.5rem; } /* Section headings (rendered as ) — tighter top/bottom rhythm. * All sections get 1rem of top breathing room above their text * (first via padding; subsequent via margin + padding with the * separator line in between). */ p { margin-top: 0; margin-bottom: 0.5rem; padding-top: 1rem; padding-left: 0.5rem; padding-right: 0.5rem; border-top: none; font-size: 13px; } p:not(:first-child) { margin-top: 0.5rem; padding-top: 0.5rem; border-top: 1px solid var(--color-fd-border); } /* Section-heading icons (Lucide SVGs rendered inside the ). * Match the 13px heading text, use a slightly thinner stroke so * they don't feel heavier than the label next to them. */ p svg { width: 13px; height: 13px; stroke-width: 1.75; } } /* Mobile sidebar drawer. * * Fumadocs renders the drawer as `fixed ... inset-y-0`, which starts it * at the top of the viewport. Our custom notebook header is also sticky * and defines `--fd-header-height`, so anchor the drawer below that * header instead of letting its search field and first section slide * underneath the nav bar. */ #nd-sidebar-mobile { top: var(--fd-docs-row-2); } /* TOC — shrink to match sidebar's 13px, make the "On this page" * heading use the dark foreground color, and add a little inline * padding so items don't hug the left border. * * The heading rule also applies to any sibling heading we render into * `tableOfContent.footer` (e.g. Contributors) via `data-toc-heading`, * so custom footer content stays visually aligned with fumadocs' own * `#toc-title`. */ #nd-toc { font-size: 13px; padding-top: 1rem; padding-right: 0; /* No horizontal padding on the container itself — each direct child * owns its own inline padding. That way full-bleed children (e.g. the * tocFooter with its `border-top` separator) can span edge-to-edge, * while normal sections (title, scroll area) still get the 0.75rem * indent via the rule below. Opt out with `data-toc-full-bleed`. */ > :not([data-toc-full-bleed]) { padding: 0.75rem; padding-top: 0.5rem; } #toc-title, [data-toc-heading] { color: var(--color-fd-foreground); font-size: 13px; } a { font-size: 13px; } } /* Vertical rules framing the three columns + the top nav. * * Note: #nd-sidebar's
) — tighter top/bottom rhythm. * All sections get 1rem of top breathing room above their text * (first via padding; subsequent via margin + padding with the * separator line in between). */ p { margin-top: 0; margin-bottom: 0.5rem; padding-top: 1rem; padding-left: 0.5rem; padding-right: 0.5rem; border-top: none; font-size: 13px; } p:not(:first-child) { margin-top: 0.5rem; padding-top: 0.5rem; border-top: 1px solid var(--color-fd-border); } /* Section-heading icons (Lucide SVGs rendered inside the
). * Match the 13px heading text, use a slightly thinner stroke so * they don't feel heavier than the label next to them. */ p svg { width: 13px; height: 13px; stroke-width: 1.75; } } /* Mobile sidebar drawer. * * Fumadocs renders the drawer as `fixed ... inset-y-0`, which starts it * at the top of the viewport. Our custom notebook header is also sticky * and defines `--fd-header-height`, so anchor the drawer below that * header instead of letting its search field and first section slide * underneath the nav bar. */ #nd-sidebar-mobile { top: var(--fd-docs-row-2); } /* TOC — shrink to match sidebar's 13px, make the "On this page" * heading use the dark foreground color, and add a little inline * padding so items don't hug the left border. * * The heading rule also applies to any sibling heading we render into * `tableOfContent.footer` (e.g. Contributors) via `data-toc-heading`, * so custom footer content stays visually aligned with fumadocs' own * `#toc-title`. */ #nd-toc { font-size: 13px; padding-top: 1rem; padding-right: 0; /* No horizontal padding on the container itself — each direct child * owns its own inline padding. That way full-bleed children (e.g. the * tocFooter with its `border-top` separator) can span edge-to-edge, * while normal sections (title, scroll area) still get the 0.75rem * indent via the rule below. Opt out with `data-toc-full-bleed`. */ > :not([data-toc-full-bleed]) { padding: 0.75rem; padding-top: 0.5rem; } #toc-title, [data-toc-heading] { color: var(--color-fd-foreground); font-size: 13px; } a { font-size: 13px; } } /* Vertical rules framing the three columns + the top nav. * * Note: #nd-sidebar's