| name | kaicalls-design |
| description | Build KaiCalls-compliant UI components and pages using the KaiCalls design system. Use when creating new dashboard pages, components, forms, tables, cards, badges, or any UI within the KaiCalls admin panel. Ensures dark-first aesthetic, proper color tokens, typography classes, motion standards, and B2B SaaS best practices. Triggers on "build a page", "create a component", "add a dashboard", "design a form", or any frontend work in the adminpanelnew codebase. |
Build KaiCalls-compliant UI using the dark-first design system, shadcn/ui components, and B2B SaaS best practices.
Design Philosophy
KaiCalls follows "Minimum Lovable Product" (MLP) principles:
- Zero Support Required: UI so intuitive users never need docs
- Every Click Invokes Emotion: Button clicks should feel satisfying with visual/motion feedback
- Micro-Celebrations: Reward actions with delightful feedback (confetti, checkmarks, sounds)
- Software Teammate: Humanize through conversational copy and helpful empty states
- Dark-First: Premium aesthetic inspired by Linear, Notion, Stripe
CRITICAL: Every interactive element should provide emotional feedback. Users should feel their actions.
IMPORTANT: Keep feedback subtle and gentle. No harsh flashing, strobing, or high-contrast animations that strain eyes. Our users include older professionals who spend long hours on screen.
Quick Reference
Core Colors (CSS Variables)
--background: #12121A
--card: #181B23
--secondary: #23263B
--surface-elevated: #2A2D3E
--kai-blue: #5C8CFF
--kai-purple: #C68BF8
--kai-btn-primary: #3575F6
--foreground: #F7F7FA
--muted-foreground: #A7A9BE
--kai-text-placeholder: #6B6D76
--kai-success-text: #34D399
--kai-error-text: #FF4B4B
--kai-warning-text: #FFC04B
--kai-info-text: #5C8CFF
Tailwind Classes
Use kai-* prefix for brand colors:
className="bg-background"
className="bg-card"
className="bg-secondary"
className="text-foreground"
className="text-muted-foreground"
className="text-kai-blue"
className="text-kai-purple"
className="border-border"
className="border-kai-table-border"
Typography Classes
<h1 className="heading-xl">Page Title</h1> // 2xl bold white
<h2 className="heading-lg">Section Title</h2> // xl semibold white
<h3 className="heading-md">Card Title</h3> // lg semibold white
<h4 className="heading-sm">Subsection</h4> // base semibold white
<p className="text-body-primary">Main content</p> // white
<p className="text-body-secondary">Helper text</p> // slate-400
<p className="text-body-tertiary">Timestamp</p> // slate-500
<span className="label-uppercase">SECTION</span> // xs uppercase tracking-wide slate-400
<label className="label-default">Field</label> // sm medium slate-400
<span className="stat-label">METRIC</span> // xs uppercase slate-400
Component Patterns
Cards
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card";
<Card>
<CardHeader>
<CardTitle>Title Here</CardTitle>
<CardDescription>Description text</CardDescription>
</CardHeader>
<CardContent>
{/* Content */}
</CardContent>
</Card>
Buttons
import { Button } from "@/components/ui/button";
<Button>Default (Primary)</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</>
Badges (Status & Temperature)
<span className="badge-hot">Hot</span> // Red: #FF4B4B33 bg, #FF6B6B text
<span className="badge-warm">Warm</span> // Yellow: #FFC04B33 bg, #FFD76B text
<span className="badge-cold">Cold</span> // Blue: #4B7BFF33 bg, #6B93FF text
<span className="status-success">Active</span> // Green
<span className="status-error">Failed</span> // Red
<span className="status-warning">Pending</span> // Yellow
<span className="status-info">Info</span> // Blue
Tables
<tr className="table-row hover:bg-kai-hover-row">
<td className="px-4 py-3">Content</td>
</tr>
<tr className="table-row-selected">
<td>Selected content</td>
</tr>
Forms & Inputs
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input id="email" placeholder="Enter email" />
</div>
Dialogs/Modals
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
<Dialog>
<DialogContent className="bg-modal-bg border-modal-border">
<DialogHeader>
<DialogTitle>Modal Title</DialogTitle>
<DialogDescription>Description here</DialogDescription>
</DialogHeader>
{/* Content */}
</DialogContent>
</Dialog>
Emotional Interactions
Every button click should invoke emotion. Users perform tedious tasks; reward them.
Keep it subtle. Feedback should be felt, not seen. Avoid:
- Bright flashes or strobing effects
- High-contrast color pops (white on dark)
- Large, jarring movements
- Animations longer than 300ms
- Anything that draws attention away from the task
Prefer: soft glows, gentle scale changes (1.02-1.05x), muted color transitions, spring physics with high damping.
Micro-Celebration Triggers
| Action | Feedback | Implementation |
|---|
| Task complete | Soft checkmark fade-in | Icon opacity 0→1 over 200ms |
| Form submit | Gentle green tint, quiet toast | Subtle bg-color shift, no flash |
| Delete/Archive | Smooth slide away | Slide-out 250ms with opacity fade |
| Toggle on | Soft snap into place | Spring with damping 0.8 |
| Save success | Soft glow around button | Box-shadow fade in/out over 400ms |
| Error | Gentle wobble + muted red | 2-3px horizontal shake, soft red |
Eye comfort guidelines:
- Use muted success green (#34D399 at 60% opacity) not bright green
- Error red should be soft (#FF4B4B with transparency), never pure red
- Confetti/particles should be sparse and low-contrast
- Prefer opacity transitions over color flashes
Button Feedback Patterns
<Button
onClick={async () => {
await action();
setSuccess(true);
setTimeout(() => setSuccess(false), 1500);
}}
className={cn(
"transition-all duration-150",
success && "bg-kai-success-text scale-105"
)}
>
{success ? <Check className="h-4 w-4" /> : "Save Changes"}
</Button>
<Button disabled={loading}>
{loading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Saving...
</>
) : (
"Save"
)}
</Button>
Toast Celebrations
import { toast } from "sonner";
toast.success("Agent created!", {
description: "Your AI assistant is ready to take calls."
});
toast("Deal closed!", {
icon: "🎉",
description: "Great work! $50,000 added to pipeline."
});
High-Anxiety Moment Patterns
Identify moments where users feel nervous and provide reassurance:
<AlertDialog>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete this agent?</AlertDialogTitle>
<AlertDialogDescription>
This will permanently remove "Sales Assistant" and all its call history.
This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Keep Agent</AlertDialogCancel>
<AlertDialogAction className="bg-destructive">
Yes, Delete Agent
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
toast.success("Agent deleted", {
description: "Don't worry, your leads are still safe."
});
Hover & Focus States
Every interactive element needs visible feedback (keep it gentle):
className="hover:scale-[1.02] hover:brightness-105 transition-all duration-150"
className="hover:shadow-elevation-md hover:-translate-y-0.5 transition-all duration-200"
className="hover:text-kai-purple/80 transition-colors duration-150"
Reduced Motion Support
Respect users who prefer reduced motion:
className="motion-safe:hover:scale-[1.02] motion-reduce:hover:opacity-80"
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
Motion Standards
All animations must run at 60fps.
| Interaction | Duration | Easing |
|---|
| Micro (toggles, buttons) | 120-160ms | ease-out |
| Small transitions | 200-240ms | ease-out |
| Screen transitions | 300-400ms | cubic-bezier(0.4, 0, 0.2, 1) |
--transition-fast: 150ms
--transition-normal: 200ms
--transition-slow: 300ms
Animation Classes
<div className="skeleton-shimmer h-4 w-32 rounded" />
<CollapsibleContent className="collapsible-content">
<ChevronIcon className="collapsible-chevron" />
</CollapsibleContent>
Elevation & Shadows
className="shadow-elevation-sm"
className="shadow-elevation-md"
className="shadow-elevation-lg"
className="shadow-elevation-xl"
className="z-dropdown"
className="z-modal"
className="z-toast"
Empty States
Never show "No data found." Always provide:
- Helpful illustration (optional)
- Encouraging copy explaining what goes here
- Clear CTA to populate data
<div className="text-center py-12">
<Illustration className="mx-auto mb-4 h-24 w-24 text-muted-foreground" />
<h3 className="heading-md mb-2">No leads yet</h3>
<p className="text-body-secondary mb-4">
Leads will appear here when callers reach your AI assistant.
</p>
<Button>Create Your First Agent</Button>
</div>
Loading States
Use skeleton loaders that match content shape:
<Card>
<CardHeader>
<Skeleton className="h-6 w-48" />
<Skeleton className="h-4 w-32 mt-2" />
</CardHeader>
<CardContent>
<Skeleton className="h-24 w-full" />
</CardContent>
</Card>
{Array.from({ length: 5 }).map((_, i) => (
<tr key={i}>
<td><Skeleton className="h-4 w-24" /></td>
<td><Skeleton className="h-4 w-32" /></td>
<td><Skeleton className="h-4 w-16" /></td>
</>
))}
Gradient Utilities
<div className="bg-gradient-kai">Gradient bg</div>
<span className="text-gradient-kai">Gradient text</span>
Page Layout Template
export default function DashboardPage() {
return (
<div className="space-y-6">
{/* Page header */}
<div className="flex items-center justify-between">
<div>
<h1 className="heading-xl">Page Title</h1>
<p className="text-body-secondary mt-1">
Brief description of this page
</p>
</div>
<Button>Primary Action</Button>
</div>
{/* Content cards */}
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
</CardHeader>
<CardContent>
{/* Content */}
</CardContent>
</Card>
);
}
Stat Card Pattern
<Card>
<CardContent className="p-6">
<div className="flex items-center justify-between">
<span className="stat-label">Total Calls</span>
<Phone className="h-4 w-4 text-muted-foreground" />
</div>
<div className="mt-2">
<span className="data-value">1,234</span>
<span className="text-kai-success-text text-sm ml-2">+12%</span>
</div>
</CardContent>
</Card>
Error Handling
Humanize errors with conversational copy:
<Alert variant="destructive">
<AlertTitle>Something went wrong</AlertTitle>
<AlertDescription>
We're looking into it. Try refreshing the page.
</AlertDescription>
</Alert>
Checklist Before Shipping
Reference Documentation
For detailed information, see: