# DESIGN-SYSTEM.md — ICAVI GESTION
*Rédigé le 2026-10-08 — basé sur la charte ICAVI SECURE + audit CSS existant*

---

## 1. FONDATIONS — IDENTITÉ DE MARQUE

### Couleurs de marque

```css
/* Palette ICAVI SECURE officielle */
--brand-50:  #eef1f8;   /* fonds très légers */
--brand-100: #d4daea;
--brand-200: #a9b5d5;
--brand-300: #7e90bf;
--brand-400: #536baa;
--brand-500: #1e2c54;   /* ← BLEU MARINE PRINCIPAL (identité) */
--brand-600: #192548;
--brand-700: #141d39;
--brand-800: #0f162b;
--brand-900: #0a0e1c;

--accent:    #f8e800;   /* ← JAUNE ICAVI */
--accent-dim:#c6ba00;   /* Jaune foncé pour état hover/active */
```

### Sémantique des couleurs (tokens CSS)

Ces tokens sont les seuls à utiliser dans les composants. Jamais les valeurs brutes directement.

```css
:root {
  /* Fond */
  --color-background:    #f4f6fb;   /* Fond général de l'application */
  --color-surface:       #ffffff;   /* Cartes, modales, panels */
  --color-surface-raised:#f8f9fc;   /* Surface légèrement surélevée */

  /* Contenu */
  --color-primary:       var(--brand-500);   /* #1e2c54 — actions principales */
  --color-primary-hover: var(--brand-600);
  --color-accent:        var(--accent);      /* #f8e800 — mise en valeur */

  /* Texte */
  --color-text-primary:  #111827;   /* Gris très foncé */
  --color-text-secondary:#4b5563;   /* Gris médium */
  --color-text-muted:    #9ca3af;   /* Gris clair */
  --color-text-inverted: #ffffff;   /* Sur fond sombre */

  /* Bordures */
  --color-border:        #e5e7eb;   /* Bordure standard */
  --color-border-strong: #d1d5db;   /* Bordure visible */

  /* États sémantiques */
  --color-success:       #16a34a;
  --color-success-light: #dcfce7;
  --color-warning:       #d97706;
  --color-warning-light: #fef3c7;
  --color-error:         #dc2626;
  --color-error-light:   #fee2e2;
  --color-info:          #2563eb;
  --color-info-light:    #dbeafe;

  /* Layout */
  --sidebar-w:           264px;
  --topbar-h:            64px;

  /* Effets */
  --radius-sm:           4px;
  --radius-md:           8px;
  --radius-lg:           12px;
  --radius-xl:           16px;
  --radius-full:         9999px;

  --shadow-sm:   0 1px 2px 0 rgb(0 0 0 / 0.05);
  --shadow-md:   0 4px 6px -1px rgb(0 0 0 / 0.10), 0 2px 4px -2px rgb(0 0 0 / 0.10);
  --shadow-lg:   0 10px 15px -3px rgb(0 0 0 / 0.10), 0 4px 6px -4px rgb(0 0 0 / 0.10);
  --shadow-brand:0 4px 14px 0 rgb(30 44 84 / 0.25);

  /* Transitions */
  --transition-fast:     150ms ease;
  --transition-base:     200ms ease;
  --transition-slow:     300ms ease;
}
```

---

## 2. TYPOGRAPHIE

### Police principale : Inter

```css
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

:root {
  --font-sans: 'Inter', system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
}

body {
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-text-primary);
  -webkit-font-smoothing: antialiased;
}
```

### Échelle typographique

| Token | Taille | Poids | Usage |
|---|---|---|---|
| `text-xs` | 11px | 400 | Labels, métadonnées |
| `text-sm` | 13px | 400/500 | Corps secondaire, tableaux |
| `text-base` | 14px | 400 | Corps principal |
| `text-md` | 15px | 500 | Emphasis, sous-titres |
| `text-lg` | 18px | 600 | Titres de sections |
| `text-xl` | 22px | 700 | Titres de pages |
| `text-2xl` | 28px | 700 | Grandes métriques dashboard |
| `text-3xl` | 36px | 700 | KPI héros |

```tsx
// Composant typographique
// components/ui/Typography.tsx
export function PageTitle({ children }: { children: React.ReactNode }) {
  return <h1 className="text-xl font-bold text-gray-900 tracking-tight">{children}</h1>;
}
export function SectionTitle({ children }: { children: React.ReactNode }) {
  return <h2 className="text-lg font-semibold text-gray-900">{children}</h2>;
}
export function Label({ children }: { children: React.ReactNode }) {
  return <span className="text-xs font-medium text-gray-500 uppercase tracking-wider">{children}</span>;
}
```

---

## 3. LAYOUT DE L'APPLICATION

### Structure globale

```
┌─────────────────────────────────────────────────────────┐
│  TOPBAR (height: 64px)                                   │
│  [Logo ICAVI]  [Breadcrumb]  [Notifs] [Avatar user]     │
├──────────────┬──────────────────────────────────────────┤
│  SIDEBAR     │  CONTENU PRINCIPAL                       │
│  (264px)     │  padding: 24px                           │
│              │                                           │
│  Navigation  │  <PageHeader>                            │
│  par module  │    <Title> + <Actions>                   │
│              │  </PageHeader>                           │
│              │                                           │
│              │  <PageContent>                           │
│              │    ...composants métier...               │
│              │  </PageContent>                          │
│              │                                           │
│  [Version]   │                                           │
└──────────────┴──────────────────────────────────────────┘
```

### Sidebar

```tsx
// Couleur fond sidebar : brand-500 (#1e2c54) — blanc sur fond bleu marine
// Logo : icavi-logo.png centré en haut
// Items nav : icône + label, hover/active avec fond bleu plus clair

const SidebarItem = ({ icon: Icon, label, to, isActive }) => (
  <Link
    to={to}
    className={cn(
      "flex items-center gap-3 px-4 py-2.5 rounded-lg text-sm font-medium transition-colors",
      isActive
        ? "bg-white/15 text-white"
        : "text-brand-200 hover:bg-white/10 hover:text-white"
    )}
  >
    <Icon size={18} />
    <span>{label}</span>
  </Link>
);
```

### Topbar

```tsx
// Fond blanc, bordure bottom, shadow légère
// Gauche : hamburger (mobile) + breadcrumb
// Droite : icône notif + avatar + nom utilisateur + rôle

const Topbar = () => (
  <header className="h-16 bg-white border-b border-gray-200 flex items-center justify-between px-6 shadow-sm">
    <Breadcrumb />
    <div className="flex items-center gap-4">
      <NotificationBell />
      <UserMenu />
    </div>
  </header>
);
```

### Grille de contenu

```tsx
// Cartes statistiques dashboard
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
  {stats.map(stat => <StatCard key={stat.key} {...stat} />)}
</div>

// Contenu à deux colonnes
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
  <div className="lg:col-span-2">{/* Liste principale */}</div>
  <div>{/* Panneau latéral */}</div>
</div>
```

---

## 4. COMPOSANTS — CATALOGUE

### 4.1 Button

```tsx
// Variantes : primary, secondary, ghost, danger, accent
// Tailles : sm, md (default), lg
// États : default, hover, active, disabled, loading

// PRIMARY — Bouton principal (actions CTA)
<button className="
  inline-flex items-center gap-2 px-4 py-2
  bg-brand-500 hover:bg-brand-600
  text-white text-sm font-medium
  rounded-lg transition-colors
  disabled:opacity-50 disabled:cursor-not-allowed
">

// SECONDARY — Action secondaire
<button className="
  inline-flex items-center gap-2 px-4 py-2
  bg-white hover:bg-gray-50
  text-gray-700 text-sm font-medium
  border border-gray-200
  rounded-lg transition-colors
">

// ACCENT — Action mise en valeur (jaune ICAVI)
<button className="
  inline-flex items-center gap-2 px-4 py-2
  bg-accent hover:bg-accent-dim
  text-brand-500 text-sm font-bold
  rounded-lg transition-colors
">

// DANGER — Suppression, annulation
<button className="
  inline-flex items-center gap-2 px-4 py-2
  bg-red-600 hover:bg-red-700
  text-white text-sm font-medium
  rounded-lg transition-colors
">

// GHOST — Action tertiaire, liens
<button className="
  inline-flex items-center gap-2 px-4 py-2
  hover:bg-gray-100
  text-gray-600 text-sm font-medium
  rounded-lg transition-colors
">
```

### 4.2 Card

```tsx
// Card standard
<div className="bg-white rounded-xl border border-gray-200 shadow-sm p-6">
  {children}
</div>

// Card avec header
<div className="bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden">
  <div className="px-6 py-4 border-b border-gray-100 flex items-center justify-between">
    <h3 className="text-base font-semibold text-gray-900">{title}</h3>
    {action}
  </div>
  <div className="p-6">{children}</div>
</div>
```

### 4.3 StatCard (Dashboard)

```tsx
// Carte de statistique avec icône, valeur et tendance
interface StatCardProps {
  label: string;
  value: string | number;
  icon: LucideIcon;
  trend?: { value: number; positive: boolean };
  color?: 'brand' | 'green' | 'yellow' | 'red';
}

// Rendu :
// ┌─────────────────────────────────┐
// │ [Icône colorée]      [+12% ↑]  │
// │                                 │
// │ 1 234 567                       │
// │ Chiffre d'affaires total        │
// └─────────────────────────────────┘
```

### 4.4 DataTable

```tsx
// Table de données avec : tri, pagination, recherche, actions par ligne
// Colonnes configurables, responsive (scroll horizontal mobile)

interface Column<T> {
  key: keyof T | string;
  header: string;
  render?: (value: unknown, row: T) => React.ReactNode;
  sortable?: boolean;
  width?: string;
}

// En-tête de colonne triable :
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-50 select-none">
  <div className="flex items-center gap-1">
    {column.header}
    <SortIcon direction={sortDirection} />
  </div>
</th>

// Ligne de données :
<tr className="border-b border-gray-100 hover:bg-gray-50 transition-colors">
  {columns.map(col => (
    <td className="px-4 py-3 text-sm text-gray-900">{...}</td>
  ))}
</tr>

// État vide :
<div className="flex flex-col items-center justify-center py-16 text-gray-400">
  <Icon size={48} strokeWidth={1} />
  <p className="mt-3 text-sm">{emptyMessage}</p>
</div>
```

### 4.5 Badge (Statuts)

```tsx
// Statuts documents
const STATUS_STYLES = {
  EN_COURS:            'bg-blue-100 text-blue-700',
  VALIDE:              'bg-green-100 text-green-700',
  LIVRE:               'bg-green-100 text-green-700',
  EN_COURS_LIVRAISON:  'bg-yellow-100 text-yellow-700',
  ENVOYE:              'bg-indigo-100 text-indigo-700',
  REFUSE:              'bg-red-100 text-red-700',
  FACTURE:             'bg-purple-100 text-purple-700',
  // Client
  active:              'bg-green-100 text-green-700',
  prospect:            'bg-blue-100 text-blue-700',
  inactive:            'bg-gray-100 text-gray-500',
  // Stock
  ok:                  'bg-green-100 text-green-700',
  low:                 'bg-yellow-100 text-yellow-700',
  critical:            'bg-red-100 text-red-700',
};

const Badge = ({ status, label }) => (
  <span className={cn(
    "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium",
    STATUS_STYLES[status] ?? 'bg-gray-100 text-gray-600'
  )}>
    {label ?? status}
  </span>
);
```

### 4.6 Form Fields

```tsx
// Input text standard
<div className="space-y-1.5">
  <label className="block text-sm font-medium text-gray-700">
    {label} {required && <span className="text-red-500">*</span>}
  </label>
  <input
    className={cn(
      "w-full px-3 py-2 text-sm rounded-lg border transition-colors",
      "placeholder:text-gray-400 focus:outline-none focus:ring-2",
      error
        ? "border-red-300 focus:border-red-400 focus:ring-red-100"
        : "border-gray-200 focus:border-brand-400 focus:ring-brand-100"
    )}
  />
  {error && <p className="text-xs text-red-600">{error}</p>}
  {hint  && <p className="text-xs text-gray-500">{hint}</p>}
</div>

// Select (natif + custom)
// Textarea
// Checkbox / Switch
// Date picker (react-day-picker ou input[type=date])
```

### 4.7 Modal / Dialog

```tsx
// Modales via shadcn/ui Dialog
// Largeurs : sm (400px), md (560px), lg (720px), xl (900px)
// Toujours avec : titre, description, boutons d'action, croix de fermeture
// Animation : fade + scale (framer-motion ou CSS)

// Pattern standard :
<Dialog open={open} onOpenChange={setOpen}>
  <DialogContent className="max-w-lg">
    <DialogHeader>
      <DialogTitle>Confirmer la suppression</DialogTitle>
      <DialogDescription>Cette action est irréversible.</DialogDescription>
    </DialogHeader>
    <div>{/* Contenu */}</div>
    <DialogFooter>
      <Button variant="ghost" onClick={() => setOpen(false)}>Annuler</Button>
      <Button variant="danger" onClick={handleConfirm}>Supprimer</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>
```

### 4.8 Toast / Notifications

```tsx
// Toasts via sonner (bibliothèque légère, compatible shadcn/ui)
import { toast } from 'sonner';

// Succès
toast.success("Document créé avec succès");

// Erreur
toast.error("Erreur lors de la création du document");

// Confirmation avec action
toast("Stock mis à jour", {
  description: "15 unités ajoutées au produit.",
  action: { label: "Voir", onClick: () => navigate('/stock') },
});

// Position : bottom-right par défaut
// Durée : 4 secondes
```

### 4.9 PageHeader

```tsx
// En-tête de page standard
interface PageHeaderProps {
  title: string;
  subtitle?: string;
  breadcrumb?: BreadcrumbItem[];
  actions?: React.ReactNode;
}

const PageHeader = ({ title, subtitle, actions }) => (
  <div className="flex items-start justify-between mb-6">
    <div>
      <h1 className="text-xl font-bold text-gray-900">{title}</h1>
      {subtitle && <p className="mt-0.5 text-sm text-gray-500">{subtitle}</p>}
    </div>
    {actions && <div className="flex items-center gap-3">{actions}</div>}
  </div>
);
```

---

## 5. ÉTATS DE L'INTERFACE

### États des données (TanStack Query)

```tsx
// Pattern standard pour chaque page de liste
const { data, isLoading, isError, error } = useQuery(...);

if (isLoading) return <TableSkeleton rows={10} />;
if (isError)   return <ErrorState message={error.message} onRetry={refetch} />;
if (!data?.data?.length) return <EmptyState icon={FileX} message="Aucun document trouvé" />;

return <DataTable data={data.data} columns={columns} />;
```

### Skeleton Loading

```tsx
// Skeleton pour les tableaux (éviter le layout shift)
const TableSkeleton = ({ rows = 5 }) => (
  <div className="space-y-2">
    {Array.from({ length: rows }).map((_, i) => (
      <div key={i} className="h-12 bg-gray-100 rounded animate-pulse" />
    ))}
  </div>
);

// Skeleton pour les cartes stat
const StatCardSkeleton = () => (
  <div className="bg-white rounded-xl border p-6 animate-pulse">
    <div className="h-4 w-24 bg-gray-200 rounded mb-4" />
    <div className="h-8 w-32 bg-gray-200 rounded" />
  </div>
);
```

### États vides

```tsx
const EmptyState = ({ icon: Icon, title, message, action }) => (
  <div className="flex flex-col items-center justify-center py-20 text-center">
    <div className="w-16 h-16 rounded-full bg-gray-100 flex items-center justify-center mb-4">
      <Icon size={28} className="text-gray-400" strokeWidth={1.5} />
    </div>
    {title  && <h3 className="text-base font-semibold text-gray-900 mb-1">{title}</h3>}
    {message && <p className="text-sm text-gray-500 max-w-sm">{message}</p>}
    {action  && <div className="mt-6">{action}</div>}
  </div>
);
```

### États d'erreur

```tsx
const ErrorState = ({ message, onRetry }) => (
  <div className="flex flex-col items-center justify-center py-20 text-center">
    <div className="w-16 h-16 rounded-full bg-red-50 flex items-center justify-center mb-4">
      <AlertCircle size={28} className="text-red-500" />
    </div>
    <h3 className="text-base font-semibold text-gray-900 mb-1">Une erreur est survenue</h3>
    <p className="text-sm text-gray-500 mb-6">{message}</p>
    {onRetry && <Button variant="secondary" onClick={onRetry}>Réessayer</Button>}
  </div>
);
```

---

## 6. PATTERNS UX PAR MODULE

### 6.1 Dashboard

```
┌─────────────────────────────────────────────────────────┐
│ Bonjour, [Prénom] ─ [date du jour]                      │
├────────┬────────┬────────┬────────────────────────────-─┤
│ Clients│Products│Low Stk │ Chiffre d'affaires           │
│  142   │  89    │   5 ⚠  │  12 450 000 FCFA             │
├────────┴────────┴────────┴──────────────────────────────┤
│ GRAPHIQUE MENSUEL (Recharts LineChart)                   │
│ Revenus par mois, sélecteur d'année                     │
├─────────────────────────┬───────────────────────────────┤
│ Dernières ventes (5)    │ Stocks faibles (5)            │
│ Tableau compact         │ Liste avec jauge              │
├─────────────────────────┴───────────────────────────────┤
│ Relances client dues                                     │
│ (10 contacts à rappeler aujourd'hui)                     │
└─────────────────────────────────────────────────────────┘
```

### 6.2 Documents

```
État du workflow documents :
PRO (EN_COURS → VALIDE) → FAC (VALIDE) → BL (EN_COURS_LIVRAISON → LIVRE)
              ↑
           DEV/BC/AVO (états propres)

Boutons contextuels selon statut courant :
- PRO EN_COURS  → [Valider] [Générer Facture] [Télécharger PDF]
- FAC VALIDE    → [Générer BL] [Télécharger PDF]
- BL EN_COURS   → [Marquer Livré] [Télécharger PDF]
- Tout doc      → [Demander suppression] (si non-admin)
                  [Approuver/Refuser suppression] (si admin)
```

### 6.3 Stock

```
Liste avec indicateurs visuels :
- Barre de progression colorée (vert/jaune/rouge selon seuil)
- Badge "CRITIQUE" / "FAIBLE" / "OK"
- Bouton "Entrée stock" rapide sur chaque ligne
- Filtre par : tous / faibles / critiques / catégorie
```

### 6.4 Bons de caisse

```
Workflow selon rôle :
EMPLOYÉ : voit uniquement ses bons + peut créer
MANAGER : voit tous les bons de son équipe + peut payer
DIRECTEUR : signe (signature numérique de M. Raymond)
           → action disponible uniquement pour user signer_id

États : EN_ATTENTE → PAYÉ → REÇU_CONFIRMÉ | ANNULÉ
```

---

## 7. RESPONSIVE

L'application est principalement desktop (écrans 1280px+). Le responsive est néanmoins prévu pour une utilisation sur tablet (768px+).

```css
/* Breakpoints Tailwind conservés */
sm:  640px   (mobile landscape — pas de support complet)
md:  768px   (tablet portrait — sidebar collapsée en overlay)
lg:  1024px  (desktop — sidebar fixe)
xl:  1280px  (desktop standard — largeur cible principale)
2xl: 1536px  (grands écrans)
```

### Sidebar mobile

```
Mobile/Tablet (< 1024px) :
- Sidebar masquée par défaut
- Bouton hamburger dans la topbar
- Sidebar en overlay avec backdrop
- Fermeture au clic sur un lien ou sur le backdrop

Desktop (≥ 1024px) :
- Sidebar fixe, toujours visible
- Pas de bouton hamburger
```

---

## 8. ICÔNES

Bibliothèque : **lucide-react** (déjà utilisée dans le projet existant)

```tsx
import { 
  LayoutDashboard, Users, Package, BarChart3, 
  FileText, ShoppingCart, Warehouse, CreditCard, 
  Calendar, FolderOpen, Settings, Bell, 
  Search, Plus, Pencil, Trash2, Download, 
  Eye, ChevronRight, ChevronDown, X,
  AlertTriangle, CheckCircle, XCircle, Info,
  TrendingUp, TrendingDown, ArrowUpRight
} from 'lucide-react';
```

Tailles standard :
- Navigation sidebar : `size={18}`
- Boutons : `size={16}`  
- PageHeader actions : `size={16}`
- Icônes de statut : `size={14}`
- Icônes grandes (states vides) : `size={40}` avec `strokeWidth={1.5}`

---

## 9. ANIMATIONS ET TRANSITIONS

```css
/* Transitions standards (via Tailwind) */
.transition-colors  → couleurs hover/focus : 150ms ease
.transition-shadow  → ombres au survol : 200ms ease
.transition-transform → déplacements : 200ms ease

/* Page transitions */
/* Utiliser Framer Motion uniquement pour les transitions de pages (fade + slide)  */
/* Éviter les animations lourdes sur les composants de liste */

/* Skeleton shimmer */
@keyframes shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.animate-shimmer {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
}
```

---

## 10. ACCESSIBILITÉ

Points clés à respecter :

```tsx
// 1. Focus visible sur tous les éléments interactifs
// focus:ring-2 focus:ring-brand-400 focus:ring-offset-1

// 2. Labels ARIA sur les icônes seules
<button aria-label="Supprimer le client">
  <Trash2 size={16} aria-hidden="true" />
</button>

// 3. Rôles sémantiques
<nav aria-label="Navigation principale">
<main>
<section aria-labelledby="section-title">

// 4. Couleurs : ratio de contraste minimum 4.5:1 pour le texte
// brand-500 sur blanc : 7.2:1 ✓
// Texte gris (gray-700) sur blanc : 4.7:1 ✓

// 5. Taille minimale des zones de clic : 44×44px (boutons, liens nav)

// 6. Messages d'erreur liés aux champs (aria-describedby)
<input aria-describedby="email-error" aria-invalid={!!errors.email} />
<p id="email-error" className="text-red-600">{errors.email?.message}</p>
```

---

## 11. CONFIGURATION TAILWIND

```typescript
// tailwind.config.ts
import type { Config } from 'tailwindcss';

export default {
  content: ['./index.html', './src/**/*.{ts,tsx}'],
  theme: {
    extend: {
      colors: {
        brand: {
          50:  '#eef1f8',
          100: '#d4daea',
          200: '#a9b5d5',
          300: '#7e90bf',
          400: '#536baa',
          500: '#1e2c54',   // Bleu marine ICAVI
          600: '#192548',
          700: '#141d39',
          800: '#0f162b',
          900: '#0a0e1c',
        },
        accent: {
          DEFAULT: '#f8e800',
          dim:     '#c6ba00',
        },
      },
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
      },
      spacing: {
        sidebar: '264px',
        topbar:  '64px',
      },
      borderRadius: {
        DEFAULT: '8px',
      },
      boxShadow: {
        brand: '0 4px 14px 0 rgb(30 44 84 / 0.25)',
      },
    },
  },
  plugins: [
    require('@tailwindcss/forms'),
  ],
} satisfies Config;
```

---

## 12. RÈGLES ET CONVENTIONS

### Ce qu'on fait ✓

- Utiliser les tokens CSS (`--color-primary`, `--color-surface`) dans les custom styles
- Utiliser les classes Tailwind brand/accent pour les composants React
- Un seul niveau d'ombrage par composant (pas `shadow-md` + `shadow-lg` en même temps)
- Espacements multiples de 4px (gap-4, p-6, mt-2...)
- Toujours un état loading + empty + error pour chaque vue de données
- Feedback immédiat sur chaque action (toast + mutation optimiste si pertinent)

### Ce qu'on évite ✗

- Couleurs hardcodées (`#1e2c54` directement dans le JSX)
- Animations sur les listes longues (>50 items)
- Modales pour les confirmations simples (utiliser les inline confirm ou toast avec action)
- Text-white sur fond jaune `--accent` (contraste insuffisant → utiliser `text-brand-500`)
- Icônes sans label sur mobile
- Tableaux sans pagination côté serveur

---

## 13. ASSETS ICAVI

### Fichiers images (dans `public/assets/`)

| Fichier | Usage | Contrainte |
|---|---|---|
| `icavi-logo.png` | Sidebar (header), page login | Fond transparent |
| `icavi-secure-logo.jpg` | Documents PDF imprimés | - |
| `icavi-watermark.png` | Filigrane documents PDF | Opacité 0.08 |
| `Cachet ICAVI SECURE.png` | Documents PDF signés | Zone réservée droite |
| `Signature de Mr Raymond T..png` | Bons de caisse signés | ⚠️ Accès restreint côté backend, jamais exposé côté React |

### Utilisation du logo dans la sidebar

```tsx
// Sidebar header
<div className="px-6 py-5 border-b border-white/10">
  <img 
    src="/assets/icavi-logo.png" 
    alt="ICAVI SECURE" 
    className="h-8 w-auto"
  />
</div>
```
