chore: added brief agents.md and story for new design system

This commit is contained in:
Jayash Tripathy
2025-12-06 20:37:32 +05:30
parent de38e23f50
commit 7618e0af45
3 changed files with 1027 additions and 2 deletions

2
.gitignore vendored
View File

@@ -105,10 +105,8 @@ CLAUDE.md
build/
.react-router/
AGENTS.md
build/
.react-router/
AGENTS.md
temp/
scripts/

View File

@@ -0,0 +1,397 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
const meta = {
title: "Design System/Philosophy",
parameters: {
layout: "fullscreen",
docs: {
description: {
component: `
# Design System Philosophy
Reusable, composable Storybook stories that demonstrate Canvas, Surface, and Layer concepts.
Key concepts and rules are preserved, but the implementation is componentized for DRYness and clarity.
`,
},
},
},
tags: ["autodocs"],
} satisfies Meta;
export default meta;
export type Story = StoryObj<typeof meta>;
/* -----------------------------
Reusable UI building blocks
-----------------------------*/
type ContainerProps = {
children?: React.ReactNode;
className?: string;
};
const DemoRoot: React.FC<ContainerProps> = ({ children, className = "" }) => (
<div className={`p-8 ${className}`}>{children}</div>
);
const Info: React.FC<{ title: string; children?: React.ReactNode; tone?: "info" | "warn" }> = ({
title,
children,
tone = "info",
}) => (
<div
className={`mb-4 rounded-md border ${tone === "warn" ? "border-red-500 bg-red-50 p-4" : "border-subtle bg-layer-1 p-4"}`}
>
<h3 className={`text-primary mb-2 text-lg font-semibold`}>{title}</h3>
<div className="text-secondary text-sm">{children}</div>
</div>
);
const Surface: React.FC<ContainerProps> = ({ children, className = "bg-surface-1 rounded-md p-6" }) => (
<div className={className}>{children}</div>
);
const Layer: React.FC<ContainerProps & { hover?: boolean }> = ({
children,
className = "bg-layer-1 hover:bg-layer-1-hover rounded-md p-4",
}) => <div className={`${className} transition-colors`}>{children}</div>;
/* Small helpers to keep stories concise */
const TwoColGrid: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<div className="grid grid-cols-2 gap-6">{children}</div>
);
/* -----------------------------
Stories (using the building blocks)
-----------------------------*/
export const ApplicationRoot: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Application Root Pattern">
This is the <strong>bg-canvas</strong> - the application-level background. It should only appear{" "}
<strong>once</strong> in your entire application at the root level.
</Info>
<Surface>
<h4 className="text-primary mb-2 font-semibold">Page Content (bg-surface-1)</h4>
<p className="text-secondary text-sm">Pages use surfaces, not canvas. This is a typical page layout.</p>
</Surface>
</DemoRoot>
),
};
export const SurfaceSiblings: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Surface Siblings Pattern">
Surfaces are <strong>siblings</strong>, not nested.
</Info>
<TwoColGrid>
<Surface>
<h4 className="text-primary mb-2 font-semibold">Surface 1</h4>
<p className="text-secondary text-sm">This is bg-surface-1 - a primary surface</p>
</Surface>
<Surface className="bg-surface-2 rounded-md p-6">
<h4 className="text-primary mb-2 font-semibold">Surface 2</h4>
<p className="text-secondary text-sm">This is bg-surface-2 - a secondary surface (sibling to surface-1)</p>
</Surface>
</TwoColGrid>
</DemoRoot>
),
};
export const LayerStacking: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Layer Stacking Pattern">Layers stack to create depth: Surface Layer 1 Layer 2 Layer 3</Info>
<Surface>
<h4 className="text-primary mb-3 font-semibold">Surface 1</h4>
<Layer className="bg-layer-1 hover:bg-layer-1-hover mb-4 rounded-md p-4">
<h5 className="text-primary mb-2 font-medium">Layer 1 (First level of depth)</h5>
<p className="text-secondary mb-3 text-sm">Hover over me to see the hover state</p>
<Layer className="bg-layer-2 hover:bg-layer-2-hover rounded-md p-3">
<h6 className="text-primary mb-2 text-sm font-medium">Layer 2 (Second level)</h6>
<p className="text-secondary mb-2 text-sm">Nested within Layer 1</p>
<Layer className="bg-layer-3 hover:bg-layer-3-hover rounded-md p-2" hover>
<p className="text-primary text-xs font-medium">Layer 3 (Third level)</p>
<p className="text-secondary text-xs">Deepest nesting level</p>
</Layer>
</Layer>
</Layer>
</Surface>
</DemoRoot>
),
};
export const SurfaceLayerAssociation: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Surface-Layer Association">
Each surface should use its corresponding layer: surface-1 layer-1, surface-2 layer-2
</Info>
<TwoColGrid>
<Surface>
<h4 className="text-primary mb-3 font-semibold">Surface 1</h4>
<Layer className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Layer 1</h5>
<p className="text-secondary text-sm">Correctly using layer-1 with surface-1</p>
</Layer>
</Surface>
<Surface className="bg-surface-2 rounded-md p-6">
<h4 className="text-primary mb-3 font-semibold">Surface 2</h4>
<Layer className="bg-layer-2 hover:bg-layer-2-hover rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Layer 2</h5>
<p className="text-secondary text-sm">Correctly using layer-2 with surface-2</p>
</Layer>
</Surface>
</TwoColGrid>
</DemoRoot>
),
};
export const ModalException: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Modal Exception Pattern">
Modals exist on a <strong>different plane</strong>, so they can use surfaces even when there&apos;s a surface
below
</Info>
<Surface>
<h4 className="text-primary mb-2 font-semibold">Main Page Content</h4>
<p className="text-secondary text-sm">This is the main page using bg-surface-1</p>
</Surface>
<div className="fixed inset-0 z-50 flex items-center justify-center">
<div className="bg-backdrop absolute inset-0" />
<div className="bg-surface-1 relative z-10 max-w-md rounded-lg p-6 shadow-lg">
<h4 className="text-primary mb-3 font-semibold">Modal Dialog</h4>
<p className="text-secondary mb-4 text-sm">
This modal uses bg-surface-1 even though the page below also uses bg-surface-1. This is allowed because
they&apos;re on different planes.
</p>
<Layer className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-3">
<p className="text-primary text-sm">Modal content can use layers as normal</p>
</Layer>
</div>
</div>
</DemoRoot>
),
};
export const CardListPattern: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Card List Pattern">Common pattern: Surface containing multiple layer-1 cards</Info>
<Surface>
<h4 className="text-primary mb-4 font-semibold">Task List</h4>
<div className="space-y-3">
{[1, 2, 3].map((item) => (
<Layer key={item} className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Task {item}</h5>
<p className="text-secondary text-sm">This is a task card using bg-layer-1 with hover state</p>
</Layer>
))}
</div>
</Surface>
</DemoRoot>
),
};
export const SidebarLayoutPattern: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Sidebar Layout Pattern">Sidebar and main content are both part of the same surface</Info>
<Surface className="bg-surface-1 flex rounded-md">
<aside className="border-subtle w-64 border-r p-4">
<h4 className="text-primary mb-3 font-semibold">Sidebar</h4>
<div className="space-y-2">
{["Home", "Projects", "Settings"].map((item) => (
<Layer key={item} className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-2">
<p className="text-primary text-sm">{item}</p>
</Layer>
))}
</div>
</aside>
<main className="flex-1 p-6">
<h4 className="text-primary mb-3 font-semibold">Main Content</h4>
<Layer className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<p className="text-primary">Content card using layer-1</p>
</Layer>
</main>
</Surface>
</DemoRoot>
),
};
export const StateVariants: Story = {
render: () => (
<DemoRoot>
<Info title="✅ State Variants">Demonstrating hover, active, and selected states</Info>
<Surface>
<div className="space-y-4">
<Layer className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Hover State</h5>
<p className="text-secondary text-sm">Hover over me to see bg-layer-1-hover</p>
</Layer>
<div className="bg-layer-1-active rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Active State</h5>
<p className="text-secondary text-sm">Using bg-layer-1-active (pressed/active)</p>
</div>
<div className="bg-layer-1-selected rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Selected State</h5>
<p className="text-secondary text-sm">Using bg-layer-1-selected (when selected)</p>
</div>
</div>
</Surface>
</DemoRoot>
),
};
export const TextColorHierarchy: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Text Color Hierarchy">Semantic text colors for different importance levels</Info>
<Surface>
<div className="bg-layer-1 rounded-md p-4">
<h4 className="text-primary mb-3 text-lg font-semibold">Primary Text</h4>
<p className="text-secondary mb-3">Secondary text for descriptions and supporting content</p>
<p className="text-tertiary mb-3 text-sm">Tertiary text for labels and metadata</p>
<input
className="placeholder-placeholder border-subtle rounded border px-3 py-2"
placeholder="Placeholder text for inputs"
/>
</div>
</Surface>
</DemoRoot>
),
};
export const CompleteExample: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Complete Example">A realistic dashboard layout using all design system concepts</Info>
<div className="bg-surface-1 mb-6 rounded-md">
<div className="border-subtle border-b p-4">
<h1 className="text-primary text-xl font-bold">Dashboard</h1>
</div>
</div>
<div className="grid grid-cols-3 gap-6">
{[
{ label: "Total Users", value: "1,234" },
{ label: "Active Projects", value: "42" },
{ label: "Completed Tasks", value: "856" },
].map((stat, idx) => (
<Surface key={idx}>
<Layer className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<p className="text-tertiary mb-1 text-sm">{stat.label}</p>
<p className="text-primary text-2xl font-bold">{stat.value}</p>
</Layer>
</Surface>
))}
</div>
<div className="mt-6 grid grid-cols-2 gap-6">
<Surface>
<h3 className="text-primary mb-4 font-semibold">Recent Activity</h3>
<div className="space-y-2">
{[1, 2, 3].map((item) => (
<Layer key={item} className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-3">
<p className="text-primary mb-1 text-sm font-medium">Activity {item}</p>
<p className="text-secondary text-xs">Description of the activity</p>
</Layer>
))}
</div>
</Surface>
<Surface className="bg-surface-2 rounded-md p-6">
<h3 className="text-primary mb-4 font-semibold">Quick Actions</h3>
<div className="space-y-2">
{["Create Project", "Invite Team", "View Reports"].map((action) => (
<Layer key={action} className="bg-layer-2 hover:bg-layer-2-hover rounded-md p-3">
<p className="text-primary text-sm">{action}</p>
</Layer>
))}
</div>
</Surface>
</div>
</DemoRoot>
),
};
export const CommonMistakes: Story = {
render: () => (
<DemoRoot>
<Info title="❌ Common Mistakes to Avoid" tone="warn">
These examples show incorrect usage patterns
</Info>
<div className="space-y-6">
<div className="border-2 border-red-500 rounded-md p-4">
<h4 className="text-primary mb-2 font-semibold"> Mistake 1: Nested Surfaces (Same Plane)</h4>
<Surface>
<p className="text-secondary mb-2 text-sm">Surface 1</p>
<div className="bg-surface-2 rounded-md p-4">
<p className="text-secondary text-sm">Surface 2 nested inside Surface 1 - WRONG!</p>
</div>
</Surface>
<p className="text-tertiary mt-2 text-xs">
Fix: Use bg-layer-1 for nested elements, or make them sibling surfaces
</p>
</div>
<div className="border-2 border-red-500 rounded-md p-4">
<h4 className="text-primary mb-2 font-semibold"> Mistake 2: Wrong Layer-Surface Association</h4>
<Surface>
<p className="text-secondary mb-2 text-sm">Surface 1</p>
<div className="bg-layer-2 rounded-md p-4">
<p className="text-secondary text-sm">Using layer-2 with surface-1 - WRONG!</p>
</div>
</Surface>
<p className="text-tertiary mt-2 text-xs"> Fix: Use bg-layer-1 with bg-surface-1</p>
</div>
<div className="border-2 border-red-500 rounded-md p-4">
<h4 className="text-primary mb-2 font-semibold"> Mistake 3: Mismatched Hover State</h4>
<Surface>
<div className="bg-layer-1 hover:bg-layer-2-hover rounded-md p-4 transition-colors">
<p className="text-secondary text-sm">bg-layer-1 with hover:bg-layer-2-hover - WRONG!</p>
</div>
</Surface>
<p className="text-tertiary mt-2 text-xs"> Fix: Use bg-layer-1 hover:bg-layer-1-hover</p>
</div>
<div className="border-2 border-red-500 rounded-md p-4">
<h4 className="text-primary mb-2 font-semibold"> Mistake 4: Canvas for Pages</h4>
<div className="bg-canvas rounded-md p-4">
<p className="text-secondary text-sm">Using bg-canvas for a page or component - WRONG!</p>
</div>
<p className="text-tertiary mt-2 text-xs">
Fix: Canvas should only be at application root. Use bg-surface-1 for pages
</p>
</div>
</div>
</DemoRoot>
),
};

View File

@@ -0,0 +1,630 @@
# Design System Philosophy Guide
## Overview
This guide explains the semantic design system philosophy for building consistent, maintainable UIs. The system is built on three core concepts: **Canvas**, **Surface**, and **Layer**.
## Core Concepts
### 1. Canvas (`bg-canvas`)
**What it is**: The application-level background that serves as the foundation for all content. The canvas is the **entire application background**, not individual pages. There is only **one canvas** in the entire application, used at the root level.
**When to use**:
- **Only at the application root** - the single root container that wraps the entire application
- The main application background (not page backgrounds)
**When NOT to use**:
- ❌ Page-level backgrounds
- ❌ Nested containers
- ❌ Cards or components
- ❌ Modals or dropdowns
- ❌ Sidebars or panels
- ❌ Anywhere else in the application
**Critical Rule**: Canvas should only appear **once** in your entire application - at the root level. All pages, routes, and components sit on top of this single canvas.
**Example**:
```tsx
// ✅ Correct: Canvas at application root (only place it should be)
// App.tsx or root layout
<div className="bg-canvas min-h-screen">
{/* All application content goes here */}
<Routes>
<Route path="/" element={<Page />} />
</Routes>
</div>;
// ✅ Correct: Pages use surfaces, not canvas
function Page() {
return <div className="bg-surface-1">{/* Page content */}</div>;
}
// ❌ Wrong: Canvas used for a page
function Page() {
return <div className="bg-canvas">{/* Don't use canvas here */}</div>;
}
// ❌ Wrong: Canvas used for a card
<div className="bg-canvas p-4 rounded-md">{/* Card content */}</div>;
```
### 2. Surface (`bg-surface-1`, `bg-surface-2`, `bg-surface-3`)
**What it is**: Top-level containers that sit directly on the canvas. Surfaces never overlap each other - they are siblings in the layout hierarchy.
**When to use**:
- Main content areas
- Sections of a page
- Primary containers
- Panels that sit side-by-side
**Surface hierarchy**:
- `bg-surface-1`: Primary surface (most common)
- `bg-surface-2`: Secondary surface (for variation)
- `bg-surface-3`: Tertiary surface (rare, for special cases)
**Rules**:
- Surfaces are **siblings**, not nested (in the same plane)
- Each surface should use its corresponding layer for nested elements
- Surfaces provide the base for stacking layers
**Exception - Different Planes**:
- Modals, overlays, and popovers exist on a **different plane** (different z-index/stacking context)
- In these cases, it's acceptable to use a surface even when there's a surface below
- This is because they are visually and functionally separate from the underlying content
**Example**:
```tsx
// ✅ Correct: Surfaces as siblings
<div className="bg-canvas">
<div className="bg-surface-1">
{/* Main content area */}
</div>
<div className="bg-surface-2">
{/* Secondary content area - sibling, not nested */}
</div>
</div>
// ✅ Correct: Page with header and main (same surface)
<div className="bg-surface-1">
<header className="border-b border-subtle">
{/* Header is part of the surface, not a separate surface */}
</header>
<main>
{/* Main is part of the surface, not a separate surface */}
</main>
</div>
// ❌ Wrong: Surface nested in surface (same plane)
<div className="bg-surface-1">
<div className="bg-surface-2">
{/* This breaks the philosophy */}
</div>
</div>
// ✅ Correct: Modal on different plane
<div className="bg-canvas">
{/* Main page content */}
<div className="bg-surface-1">
Page content
</div>
{/* Modal overlay - different plane */}
<div className="fixed inset-0 z-50">
<div className="bg-backdrop fixed inset-0" />
<div className="bg-surface-1 rounded-lg shadow-lg p-6">
{/* Modal can use surface-1 even though page uses surface-1 */}
Modal content
</div>
</div>
</div>
```
### 3. Layer (`bg-layer-1`, `bg-layer-2`, `bg-layer-3`)
**What it is**: Stacking layers that create depth within a surface. Layers stack on top of each other in a specific order.
**When to use**:
- Cards within a surface
- Group headers
- Nested containers
- Dropdowns and modals
- Sidebars
- Any element that needs to appear "on top" of a surface
**Layer hierarchy**:
- `bg-layer-1`: First layer (closest to surface)
- `bg-layer-2`: Second layer (on top of layer-1)
- `bg-layer-3`: Third layer (on top of layer-2)
**Critical Rule - Layer-to-Surface Association**:
- `bg-surface-1` → use `bg-layer-1` for nested elements
- `bg-surface-2` → use `bg-layer-2` for nested elements
- `bg-surface-3` → use `bg-layer-3` for nested elements
**Example**:
```tsx
// ✅ Correct: Surface-1 with layer-1
<div className="bg-surface-1 p-4">
<div className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-3">
Card content
</div>
</div>
// ✅ Correct: Surface-2 with layer-2
<div className="bg-surface-2 p-4">
<div className="bg-layer-2 hover:bg-layer-2-hover rounded-md p-3">
Card content
</div>
</div>
// ❌ Wrong: Surface-1 with layer-2
<div className="bg-surface-1 p-4">
<div className="bg-layer-2">
{/* Wrong layer for this surface */}
</div>
</div>
```
## Stacking Layers
### How to Stack Layers
Layers stack in order: surface → layer-1 → layer-2 → layer-3
**Pattern**:
```
Canvas
└── Surface
└── Layer 1 (first level of depth)
└── Layer 2 (second level of depth)
└── Layer 3 (third level of depth)
```
**Example - Proper Stacking**:
```tsx
// ✅ Correct: Proper layer stacking
<div className="bg-surface-1 p-4">
{/* Layer 1: Card */}
<div className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<h3>Card Title</h3>
{/* Layer 2: Nested section */}
<div className="bg-layer-2 hover:bg-layer-2-hover rounded p-2 mt-2">
Nested content
{/* Layer 3: Deeply nested */}
<div className="bg-layer-3 hover:bg-layer-3-hover rounded p-1 mt-1">Deep content</div>
</div>
</div>
</div>
```
**When to use each layer**:
- **Layer 1**: Most common - cards, headers, primary nested elements
- **Layer 2**: Secondary depth - nested cards, sub-sections
- **Layer 3**: Deep nesting - rarely needed, for complex hierarchies
## State Variants
### Hover States
**Critical Rule**: Hover must always match the base background layer.
**Pattern**: `bg-layer-X hover:bg-layer-X-hover`
**Examples**:
```tsx
// ✅ Correct: Matching hover
<div className="bg-layer-1 hover:bg-layer-1-hover">
Hoverable element
</div>
<div className="bg-layer-2 hover:bg-layer-2-hover">
Hoverable element
</div>
// ❌ Wrong: Mismatched hover
<div className="bg-layer-1 hover:bg-layer-2-hover">
{/* Never do this */}
</div>
```
### Active States
Use `-active` variants when an element is in an active/pressed state.
```tsx
// ✅ Correct: Active state
<button
className={cn("bg-layer-1 hover:bg-layer-1-hover", {
"bg-layer-1-active": isActive,
})}
>
Button
</button>
```
### Selected States
Use `-selected` variants only when there's actual selection logic.
```tsx
// ✅ Correct: Selected state with logic
<div className={cn(
"bg-layer-1 hover:bg-layer-1-hover",
{
"bg-layer-1-selected": isSelected
}
)}>
Selectable item
</div>
// ✅ Correct: With data attribute
<div className="bg-layer-1 hover:bg-layer-1-hover data-[selected]:bg-layer-1-selected">
Selectable item
</div>
```
## Common Patterns
### Pattern 1: Application Root Layout
```tsx
// ✅ Correct: Application root (only place for canvas)
// App.tsx or root layout
<div className="bg-canvas min-h-screen">
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/dashboard" element={<DashboardPage />} />
</Routes>
</div>;
// ✅ Correct: Individual page structure
function HomePage() {
return (
<div className="bg-surface-1">
{/* Header - part of the page surface, uses layer for depth */}
<header className="border-b border-subtle">
<div className="bg-layer-1 hover:bg-layer-1-hover px-4 py-2">Header content</div>
</header>
{/* Main content - part of the page surface */}
<main className="p-6">
<div className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">Content card</div>
</main>
</div>
);
}
```
### Pattern 2: Card with Nested Elements
```tsx
// ✅ Correct: Card with proper layering
<div className="bg-surface-1 p-4">
<div className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<h3 className="text-primary font-semibold">Card Title</h3>
{/* Nested section */}
<div className="bg-layer-2 hover:bg-layer-2-hover rounded p-3 mt-3">
<p className="text-secondary">Nested content</p>
</div>
</div>
</div>
```
### Pattern 3: Dropdown/Modal
```tsx
// ✅ Correct: Modal structure (different plane exception)
function PageWithModal() {
return (
<div className="bg-surface-1">
{/* Main page content */}
<div>Page content</div>
{/* Modal - different plane, can use surface even with surface below */}
{isModalOpen && (
<div className="fixed inset-0 z-50">
<div className="bg-backdrop fixed inset-0" />
<div className="bg-surface-1 rounded-lg shadow-lg p-6">
<div className="bg-layer-1 hover:bg-layer-1-hover rounded p-2">Modal content</div>
</div>
</div>
)}
</div>
);
}
```
### Pattern 4: Sidebar Layout
```tsx
// ✅ Correct: Sidebar with main content (page level, not app root)
// Both sidebar and main are siblings on the same surface
function DashboardPage() {
return (
<div className="bg-surface-1 flex">
{/* Sidebar - part of the page surface */}
<aside className="border-r border-subtle w-64">
<div className="bg-layer-1 hover:bg-layer-1-hover p-4">Sidebar item</div>
</aside>
{/* Main content - part of the page surface */}
<main className="flex-1 p-6">
<div className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">Main content</div>
</main>
</div>
);
}
```
### Pattern 5: List with Items
```tsx
// ✅ Correct: List structure
<div className="bg-surface-1 p-4">
<div className="bg-layer-1 hover:bg-layer-1-hover rounded-md mb-2 p-3">List item 1</div>
<div className="bg-layer-1 hover:bg-layer-1-hover rounded-md mb-2 p-3">List item 2</div>
<div className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-3">List item 3</div>
</div>
```
### Pattern 6: Form with Inputs
```tsx
// ✅ Correct: Form structure
<div className="bg-surface-1 p-6">
<form className="bg-layer-1 rounded-md p-4 space-y-4">
<div>
<label className="text-primary font-medium">Name</label>
<input className="bg-surface-1 border border-subtle rounded-md px-3 py-2 text-primary" type="text" />
</div>
<button className="bg-layer-2 hover:bg-layer-2-hover rounded-md px-4 py-2 text-primary">Submit</button>
</form>
</div>
```
## Decision Tree
### When to use Canvas?
```
Is this the root container of the entire application?
(Only one place in the whole app)
├─ YES → Use bg-canvas (application root only)
└─ NO → Continue to Surface decision
```
### When to use Surface?
```
Is this a top-level container that sits on canvas?
AND
Is it a sibling to other containers (not nested)?
OR
Is this a modal/overlay on a different plane (z-index)?
├─ YES → Use bg-surface-1 (or surface-2/3 for variation)
└─ NO → Continue to Layer decision
```
### When to use Layer?
```
Is this nested within a surface?
├─ YES → Use bg-layer-1 (or layer-2/3 for deeper nesting)
│ Match layer number to surface number
└─ NO → Re-evaluate: Should this be a surface?
```
## Text Colors
Use semantic text colors that match the hierarchy:
- `text-primary`: Main text, headings, important content
- `text-secondary`: Secondary text, descriptions
- `text-tertiary`: Tertiary text, labels, metadata
- `text-placeholder`: Placeholder text, hints
**Example**:
```tsx
<div className="bg-layer-1 p-4">
<h2 className="text-primary font-semibold">Title</h2>
<p className="text-secondary">Description text</p>
<span className="text-tertiary text-sm">Metadata</span>
<input className="placeholder-placeholder" placeholder="Enter text..." />
</div>
```
## Border Colors
Use semantic border colors:
- `border-subtle`: Subtle borders, dividers
- `border-subtle-1`: Slightly more visible borders
- `border-strong`: Strong borders, emphasis
- `border-strong-1`: Very strong borders
**Example**:
```tsx
<div className="bg-layer-1 border border-subtle rounded-md p-4">
<div className="border-b border-subtle-1 pb-2 mb-2">Section with divider</div>
</div>
```
## Common Mistakes to Avoid
### ❌ Mistake 1: Canvas for Pages or Cards
```tsx
// ❌ Wrong: Canvas used for a page
function Page() {
return <div className="bg-canvas">Page content</div>;
}
// ❌ Wrong: Canvas used for a card
<div className="bg-canvas rounded-md p-4">Card content</div>;
// ✅ Correct: Pages use surfaces
function Page() {
return (
<div className="bg-surface-1">
<div className="bg-layer-1 rounded-md p-4">Card content</div>
</div>
);
}
```
### ❌ Mistake 2: Nested Surfaces (Same Plane)
```tsx
// ❌ Wrong: Nested surfaces in same plane
<div className="bg-surface-1">
<div className="bg-surface-2">
Nested surface
</div>
</div>
// ✅ Correct: Use layer instead
<div className="bg-surface-1">
<div className="bg-layer-1">
Nested layer
</div>
</div>
// ✅ Correct: Exception - Modal on different plane
<div className="bg-canvas">
<div className="bg-surface-1">Page content</div>
<div className="fixed inset-0 z-50">
<div className="bg-surface-1">Modal (different plane)</div>
</div>
</div>
```
### ❌ Mistake 3: Wrong Layer for Surface
```tsx
// ❌ Wrong: surface-1 with layer-2
<div className="bg-surface-1">
<div className="bg-layer-2">
Content
</div>
</div>
// ✅ Correct: surface-1 with layer-1
<div className="bg-surface-1">
<div className="bg-layer-1">
Content
</div>
</div>
```
### ❌ Mistake 4: Mismatched Hover
```tsx
// ❌ Wrong
<div className="bg-layer-1 hover:bg-layer-2-hover">
Content
</div>
// ✅ Correct
<div className="bg-layer-1 hover:bg-layer-1-hover">
Content
</div>
```
### ❌ Mistake 5: Missing Hover Prefix
```tsx
// ❌ Wrong
<div className="bg-layer-1-hover">
Content
</div>
// ✅ Correct
<div className="bg-layer-1 hover:bg-layer-1-hover">
Content
</div>
```
## Best Practices
1. **Canvas is Application Root Only**: Canvas should only appear once in your entire application - at the root level (App.tsx or root layout). All pages use surfaces, not canvas.
2. **Use Surfaces for Pages and Top-Level Containers**: Surfaces are siblings, not nested (except modals/overlays on different planes)
3. **Match Layers to Surfaces**: surface-1 → layer-1, surface-2 → layer-2, etc.
4. **Stack Layers Properly**: Use layer-1 first, then layer-2, then layer-3 as needed
5. **Always Match Hover States**: If base is `bg-layer-X`, hover must be `hover:bg-layer-X-hover`
6. **Use Semantic Text Colors**: Match text color to importance (primary, secondary, tertiary, placeholder)
7. **Keep It Simple**: Don't over-nest. Most components only need layer-1
8. **Test Visual Hierarchy**: Ensure the stacking creates clear visual depth
## Quick Reference
### Hierarchy Structure
```
Canvas (one per page)
└── Surface 1 (top-level container)
└── Layer 1 (first level of depth)
└── Layer 2 (second level)
└── Layer 3 (third level)
```
### Common Combinations
- Application Root: `bg-canvas` (only one place in entire app)
- Single Surface Page: `bg-surface-1``bg-layer-1`
- Multiple Surfaces Page: Grid of `bg-surface-1` (or `bg-surface-2`) as siblings
- Card: `bg-surface-1``bg-layer-1 hover:bg-layer-1-hover`
- Nested Card: `bg-surface-1``bg-layer-1``bg-layer-2`
- Sidebar Layout: `bg-surface-1` (sidebar) + `bg-surface-1` (main) - both siblings
### State Variants
- Hover: `bg-layer-X hover:bg-layer-X-hover`
- Active: `bg-layer-X-active` (when pressed/active)
- Selected: `bg-layer-X-selected` (when selected)
## Alignment Checklist
When reviewing components, ensure:
- [ ] Canvas is only used at the application root (one place in entire app)
- [ ] Pages use surfaces, not canvas
- [ ] Surfaces are siblings, not nested (except modals/overlays on different planes)
- [ ] Layers match their surface (surface-1 → layer-1)
- [ ] Hover states match base layers
- [ ] Layers stack properly (1 → 2 → 3)
- [ ] Text colors are semantic (primary, secondary, tertiary, placeholder)
- [ ] Borders use semantic colors (subtle, strong)
- [ ] No unnecessary nesting
- [ ] Visual hierarchy is clear
- [ ] State variants are used correctly
- [ ] Modals/overlays use surfaces (exception to nesting rule)