Obsidian Rail.
A precision dark dev-tool surface. Near-black background, every divider a single 1px hairline at 8% white, Inter Display for headings and Geist Mono for IDs and timestamps with tabular-nums, a single electric mint accent reserved for active status pills and the primary CTA. Built for infrastructure dashboards, observability tools, and developer-platform marketing pages where the chrome itself reads as a precision instrument.
The kitchen sink.
Build with Obsidian Rail.
A complete design system, ready for your AI coding agent. Every primitive, token, and pattern below is generated straight from DESIGN.md — drop the file in your project and ship matching UI in minutes.
Palette
Type scale
Buttons
Form controls
Select & toggle
Labeling
Cards
Prose-first token file — decisions live next to their reasoning.
Tabs & breadcrumb
Spacing scale
Fine micro-scale (1–5px) for pills, editorial scale (12–21px) for the grid.
Border radius scale
The system's own radius tokens — sm for chips and inputs, md for buttons, lg for cards, pill for fully-rounded CTAs.
Depth & elevation
Charts
The states behind the resting style.
Tokens describe the resting state. A real product needs every interaction state. Hover, focus, active, disabled, loading — all derived from the system's resting tokens.
Button
Input
Card
Tab
DESIGN.md
1---2name: "Obsidian Rail"3description: "A precision dark dev-tool surface. Near-black background, every divider a single 1px hairline at 8% white, Inter Display for headings and Geist Mono for IDs and timestamps with tabular-nums, a single electric mint accent reserved for active status pills and the primary CTA. Built for infrastructure dashboards, observability tools, and developer-platform marketing pages where the chrome itself reads as a precision instrument."4tags: [dark, modern, minimal, saas, premium]5colors:6 primary: "#f5f6f7"7 secondary: "#8b8e93"8 tertiary: "#f5f6f7"9 neutral: "#1a1c1e"10 surface: "#0c0d0f"11typography:12 display: Inter13 body: Inter14 mono: "Geist Mono"15 scale:16 hero: "4.25rem / 1.02 / 600 / -0.035em"17 h1: "2.5rem / 1.12 / 600 / -0.025em"18 h2: "1.5rem / 1.25 / 600 / -0.012em"19 body: "0.9375rem / 1.6 / 400 / -0.005em"20radius:21 sm: 4px22 md: 6px23 lg: 8px24 pill: 9999px25shadows:26 card: "rgba(0,0,0,0.20) 0 1px 2px"27 button: none28borders:29 card: "1px solid rgba(245,246,247,0.08)"30 divider: rgba(245,246,247,0.08)31buttons:32 primary:33 background: #5fe3b134 color: #0c0d0f35 border: none36 shape: rounded37 padding: 9px 18px38 font: 600 / 0.8125rem39 secondary:40 background: #1a1c1e41 color: #f5f6f742 border: 1px solid rgba(245,246,247,0.10)43 shape: rounded44 padding: 9px 18px45 font: 500 / 0.8125rem46 outline:47 background: transparent48 color: #f5f6f749 border: 1px solid rgba(245,246,247,0.14)50 shape: rounded51 padding: 9px 18px52 font: 500 / 0.8125rem53 ghost:54 background: transparent55 color: #8b8e9356 border: none57 shape: rounded58 padding: 9px 14px59 font: 500 / 0.8125rem60charts:61 variant: "thin-bars"62 stroke_width: 1.2563 fill_opacity: 0.0664 gridlines: false65 bar_gap: 3px66 highlight: single67 dot_marker: true68fonts_url: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600&display=swap"69dependencies: ["lucide-react"]70---71 72# Obsidian Rail73 74## AI Build Instructions75 76> **Read this section before writing any code.** The rules below77> are non-negotiable. Every value used in the UI must come from this78> file's frontmatter — never substitute, approximate, or invent new79> colors, fonts, radii, or shadows. If a value is missing, ask the80> user before adding one.81 82### 1 · Your role83 84You are building UI for a project that has adopted **Obsidian Rail** as its85design system. Treat `DESIGN.md` as the single source of truth.86Your job is to translate the user's product requirements into87components and pages that look like they were designed by the same88person who authored this file.89 90### 2 · Token compliance91 92- Pull every color, font family, radius, shadow, and spacing value93 from the frontmatter at the top of this file.94- Use semantic roles (e.g. `primary`, `accent`, `muted`) — never95 hard-code hex values that bypass the system.96- When a token can be expressed as a CSS variable, declare it once97 in your global stylesheet and reference it everywhere downstream.98- The Google Fonts `<link>` is provided in the Typography section.99 Add it to `<head>` before any component renders.100 101### 3 · Component recipes102 103Use these recipes verbatim when building the corresponding component.104 105#### Buttons106 107Four variants are defined. Pick one — never blend variants or invent a fifth.108 109- **Primary** — rounded shape, bg `#5fe3b1`, text `#0c0d0f`, padding `9px 18px`, weight `600`.110- **Secondary** — rounded shape, bg `#1a1c1e`, text `#f5f6f7`, border `1px solid rgba(245,246,247,0.10)`, padding `9px 18px`, weight `500`.111- **Outline** — rounded shape, text `#f5f6f7`, border `1px solid rgba(245,246,247,0.14)`, padding `9px 18px`, weight `500`.112- **Ghost** — rounded shape, text `#8b8e93`, padding `9px 14px`, weight `500`.113 114Reach for **primary** as the single dominant CTA per screen.115**Secondary** for the supporting action. **Outline** for tertiary116actions in toolbars. **Ghost** for inline links and table actions.117 118#### Cards119 120- Background: `#0c0d0f`121- Border: `1px solid rgba(245,246,247,0.08)`122- Shadow: `rgba(0,0,0,0.20) 0 1px 2px`123- Radius: `radius.lg` (`8px`)124- Internal padding: `20px` for compact cards, `24–28px` for content cards.125 126#### Tabs127 128Variant: `underline`. Flat row of labels. Active tab gets a 2px underline in the accent color — no fill.129 130#### Charts131 132- Bar/line variant: `thin-bars`133- No gridlines — let the bars/lines carry the data.134- Highlight strategy: `single` — emphasize a single bar/point per chart.135 136#### Typography pairings137 138- **Display (`Inter`)** — h1, h2, hero headlines, brand wordmarks.139- **Body (`Inter`)** — paragraphs, labels, button text, form inputs.140- **Mono (`Geist Mono`)** — code, eyebrows, metadata, numerals in tables.141 142### 4 · Hard constraints143 144Never do any of the following without explicit instruction from the user:145 146- Introduce a new color, font, radius, or shadow that isn't declared above.147- Mix this system with another (e.g. don't paste in Material or Bootstrap defaults).148- Use generic gradient defaults (purple→blue, peach→pink) — they break the system's voice.149- Reach for emoji icons. Use a consistent icon library and size icons in line with body type.150- Add motion that exceeds the system's restraint — keep transitions short (≤200ms) and subtle.151 152### 5 · Before you finish — verify153 154Run through this checklist for every screen you produce:155 156- [ ] Every color used appears in the Colors table above.157- [ ] Headlines use the display font; body copy uses the body font.158- [ ] Buttons match one of the declared variants exactly (shape, padding, weight).159- [ ] Border-radius values come from `radius.sm` / `radius.md` / `radius.lg` / `radius.pill`.160- [ ] Cards and dividers use the declared border + shadow tokens.161- [ ] No values were invented; if you needed something missing, you stopped and asked.162 163---164 165## 1. Atmosphere166 167Obsidian Rail is a precision dark dev-tool surface. The page is near-black `#0c0d0f` — slightly warmer than true black, never blue. Cards lift to `#1a1c1e`, a 4% lightness step, edged with a single 1px hairline at 8% white. There are no shadows beyond a 1px lift; depth comes entirely from tonal-step + hairline. Headings run in Inter 600 at 68px, body in Inter 400 at 15px on a 1.6 leading. Every ID, timestamp, region, percentage, latency runs in Geist Mono with `font-variant-numeric: tabular-nums` — column-aligned to the millisecond. The single accent is electric mint `#5fe3b1` reserved for active status pills, the primary CTA, and the focus ring — never as a fill, never as a chart background.168 169The discipline is in the hairline: every divider, every card edge, every table row separator is the same 1px at 8% white. Anything thicker reads as a brand-y SaaS card stack; anything dimmer disappears.170 171**Signature moves**172- Near-black warm `#0c0d0f` page → `#1a1c1e` card — single 4% tonal step, never two173- Every divider, card edge, row separator: 1px at 8% white — one hairline value, system-wide174- Geist Mono with tabular-nums on every ID, timestamp, region, percentage, latency175- Mint `#5fe3b1` exclusively on active status pill + primary CTA + focus ring176- Inter 600 at 68px for hero — calm authority, never display-serif drama177- 15px body — dev consoles need density, not marketing spacing178 179## 2. Palette180 181### Surfaces182- **Page** `#0c0d0f` — near-black, slight warm undertone183- **Card** `#1a1c1e` — elevated surface, 4% tonal step184- **Hairline** `rgba(245,246,247,0.08)` — every divider, every card edge185 186### Ink187- **Bone** `#f5f6f7` — primary text188- **Bone 50** `#8b8e93` — secondary text, mono labels189 190### Accent191- **Mint** `#5fe3b1` — active status pill, primary CTA, focus ring, "operational" indicator192- **Mint Soft** `rgba(95,227,177,0.12)` — focus ring background, hovered status pill193 194### Status (semantic only — never UI accent)195- Operational `#5fe3b1` (= mint, the accent doubles as healthy status)196- Degraded `#e8b95f` — used only on degraded status badges197- Down `#e87a5f` — used only on down status badges198 199## 3. Typography200 201| Role | Font | Size | Weight | Leading | Tracking |202|------|------|------|--------|---------|----------|203| Hero | Inter | 68px | 600 | 1.02 | -0.035em |204| H1 | Inter | 40px | 600 | 1.12 | -0.025em |205| H2 | Inter | 24px | 600 | 1.25 | -0.012em |206| Body | Inter | 15px | 400 | 1.6 | -0.005em |207| UI / Button | Inter | 13px | 500 | 1.4 | 0 |208| ID / Region / Latency | Geist Mono | 13px | 500 | 1.0 | 0 tabular-nums |209| Big Metric | Geist Mono | 28px | 600 | 1.0 | 0 tabular-nums |210| Label | Geist Mono | 11px | 500 | 1.0 | 0.06em uppercase |211| Timestamp | Geist Mono | 12px | 500 | 1.0 | 0 tabular-nums |212 213Inter for prose; Geist Mono for every numeric or ID string. The tabular-nums variant is what makes a deploy-log column-align like a terminal.214 215## 4. Buttons216 217### Primary (Mint Compact)218```css219background: #5fe3b1;220color: #0c0d0f;221padding: 9px 18px;222border-radius: 6px;223font-weight: 600;224```225 226The mint button is the only saturated color on the page — its single appearance carries every primary action. Compact 9px vertical padding because dev tools live in toolbars.227 228### Secondary (Card Lift)229- `#1a1c1e` background, 1px hairline at 10% white, bone text — same compact shape230 231### Outline & Ghost232- Outline: transparent, 1px hairline at 14% white233- Ghost: no border, bone-50, hover lifts to bone234 235## 5. Cards236 237```css238background: #1a1c1e;239border: 1px solid rgba(245,246,247,0.08);240border-radius: 8px;241box-shadow: rgba(0,0,0,0.20) 0 1px 2px;242```243 244The 4% tonal step is what separates the card from the page; the 1px hairline is the only edge treatment. No gradient borders, no glow, no inset highlight. The active card adds a 1px mint top hairline — the only place mint appears on a card edge.245 246## 6. Charts247 248Thin precise bars (3px wide, 3px gap). One bar in mint, others in 22% bone. Line charts at 1.25px bone with a 6% mint fill, ending in a mint dot marker. NO gridlines — the card edge frames the chart. Y-axis labels in Geist Mono uppercase 11px aligned right.249 250## 7. Tabs251 252Underline 1.5px in mint for the active state. Inactive tabs are bone-50 in Inter 500. Hover lifts to bone. Tabs sit on a 1px hairline baseline at 8% white.253 254## 8. Spacing255 256- Base 4px (table-row aware)257- Scale: `4, 8, 12, 16, 20, 24, 32, 48, 64, 96`258- Section padding: 64px desktop, 32px mobile — dev density259 260## 9. Do's & don'ts261 262✅ **Do**263- Use the single 4% tonal step (page → card) and the single 1px hairline at 8% white system-wide264- Use Geist Mono with tabular-nums on every ID, timestamp, region, percentage, latency265- Reserve mint for active status pill + primary CTA + focus ring + "operational" indicator266- Use 15px body — dev consoles need density, not marketing spacing267 268❌ **Don't**269- Use gradient borders, glows, or inset highlights — the hairline is the only chrome270- Use a second UI accent — mint alone, plus muted status colors for degraded/down only271- Use rounded-full pills for status — 6px capsule with mint or muted-amber/red text272- Use shadows beyond the 1px lift — the tonal step IS the depth273 274---275 276## Tokens277 278> Generated from the same source the live preview renders from.279> Treat the values below as the contract — never substitute approximations.280 281### Colors282 283| Role | Value |284|-----------|-------|285| primary | `#f5f6f7` |286| secondary | `#8b8e93` |287| tertiary | `#f5f6f7` |288| neutral | `#1a1c1e` |289| surface | `#0c0d0f` |290 291### Typography292 293- **Display:** Inter294- **Body:** Inter295- **Mono:** Geist Mono296 297| Role | size / leading / weight / tracking |298|------|------------------------------------|299| Hero | 4.25rem / 1.02 / 600 / -0.035em |300| H1 | 2.5rem / 1.12 / 600 / -0.025em |301| H2 | 1.5rem / 1.25 / 600 / -0.012em |302| Body | 0.9375rem / 1.6 / 400 / -0.005em |303 304### Radius305 306- sm: `4px`307- md: `6px`308- lg: `8px`309- pill: `9999px`310 311### Shadows312 313- **card:** `rgba(0,0,0,0.20) 0 1px 2px`314- **button:** `none`315 316### Borders317 318- **card:** `1px solid rgba(245,246,247,0.08)`319- **divider:** `rgba(245,246,247,0.08)`320 321### Buttons322 323Four variants, each fully tokenized. The preview renders from these exact values.324 325#### Primary326 327| Property | Value |328|----------|-------|329| shape | `rounded` |330| background | `#5fe3b1` |331| color | `#0c0d0f` |332| border | `none` |333| padding | `9px 18px` |334| fontWeight | `600` |335| fontSize | `0.8125rem` |336 337#### Secondary338 339| Property | Value |340|----------|-------|341| shape | `rounded` |342| background | `#1a1c1e` |343| color | `#f5f6f7` |344| border | `1px solid rgba(245,246,247,0.10)` |345| padding | `9px 18px` |346| fontWeight | `500` |347| fontSize | `0.8125rem` |348 349#### Outline350 351| Property | Value |352|----------|-------|353| shape | `rounded` |354| background | `transparent` |355| color | `#f5f6f7` |356| border | `1px solid rgba(245,246,247,0.14)` |357| padding | `9px 18px` |358| fontWeight | `500` |359| fontSize | `0.8125rem` |360 361#### Ghost362 363| Property | Value |364|----------|-------|365| shape | `rounded` |366| background | `transparent` |367| color | `#8b8e93` |368| border | `none` |369| padding | `9px 14px` |370| fontWeight | `500` |371| fontSize | `0.8125rem` |372 373### Charts374 375| Property | Value |376|----------|-------|377| variant | `thin-bars` |378| strokeWidth | `1.25` |379| fillOpacity | `0.06` |380| gridlines | `false` |381| barGap | `3px` |382| highlight | `single` |383| dotMarker | `true` |384 385---386 387## Pro tokens388 389> Production-fidelity tokens. States, density, motion, elevation,390> content rules and a measured WCAG contract — derived from the391> resting tokens unless explicitly authored.392 393### States394 395#### Button396 397- **hover** — shadow: `0 0 24px -4px rgba(245, 246, 247, 0.5), 0 8px 24px -8px rgba(0,0,0,0.6)`, filter: `brightness(1.1)`398- **focus** — outline: `1.5px solid #f5f6f7`, outline-offset: `3px`399- **active** — transform: `translateY(1px)`, filter: `brightness(0.92)`400- **disabled** — opacity: `0.35`, filter: `saturate(0.4)`401- **loading** — opacity: `0.6`402- **selected** — bg: `#f5f6f7`, color: `#0A0A0A`403 404#### Input405 406- **hover** — border: `1px solid rgba(245, 246, 247, 0.5)`407- **focus** — border: `1px solid #f5f6f7`, shadow: `0 0 0 3px rgba(245, 246, 247, 0.2)`408- **disabled** — opacity: `0.35`409- **error** — border: `1px solid #F87171`, shadow: `0 0 0 3px rgba(248,113,113,0.2)`410 411#### Card412 413- **hover** — shadow: `0 16px 40px -12px rgba(0,0,0,0.7), 0 0 0 1px rgba(245, 246, 247, 0.18)`, transform: `translateY(-2px)`414- **selected** — border: `1px solid #f5f6f7`, shadow: `0 0 0 1px #f5f6f7`415- **dragging** — shadow: `0 24px 60px -16px rgba(0,0,0,0.85)`, transform: `scale(1.02)`, opacity: `0.85`416 417#### Tab418 419- **hover** — color: `#f5f6f7`420- **focus** — outline: `1.5px solid #f5f6f7`, outline-offset: `2px`421- **selected** — color: `#f5f6f7`, border: `0 0 1.5px 0 solid #f5f6f7`422 423### Density424 425| Mode | padding × | row × | body | radius × | Use for |426|------|-----------|-------|------|----------|---------|427| compact | 0.72 | 0.78 | 0.8125rem | 0.85 | Information-dense — tables, IDEs, dashboards |428| comfortable | 1 | 1 | 0.9375rem | — | Default — most product UI |429| spacious | 1.35 | 1.3 | 1rem | 1.15 | Editorial — marketing, long-form, settings |430 431### Motion432 433**Signature — Glide.** Fließende, leicht beschleunigte Übergänge mit Accent-Glow auf hover. Premium-Feeling durch kontrollierte Lichtspiele.434 435```css436transition: all 280ms cubic-bezier(0.32, 0.72, 0, 1);437```438 439| Token | Value |440|-------|-------|441| duration.instant | `100ms` |442| duration.fast | `180ms` |443| duration.base | `280ms` |444| duration.slow | `450ms` |445| easing.standard | `cubic-bezier(0.32, 0.72, 0, 1)` |446| easing.decelerate | `cubic-bezier(0.0, 0, 0.2, 1)` |447| easing.accelerate | `cubic-bezier(0.4, 0, 1, 1)` |448| easing.spring | `cubic-bezier(0.5, 1.25, 0.55, 1)` |449 450### Elevation451 452Five-level scale, system-specific recipe.453 454| Level | Shadow | Recipe |455|-------|--------|--------|456| level0 | `none` | Flat — Hairline mit Accent-Hauch. |457| level1 | `0 2px 4px rgba(0,0,0,0.45)` | Subtle drop — list items. |458| level2 | `0 12px 28px -8px rgba(0,0,0,0.6)` | Popover — vom Canvas gelöst. |459| level3 | `0 20px 48px -12px rgba(0,0,0,0.7), 0 0 32px -8px rgba(245, 246, 247, 0.25)` | Sheet — Accent-Halo. |460| level4 | `0 40px 96px -16px rgba(0,0,0,0.85), 0 0 64px -12px rgba(245, 246, 247, 0.4)` | Modal — voller Accent-Rim, dramatisch. |461 462### Content463 464- **measure:** `66ch` (max line length for body prose)465- **paragraph spacing:** `1.3em`466- **list indent:** `1.5em`467- **list gap:** `0.5em`468- **link:** color `#f5f6f7`, underline `hover`469- **blockquote:** border `2px solid #f5f6f7`, padding `0.8em 1.2em`470- **code:** background `rgba(245, 246, 247, 0.12)`, color `#f5f6f7`471 472### Accessibility (WCAG 2.1)473 474**Overall:** AA475 476| Pair | Ratio | Required | Grade | Suggested fix |477|------|-------|----------|-------|---------------|478| Body text on surface | 17.97:1 | AA | AAA | — |479| Body text on canvas | 15.79:1 | AA | AAA | — |480| Muted text on surface | 5.91:1 | AA | AA | — |481| Accent on surface | 17.97:1 | AA-Large | AAA | — |482| Accent on canvas | 15.79:1 | AA-Large | AAA | — |483 Wire it into your agent.
# CLAUDE.md Reference @DESIGN.md for all styling decisions. Apply tokens strictly — do not introduce colors, fonts, or radii outside the system. When in doubt, prefer the values declared in DESIGN.md frontmatter.Three snippets.
Google Fonts link
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600&display=swap" />Install dependencies
npm install lucide-reactTailwind config
// tailwind.config.jsexport default { theme: { extend: { fontFamily: { display: ['"Inter"', 'serif'], sans: ['"Inter"', 'sans-serif'], mono: ['"Geist Mono"', 'monospace'], }, colors: { primary: '#f5f6f7', secondary: '#8b8e93', accent: '#f5f6f7', neutral: '#1a1c1e', surface: '#0c0d0f', }, borderRadius: { sm: '4px', md: '6px', lg: '8px', }, }, },};Try another system.
Atelier Glass
A studio interface built around real glassmorphism — frosted backdrop-blur cards floating over a soft tonal lavender-bone backdrop. Plus Jakarta Sans for UI, Spectral italic for accent display, a single indigo reserved for the active panel ring and the primary CTA. Built for creative studios, design tools, and product surfaces where the glass IS the interface chrome.
Slate Material
tonal-surface with a slate-blue seed — cool tonal surfaces, full-rounded tonal buttons, Roboto Flex throughout. The trustworthy B2B tonal-surface dialect.