26 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	🎨 Design System & Composants Visuels - Notytex Class Dashboard
Vue d'ensemble
Le Class Dashboard de Notytex représente l'excellence en matière d'interface utilisateur moderne, combinant une hiérarchie visuelle claire, des animations fluides et une adaptation responsive parfaite. Ce système de design privilégie l'experience utilisateur avec des interactions naturelles et des feedback visuels immédiats.
📐 Design System Global
🎨 Palette de Couleurs
Couleurs Primaires
/* Bleu - Action principale, navigation */
--primary-blue: #3B82F6
--primary-blue-dark: #1D4ED8
--primary-blue-light: #93C5FD
/* Gradient hero sections */
--gradient-indigo: from-indigo-600 to-purple-600
--gradient-blue: from-blue-50 to-indigo-100
Couleurs Sémantiques par État
/* Rouge - Urgence, non commencé */
--status-error: #EF4444
--status-error-bg: #FEF2F2
--status-error-border: #FECACA
/* Orange - En cours, attention */
--status-warning: #F59E0B  
--status-warning-bg: #FEF3C7
--status-warning-border: #FDE68A
/* Vert - Terminé, succès */
--status-success: #10B981
--status-success-bg: #ECFDF5
--status-success-border: #D1FAE5
/* Gris - Neutre, secondaire */
--neutral-gray: #6B7280
--neutral-gray-light: #F3F4F6
--neutral-gray-border: #E5E7EB
Couleurs Métier
/* Domaines d'évaluation */
--domain-green: #059669
--domain-green-bg: #ECFDF5
--domain-green-accent: #10B981
/* Compétences */
--competence-purple: #7C3AED
--competence-purple-bg: #F3E8FF
--competence-purple-accent: #8B5CF6
/* Résultats et statistiques */
--results-orange: #EA580C
--results-orange-bg: #FFF7ED
--results-orange-accent: #FB923C
📝 Typographie
Hiérarchie des Titres
/* H1 - Titre principal (Hero) */
.text-4xl.font-bold {
  font-size: 2.25rem;    /* 36px */
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.025em;
}
/* H2 - Titres de sections */
.text-xl.font-bold {
  font-size: 1.25rem;    /* 20px */
  font-weight: 700;
  line-height: 1.3;
  color: #1F2937;
}
/* H3 - Titres de cards */
.text-lg.font-semibold {
  font-size: 1.125rem;   /* 18px */
  font-weight: 600;
  line-height: 1.4;
  color: #374151;
}
Corps de Texte
/* Texte principal */
.text-base {
  font-size: 1rem;       /* 16px */
  line-height: 1.5;
  color: #374151;
}
/* Texte secondaire */
.text-sm {
  font-size: 0.875rem;   /* 14px */
  line-height: 1.4;
  color: #6B7280;
}
/* Texte de métadonnées */
.text-xs {
  font-size: 0.75rem;    /* 12px */
  line-height: 1.3;
  color: #9CA3AF;
}
Nombres et Statistiques
/* Gros nombres (moyennes) */
.text-3xl.font-bold {
  font-size: 1.875rem;   /* 30px */
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.025em;
}
📏 Système d'Espacement
Espacement Interne (Padding)
/* Cards principales */
.p-6 { padding: 1.5rem; }      /* 24px */
/* Sections compactes */
.p-4 { padding: 1rem; }        /* 16px */
/* Éléments fins */
.p-3 { padding: 0.75rem; }     /* 12px */
/* Micro-espacements */
.p-2 { padding: 0.5rem; }      /* 8px */
Espacement Externe (Margin)
/* Séparation entre sections */
.space-y-8 > * + * { margin-top: 2rem; }      /* 32px */
/* Séparation entre cards */
.space-y-6 > * + * { margin-top: 1.5rem; }    /* 24px */
/* Séparation entre éléments */
.space-y-4 > * + * { margin-top: 1rem; }      /* 16px */
Grid et Gaps
/* Gap principal (desktop) */
.gap-6 { gap: 1.5rem; }        /* 24px */
/* Gap réduit (mobile) */
.gap-4 { gap: 1rem; }          /* 16px */
/* Gap micro-interactions */
.gap-2 { gap: 0.5rem; }        /* 8px */
🔲 Système de Grilles
Grille Principale (Desktop)
/* Grid responsive 4 colonnes */
.grid-cols-1.md:grid-cols-2.lg:grid-cols-4 {
  grid-template-columns: 
    repeat(1, 1fr);              /* Mobile */
    repeat(2, 1fr);              /* Tablet */
    repeat(4, 1fr);              /* Desktop */
}
/* Statistics grid adaptatif */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1.5rem;
}
Layout Containers
/* Conteneur principal */
.max-w-7xl.mx-auto {
  max-width: 80rem;     /* 1280px */
  margin: 0 auto;
}
/* Padding container responsive */
.px-8.py-8 {
  padding: 2rem;        /* Desktop */
}
.px-4.py-6 {
  padding: 1.5rem 1rem; /* Mobile */
}
🧩 Composants Visuels Principaux
🏆 Hero Section
Structure & Style
<!-- Hero avec gradient et informations contextuelles -->
<div class="bg-gradient-to-r from-indigo-600 to-purple-600 text-white rounded-xl p-8 shadow-lg">
  <div class="flex items-center justify-between">
    <div class="flex-1">
      <h1 class="text-4xl font-bold mb-2">6ème A 🏫</h1>
      <p class="text-xl opacity-90 mb-1">Dashboard de gestion de classe</p>
      <div class="flex items-center space-x-6 text-sm opacity-75 mt-3">
        <!-- Métadonnées avec icônes -->
      </div>
    </div>
  </div>
</div>
Guidelines d'Usage
- Gradient: Toujours utiliser des gradients cohérents (from-indigo-600 to-purple-600)
- Contraste: Assurer un contraste minimum 4.5:1 sur le texte blanc
- Icônes: SVG inline 16x16px (w-4 h-4) pour les métadonnées
- Responsive: Masquer les éléments décoratifs sur mobile avec hidden md:block
🃏 Action Cards
Styles par Priorité
<!-- ROUGE - Priorité maximale -->
<a href="#" class="group bg-gradient-to-r from-red-500 to-red-600 text-white rounded-xl p-6 hover:from-red-600 hover:to-red-700 transition-all duration-300 transform hover:scale-[1.02] shadow-lg hover:shadow-xl">
<!-- VERT - Action positive -->
<a href="#" class="group bg-gradient-to-r from-green-500 to-green-600 text-white rounded-xl p-6 hover:from-green-600 hover:to-green-700 transition-all duration-300 transform hover:scale-[1.02] shadow-lg hover:shadow-xl">
<!-- BLEU - Action standard -->
<a href="#" class="group bg-gradient-to-r from-blue-500 to-blue-600 text-white rounded-xl p-6 hover:from-blue-600 hover:to-blue-700 transition-all duration-300 transform hover:scale-[1.02] shadow-lg hover:shadow-xl">
<!-- ORANGE - Informations -->
<a href="#" class="group bg-gradient-to-r from-orange-500 to-orange-600 text-white rounded-xl p-6 hover:from-orange-600 hover:to-orange-700 transition-all duration-300 transform hover:scale-[1.02] shadow-lg hover:shadow-xl">
Structure Interne
<div class="flex items-center">
  <!-- Icône avec hover effect -->
  <div class="w-12 h-12 bg-white/20 rounded-xl flex items-center justify-center mr-4 group-hover:bg-white/30 transition-colors">
    <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20">
      <!-- Icône SVG -->
    </svg>
  </div>
  
  <!-- Contenu textuel -->
  <div>
    <h3 class="text-lg font-bold mb-1">Titre Action</h3>
    <p class="text-sm opacity-90">Description contextuelle</p>
  </div>
</div>
Animations & Interactions
- Transform: hover:scale-[1.02]pour micro-zoom
- Shadow: Progression shadow-lg→shadow-xl
- Background: Gradient transition avec états hover
- Durée: transition-all duration-300pour fluidité
🏷️ Navigation par Trimestre (Tabs)
Structure HTML
<nav class="trimester-tabs" role="tablist" aria-label="Navigation par trimestre">
  <button data-trimester-tab="1" 
          class="trimester-tab active"
          role="tab" aria-selected="true">
    <div class="flex items-center">
      <div class="w-3 h-3 rounded-full bg-gradient-to-r from-blue-500 to-blue-600 mr-2"></div>
      Trimestre 1
    </div>
  </button>
</nav>
États Visuels
/* État actif */
.trimester-tab.active {
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  color: white;
  box-shadow: 0 4px 20px rgba(59, 130, 246, 0.3);
  transform: scale(1.02);
}
/* État inactif */
.trimester-tab:not(.active) {
  background: white;
  color: #374151;
  border: 2px solid #e5e7eb;
}
/* Hover inactif */
.trimester-tab:not(.active):hover {
  background: #f9fafb;
  border-color: #d1d5db;
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
Animations Avancées
- Shimmer Effect: Effet de brillance au hover
- Scale Animation: Légère augmentation de taille pour l'état actif
- Color Transition: Progression fluide des couleurs
- Shadow Progression: Élévation visuelle au hover
📊 Statistics Cards
Trois Types Principaux
1. Card Domaines (Vert)
<div class="bg-white rounded-xl shadow-lg p-6" data-stats-card="domains">
  <div class="flex items-center justify-between mb-4">
    <h3 class="text-lg font-semibold text-green-900 flex items-center">
      <svg class="w-5 h-5 text-green-500 mr-2"><!-- Icône --></svg>
      Domaines
    </h3>
    <div class="w-10 h-10 bg-green-500 rounded-xl flex items-center justify-center">
      <svg class="w-5 h-5 text-white"><!-- Icône --></svg>
    </div>
  </div>
  
  <div class="space-y-4">
    <div class="text-center">
      <div class="text-3xl font-bold text-green-900" data-domains-count>0</div>
      <div class="text-sm text-green-700">domaines évalués</div>
    </div>
    
    <!-- Liste dynamique -->
    <div class="space-y-2" data-domains-list></div>
  </div>
</div>
2. Card Compétences (Violet)
<!-- Structure similaire avec couleurs purple-* -->
<div class="bg-white rounded-xl shadow-lg p-6" data-stats-card="competences">
  <!-- Icône: étoile, couleurs purple -->
</div>
3. Card Résultats (Orange)
<div class="bg-white rounded-xl shadow-lg p-6" data-stats-card="results">
  <!-- Contenu principal -->
  <div class="text-center">
    <div class="text-3xl font-bold text-orange-900" data-result="mean">0.0</div>
    <div class="text-sm text-orange-700">moyenne générale</div>
    <div class="text-xs text-orange-600 mt-1" data-result="assessments_count">0 évaluation(s)</div>
  </div>
  
  <!-- Grid 2x2 des statistiques -->
  <div class="grid grid-cols-2 gap-3 text-sm">
    <div class="bg-orange-50 rounded-lg p-3 border border-orange-100">
      <div class="flex justify-between items-center">
        <span class="text-orange-800 font-medium">Min:</span>
        <span class="text-orange-900 font-bold" data-result="min">0.0</span>
      </div>
    </div>
    <!-- Répéter pour max, médiane, écart-type -->
  </div>
</div>
Animations des Nombres
// Animation fluide des statistiques avec easing
animateNumber(element, targetValue, duration = 1000) {
  const startValue = parseFloat(element.textContent) || 0;
  const easeOut = 1 - Math.pow(1 - progress, 3); // Cubic easing
  // Animation avec requestAnimationFrame
}
🎯 Progress Indicators
Trois États Principaux
Complété (Vert)
<div class="inline-flex items-center rounded-full text-xs font-medium border px-3 py-2 bg-green-100 text-green-800 border-green-200">
  <svg class="w-4 h-4 mr-2" fill="currentColor"><!-- Check icon --></svg>
  <span class="font-semibold">Correction 100%</span>
</div>
En Cours (Orange avec Cercle)
<div class="inline-flex items-center rounded-full text-xs font-medium border px-3 py-2 bg-orange-100 text-orange-800 border-orange-200">
  <div class="relative w-4 h-4 mr-2">
    <svg class="w-4 h-4 transform -rotate-90" viewBox="0 0 16 16">
      <circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="2" fill="none" class="text-orange-300"/>
      <circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="2" fill="none" 
              class="text-orange-600" stroke-dasharray="37.7" 
              stroke-dashoffset="{{ 37.7 - (37.7 * progress.percentage / 100) }}"/>
    </svg>
  </div>
  <span class="font-semibold">Correction {{ percentage }}%</span>
</div>
Non Commencé (Rouge)
<div class="inline-flex items-center rounded-full text-xs font-medium border px-3 py-2 bg-red-100 text-red-800 border-red-200">
  <svg class="w-4 h-4 mr-2" fill="currentColor"><!-- Warning icon --></svg>
  <span class="font-semibold">Correction 0%</span>
</div>
Calcul des Dashoffset
/* Cercle de progression SVG */
circle {
  stroke-dasharray: 37.7; /* 2π × 6 (rayon) */
  stroke-dashoffset: calc(37.7 - (37.7 * var(--percentage) / 100));
  transition: stroke-dashoffset 1s ease-in-out;
}
🎭 États Visuels et Feedback
📱 Loading States
Skeleton Loading
@keyframes skeletonPulse {
  0%, 100% {
    opacity: 1;
    background-color: #e5e7eb;
  }
  50% {
    opacity: 0.7;
    background-color: #f3f4f6;
  }
}
.skeleton-item {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: skeletonPulse 1.5s ease-in-out infinite;
  border-radius: 0.375rem;
}
Loading Overlay
<div class="loading-overlay" data-loading-overlay>
  <div class="loading-spinner"></div>
</div>
.loading-overlay {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(255, 255, 255, 0.8);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1040;
}
.loading-spinner {
  width: 32px; height: 32px;
  border: 3px solid #e5e7eb;
  border-top: 3px solid #3b82f6;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}
❌ Error States
Error Cards
<div class="bg-red-50 border border-red-200 rounded-lg p-4">
  <div class="flex">
    <div class="flex-shrink-0">
      <svg class="h-5 w-5 text-red-400" fill="currentColor">
        <!-- Error icon -->
      </svg>
    </div>
    <div class="ml-3">
      <p class="text-sm font-medium text-red-800">Message d'erreur</p>
    </div>
  </div>
</div>
🎉 Success States
Toast Notifications
// Notification de succès avec auto-dismiss
Notytex.utils.showToast('Trimestre 1 chargé', 'success', 1500);
🔄 Empty States
Pas d'Évaluations
<div class="text-center py-12">
  <div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
    <svg class="w-8 h-8 text-gray-400" fill="currentColor">
      <!-- Document icon -->
    </svg>
  </div>
  <h3 class="text-sm font-medium text-gray-900 mb-1">
    Aucune évaluation pour cette classe
  </h3>
  <p class="text-sm text-gray-500 mb-4">Créez votre première évaluation pour cette classe</p>
  <a href="#" class="inline-flex items-center text-sm bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white px-4 py-2 rounded-lg transition-all duration-300 font-semibold shadow-lg hover:shadow-xl transform hover:scale-[1.02]">
    <svg class="w-4 h-4 mr-2" fill="currentColor"><!-- Plus icon --></svg>
    Créer une évaluation
  </a>
</div>
📱 Adaptation Responsive
🖥️ Breakpoints
/* Mobile First Approach */
/* xs: 0px - 639px */     /* Mobile */
/* sm: 640px - 767px */   /* Mobile large */
/* md: 768px - 1023px */  /* Tablette */
/* lg: 1024px - 1279px */ /* Desktop */
/* xl: 1280px+ */         /* Large desktop */
📱 Mobile (< 768px)
Layout Changes
- Grid: grid-cols-1(stack vertical)
- Cards: Pleine largeur avec rounded-lg(bordures réduites)
- Padding: Réduit à p-4au lieu dep-6
- Navigation: Tabs en scroll horizontal
- Actions: Stack vertical des action cards
Touch Optimizations
/* Zones de touch plus grandes */
.trimester-tab {
  min-height: 44px; /* Apple guidelines */
  min-width: 44px;
}
/* Feedback tactile */
.trimester-tab:active {
  transform: scale(0.98);
  transition: transform 0.1s ease;
}
/* Disable hover effects */
@media (hover: none) and (pointer: coarse) {
  .stats-card:hover {
    transform: none;
    transition-duration: 0.15s;
  }
}
📱 Tablette (768px - 1023px)
Layout Adaptatif
- Grid: md:grid-cols-2(2 colonnes)
- Statistics: Grid 2x2 pour les cards principales
- Navigation: Tabs centrés avec plus d'espacement
- Hover: Effets réduits mais présents
🖥️ Desktop (1024px+)
Enhancements
/* Effets avancés activés */
.stats-card:hover {
  transform: translateY(-6px) scale(1.02);
}
/* Grilles optimisées */
.stats-grid {
  grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
  gap: 2rem;
}
/* Animations plus prononcées */
.trimester-tab:not(.active):hover {
  transform: translateY(-3px) scale(1.05);
}
⚡ Animations et Micro-interactions
🌊 Système de Transitions
Design Tokens
:root {
  --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
  --transition-normal: 300ms cubic-bezier(0.4, 0, 0.2, 1);
  --transition-slow: 500ms cubic-bezier(0.4, 0, 0.2, 1);
  --transition-spring: 400ms cubic-bezier(0.34, 1.56, 0.64, 1);
  --transition-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
Usage Pattern
/* Standard pour la plupart des interactions */
.transition-all.duration-300 {
  transition: all var(--transition-normal);
}
/* Rapide pour les feedbacks immédiats */
.transition-colors.duration-150 {
  transition: color var(--transition-fast), 
              background-color var(--transition-fast);
}
🎯 Animations de Chargement
Cascade d'Apparition
animateInitialLoad() {
  const elements = [...this.elements.trimesterTabs, ...this.elements.statsCards];
  
  elements.forEach((element, index) => {
    element.style.opacity = '0';
    element.style.transform = 'translateY(30px)';
    
    setTimeout(() => {
      element.style.transition = 'opacity 300ms ease-out, transform 300ms ease-out';
      element.style.opacity = '1';
      element.style.transform = 'translateY(0)';
    }, index * 50); // 50ms de délai entre chaque élément
  });
}
Animation des Nombres
// Compteur animé avec easing
animateNumber(element, targetValue, duration = 1000) {
  const startValue = parseFloat(element.textContent) || 0;
  const startTime = Date.now();
  
  const animate = () => {
    const elapsed = Date.now() - startTime;
    const progress = Math.min(elapsed / duration, 1);
    
    // Cubic ease-out: 1 - (1-t)³
    const easeOut = 1 - Math.pow(1 - progress, 3);
    const currentValue = startValue + (targetValue - startValue) * easeOut;
    
    element.textContent = isInteger ? Math.round(currentValue) : currentValue.toFixed(1);
    
    if (progress < 1) requestAnimationFrame(animate);
  };
  
  requestAnimationFrame(animate);
}
🔄 Transitions entre États
Changement de Trimestre
async animateTrimesterTransition() {
  const content = this.elements.statsContent;
  
  // Animation de sortie
  content.style.opacity = '0.6';
  content.style.transform = 'translateY(10px)';
  content.style.transition = 'opacity 300ms ease-out, transform 300ms ease-out';
  
  await new Promise(resolve => setTimeout(resolve, 150));
  
  // Animation d'entrée
  content.style.opacity = '1';
  content.style.transform = 'translateY(0)';
}
Expansion de Cards
@keyframes cardExpand {
  from {
    height: 0;
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    height: auto;
    opacity: 1;
    transform: translateY(0);
  }
}
💫 Effets Avancés
Shimmer Effect (Tabs)
.trimester-tab::before {
  content: '';
  position: absolute;
  top: 0; left: -100%;
  width: 100%; height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.6), transparent);
  transition: left 500ms ease;
}
.trimester-tab:hover::before {
  left: 100%;
}
Ripple Effect (Mobile)
addRippleEffect(element, touch) {
  const ripple = document.createElement('span');
  const rect = element.getBoundingClientRect();
  const size = Math.max(rect.width, rect.height);
  
  ripple.style.width = ripple.style.height = size + 'px';
  ripple.style.left = (touch.clientX - rect.left - size/2) + 'px';
  ripple.style.top = (touch.clientY - rect.top - size/2) + 'px';
  ripple.className = 'ripple';
  
  element.appendChild(ripple);
  setTimeout(() => ripple.remove(), 600);
}
.ripple {
  position: absolute;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.6);
  animation: ripple 0.6s ease-out;
  pointer-events: none;
}
@keyframes ripple {
  from {
    opacity: 0.6;
    transform: scale(0);
  }
  to {
    opacity: 0;
    transform: scale(2);
  }
}
♿ Accessibilité Visuelle
🎯 Principes WCAG 2.1
Contraste des Couleurs
- AA Standard: Minimum 4.5:1 pour le texte normal
- AAA Enhanced: Minimum 7:1 pour le texte important
- Large Text: Minimum 3:1 pour texte ≥18pt ou gras ≥14pt
Vérifications Automatiques
/* Vérification des contrastes */
.text-green-900    /* #14532d sur #ffffff = 13.64:1 ✅ AAA */
.text-orange-800   /* #9a3412 sur #ffffff = 6.94:1 ✅ AAA */
.text-purple-800   /* #6b21a8 sur #ffffff = 8.33:1 ✅ AAA */
.text-gray-600     /* #4b5563 sur #ffffff = 7.23:1 ✅ AAA */
🎨 Support High Contrast
@media (prefers-contrast: high) {
  .stats-card {
    border: 2px solid #1f2937;
    background: #ffffff;
  }
  
  .trimester-tab.active {
    background: #1f2937;
    color: #ffffff;
    border: 2px solid #1f2937;
  }
  
  .trimester-tab:not(.active) {
    background: #ffffff;
    color: #1f2937;
    border: 2px solid #6b7280;
  }
}
♿ Navigation Clavier
Focus Visible Amélioré
.trimester-tab:focus-visible,
.stats-card-header:focus-visible {
  outline: 2px solid #3b82f6;
  outline-offset: 2px;
  border-radius: 0.75rem;
}
Navigation Logique
handleKeyboardNavigation(event) {
  if (event.target.matches('[data-trimester-tab]')) {
    switch (event.key) {
      case 'ArrowLeft':
        // Naviguer vers l'onglet précédent
        break;
      case 'ArrowRight':
        // Naviguer vers l'onglet suivant
        break;
      case 'Enter':
      case ' ':
        event.target.click();
        break;
    }
  }
}
📢 ARIA et Screen Readers
Tabs Navigation
<nav class="trimester-tabs" role="tablist" aria-label="Navigation par trimestre">
  <button data-trimester-tab="1" 
          class="trimester-tab active"
          role="tab" 
          aria-selected="true"
          aria-controls="trimester-1-panel">
    Trimestre 1
  </button>
</nav>
Live Regions pour Updates
<!-- Annonces automatiques des changements -->
<div aria-live="polite" aria-atomic="true" class="sr-only" data-live-region></div>
// Annoncer les changements
announceChange(message) {
  const liveRegion = document.querySelector('[data-live-region]');
  liveRegion.textContent = message;
  // Auto-clear after announcement
  setTimeout(() => liveRegion.textContent = '', 1000);
}
🎭 Reduced Motion Support
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  
  .stats-card:hover,
  .trimester-tab:hover {
    transform: none;
  }
}
🛠️ Guidelines d'Implémentation
📋 Checklist de Qualité
Visual Consistency
- Utilisation cohérente des couleurs sémantiques
- Espacement basé sur le système (multiples de 4px/0.25rem)
- Typographie respectant la hiérarchie définie
- Border-radius cohérents (rounded-xl= 12px pour cards)
Interaction Design
- Hover states définis pour tous les éléments interactifs
- Focus states visibles et accessibles
- Loading states pour toutes les actions asynchrones
- Feedback visuel immédiat sur les interactions
Responsive Behavior
- Test sur mobile (320px min-width)
- Test sur tablette (768px - 1023px)
- Test sur desktop (1024px+)
- Touch targets ≥44px sur mobile
Performance
- Animations utilisant transformetopacityuniquement
- will-changedéfini pour les animations critiques
- GPU acceleration avec backface-visibility: hidden
- Debouncing sur les événements fréquents (resize, scroll)
🎨 Styleguide d'Utilisation
Do's
✅ Utiliser les gradients définis (from-blue-500 to-blue-600)
✅ Maintenir des transitions cohérentes (300ms par défaut)
✅ Grouper les éléments liés avec space-y-*
✅ Utiliser group + group-hover: pour les effets de groupe
✅ Préfixer les data attributes (data-stats-card)
Don'ts
❌ Créer de nouveaux gradients sans justification
❌ Utiliser des animations CSS pures pour les transitions complexes
❌ Omettre les états loading/error
❌ Négliger les tests sur appareils tactiles
❌ Ignorer les préférences utilisateur (reduced-motion)
📊 Métriques de Performance
Core Web Vitals Targets
- LCP: < 2.5s (Largest Contentful Paint)
- FID: < 100ms (First Input Delay)
- CLS: < 0.1 (Cumulative Layout Shift)
Animation Performance
- 60 FPS: Toutes les animations maintienues à 60fps
- Transform Only: Éviter les animations de propriétés layout
- RAF: Utiliser requestAnimationFramepour les animations JS
🔮 Évolutions Futures
🌙 Dark Theme Support
/* Préparation du thème sombre */
@media (prefers-color-scheme: dark) {
  :root {
    --bg-primary: #1f2937;
    --bg-secondary: #111827;
    --text-primary: #f9fafb;
    --text-secondary: #d1d5db;
  }
  
  .stats-card {
    background: var(--bg-primary);
    border: 1px solid #374151;
  }
}
📱 Progressive Web App
- Gestures Avancés: Swipe, pinch-to-zoom, long-press
- Offline Support: Cache des données critiques
- Native Animations: Integration avec les APIs mobiles