Color System
Our color palette defines the visual identity of Andiron. Use CSS variables for consistency.
Brand Colors
Backgrounds
Text Colors
Status Colors
Extended Palette
Typography
Manrope is our primary typeface, providing excellent readability across all sizes.
Font Stack
--font-sans: 'Manrope', system-ui, -apple-system, BlinkMacSystemFont,
'SF Pro Text', 'Segoe UI', sans-serif;
Iconography
We use Font Awesome 6 as our primary icon library, with custom hover icons for key interactions.
Icon Library
Package: @fortawesome/react-fontawesome + @fortawesome/free-solid-svg-icons
Navigation & UI Icons
Status & Feedback Icons
Data & Analytics Icons
Action Icons
Icon Sizing
| Context | Size | Example |
|---|---|---|
| Inline with text | 12-13px | Completed |
| Buttons | 14-16px | |
| Card headers | 16-18px | |
| Feature icons | 20-24px | |
| Empty states | 32-48px |
Custom Hover Icons (Andi Icons)
Located in src/components/icons/hover/. These are custom SVG icons with micro-interactions on hover.
| Component | Animation | Usage |
|---|---|---|
MenuHoverIcon | Lines shift | Hamburger menu |
CloseHoverIcon | Rotates 90° | Close buttons |
BellHoverIcon | Rings | Notifications |
SearchHoverIcon | Sparkle reveals | Search inputs |
SendHoverIcon | Plane flies | Chat send |
DownloadHoverIcon | Arrow drops | Download buttons |
SettingsHoverIcon | Rotates | Settings gear |
import { MenuHoverIcon } from '@/components/icons/hover';
// Wrap parent in group class for hover trigger
<button className="group">
<MenuHoverIcon width={16} height={16} />
</button>
Spacing & Layout
Consistent spacing creates visual rhythm. We use an 8px base scale.
Common Padding Patterns
| Component | Padding |
|---|---|
| Modal header | 24px horizontal, 24px top, 18px bottom |
| Modal body | 24px horizontal, 28px bottom |
| Card | 20px (or 16px compact) |
| Button (primary) | 10px 20px |
| Button (small) | 8px 16px |
| Input | 12px 14px |
| Table cell | 10px 12px |
Border Radius
Rounded corners add softness and friendliness to our UI.
Component-Specific Radii
| Component | Border Radius | Tailwind |
|---|---|---|
| Modals (center) | 16px | rounded-2xl |
| Blade/Drawer panels | 28px | rounded-l-[28px] |
| Cards | 12px | rounded-xl |
| Buttons (primary) | 9999px | rounded-full |
| Buttons (secondary) | 10px | rounded-[10px] |
| Inputs | 10px | rounded-[10px] |
| Tags/Badges | 9999px | rounded-full |
| Tables | 12px | rounded-xl |
Shadows & Elevation
Shadows create depth and hierarchy in our interface.
Inputs
Form inputs with consistent styling and focus states.
Standard Input
Dark Theme Input
.input {
padding: 12px 14px;
font-size: 15px;
background: var(--bg-surface-soft);
border: 1px solid rgba(148, 163, 184, 0.35);
border-radius: 10px;
transition: all 200ms;
}
.input:focus {
border-color: #2563eb;
background: #ffffff;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}
Cards
Cards group related content with subtle elevation.
Standard Card
Hover to see the lift effect. Cards have 12px radius and subtle shadow.
Revenue
12%vs last month
Info Panel
Modals & Blades
Modals appear centered with backdrop; Blades slide in from the right edge for detail views.
Modal Types
| Type | Width | Border Radius | Use Case |
|---|---|---|---|
| Center Modal | min(560px, 90vw) | 16px | Confirmations, forms, settings |
| Blade Panel | min(720px, 94vw) | 28px left | Detail views, task panels |
| Wide Blade | min(960px, 94vw) | 28px left | Complex editors, large forms |
Blade Anatomy
Blade Styling
/* Blade Panel */
w-[min(720px,94vw)]
bg-bg-surface
border-l border-border-soft
rounded-l-[28px]
shadow-[-20px_0_44px_rgba(12,18,30,0.35)]
animate-[slideIn_0.22s_ease-out]
/* Mobile: Full width, no radius */
max-[640px]:w-full
max-[640px]:rounded-none
Backdrop Overlay
/* Blade overlay - darker */
bg-black/50
/* Modal overlay - lighter */
bg-slate-900/30 backdrop-blur-sm
Modal UX Requirements
role="dialog" aria-modal="true"
Badges & Tags
Use badges for status indicators and tags for categorization.
Status Badges
Tags
Accordions
Collapsible panels for settings, filters, and grouped content. Use for progressive disclosure.
Single-Panel Accordion
Use for settings sections, FAQs, and grouped form fields. Chevron rotates on expand. Include aria-expanded and aria-label for accessibility.
Configure how you receive notifications. You can toggle email digests, push alerts, and in-app reminders.
<!-- Use src/components/settings/Accordion.tsx -->
<Accordion title="Section title" defaultOpen={false} description="Optional subtext">
{children}
</Accordion>
Filter Accordion
Use for workspace filters (date range, dimensions, metrics). Summary shows active filter state; panel contains filter controls.
<!-- Use WorkspaceFiltersAccordion -->
<WorkspaceFiltersAccordion
title="Filters"
summary="Last 30 days · 3 metrics"
sections={filterSections}
defaultOpen={false}
/>
Accordion UX Guidelines
button or summary as trigger; ensure aria-expanded and aria-label
Workflow Steps
Steppers and step lists for onboarding, wizards, integrations, and campaign phase displays.
Horizontal Stepper
Use for multi-step forms (signup, onboarding, task creation). Connect steps with a line; current step uses accent; completed steps show checkmark.
/* States: .completed, .active, (default = upcoming) */
.ds-stepper-item.completed .ds-stepper-dot { /* checkmark, green */ }
.ds-stepper-item.active .ds-stepper-dot { /* accent, current */ }
/* Connector line turns accent when preceding step completed */
Vertical Step List (Sidebar)
Use in wizards (e.g. SignupWizard) as a clickable sidebar. Current step highlighted with accent.
Phase Accordion (Campaign / Workflow)
Use for campaign phases and workflow steps (e.g. CampaignDetailScreen). Each phase is an accordion; steps nest inside.
<!-- WhitelabelChatApp: AccordionItem -->
<AccordionItem title="Phase name" isPhase={true}>
{phase.steps.map(step => <StepRow key={step.id} {...step} />)}
</AccordionItem>
Workflow Steps UX Guidelines
Toggle Switch
Toggle switches for binary on/off settings.
Loading States
Provide visual feedback during async operations to reduce perceived wait time.
Loading Spinner
Use for quick operations (< 3 seconds).
.spinner {
width: 28px;
height: 28px;
border: 3px solid var(--border-soft);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
Skeleton Loader
Use when loading structured content (cards, lists, tables).
.skeleton {
background: linear-gradient(90deg,
var(--bg-surface-soft) 0%,
var(--bg-surface) 50%,
var(--bg-surface-soft) 100%);
background-size: 200% 100%;
animation: shimmer 1.5s ease-in-out infinite;
border-radius: 4px;
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
Button Loading State
Loading UX Guidelines
aria-label="Loading" on spinner containers
Empty States
Guide users when there's no data to display with helpful messaging and actions.
Standard Empty State
No items to display
Rich Empty State (with Action)
No projects yet
Create your first project to start organizing your work.
Copy Guidelines
| Element | Guidelines |
|---|---|
| Icon | Related to content type (inbox, folder, chart, etc.) |
| Title | Describe what's missing ("No products", "No results") |
| Description | Explain why it's empty or how to fix it |
| Action | Primary action to create/add content (optional) |
Error Handling
Gracefully handle errors with clear messaging and recovery options.
Inline Error
Use below form fields or in small UI areas.
Please enter a valid email address
Error Card
Use for section-level or page-level errors.
Something went wrong
We couldn't load your data. Please try again.
Error UX Guidelines
Toast Notifications
Non-blocking, ephemeral messages for system feedback and confirmations.
Toast Types
Toast Styling
.toast {
min-width: 260px;
max-width: 360px;
padding: 10px 12px;
border-radius: 10px;
background: var(--bg-surface);
border: 1px solid var(--border-soft);
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.35);
font-size: 13px;
}
.toast.success { border-color: #16a34a; }
.toast.error { border-color: #dc2626; }
.toast.info { border-color: #2563eb; }
Toast UX Guidelines
| Rule | Details |
|---|---|
| Position | Bottom-right on desktop, top-center on mobile |
| Duration | Success: 3s, Error: 5s (or until dismissed) |
| Dismissal | Auto-dismiss or click to close |
| Stacking | Stack newest on top, max 3 visible |
Form Validation
Validate input as users type and on submission for immediate feedback.
Validation Timing
| Event | Behavior |
|---|---|
| On blur | Validate when field loses focus (first touch) |
| On change | Re-validate on change after first error shown |
| On submit | Validate all fields, focus first error |
Validation States
This field is required
Looks good!
Error Message Placement
<div class="input-group">
<label class="input-label">Email</label>
<input
type="email"
class="input input--error"
aria-invalid="true"
aria-describedby="email-error"
/>
<p id="email-error" class="field-error">
Please enter a valid email
</p>
</div>
Button States During Submission
Left: Ready | Center: Submitting | Right: Disabled (invalid form)
Animations
Consistent motion creates a polished, responsive feel.
Timing & Easing
| Type | Duration | Easing | Usage |
|---|---|---|---|
| Fast | 100ms | ease | Button press feedback |
| Normal | 180-200ms | ease-out | Hovers, color transitions |
| Smooth | 220ms | ease-out | Modals, panels |
| Slow | 300ms | ease-in-out | Complex transitions |
Animation Previews
Accessibility (WCAG 2.2 AA)
All components must meet WCAG 2.2 Level AA standards.
Color Contrast Requirements
| Element Type | Minimum Ratio |
|---|---|
| Normal text (< 18px) | 4.5:1 |
| Large text (≥ 18px or 14px bold) | 3:1 |
| UI components | 3:1 |
Critical Rules
Contrast Examples
Focus States
All interactive elements must have visible focus indicators:
.focusable:focus-visible {
outline: none;
box-shadow: 0 0 0 2px var(--accent),
0 0 0 4px rgba(199, 240, 39, 0.3);
}
Keyboard Navigation
All functionality must be operable via keyboard.
Focus Management Rules
Focus Trap Pattern
// Escape key handler for modals
useEffect(() => {
const handleEscape = (e) => {
if (e.key === 'Escape') onClose();
};
document.addEventListener('keydown', handleEscape);
return () => document.removeEventListener('keydown', handleEscape);
}, [onClose]);
Standard Keyboard Shortcuts
| Key | Action |
|---|---|
Tab | Move focus forward |
Shift + Tab | Move focus backward |
Enter / Space | Activate focused element |
Escape | Close modal/dropdown/popover |
Arrow keys | Navigate within components (menus, tabs) |
Responsive Breakpoints
Mobile-first breakpoints for responsive design.
| Token | Width | Usage |
|---|---|---|
xs | 480px | Small phones |
sm | 600px | Large phones / small tablets |
md | 768px | Tablets |
lg | 960px | Small desktops |
xl | 1280px | Large desktops |
Media Query Patterns
/* Mobile-first (min-width) */
@media (min-width: 768px) { /* md and up */ }
@media (min-width: 960px) { /* lg and up */ }
/* Desktop-first (max-width) */
@media (max-width: 767px) { /* below md */ }
@media (max-width: 639px) { /* mobile only */ }
Tailwind Examples
<!-- Mobile: full width, Desktop: 1/3 width -->
<div class="w-full md:w-1/3">
<!-- Hide on mobile -->
<div class="hidden md:block">
<!-- Mobile-only -->
<div class="block md:hidden">
CSS Variables Reference
Complete list of CSS custom properties for theming.
:root {
/* Layout */
--left-width: 260px;
--right-width: 360px;
--divider-width: 10px;
--min-panel-width: 180px;
/* Backgrounds */
--bg-app: #f3f4f6;
--bg-sidebar: #05060b;
--bg-surface: #ffffff;
--bg-surface-soft: #f9fafb;
/* Borders */
--border-soft: #e5e7eb;
--border-strong: #111827;
/* Accent */
--accent: #C7F027;
--accent-soft: #f8ffbf;
/* Text */
--text-main: #111827;
--text-muted: #6b7280;
--text-on-dark: #f9fafb;
--text-on-accent: #0f172a;
/* Status */
--color-success: #22c55e;
--color-error: #ef4444;
--color-warning: #f97316;
--color-info: #3b82f6;
/* Font */
--font-sans: 'Manrope', system-ui, -apple-system,
BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', sans-serif;
}