Add Mylder brand design system with warm amber accent

- Implement comprehensive design system with OKLCH colors
- Add warm stone neutrals replacing cold zinc grays
- Add amber brand color for CTAs and accents
- Update typography to Plus Jakarta Sans + JetBrains Mono
- Add brand variants to Button and Badge components
- Add utility classes: glass, shadow-brand, text-gradient-brand
- Update all pages to use semantic design tokens
- Add design system documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-13 16:19:06 +01:00
parent 01739a50cd
commit 53dbb0ed97
12 changed files with 1000 additions and 166 deletions

View File

@@ -39,11 +39,11 @@ export default function LoginPage() {
}
return (
<div className="min-h-screen flex items-center justify-center bg-zinc-50 dark:bg-zinc-950 px-4">
<div className="min-h-screen flex items-center justify-center bg-background px-4">
<Card className="w-full max-w-md">
<CardHeader className="text-center">
<Link href="/" className="inline-flex items-center justify-center gap-2 mb-4">
<Bot className="h-8 w-8 text-primary" />
<Bot className="h-8 w-8 text-brand" />
<span className="text-xl font-bold">Mylder</span>
</Link>
<CardTitle>Welcome back</CardTitle>
@@ -76,11 +76,11 @@ export default function LoginPage() {
/>
</div>
{error && (
<p className="text-sm text-red-500">{error}</p>
<p className="text-sm text-destructive">{error}</p>
)}
</CardContent>
<CardFooter className="flex flex-col gap-4">
<Button type="submit" className="w-full" disabled={isLoading}>
<Button type="submit" variant="brand" className="w-full" disabled={isLoading}>
{isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
@@ -90,9 +90,9 @@ export default function LoginPage() {
'Sign In'
)}
</Button>
<p className="text-sm text-center text-zinc-500">
<p className="text-sm text-center text-muted-foreground">
Don&apos;t have an account?{' '}
<Link href="/signup" className="text-primary hover:underline">
<Link href="/signup" className="text-brand hover:underline">
Sign up
</Link>
</p>

View File

@@ -57,11 +57,11 @@ export default function SignupPage() {
}
return (
<div className="min-h-screen flex items-center justify-center bg-zinc-50 dark:bg-zinc-950 px-4">
<div className="min-h-screen flex items-center justify-center bg-background px-4">
<Card className="w-full max-w-md">
<CardHeader className="text-center">
<Link href="/" className="inline-flex items-center justify-center gap-2 mb-4">
<Bot className="h-8 w-8 text-primary" />
<Bot className="h-8 w-8 text-brand" />
<span className="text-xl font-bold">Mylder</span>
</Link>
<CardTitle>Create your account</CardTitle>
@@ -118,11 +118,11 @@ export default function SignupPage() {
/>
</div>
{error && (
<p className="text-sm text-red-500">{error}</p>
<p className="text-sm text-destructive">{error}</p>
)}
</CardContent>
<CardFooter className="flex flex-col gap-4">
<Button type="submit" className="w-full" disabled={isLoading}>
<Button type="submit" variant="brand" className="w-full" disabled={isLoading}>
{isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
@@ -132,9 +132,9 @@ export default function SignupPage() {
'Create Account'
)}
</Button>
<p className="text-sm text-center text-zinc-500">
<p className="text-sm text-center text-muted-foreground">
Already have an account?{' '}
<Link href="/login" className="text-primary hover:underline">
<Link href="/login" className="text-brand hover:underline">
Log in
</Link>
</p>

View File

@@ -20,11 +20,11 @@ export default async function DashboardPage() {
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="flex items-center justify-between mb-8">
<div>
<h1 className="text-2xl font-bold text-zinc-900 dark:text-white">Projects</h1>
<p className="text-zinc-500">Manage your AI-powered development projects</p>
<h1 className="text-2xl font-bold text-foreground">Projects</h1>
<p className="text-muted-foreground">Manage your AI-powered development projects</p>
</div>
<Link href="/projects/new">
<Button className="gap-2">
<Button variant="brand" className="gap-2">
<Plus className="h-4 w-4" />
New Project
</Button>
@@ -35,11 +35,11 @@ export default async function DashboardPage() {
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{projects.map((project) => (
<Link key={project.id} href={`/projects/${project.id}`}>
<Card className="h-full hover:border-primary/50 transition-colors cursor-pointer">
<Card className="h-full hover:border-brand/50 hover:shadow-md transition-all cursor-pointer">
<CardHeader>
<div className="flex items-start justify-between">
<CardTitle className="text-lg">{project.name}</CardTitle>
<Badge variant={project.status === 'active' ? 'default' : 'secondary'}>
<Badge variant={project.status === 'active' ? 'brand' : 'secondary'}>
{project.status}
</Badge>
</div>
@@ -48,7 +48,7 @@ export default async function DashboardPage() {
</CardDescription>
</CardHeader>
<CardContent>
<div className="flex items-center gap-4 text-sm text-zinc-500">
<div className="flex items-center gap-4 text-sm text-muted-foreground">
{project.tech_stack && project.tech_stack.length > 0 && (
<div className="flex gap-1">
{project.tech_stack.slice(0, 3).map((tech: string) => (
@@ -59,7 +59,7 @@ export default async function DashboardPage() {
</div>
)}
</div>
<div className="flex items-center gap-1 text-xs text-zinc-400 mt-4">
<div className="flex items-center gap-1 text-xs text-muted-foreground mt-4">
<Clock className="h-3 w-3" />
Updated {new Date(project.updated_at).toLocaleDateString()}
</div>
@@ -71,17 +71,17 @@ export default async function DashboardPage() {
) : (
<Card className="border-dashed">
<CardContent className="flex flex-col items-center justify-center py-16">
<div className="w-16 h-16 rounded-full bg-zinc-100 dark:bg-zinc-800 flex items-center justify-center mb-4">
<FolderOpen className="h-8 w-8 text-zinc-400" />
<div className="w-16 h-16 rounded-full bg-muted flex items-center justify-center mb-4">
<FolderOpen className="h-8 w-8 text-muted-foreground" />
</div>
<h3 className="text-lg font-semibold text-zinc-900 dark:text-white mb-2">
<h3 className="text-lg font-semibold text-foreground mb-2">
No projects yet
</h3>
<p className="text-zinc-500 text-center mb-6 max-w-sm">
<p className="text-muted-foreground text-center mb-6 max-w-sm">
Create your first project to start building with AI assistance.
</p>
<Link href="/projects/new">
<Button className="gap-2">
<Button variant="brand" className="gap-2">
<Plus className="h-4 w-4" />
Create Your First Project
</Button>

View File

@@ -34,21 +34,21 @@ export default async function ProjectPage({ params }: { params: Promise<{ id: st
return (
<div className="h-[calc(100vh-4rem)] flex flex-col">
{/* Project Header */}
<div className="border-b bg-white dark:bg-zinc-950 px-4 py-3">
<div className="border-b bg-card px-4 py-3">
<div className="max-w-7xl mx-auto flex items-center justify-between">
<div className="flex items-center gap-4">
<Link href="/dashboard" className="text-zinc-500 hover:text-zinc-900 dark:hover:text-white">
<Link href="/dashboard" className="text-muted-foreground hover:text-foreground transition-colors">
<ArrowLeft className="h-5 w-5" />
</Link>
<div>
<div className="flex items-center gap-2">
<h1 className="text-lg font-semibold">{project.name}</h1>
<Badge variant={project.status === 'active' ? 'default' : 'secondary'}>
<Badge variant={project.status === 'active' ? 'brand' : 'secondary'}>
{project.status}
</Badge>
</div>
{project.description && (
<p className="text-sm text-zinc-500">{project.description}</p>
<p className="text-sm text-muted-foreground">{project.description}</p>
)}
</div>
</div>

View File

@@ -89,7 +89,7 @@ export default function NewProjectPage() {
return (
<div className="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<Link href="/dashboard" className="inline-flex items-center gap-2 text-sm text-zinc-500 hover:text-zinc-900 dark:hover:text-white mb-6">
<Link href="/dashboard" className="inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors mb-6">
<ArrowLeft className="h-4 w-4" />
Back to Projects
</Link>
@@ -125,9 +125,9 @@ export default function NewProjectPage() {
/>
</div>
{error && (
<p className="text-sm text-red-500">{error}</p>
<p className="text-sm text-destructive">{error}</p>
)}
<Button type="submit" className="w-full" disabled={isLoading || !name}>
<Button type="submit" variant="brand" className="w-full" disabled={isLoading || !name}>
{isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />

View File

@@ -3,120 +3,381 @@
@custom-variant dark (&:is(.dark *));
/* ============================================
MYLDER DESIGN SYSTEM
Warm neutrals + Amber accent
============================================ */
@theme inline {
/* Color mappings */
--color-background: var(--background);
--color-background-subtle: var(--background-subtle);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
/* Brand colors */
--color-brand: var(--brand);
--color-brand-foreground: var(--brand-foreground);
--color-brand-muted: var(--brand-muted);
/* Semantic colors */
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-success: var(--success);
--color-success-foreground: var(--success-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
--color-info: var(--info);
--color-info-foreground: var(--info-foreground);
/* UI colors */
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
/* Chart colors */
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
/* Sidebar colors */
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
/* Typography */
--font-sans: var(--font-sans);
--font-mono: var(--font-mono);
/* Border radius */
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--radius-2xl: calc(var(--radius) + 8px);
--radius-3xl: calc(var(--radius) + 16px);
}
/* ============================================
LIGHT MODE (Default)
Warm stone neutrals + amber accent
============================================ */
:root {
/* Base radius */
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
/* Typography */
--font-sans: 'Plus Jakarta Sans', var(--font-geist-sans), system-ui, sans-serif;
--font-mono: 'JetBrains Mono', var(--font-geist-mono), monospace;
/* Brand - Amber */
--brand: oklch(0.75 0.16 75);
--brand-foreground: oklch(0.20 0.02 75);
--brand-muted: oklch(0.92 0.06 75);
/* Backgrounds - Warm white */
--background: oklch(0.99 0.002 75);
--background-subtle: oklch(0.975 0.004 75);
--foreground: oklch(0.15 0.01 75);
/* Cards & Surfaces */
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--card-foreground: oklch(0.15 0.01 75);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
--popover-foreground: oklch(0.15 0.01 75);
/* Primary - Dark (for contrast) */
--primary: oklch(0.20 0.01 75);
--primary-foreground: oklch(0.98 0.002 75);
/* Secondary - Light gray */
--secondary: oklch(0.955 0.006 75);
--secondary-foreground: oklch(0.25 0.01 75);
/* Muted - Subtle */
--muted: oklch(0.955 0.006 75);
--muted-foreground: oklch(0.50 0.01 75);
/* Accent - Warm amber tint */
--accent: oklch(0.96 0.04 75);
--accent-foreground: oklch(0.25 0.02 75);
/* Semantic states */
--destructive: oklch(0.55 0.22 25);
--destructive-foreground: oklch(0.98 0 0);
--success: oklch(0.65 0.18 145);
--success-foreground: oklch(0.98 0 0);
--warning: oklch(0.80 0.15 85);
--warning-foreground: oklch(0.25 0.02 85);
--info: oklch(0.65 0.15 240);
--info-foreground: oklch(0.98 0 0);
/* Borders & Inputs */
--border: oklch(0.90 0.006 75);
--input: oklch(0.90 0.006 75);
--ring: oklch(0.75 0.16 75);
/* Charts - Vibrant palette */
--chart-1: oklch(0.75 0.16 75);
--chart-2: oklch(0.60 0.15 200);
--chart-3: oklch(0.65 0.18 280);
--chart-4: oklch(0.70 0.16 145);
--chart-5: oklch(0.65 0.20 25);
/* Sidebar */
--sidebar: oklch(0.985 0.003 75);
--sidebar-foreground: oklch(0.15 0.01 75);
--sidebar-primary: oklch(0.75 0.16 75);
--sidebar-primary-foreground: oklch(0.20 0.02 75);
--sidebar-accent: oklch(0.96 0.04 75);
--sidebar-accent-foreground: oklch(0.25 0.02 75);
--sidebar-border: oklch(0.90 0.006 75);
--sidebar-ring: oklch(0.75 0.16 75);
}
/* ============================================
DARK MODE
Warm dark + amber accent
============================================ */
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
/* Brand - Slightly brighter for dark bg */
--brand: oklch(0.78 0.15 75);
--brand-foreground: oklch(0.15 0.02 75);
--brand-muted: oklch(0.30 0.06 75);
/* Backgrounds - Warm dark */
--background: oklch(0.14 0.008 75);
--background-subtle: oklch(0.18 0.01 75);
--foreground: oklch(0.96 0.004 75);
/* Cards & Surfaces */
--card: oklch(0.20 0.01 75);
--card-foreground: oklch(0.96 0.004 75);
--popover: oklch(0.20 0.01 75);
--popover-foreground: oklch(0.96 0.004 75);
/* Primary - Light (for contrast) */
--primary: oklch(0.94 0.004 75);
--primary-foreground: oklch(0.18 0.01 75);
/* Secondary */
--secondary: oklch(0.26 0.012 75);
--secondary-foreground: oklch(0.94 0.004 75);
/* Muted */
--muted: oklch(0.26 0.012 75);
--muted-foreground: oklch(0.65 0.01 75);
/* Accent */
--accent: oklch(0.30 0.04 75);
--accent-foreground: oklch(0.94 0.004 75);
/* Semantic states - Adjusted for dark */
--destructive: oklch(0.65 0.20 22);
--destructive-foreground: oklch(0.98 0 0);
--success: oklch(0.70 0.16 145);
--success-foreground: oklch(0.15 0 0);
--warning: oklch(0.82 0.14 85);
--warning-foreground: oklch(0.20 0.02 85);
--info: oklch(0.70 0.14 240);
--info-foreground: oklch(0.15 0 0);
/* Borders & Inputs */
--border: oklch(1 0 0 / 12%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
--ring: oklch(0.78 0.15 75);
/* Charts - Adjusted for dark */
--chart-1: oklch(0.78 0.15 75);
--chart-2: oklch(0.68 0.14 200);
--chart-3: oklch(0.72 0.16 280);
--chart-4: oklch(0.75 0.15 145);
--chart-5: oklch(0.72 0.18 25);
/* Sidebar */
--sidebar: oklch(0.18 0.01 75);
--sidebar-foreground: oklch(0.96 0.004 75);
--sidebar-primary: oklch(0.78 0.15 75);
--sidebar-primary-foreground: oklch(0.15 0.02 75);
--sidebar-accent: oklch(0.26 0.03 75);
--sidebar-accent-foreground: oklch(0.94 0.004 75);
--sidebar-border: oklch(1 0 0 / 12%);
--sidebar-ring: oklch(0.78 0.15 75);
}
/* ============================================
BASE STYLES
============================================ */
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
@apply bg-background text-foreground antialiased;
}
/* Smooth scrolling */
html {
scroll-behavior: smooth;
}
/* Focus visible styles */
:focus-visible {
@apply outline-2 outline-offset-2 outline-ring;
}
/* Selection color */
::selection {
background: oklch(0.75 0.16 75 / 0.3);
}
.dark ::selection {
background: oklch(0.78 0.15 75 / 0.4);
}
}
/* ============================================
UTILITY CLASSES
============================================ */
@layer utilities {
/* Brand text gradient */
.text-gradient-brand {
background: linear-gradient(90deg, oklch(0.70 0.18 75), oklch(0.65 0.16 85));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Brand background gradient */
.bg-gradient-brand {
background: linear-gradient(135deg, oklch(0.75 0.16 75), oklch(0.70 0.18 65));
}
/* Subtle brand tint */
.bg-brand-subtle {
background: linear-gradient(135deg,
oklch(0.75 0.16 75 / 0.05),
oklch(0.75 0.16 75 / 0.1));
}
/* Brand glow shadow */
.shadow-brand {
box-shadow:
0 0 0 1px oklch(0.75 0.16 75 / 0.1),
0 4px 16px oklch(0.75 0.16 75 / 0.15);
}
.shadow-brand-lg {
box-shadow:
0 0 0 1px oklch(0.75 0.16 75 / 0.15),
0 8px 32px oklch(0.75 0.16 75 / 0.2);
}
.dark .shadow-brand {
box-shadow:
0 0 0 1px oklch(0.78 0.15 75 / 0.2),
0 4px 16px oklch(0.78 0.15 75 / 0.2);
}
.dark .shadow-brand-lg {
box-shadow:
0 0 0 1px oklch(0.78 0.15 75 / 0.25),
0 8px 32px oklch(0.78 0.15 75 / 0.25);
}
/* Glass effect */
.glass {
background: oklch(1 0 0 / 0.8);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.dark .glass {
background: oklch(0.14 0.008 75 / 0.8);
}
/* Shimmer loading animation */
.shimmer {
background: linear-gradient(
90deg,
oklch(0.95 0 0) 0%,
oklch(0.90 0 0) 50%,
oklch(0.95 0 0) 100%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
.dark .shimmer {
background: linear-gradient(
90deg,
oklch(0.25 0 0) 0%,
oklch(0.30 0 0) 50%,
oklch(0.25 0 0) 100%
);
background-size: 200% 100%;
}
}
/* ============================================
ANIMATIONS
============================================ */
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scale-in {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes pulse-brand {
0%, 100% {
box-shadow: 0 0 0 0 oklch(0.75 0.16 75 / 0.4);
}
50% {
box-shadow: 0 0 0 8px oklch(0.75 0.16 75 / 0);
}
}

View File

@@ -1,16 +1,18 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { Plus_Jakarta_Sans, JetBrains_Mono } from "next/font/google";
import { Toaster } from "@/components/ui/sonner";
import "./globals.css";
const geistSans = Geist({
const plusJakarta = Plus_Jakarta_Sans({
variable: "--font-geist-sans",
subsets: ["latin"],
weight: ["300", "400", "500", "600", "700", "800"],
});
const geistMono = Geist_Mono({
const jetbrainsMono = JetBrains_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
weight: ["400", "500", "600", "700"],
});
export const metadata: Metadata = {
@@ -26,7 +28,7 @@ export default function RootLayout({
return (
<html lang="en" suppressHydrationWarning>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
className={`${plusJakarta.variable} ${jetbrainsMono.variable} antialiased`}
>
{children}
<Toaster />

View File

@@ -4,13 +4,13 @@ import { ArrowRight, Layers, MessageSquare, Zap, Clock, Shield, Users } from 'lu
export default function LandingPage() {
return (
<div className="min-h-screen bg-gradient-to-b from-zinc-50 to-white dark:from-zinc-950 dark:to-zinc-900">
<div className="min-h-screen bg-gradient-to-b from-background to-background-subtle">
{/* Navigation */}
<nav className="fixed top-0 w-full z-50 border-b bg-white/80 backdrop-blur-sm dark:bg-zinc-950/80 dark:border-zinc-800">
<nav className="fixed top-0 w-full z-50 border-b glass">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16 items-center">
<div className="flex items-center gap-2">
<Layers className="h-8 w-8 text-primary" />
<Layers className="h-8 w-8 text-brand" />
<span className="text-xl font-bold">Mylder</span>
</div>
<div className="flex items-center gap-4">
@@ -18,7 +18,7 @@ export default function LandingPage() {
<Button variant="ghost">Log in</Button>
</Link>
<Link href="/signup">
<Button>Start a Project</Button>
<Button variant="brand">Start a Project</Button>
</Link>
</div>
</div>
@@ -28,21 +28,21 @@ export default function LandingPage() {
{/* Hero Section */}
<section className="pt-32 pb-20 px-4 sm:px-6 lg:px-8">
<div className="max-w-4xl mx-auto text-center">
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-primary/10 text-primary text-sm font-medium mb-8">
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-brand/10 text-brand text-sm font-medium mb-8">
<Zap className="h-4 w-4" />
Professional Software Development
</div>
<h1 className="text-4xl sm:text-6xl font-bold tracking-tight text-zinc-900 dark:text-white mb-6">
<h1 className="text-4xl sm:text-6xl font-bold tracking-tight text-foreground mb-6">
Your vision,
<span className="text-primary"> professionally built</span>
<span className="text-gradient-brand"> professionally built</span>
</h1>
<p className="text-xl text-zinc-600 dark:text-zinc-400 mb-8 max-w-2xl mx-auto">
<p className="text-xl text-muted-foreground mb-8 max-w-2xl mx-auto">
A lean, professional process to bring your software ideas to life.
Chat with us, get real-time updates, and launch with confidence.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link href="/signup">
<Button size="lg" className="gap-2">
<Button variant="brand" size="lg" className="gap-2">
Describe Your Project <ArrowRight className="h-4 w-4" />
</Button>
</Link>
@@ -56,13 +56,13 @@ export default function LandingPage() {
</section>
{/* How It Works */}
<section id="how-it-works" className="py-20 px-4 sm:px-6 lg:px-8 bg-zinc-50 dark:bg-zinc-900/50">
<section id="how-it-works" className="py-20 px-4 sm:px-6 lg:px-8 bg-muted/50">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-16">
<h2 className="text-3xl font-bold text-zinc-900 dark:text-white mb-4">
<h2 className="text-3xl font-bold text-foreground mb-4">
A streamlined process from idea to launch
</h2>
<p className="text-lg text-zinc-600 dark:text-zinc-400">
<p className="text-lg text-muted-foreground">
No complexity. No surprises. Just professional software development.
</p>
</div>
@@ -90,10 +90,10 @@ export default function LandingPage() {
<section id="features" className="py-20 px-4 sm:px-6 lg:px-8">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-16">
<h2 className="text-3xl font-bold text-zinc-900 dark:text-white mb-4">
<h2 className="text-3xl font-bold text-foreground mb-4">
Why clients choose Mylder
</h2>
<p className="text-lg text-zinc-600 dark:text-zinc-400">
<p className="text-lg text-muted-foreground">
A modern approach to software development that puts you in control.
</p>
</div>
@@ -133,47 +133,47 @@ export default function LandingPage() {
</section>
{/* Pricing Section */}
<section id="pricing" className="py-20 px-4 sm:px-6 lg:px-8 bg-zinc-50 dark:bg-zinc-900/50">
<section id="pricing" className="py-20 px-4 sm:px-6 lg:px-8 bg-muted/50">
<div className="max-w-4xl mx-auto">
<div className="text-center mb-16">
<h2 className="text-3xl font-bold text-zinc-900 dark:text-white mb-4">
<h2 className="text-3xl font-bold text-foreground mb-4">
Transparent, project-based pricing
</h2>
<p className="text-lg text-zinc-600 dark:text-zinc-400">
<p className="text-lg text-muted-foreground">
Every project is unique. Get a custom quote based on your specific needs.
</p>
</div>
<div className="bg-white dark:bg-zinc-900 rounded-2xl border dark:border-zinc-800 p-8 md:p-12">
<div className="bg-card rounded-2xl border p-8 md:p-12 shadow-sm">
<div className="text-center">
<h3 className="text-2xl font-bold text-zinc-900 dark:text-white mb-4">
<h3 className="text-2xl font-bold text-foreground mb-4">
Start with a free consultation
</h3>
<p className="text-zinc-600 dark:text-zinc-400 mb-8 max-w-xl mx-auto">
<p className="text-muted-foreground mb-8 max-w-xl mx-auto">
Describe your project idea and we'll get back to you with a clear scope,
timeline, and quote. No obligations, no pressure.
</p>
<div className="grid sm:grid-cols-3 gap-6 mb-10 text-left">
<div className="flex items-start gap-3">
<svg className="h-5 w-5 text-primary mt-0.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<svg className="h-5 w-5 text-brand mt-0.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span className="text-sm text-zinc-600 dark:text-zinc-400">Fixed-price projects with clear deliverables</span>
<span className="text-sm text-muted-foreground">Fixed-price projects with clear deliverables</span>
</div>
<div className="flex items-start gap-3">
<svg className="h-5 w-5 text-primary mt-0.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<svg className="h-5 w-5 text-brand mt-0.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span className="text-sm text-zinc-600 dark:text-zinc-400">Milestone-based payments for larger projects</span>
<span className="text-sm text-muted-foreground">Milestone-based payments for larger projects</span>
</div>
<div className="flex items-start gap-3">
<svg className="h-5 w-5 text-primary mt-0.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<svg className="h-5 w-5 text-brand mt-0.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span className="text-sm text-zinc-600 dark:text-zinc-400">Retainer options for ongoing development</span>
<span className="text-sm text-muted-foreground">Retainer options for ongoing development</span>
</div>
</div>
<Link href="/signup">
<Button size="lg" className="gap-2">
<Button variant="brand" size="lg" className="gap-2">
Describe Your Project <ArrowRight className="h-4 w-4" />
</Button>
</Link>
@@ -183,7 +183,7 @@ export default function LandingPage() {
</section>
{/* CTA Section */}
<section className="py-20 px-4 sm:px-6 lg:px-8 bg-primary text-primary-foreground">
<section className="py-20 px-4 sm:px-6 lg:px-8 bg-gradient-brand text-brand-foreground">
<div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-4">
Ready to bring your idea to life?
@@ -200,13 +200,13 @@ export default function LandingPage() {
</section>
{/* Footer */}
<footer className="py-12 px-4 sm:px-6 lg:px-8 border-t dark:border-zinc-800">
<footer className="py-12 px-4 sm:px-6 lg:px-8 border-t">
<div className="max-w-6xl mx-auto flex flex-col md:flex-row justify-between items-center gap-4">
<div className="flex items-center gap-2">
<Layers className="h-6 w-6 text-primary" />
<Layers className="h-6 w-6 text-brand" />
<span className="font-semibold">Mylder</span>
</div>
<p className="text-sm text-zinc-500">
<p className="text-sm text-muted-foreground">
&copy; {new Date().getFullYear()} Mylder. All rights reserved.
</p>
</div>
@@ -218,23 +218,23 @@ export default function LandingPage() {
function StepCard({ step, title, description }: { step: string; title: string; description: string }) {
return (
<div className="text-center">
<div className="w-12 h-12 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-xl font-bold mx-auto mb-4">
<div className="w-12 h-12 rounded-full bg-brand text-brand-foreground flex items-center justify-center text-xl font-bold mx-auto mb-4">
{step}
</div>
<h3 className="text-lg font-semibold text-zinc-900 dark:text-white mb-2">{title}</h3>
<p className="text-zinc-600 dark:text-zinc-400">{description}</p>
<h3 className="text-lg font-semibold text-foreground mb-2">{title}</h3>
<p className="text-muted-foreground">{description}</p>
</div>
)
}
function FeatureCard({ icon, title, description }: { icon: React.ReactNode; title: string; description: string }) {
return (
<div className="p-6 rounded-xl border bg-white dark:bg-zinc-900 dark:border-zinc-800">
<div className="w-12 h-12 rounded-lg bg-primary/10 flex items-center justify-center text-primary mb-4">
<div className="p-6 rounded-xl border bg-card shadow-sm hover:shadow-md transition-shadow">
<div className="w-12 h-12 rounded-lg bg-brand/10 flex items-center justify-center text-brand mb-4">
{icon}
</div>
<h3 className="text-lg font-semibold text-zinc-900 dark:text-white mb-2">{title}</h3>
<p className="text-zinc-600 dark:text-zinc-400">{description}</p>
<h3 className="text-lg font-semibold text-foreground mb-2">{title}</h3>
<p className="text-muted-foreground">{description}</p>
</div>
)
}

View File

@@ -31,12 +31,12 @@ export function DashboardNav({ user }: { user: SupabaseUser }) {
.toUpperCase() || user.email?.[0].toUpperCase() || '?'
return (
<nav className="fixed top-0 w-full z-50 border-b bg-white/80 backdrop-blur-sm dark:bg-zinc-950/80 dark:border-zinc-800">
<nav className="fixed top-0 w-full z-50 border-b glass">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16 items-center">
<div className="flex items-center gap-8">
<Link href="/dashboard" className="flex items-center gap-2">
<Bot className="h-8 w-8 text-primary" />
<Bot className="h-8 w-8 text-brand" />
<span className="text-xl font-bold">Mylder</span>
</Link>
<div className="hidden md:flex items-center gap-4">
@@ -61,7 +61,7 @@ export function DashboardNav({ user }: { user: SupabaseUser }) {
{user.user_metadata?.full_name && (
<p className="font-medium">{user.user_metadata.full_name}</p>
)}
<p className="text-sm text-zinc-500 truncate">{user.email}</p>
<p className="text-sm text-muted-foreground truncate">{user.email}</p>
</div>
</div>
<DropdownMenuSeparator />

View File

@@ -11,10 +11,26 @@ const badgeVariants = cva(
variant: {
default:
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
brand:
"border-transparent bg-brand text-brand-foreground [a&]:hover:bg-brand/90",
"brand-outline":
"border-brand/30 bg-brand/10 text-brand [a&]:hover:bg-brand/20",
secondary:
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
destructive:
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
success:
"border-transparent bg-success text-success-foreground [a&]:hover:bg-success/90",
"success-outline":
"border-success/30 bg-success/10 text-success [a&]:hover:bg-success/20",
warning:
"border-transparent bg-warning text-warning-foreground [a&]:hover:bg-warning/90",
"warning-outline":
"border-warning/30 bg-warning/10 text-warning [a&]:hover:bg-warning/20",
info:
"border-transparent bg-info text-info-foreground [a&]:hover:bg-info/90",
"info-outline":
"border-info/30 bg-info/10 text-info [a&]:hover:bg-info/20",
outline:
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
},

View File

@@ -10,15 +10,24 @@ const buttonVariants = cva(
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
brand:
"bg-brand text-brand-foreground hover:bg-brand/90 shadow-brand hover:shadow-brand-lg transition-shadow",
destructive:
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
success:
"bg-success text-success-foreground hover:bg-success/90",
outline:
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
"outline-brand":
"border-brand/30 bg-brand/5 text-brand hover:bg-brand/10 hover:border-brand/50",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost:
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
"ghost-brand":
"text-brand hover:bg-brand/10 hover:text-brand",
link: "text-primary underline-offset-4 hover:underline",
"link-brand": "text-brand underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",

546
src/styles/design-system.md Normal file
View File

@@ -0,0 +1,546 @@
# Mylder Brand Design System
## Brand Identity
**Tagline**: Intelligent Automation, Human Touch
**Personality**: Professional, Approachable, Innovative, Trustworthy
**Aesthetic**: Refined Tech-Forward Minimalism with Warm Energy
---
## Color System (OKLCH)
### Philosophy
Using OKLCH color space for perceptually uniform colors. Warm stone neutrals replace cold grays to feel more human/approachable for an AI platform. Amber accent represents energy and intelligence.
### Primary Palette
#### Brand Colors
```css
/* Amber - Primary Brand Accent */
--brand: oklch(0.75 0.16 75); /* Vibrant amber */
--brand-hover: oklch(0.70 0.18 75); /* Darker on hover */
--brand-muted: oklch(0.85 0.08 75); /* Soft amber for backgrounds */
--brand-foreground: oklch(0.20 0.02 75); /* Dark text on brand */
/* Stone - Warm Neutrals (replaces zinc/gray) */
--stone-50: oklch(0.985 0.002 75); /* Near white, warm */
--stone-100: oklch(0.965 0.004 75); /* Subtle warm */
--stone-200: oklch(0.925 0.006 75); /* Light warm */
--stone-300: oklch(0.87 0.008 75); /* Medium-light */
--stone-400: oklch(0.70 0.01 75); /* Medium */
--stone-500: oklch(0.55 0.012 75); /* Medium-dark */
--stone-600: oklch(0.45 0.014 75); /* Dark */
--stone-700: oklch(0.35 0.012 75); /* Darker */
--stone-800: oklch(0.25 0.01 75); /* Very dark */
--stone-900: oklch(0.18 0.008 75); /* Near black, warm */
--stone-950: oklch(0.12 0.006 75); /* Deepest */
```
### Semantic Colors
#### Light Mode
```css
:root {
/* Backgrounds */
--background: oklch(0.99 0.002 75); /* Warm white */
--background-subtle: oklch(0.975 0.004 75); /* Subtle warmth */
--foreground: oklch(0.15 0.01 75); /* Warm black */
/* Cards & Surfaces */
--card: oklch(1 0 0); /* Pure white cards */
--card-foreground: oklch(0.15 0.01 75);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.15 0.01 75);
/* Primary (Dark buttons/CTAs) */
--primary: oklch(0.20 0.01 75);
--primary-foreground: oklch(0.98 0.002 75);
/* Secondary (Light buttons) */
--secondary: oklch(0.955 0.006 75);
--secondary-foreground: oklch(0.25 0.01 75);
/* Muted (Disabled, hints) */
--muted: oklch(0.955 0.006 75);
--muted-foreground: oklch(0.50 0.01 75);
/* Accent (Amber brand) */
--accent: oklch(0.92 0.06 75);
--accent-foreground: oklch(0.25 0.02 75);
/* Brand (Primary amber) */
--brand: oklch(0.75 0.16 75);
--brand-foreground: oklch(0.20 0.02 75);
/* Destructive */
--destructive: oklch(0.55 0.22 25);
--destructive-foreground: oklch(0.98 0 0);
/* Success */
--success: oklch(0.65 0.18 145);
--success-foreground: oklch(0.98 0 0);
/* Warning */
--warning: oklch(0.80 0.15 85);
--warning-foreground: oklch(0.25 0.02 85);
/* Info */
--info: oklch(0.65 0.15 240);
--info-foreground: oklch(0.98 0 0);
/* Borders & Inputs */
--border: oklch(0.90 0.006 75);
--input: oklch(0.90 0.006 75);
--ring: oklch(0.75 0.16 75); /* Amber focus ring */
}
```
#### Dark Mode
```css
.dark {
/* Backgrounds */
--background: oklch(0.14 0.008 75); /* Warm dark */
--background-subtle: oklch(0.18 0.01 75);
--foreground: oklch(0.96 0.004 75); /* Warm white */
/* Cards & Surfaces */
--card: oklch(0.20 0.01 75);
--card-foreground: oklch(0.96 0.004 75);
--popover: oklch(0.20 0.01 75);
--popover-foreground: oklch(0.96 0.004 75);
/* Primary (Light buttons on dark) */
--primary: oklch(0.94 0.004 75);
--primary-foreground: oklch(0.18 0.01 75);
/* Secondary */
--secondary: oklch(0.26 0.012 75);
--secondary-foreground: oklch(0.94 0.004 75);
/* Muted */
--muted: oklch(0.26 0.012 75);
--muted-foreground: oklch(0.65 0.01 75);
/* Accent (Amber, slightly brighter for dark) */
--accent: oklch(0.30 0.04 75);
--accent-foreground: oklch(0.94 0.004 75);
/* Brand (Amber, adjusted for dark) */
--brand: oklch(0.78 0.15 75);
--brand-foreground: oklch(0.15 0.02 75);
/* Destructive */
--destructive: oklch(0.65 0.20 22);
--destructive-foreground: oklch(0.98 0 0);
/* Success */
--success: oklch(0.70 0.16 145);
--success-foreground: oklch(0.15 0 0);
/* Warning */
--warning: oklch(0.82 0.14 85);
--warning-foreground: oklch(0.20 0.02 85);
/* Info */
--info: oklch(0.70 0.14 240);
--info-foreground: oklch(0.15 0 0);
/* Borders & Inputs */
--border: oklch(1 0 0 / 12%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.78 0.15 75);
}
```
### Chart Colors (Data Visualization)
```css
/* Light mode - vibrant, distinguishable */
--chart-1: oklch(0.75 0.16 75); /* Amber (brand) */
--chart-2: oklch(0.60 0.15 200); /* Teal */
--chart-3: oklch(0.65 0.18 280); /* Purple */
--chart-4: oklch(0.70 0.16 145); /* Green */
--chart-5: oklch(0.65 0.20 25); /* Coral */
/* Dark mode - adjusted for contrast */
--chart-1: oklch(0.78 0.15 75);
--chart-2: oklch(0.68 0.14 200);
--chart-3: oklch(0.72 0.16 280);
--chart-4: oklch(0.75 0.15 145);
--chart-5: oklch(0.72 0.18 25);
```
---
## Typography
### Font Stack
```css
/* Primary - Display & Headings */
--font-display: 'Plus Jakarta Sans', system-ui, sans-serif;
/* Body - Reading & UI */
--font-body: 'Plus Jakarta Sans', system-ui, sans-serif;
/* Mono - Code & Technical */
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
```
### Type Scale (Fluid)
```css
/* Using clamp() for fluid typography */
--text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.8rem); /* 12-13px */
--text-sm: clamp(0.8125rem, 0.77rem + 0.21vw, 0.875rem); /* 13-14px */
--text-base: clamp(0.9375rem, 0.9rem + 0.19vw, 1rem); /* 15-16px */
--text-lg: clamp(1.0625rem, 1rem + 0.31vw, 1.125rem); /* 17-18px */
--text-xl: clamp(1.1875rem, 1.1rem + 0.44vw, 1.25rem); /* 19-20px */
--text-2xl: clamp(1.375rem, 1.25rem + 0.63vw, 1.5rem); /* 22-24px */
--text-3xl: clamp(1.625rem, 1.45rem + 0.88vw, 1.875rem); /* 26-30px */
--text-4xl: clamp(2rem, 1.75rem + 1.25vw, 2.25rem); /* 32-36px */
--text-5xl: clamp(2.5rem, 2.1rem + 2vw, 3rem); /* 40-48px */
--text-6xl: clamp(3rem, 2.5rem + 2.5vw, 3.75rem); /* 48-60px */
```
### Line Heights
```css
--leading-none: 1;
--leading-tight: 1.25;
--leading-snug: 1.375;
--leading-normal: 1.5;
--leading-relaxed: 1.625;
--leading-loose: 2;
```
### Font Weights
```css
--font-light: 300;
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
--font-extrabold: 800;
```
### Letter Spacing
```css
--tracking-tighter: -0.05em;
--tracking-tight: -0.025em;
--tracking-normal: 0;
--tracking-wide: 0.025em;
--tracking-wider: 0.05em;
--tracking-widest: 0.1em;
```
---
## Spacing & Layout
### Spacing Scale
```css
/* Base unit: 4px */
--space-0: 0;
--space-px: 1px;
--space-0.5: 0.125rem; /* 2px */
--space-1: 0.25rem; /* 4px */
--space-1.5: 0.375rem; /* 6px */
--space-2: 0.5rem; /* 8px */
--space-2.5: 0.625rem; /* 10px */
--space-3: 0.75rem; /* 12px */
--space-3.5: 0.875rem; /* 14px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-7: 1.75rem; /* 28px */
--space-8: 2rem; /* 32px */
--space-9: 2.25rem; /* 36px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-14: 3.5rem; /* 56px */
--space-16: 4rem; /* 64px */
--space-20: 5rem; /* 80px */
--space-24: 6rem; /* 96px */
--space-28: 7rem; /* 112px */
--space-32: 8rem; /* 128px */
```
### Container Widths
```css
--container-xs: 20rem; /* 320px */
--container-sm: 24rem; /* 384px */
--container-md: 28rem; /* 448px */
--container-lg: 32rem; /* 512px */
--container-xl: 36rem; /* 576px */
--container-2xl: 42rem; /* 672px */
--container-3xl: 48rem; /* 768px */
--container-4xl: 56rem; /* 896px */
--container-5xl: 64rem; /* 1024px */
--container-6xl: 72rem; /* 1152px */
--container-7xl: 80rem; /* 1280px */
--container-full: 100%;
```
### Breakpoints
```css
--screen-sm: 640px;
--screen-md: 768px;
--screen-lg: 1024px;
--screen-xl: 1280px;
--screen-2xl: 1536px;
```
---
## Border Radius
```css
--radius-none: 0;
--radius-sm: 0.25rem; /* 4px - subtle */
--radius-md: 0.5rem; /* 8px - default */
--radius-lg: 0.75rem; /* 12px - cards */
--radius-xl: 1rem; /* 16px - modals */
--radius-2xl: 1.5rem; /* 24px - large surfaces */
--radius-3xl: 2rem; /* 32px - hero elements */
--radius-full: 9999px; /* Pills, avatars */
```
---
## Shadows
### Light Mode
```css
--shadow-xs: 0 1px 2px oklch(0 0 0 / 0.04);
--shadow-sm: 0 1px 3px oklch(0 0 0 / 0.06), 0 1px 2px oklch(0 0 0 / 0.04);
--shadow-md: 0 4px 6px -1px oklch(0 0 0 / 0.06), 0 2px 4px -1px oklch(0 0 0 / 0.04);
--shadow-lg: 0 10px 15px -3px oklch(0 0 0 / 0.06), 0 4px 6px -2px oklch(0 0 0 / 0.03);
--shadow-xl: 0 20px 25px -5px oklch(0 0 0 / 0.08), 0 10px 10px -5px oklch(0 0 0 / 0.03);
--shadow-2xl: 0 25px 50px -12px oklch(0 0 0 / 0.15);
/* Brand glow (for CTAs) */
--shadow-brand: 0 0 0 1px oklch(0.75 0.16 75 / 0.1),
0 4px 16px oklch(0.75 0.16 75 / 0.15);
--shadow-brand-lg: 0 0 0 1px oklch(0.75 0.16 75 / 0.15),
0 8px 32px oklch(0.75 0.16 75 / 0.2);
```
### Dark Mode
```css
--shadow-xs: 0 1px 2px oklch(0 0 0 / 0.2);
--shadow-sm: 0 1px 3px oklch(0 0 0 / 0.3), 0 1px 2px oklch(0 0 0 / 0.2);
--shadow-md: 0 4px 6px -1px oklch(0 0 0 / 0.3), 0 2px 4px -1px oklch(0 0 0 / 0.2);
--shadow-lg: 0 10px 15px -3px oklch(0 0 0 / 0.3), 0 4px 6px -2px oklch(0 0 0 / 0.2);
--shadow-xl: 0 20px 25px -5px oklch(0 0 0 / 0.35), 0 10px 10px -5px oklch(0 0 0 / 0.2);
--shadow-2xl: 0 25px 50px -12px oklch(0 0 0 / 0.5);
/* Brand glow (brighter for dark) */
--shadow-brand: 0 0 0 1px oklch(0.78 0.15 75 / 0.2),
0 4px 16px oklch(0.78 0.15 75 / 0.2);
--shadow-brand-lg: 0 0 0 1px oklch(0.78 0.15 75 / 0.25),
0 8px 32px oklch(0.78 0.15 75 / 0.25);
```
---
## Motion & Animation
### Durations
```css
--duration-instant: 0ms;
--duration-fast: 100ms;
--duration-normal: 200ms;
--duration-slow: 300ms;
--duration-slower: 500ms;
--duration-slowest: 700ms;
```
### Easings
```css
--ease-linear: linear;
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
--ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);
```
### Common Animations
```css
/* Fade */
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
/* Slide up */
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Scale */
@keyframes scale-in {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* Pulse (for loading states) */
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
/* Shimmer (skeleton loading) */
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
```
---
## Component Patterns
### Button Variants
```tsx
// Primary (brand amber)
<Button variant="brand">Get Started</Button>
// Default (dark)
<Button variant="default">Submit</Button>
// Secondary (light)
<Button variant="secondary">Cancel</Button>
// Ghost (transparent)
<Button variant="ghost">Menu</Button>
// Outline (bordered)
<Button variant="outline">Learn More</Button>
// Destructive (red)
<Button variant="destructive">Delete</Button>
```
### Card Styles
```tsx
// Default card
<Card className="bg-card shadow-sm hover:shadow-md transition-shadow">
// Elevated card (more prominent)
<Card className="bg-card shadow-lg">
// Interactive card
<Card className="bg-card shadow-sm hover:shadow-lg hover:border-brand/20 transition-all cursor-pointer">
// Brand accent card
<Card className="bg-gradient-to-br from-brand/5 to-brand/10 border-brand/20">
```
### Input Styles
```tsx
// Default input
<Input className="border-input focus:border-brand focus:ring-brand/20" />
// With icon
<div className="relative">
<Icon className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" />
<Input className="pl-10" />
</div>
```
---
## Gradients
### Brand Gradients
```css
/* Subtle background */
--gradient-brand-subtle: linear-gradient(135deg,
oklch(0.75 0.16 75 / 0.05) 0%,
oklch(0.75 0.16 75 / 0.1) 100%);
/* Hero gradient */
--gradient-brand-hero: linear-gradient(135deg,
oklch(0.75 0.16 75) 0%,
oklch(0.70 0.18 65) 100%);
/* Text gradient */
--gradient-brand-text: linear-gradient(90deg,
oklch(0.70 0.18 75) 0%,
oklch(0.65 0.16 85) 100%);
```
### Background Gradients
```css
/* Warm fade (light mode) */
--gradient-warm: linear-gradient(180deg,
oklch(0.99 0.002 75) 0%,
oklch(0.975 0.006 75) 100%);
/* Dark gradient */
--gradient-dark: linear-gradient(180deg,
oklch(0.14 0.008 75) 0%,
oklch(0.10 0.006 75) 100%);
```
---
## Iconography
### Icon Library
- Primary: **Lucide React** (consistent with shadcn/ui)
- Size scale: 16px, 20px, 24px, 32px
- Stroke width: 1.5px (default), 2px (bold)
### Icon Colors
```css
/* Default */
.icon { color: var(--foreground); }
/* Muted */
.icon-muted { color: var(--muted-foreground); }
/* Brand */
.icon-brand { color: var(--brand); }
/* On interactive elements */
.btn:hover .icon { color: var(--brand); }
```
---
## Usage Guidelines
### Do
- Use warm stone colors for neutrals
- Use amber brand color for primary CTAs and accents
- Maintain consistent spacing (multiples of 4px)
- Use subtle shadows and transitions
- Ensure 4.5:1 contrast ratio for text
### Don't
- Mix cold grays with warm neutrals
- Overuse the brand amber color
- Use pure black (#000) or white (#fff)
- Add excessive shadows or effects
- Forget dark mode support
---
## Implementation
See `globals.css` for the complete CSS implementation with all variables defined.