From lo-design
Implements the StockTaper / Loosely Organized Research Facility design system for building UI components, pages, and layouts. Use when the user asks to "build a component", "create a page", "add a section", "style this", "design a layout", "update the UI", "add a card", "create a form", "add dark mode", "fix dark mode", "theme toggle", mentions design tokens, or references the StockTaper visual language. Covers color tokens, typography (IBM Plex Mono), dark mode (CSS variable swap via next-themes), dashed-border aesthetic, component patterns, responsive grids, and MDX prose styling.
How this skill is triggered — by the user, by Claude, or both
Slash command
/lo-design:stocktaper-design-systemThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
This design system defines the visual language for the Loosely Organized Research Facility. Every component, page, and layout MUST adhere to these constraints. The aesthetic is **monochromatic, monospace, minimal** -- inspired by vintage research documents and financial tickers.
This design system defines the visual language for the Loosely Organized Research Facility. Every component, page, and layout MUST adhere to these constraints. The aesthetic is monochromatic, monospace, minimal -- inspired by vintage research documents and financial tickers.
IMPORTANT: Never introduce these anti-patterns:
@import for Tailwind plugins (use @plugin in Tailwind v4)@theme inline (breaks dark mode -- use @theme so utilities emit CSS variable references)dark: prefixed Tailwind utilities (dark mode is handled by CSS variable swap, not utility prefixes).dark class, so both themes maintain the same vintage monochrome aestheticAll colors are CSS custom properties defined in src/app/globals.css and exposed as Tailwind utilities via @theme (NOT @theme inline -- this is critical for dark mode to work, see Dark Mode section).
| Token | Hex | Usage |
|---|---|---|
--color-cream | #FBF7EB | Page background, card backgrounds |
--color-ink | #141414 | Primary text, headings, high-contrast |
--color-charcoal | #393939 | Secondary text, borders, subtle UI |
--color-muted | #474747 | Tertiary text, metadata, placeholders |
--color-divider | #d4c9a8 | Borders, separators, horizontal rules |
--color-positive | #2F7D31 | Success states, gains, published badge |
--color-negative | #C6392C | Error states, losses, warnings |
--color-warning | #D97706 | Warning states, caution indicators |
bg-creamtext-inktext-charcoal or text-mutedborder-divider with border-dashedDark mode is built into the system and requires NO special handling from component authors. It works automatically through CSS custom property overrides.
.dark class on <html> (class strategy, system-aware)@theme in globals.css defines light-mode CSS variables as Tailwind utilities.dark {} in globals.css overrides those same variables with dark-mode values@theme (not @theme inline) is used, Tailwind utilities emit var(--color-*) references that respond to the .dark overrideCRITICAL: Using @theme inline would bake literal hex values into utilities, breaking dark mode. Always use @theme.
| Token | Light (default) | Dark (.dark class) |
|---|---|---|
--color-cream | #FBF7EB (warm parchment) | #1E1E1E (near black) |
--color-ink | #141414 (near black) | #E8E2D4 (warm white) |
--color-charcoal | #393939 (dark gray) | #C4BFAF (light gray) |
--color-muted | #474747 (mid gray) | #9E9888 (muted warm) |
--color-divider | #d4c9a8 (tan) | #333333 (dark gray) |
--color-positive | #2F7D31 (deep green) | #4CAF50 (bright green) |
--color-negative | #C6392C (deep red) | #EF5350 (bright red) |
--color-warning | #D97706 (amber) | #F59E0B (bright amber) |
--color-code-bg | #393939 | #1e1e1e |
--color-code-text | #FBF7EB | #E8E2D4 |
--color-code-inline-bg | rgba(57,57,57,0.1) | rgba(255,255,255,0.1) |
| Component | Location | Purpose |
|---|---|---|
| ThemeProvider | src/components/ThemeProvider.tsx | Wraps app in next-themes provider (class strategy, system default) |
| ThemeToggle | src/components/ui/ThemeToggle.tsx | Moon/sun SVG icon button for manual toggle |
ThemeToggle lives in the Header alongside navigation links.
dark: prefixed utilities -- the variable-swap approach handles everythingbg-cream, text-ink, etc.)@theme inline -- this bakes literal values and breaks the .dark overridebg-charcoal/10 will use the correct charcoal value in both themes.prose overrides in globals.css reference var() valuesFor the full dark mode color table and usage patterns, consult references/design-tokens.md.
For detailed scale and patterns, consult references/typography-scale.md.
font-mono everywhere (maps to IBM Plex Mono)text-base (16px) with leading-relaxedtext-4xl md:text-5xl font-bold tracking-tighttext-2xl font-bold tracking-tighttext-xl font-bold uppercasetext-xs uppercase tracking-[0.5px]Dashed borders are the defining visual element. Use them consistently.
| Context | Classes |
|---|---|
| Cards | border border-dashed border-divider rounded-[var(--radius-card)] |
| Code blocks | border border-dashed border-divider |
| Tables | border border-dashed border-divider divide-y divide-dashed divide-divider |
| Horizontal rules | border-divider (solid, exception to dashed) |
| Links | underline decoration-dashed underline-offset-4 |
| Link hover | decoration-solid (dashed -> solid transition) |
--radius-card: 6px /* Cards, containers */
--radius-button: 4.8px /* Buttons, inputs */
--radius-full: 9999px /* Pill shapes: badges, topic tags */
For full grid and spacing patterns, consult references/layout-patterns.md.
All page content wraps in Container:
max-w-[1152px]px-6mx-autogrid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6
Adjusts column count by passing columns prop (1, 2, or 3).
For the full component catalog with props and examples, consult references/component-catalog.md.
| Component | Location | Purpose |
|---|---|---|
| Container | src/components/layout/ | Max-width page wrapper |
| Header | src/components/layout/ | Site navigation |
| Footer | src/components/layout/ | Copyright bar |
| Button | src/components/ui/ | Primary/secondary actions |
| Badge | src/components/ui/ | Status indicators |
| DossierCard | src/components/ui/ | Bordered content card with badge |
| Divider | src/components/ui/ | Horizontal separator |
| ArrowLink | src/components/ui/ | Text link with -> glyph |
| TopicTag | src/components/ui/ | Pill-style topic label |
| ContentCard | src/components/content/ | Post preview card |
| ContentGrid | src/components/content/ | Responsive card grid |
| ContentMeta | src/components/content/ | Date, reading time, status |
| CopyButton | src/components/mdx/ | Clipboard copy for code blocks |
| ExperimentEmbed | src/components/mdx/ | Lazy-loaded interactive experiments |
| ThemeProvider | src/components/ | next-themes wrapper (class strategy) |
| ThemeToggle | src/components/ui/ | Dark/light mode toggle button |
src/components/layout/): Structural wrappers, navigationsrc/components/ui/): Reusable atomic elementssrc/components/content/): Content-specific compositionssrc/components/mdx/): Components used inside MDX renderingEvery component in this system follows these conventions:
// 1. Import cn utility for conditional classes
import { cn } from "@/lib/utils"
// 2. Define props interface
interface ComponentNameProps {
className?: string // ALWAYS accept className for composition
children?: React.ReactNode
// ... specific props
}
// 3. Export named function component
export function ComponentName({ className, children, ...props }: ComponentNameProps) {
return (
<div className={cn(
// Base classes first
"font-mono text-ink",
// Then structural classes
"border border-dashed border-divider rounded-[var(--radius-card)]",
// Then allow override
className
)}>
{children}
</div>
)
}
Before finalizing any component:
font-mono (no sans/serif)dashed where applicableclassName prop for compositioncn() from @/lib/utils for class mergingdark: prefixed utilities (dark mode uses CSS variable swap)For full MDX prose configuration, consult references/mdx-content-guide.md.
All MDX rendering is handled through mdx-components.tsx at the project root. Custom components override every HTML element to enforce the design system within prose content.
text-4xl (h1) to text-base (h6), with h3/h6 uppercasetext-charcoal decoration-dashed with decoration-solid on hoverbg-charcoal/10 rounded px-1.5 py-0.5 text-smbg-charcoal text-cream border-dashed with language badge + copy buttondivide-dashedborder-l-2 border-divider pl-4 italic text-mutedrounded-[var(--radius-card)] with optional figcaptiontitle: string # Required
date: YYYY-MM-DD # Required
description: string # Required, used in cards and meta
topics: string[] # Required, displayed as TopicTags
status: enum # Required: draft | field-notes | published | experiment | classified
readingTime: string # Optional, e.g. "8 min read"
| Type | Directory | URL Pattern |
|---|---|---|
| Research | content/research/ | /research/[slug] |
| Thoughts | content/thoughts/ | /thoughts/[slug] |
| Experiments | src/experiments/ | /experiments/[slug] |
@plugin not @import for plugins in CSS"use client" only when needed@/* = ./src/*, @content/* = ./content/*User says: "Add a callout box component"
Actions:
src/components/ui/Callout.tsxborder-dividerfont-mono text-sm for body textvariant prop for info/warning/success using design tokensclassName for compositionUser says: "Add a featured research section to the homepage"
Actions:
Container for max-width constrainttext-2xl font-bold tracking-tight text-inkContentGrid with columns={2} for cardsDivider above/below sectionUser says: "I need a custom aside element for MDX"
Actions:
src/components/mdx/mdx-components.tsxborder-l-2 border-divider left accentbg-cream background (or bg-charcoal/5 for subtle contrast)text-muted for supporting textCause: Missing design tokens or wrong border style
Solution: Verify all borders use border-dashed border-divider. Check no solid borders crept in. Confirm rounded-[var(--radius-card)] not arbitrary radius values.
Cause: Missing font import or wrong weight
Solution: Ensure @fontsource/ibm-plex-mono is imported for weight 400 and 700 only. Never reference weight 900 (does not exist). All text should use font-mono.
Cause: Tailwind v4 configuration issue
Solution: Check that src/app/globals.css has @theme block (NOT @theme inline) with CSS variables mapped to Tailwind utilities. Typography plugin must use @plugin "@tailwindcss/typography" not @import.
Cause: @theme inline used instead of @theme, or hardcoded hex values
Solution: The @theme directive (without inline) makes Tailwind emit var(--color-*) references. The .dark {} block in globals.css overrides those variables. If @theme inline is used, literal hex values get baked in and CSS variable overrides won't apply. Also check that no components use hardcoded hex values or dark: utility prefixes.
Cause: Theme not detected before first paint
Solution: The ThemeProvider uses next-themes with attribute="class" and enableSystem. next-themes injects a blocking script to prevent flash. Ensure ThemeProvider wraps the app in layout.tsx.
Cause: Component not registered in mdx-components.tsx
Solution: Verify the element override exists in the useMDXComponents export. All MDX elements (h1-h6, p, a, ul, ol, code, pre, table, img, blockquote, hr) must have custom mappings.
npx claudepluginhub looselyorganized/lo-plugin --plugin lo-designBuilds scalable Tailwind CSS design systems using design tokens, component variants, responsive patterns, and accessibility. Use for component libraries, theming, UI standardization, and dark mode setup.
Extracts Stitch designs to generate CSS custom properties with dark mode tokens, Tailwind v4 @theme block, and semantic design system document. Use before framework component skills.
Generates consistent production-grade SaaS UI for React apps using Casper Studios design system on shadcn/ui, Tailwind CSS v4, and Vite. For internal tools, dashboards, prototypes, client apps.