Zenoba Design System
Complete guide to tokens, colors, typography and visual components. Direction A — inspired by Linear and Stripe.
Design Philosophy
The Zenoba design system follows a minimalist approach inspired by Linear, Stripe and Vercel. Every element serves a functional purpose. No superfluous decoration, no distracting visual effects. The interface must be calm, intelligent and professional.
Simple by default
Advanced features are hidden until the user needs them. Strict progressive disclosure.
Powerful on demand
Configuration tools, advanced filters and expert views are accessible without overloading the main interface.
Visual precision
4px grid, 1px hairline borders, lightweight typography (font-weight 400-500). Zero visual noise.
Color Palette
Brand and accents
Semantic colors
Surfaces and text — Light mode
Surfaces and text — Dark mode
/* CSS */
.card { background: var(--surface); border: 1px solid var(--border); }
.label { color: var(--foreground-muted); }
/* Tailwind */
<div className="bg-surface border border-border text-foreground" />
<span className="text-foreground-muted" />Typography
Primary font: Geist Sans (Vercel). Fallback: Inter, system-ui. Headings use font-weight 500 (medium). Body text uses font-weight 400 (regular). Bold (700) is NEVER used in the interface — it breaks the visual balance of the design system.
text-3xl font-mediumtext-xl font-mediumtext-base font-mediumtext-sm (corps de texte)text-xs text-foreground-mutedForbidden: font-bold / font-weight: 700. Only use font-medium (500) for headings and font-normal (400) for body text.
Border Radius
Constrained radius scale. Each context has its predefined radius. Do not invent intermediate values.
--radius-sminputs--radius-mdcards--radius-lgmodals--radius-xlpanelsrounded-full (9999px)Shadows
The Zenoba design system replaces shadows with 1px hairline borders (Linear style). Classic box-shadows are not used on cards and sections. Exception: popovers, dropdowns and modals use --shadow-md for elevation.
/* Pas de box-shadow generiques dans le design system Zenoba. On utilise des bordures hairline 1px a la place. */ /* Correct */ <div className="border border-border" /> /* Incorrect */ <div className="shadow-lg" /> /* Ne pas utiliser */ /* Exceptions : les popover/dropdown utilisent --shadow-md */ --shadow-md: 0 2px 8px rgba(0,0,0,0.06), 0 0 0 1px rgba(0,0,0,0.04);
Spacing
Base grid: 4px. All spacings (padding, margin, gap) must be multiples of 4px. This ensures pixel-perfect alignment across the entire interface.
/* Base : 4px (Tailwind : 1 unit = 4px) */ p-1 = 4px p-2 = 8px p-3 = 12px p-4 = 16px p-5 = 20px p-6 = 24px gap-1 = 4px gap-2 = 8px gap-3 = 12px gap-4 = 16px gap-6 = 24px gap-8 = 32px
CSS Variables and Tailwind Classes
All components use CSS variables (custom properties) that automatically switch between light and dark modes. Here is the mapping between variables, values and Tailwind classes.
--foreground#171717text-foreground--foreground-muted#737373text-foreground-muted--foreground-subtle#A3A3A3text-foreground-subtle--background#FAFAFAbg-background--surface#FFFFFFbg-surface--surface-hover#F5F5F5bg-surface-hover--border#E5E5E5border-border--border-subtle#F0F0F0border-border-subtle--primaryvar(--primary)bg-primary / text-primary--successvar(--success)text-success--warningvar(--warning)text-warning--dangervar(--danger)text-dangerButtons
Four button variants: Primary (main action), Gradient CTA (marketing pages), Outline (secondary actions) and Ghost (tertiary actions). Standard height: 36px (h-9). Border radius: 10px.
/* Primary */ <button className="h-9 px-4 rounded-[10px] bg-primary text-white text-sm font-medium hover:bg-primary-hover transition-colors"> /* Gradient CTA (pages marketing) */ <button className="h-9 px-4 rounded-[10px] bg-gradient-to-r from-primary to-accent text-white text-sm font-medium hover:opacity-90 transition-opacity"> /* Outline */ <button className="h-9 px-4 rounded-[10px] border border-border bg-surface text-foreground text-sm font-medium hover:bg-surface-hover transition-colors"> /* Ghost */ <button className="h-9 px-4 rounded-[10px] text-foreground-muted text-sm font-medium hover:bg-surface-hover hover:text-foreground transition-colors">
Icons
Exclusive library: Lucide React. StrokeWidth fixed at 1.75 (thinner than default). No emoji in code. Sizes adapted to usage context.
import { Plus, Settings, Trash2 } from 'lucide-react';
/* Standard : strokeWidth 1.75, taille adaptee au contexte */
<Plus size={16} strokeWidth={1.75} className="text-foreground" />
<Settings size={14} strokeWidth={1.75} className="text-foreground-muted" />
<Trash2 size={14} strokeWidth={1.75} className="text-danger" />Dark Mode
Dark mode uses the .dark class on the HTML root. CSS variables switch automatically — no dark: prefix is needed for design system tokens. Exception: native Tailwind colors (bg-blue-50) require a dark: override.
/* globals.css — les tokens basculent automatiquement */
:root {
--background: #FAFAFA;
--surface: #FFFFFF;
--foreground: #171717;
--border: #E5E5E5;
--primary: var(--primary);
}
.dark {
--background: #0A0A0B;
--surface: #141414;
--foreground: #FAFAFA;
--border: #262626;
--primary: #6B6CFF;
}
/* Pas besoin de dark: prefix dans les composants.
Les classes Tailwind (bg-surface, text-foreground, border-border)
utilisent les CSS variables qui basculent automatiquement. */
/* Exception : couleurs Tailwind natives */
<div className="bg-blue-50 dark:bg-blue-950/30" />Anti-patterns
No Bootstrap components, no .btn, .card, .container Bootstrap classes. Zenoba uses exclusively Tailwind + CSS variables.
No MUI components, no ripple effects, no Material elevation. Zenoba aesthetics are flatter and more minimalist.
Maximum font-weight is 500 (medium). Bold 700 breaks the visual balance. Use font-medium for headings, font-normal for text.
No shadow-lg, shadow-xl, shadow-2xl. Cards use 1px hairline borders (border-border). Only popovers have a light shadow.
No excessive backdrop-blur, no decorative transparency, no colored background gradient. The background is opaque and neutral.
Use Lucide icons for all iconography. Emoji are reserved for user content (chat, comments), never in the system interface.
Avatars
Avatars are generated by the Boring Avatars library (same lib as Linear). The palette uses the 5 Zenoba brand colors. The UserAvatar component accepts a name (unique SVG generation), a real photo (src), an online indicator and several visual variants.
import { UserAvatar } from '@/components/shared/user-avatar';
/* Palette Zenoba : var(--primary), var(--secondary), var(--accent), var(--success), var(--warning) */
/* Avatar genere (boring-avatars, variant beam) */
<UserAvatar name="Khalid Amrani" size={32} />
/* Avec indicateur en ligne */
<UserAvatar name="Khalid Amrani" size={32} online />
/* Avec photo reelle */
<UserAvatar name="Marie Roy" size={40} src="/avatars/marie.jpg" />
/* Variantes disponibles : beam, marble, pixel, sunset, ring, bauhaus */
<UserAvatar name="Jean Doe" variant="marble" />