Aller au contenu

Design: Host Shell

Brand: Papillon HR Suite

Date: 24/02/2026

Version: 1.0

Author: DESIGNER (Claude — Senior UX/UI Designer)


For the DEVELOPER: This document is your single source of truth for Sprint 0 implementation. Every layout, state, interaction, token, and French string is specified here. If something is ambiguous, the design is wrong — flag it. You should never need to guess.


Table of Contents

  1. Design Decisions (Open Questions Resolved)
  2. Design Token System
  3. Layout Wireframes (All Breakpoints)
  4. Authentication Screens
  5. App Shell Layout
  6. Dashboard
  7. Navigation
  8. Sync Status Indicator
  9. Responsive Behavior
  10. Dark Mode
  11. Notification Panel
  12. PWA Spec
  13. Shared Component Specs
  14. French Micro-copy Document
  15. Brand Compliance Checklist

1. Design Decisions

These resolve the open questions from docs/specs/host-shell.md §10. Each decision includes rationale.

Q1: Bottom navigation — 4 tabs or 5?

Decision: 4 tabs.

Tab Icon Label Rationale
1 home Accueil Dashboard — universal landing
2 calendar Congés Most-used by P4 (Employee), P2 (RH)
3 qr-code Pointage Daily action for P4, needs one-tap access
4 menu Plus Opens full module list as bottom sheet

Why 4, not 5: On a 360px screen, 5 tabs creates cramped 72px-wide targets. 4 tabs at 90px each sits comfortably above the 48px minimum touch target. The "Plus" tab opens all other modules — no one is locked out. Notification bell lives in the top bar, not the bottom nav (it's a status indicator, not a primary action).

Q2: Sidebar grouping

Decision: Functional groups with subtle visual separators, not nested menus.

Groups: - Quotidien (Daily): Tableau de bord, Congés & Absences, Pointage QR - Finance: Lignes budgétaires, Engagements, Paie, Notes de frais - Ressources Humaines: Employés, Performance, Compétences, Formation, Recrutement - Commercial: CRM Interne - Administration* (admin-only): Paramètres, Utilisateurs, Audit, Abonnement

(*) = locked "Bientôt" items

Why this grouping: Maps to mental models of the 3 primary desktop personas. P2 (RH) thinks "daily tasks" vs. "employee management." P3 (Comptable) thinks "finance." Groups use label headers (not collapsible accordions) to keep all items scannable — the sidebar should never hide information behind a click.

Q3: Dashboard layout

Decision: Stacked cards on mobile (1 column), 2×2 grid on tablet, 4-column grid on desktop. Two KPI cards visible above the fold on phone.

Why: On a 360px screen with 16px padding, a card is 328px wide — perfect for readability. Showing 2 KPI cards above the fold (each ~160px tall including padding) gives immediate value without scrolling. Quick actions section sits just below the fold, reachable with a thumb-swipe.

Q4: Locked module click behavior

Decision: Bottom sheet preview (mobile) / Popover card (desktop).

On tap, locked modules show a mini preview card with: - Module icon (full color, not greyed) - Module name and one-line description - "Bientôt disponible" badge - "Être notifié à la sortie" toggle (opt-in for launch notification) - Subtle illustration or icon hinting at the module's purpose

Why not a toast: Toasts are dismissive — they say "go away." A preview card says "look what's coming" and builds anticipation. The notification toggle creates engagement. Why not greyed-out icons in the sidebar: Grey communicates "disabled/broken." Instead, locked items use 50% opacity with a small ✦ Bientôt badge — still visible, clearly different, but aspirational.

Q5: Notification panel

Decision: Slide-in panel from the right (desktop/tablet), full-screen bottom sheet (mobile).

Why: A dropdown is too small for notification content (icon + title + body + timestamp). A right slide-in panel (320px wide on desktop) gives ample space and doesn't obscure the main content entirely. On mobile, a bottom sheet is the native pattern — users expect it from WhatsApp, Wave, and M-Pesa.

Q6: Login screen

Decision: Centered card on mobile. Split layout on desktop (branding left, form right).

Why: On mobile (360px), a split layout wastes precious space. A centered form with the Papillon logo above feels like a premium app login (think Wise or Wave). On desktop (1024px+), the left panel shows a warm branded illustration with the tagline, giving the first impression its gravitas. The form sits on the right in a clean white card.

Q7: Illustration style

Decision: Warm geometric flat illustrations with African-inspired color tones. No human faces (avoids representation bias). Abstract shapes suggesting growth, connection, community.

Used in: login screen branding panel, empty states, offline landing, locked module previews.

Style references: Abstract shapes like Notion's empty states but warmer — amber, teal, and earth tones. Circles and gentle curves (not sharp corporate angles). Could be implemented as simple SVG compositions to respect the performance budget.

Sprint 0 implementation: Use simple SVG geometric compositions (circles, arcs, dots) that can be created inline — no external illustration files needed. Each empty state gets a unique but consistent composition.

Q8: Animation philosophy

Decision: Signature transitions only, not pervasive micro-animations. Three signature moments:

  1. Page transition: Content area fades in with a subtle 200ms upward slide (12px). Feels alive without being slow.
  2. Sync pulse: The sync indicator uses a gentle breathing pulse (1.5s ease-in-out loop) when syncing. Calm, not urgent.
  3. Success flash: On successful actions (save, approve, submit), a brief green checkmark scales in (150ms) then fades (300ms). Satisfying.

Why minimal: Heavy animations kill performance on low-end Android. Three memorable transitions create more personality than 50 subtle ones. All animations respect prefers-reduced-motion.

Q9: Celebration moments

Decision: Two celebration moments in the shell:

  1. First login ever (per user): Subtle confetti burst (3s, then gone) with "Bienvenue sur Papillon ! 🦋" toast. Only triggers once. Stored in localStorage.
  2. PWA install success: Warm "Papillon est installé ! Accédez-y depuis votre écran d'accueil." toast with a butterfly icon animation.

Why these two: They mark genuine milestones — the user's first experience and their commitment to the platform. Module-specific celebrations (payroll completion, etc.) are designed per module, not in the shell.


2. Design Token System

All values below are implemented as CSS custom properties in theme.ts. Token names follow the pattern: --{category}-{element}-{variant}.

2.1 Color Tokens — Light Mode

Brand Colors

Token Value Usage
--color-primary #F59E0B Primary buttons, active nav, links, accents
--color-primary-hover #D97706 Primary button hover/press state
--color-primary-light #FEF3C7 Primary tint backgrounds, selected states
--color-primary-subtle #FFFBEB Very light primary wash, card highlights
--color-secondary #0D6B6E Sidebar background, secondary buttons, section headers
--color-secondary-hover #0A5456 Secondary button hover state
--color-secondary-light #CCFBF1 Secondary tint backgrounds
--color-secondary-dark #083F41 Sidebar text/icons active state

Neutral Colors

Token Value Usage
--color-bg-primary #FFFDF7 Page background (warm off-white)
--color-bg-secondary #FFF9EE Card backgrounds, elevated surfaces
--color-bg-tertiary #F5F0E8 Input backgrounds, table row alternating
--color-surface #FFFFFF Modal, dropdown, floating surfaces
--color-border #E8E0D4 Card borders, dividers, input borders
--color-border-light #F0EBE3 Subtle separators, group dividers
--color-border-focus #F59E0B Input focus ring (= primary)

Text Colors

Token Value Usage
--color-text-primary #1C1917 Headings, primary body text
--color-text-secondary #57534E Secondary text, descriptions, placeholders
--color-text-tertiary #A8A29E Disabled text, timestamps, hints
--color-text-inverse #FFFDF7 Text on dark backgrounds
--color-text-on-primary #1C1917 Text on amber/gold backgrounds (dark for contrast)

Semantic Colors

Token Value Usage
--color-success #16A34A Success states, synced indicator, approved
--color-success-light #DCFCE7 Success background tint
--color-warning #F59E0B Warning states (shares primary for warmth)
--color-warning-light #FEF9C3 Warning background tint
--color-error #DC2626 Error states, destructive actions
--color-error-light #FEE2E2 Error background tint
--color-info #2563EB Informational states, links
--color-info-light #DBEAFE Info background tint

Sync Status Colors

Token Value Usage
--color-sync-synced #16A34A Green — all synced
--color-sync-pending #F59E0B Orange/amber — operations queued
--color-sync-syncing #2563EB Blue — actively syncing
--color-sync-offline #78716C Warm grey — no connectivity
Token Value Usage
--color-sidebar-bg #0D6B6E Sidebar background
--color-sidebar-bg-hover #0A5456 Nav item hover
--color-sidebar-bg-active #083F41 Active nav item background
--color-sidebar-text #CCFBF1 Sidebar text default
--color-sidebar-text-active #FFFFFF Sidebar active item text
--color-sidebar-icon #5EEAD4 Sidebar icons default
--color-sidebar-icon-active #F59E0B Sidebar active icon (amber accent)
--color-sidebar-divider #0A5456 Group separator lines
--color-sidebar-group-label #5EEAD4 Group header text (e.g., "QUOTIDIEN")

2.2 Typography Tokens

Font Family: Inter, system-ui, -apple-system, sans-serif (Inter supports full Latin Extended including all French diacritics: é è ê ë ç à â ù û ô î ï)

Token Size Weight Line Height Letter Spacing Usage
--font-display 32px 700 1.2 -0.02em Login screen title, major headings
--font-h1 24px 700 1.3 -0.01em Page titles
--font-h2 20px 600 1.35 0 Section titles, card headers
--font-h3 18px 600 1.4 0 Sub-section titles
--font-h4 16px 600 1.4 0 Small section titles, bold labels
--font-body 16px 400 1.5 0 Default body text
--font-body-medium 16px 500 1.5 0 Emphasized body text, nav labels
--font-small 14px 400 1.4 0 Secondary descriptions, table cells
--font-caption 12px 400 1.4 0.02em Timestamps, badges, helper text
--font-overline 11px 600 1.2 0.08em Sidebar group labels, uppercase labels

2.3 Spacing Tokens

Base unit: 4px. All spacing uses multiples of 4.

Token Value Usage
--space-1 4px Inline icon gaps, tight padding
--space-2 8px Icon-to-text gap, compact padding
--space-3 12px Input padding, small gaps between related items
--space-4 16px Standard padding, gap between form fields
--space-5 20px Card internal padding (mobile)
--space-6 24px Card internal padding (desktop), section gaps
--space-8 32px Between cards, between sections
--space-10 40px Large section separators
--space-12 48px Page top/bottom padding
--space-16 64px Major layout gaps

2.4 Border Radius Tokens

Token Value Usage
--radius-sm 6px Badges, small tags
--radius-md 8px Buttons, inputs
--radius-lg 12px Cards, modals
--radius-xl 16px Large cards, panels, bottom sheets
--radius-full 9999px Avatar circles, pills

2.5 Shadow / Elevation Tokens

Token Value Usage
--shadow-sm 0 1px 2px rgba(28,25,23,0.05) Subtle lift — inputs, small cards
--shadow-md 0 4px 12px rgba(28,25,23,0.08) Cards, elevated surfaces
--shadow-lg 0 8px 24px rgba(28,25,23,0.12) Modals, dropdowns, popovers
--shadow-xl 0 16px 48px rgba(28,25,23,0.16) Toasts, floating action panels
--shadow-sidebar 2px 0 8px rgba(13,107,110,0.15) Sidebar edge shadow
--shadow-focus 0 0 0 3px rgba(245,158,11,0.3) Focus ring (amber glow)

2.6 Animation Tokens

Token Value Usage
--duration-instant 100ms Button state change, toggle
--duration-fast 150ms Success checkmark, small transitions
--duration-normal 200ms Page content fade-in, slide-in
--duration-slow 300ms Modal open/close, panel slide
--duration-sync-pulse 1500ms Sync indicator breathing animation
--easing-default cubic-bezier(0.4, 0, 0.2, 1) Standard easing
--easing-enter cubic-bezier(0, 0, 0.2, 1) Elements entering (decelerate)
--easing-exit cubic-bezier(0.4, 0, 1, 1) Elements leaving (accelerate)

2.7 Layout Tokens

Token Value Usage
--sidebar-width 260px Expanded sidebar
--sidebar-width-collapsed 68px Collapsed sidebar (icons only)
--topbar-height 56px Top bar height (mobile)
--topbar-height-desktop 64px Top bar height (desktop)
--bottomnav-height 64px Bottom navigation bar (mobile)
--content-max-width 1200px Max width for content area
--content-padding-mobile 16px Content area horizontal padding (phone)
--content-padding-tablet 24px Content area horizontal padding (tablet)
--content-padding-desktop 32px Content area horizontal padding (desktop)

2.8 Z-Index Scale

Token Value Usage
--z-base 0 Default stacking
--z-sidebar 100 Sidebar overlay on mobile
--z-topbar 200 Top bar (above sidebar on mobile)
--z-dropdown 300 Dropdowns, popovers
--z-modal-backdrop 400 Modal backdrop overlay
--z-modal 500 Modal content
--z-toast 600 Toast notifications (topmost)
--z-sync-panel 350 Sync detail panel

3. Layout Wireframes

3.1 Phone — 360px

┌──────────────────────────────────────┐
│ [☰]  Papillon    [●sync] [🔔2]      │  ← Top bar (56px)
├──────────────────────────────────────┤
│                                      │
│  ┌──────────────────────────────┐    │
│  │  👥 12 employés actifs       │    │  ← KPI Card 1
│  │       +2 ce mois             │    │
│  └──────────────────────────────┘    │
│                                      │
│  ┌──────────────────────────────┐    │
│  │  📋 3 demandes en attente    │    │  ← KPI Card 2
│  │       congés à approuver     │    │
│  └──────────────────────────────┘    │
│                                      │  ← Scrollable content
│  ── Actions rapides ──────────────   │
│                                      │
│  ┌──────────┐  ┌──────────────┐      │
│  │ 🏖 Congé │  │ ✅ Approuver │      │  ← Quick actions (2-col)
│  └──────────┘  └──────────────┘      │
│                                      │
│  ┌──────────┐  ┌──────────────┐      │
│  │ 📍 Pointer│  │ 📊 Budget   │      │
│  └──────────┘  └──────────────┘      │
│                                      │
├──────────────────────────────────────┤
│  🏠       📅       📱       ≡        │  ← Bottom nav (64px)
│ Accueil  Congés  Pointage  Plus      │
└──────────────────────────────────────┘

3.2 Tablet — 768px

┌────┬───────────────────────────────────────────────────┐
│    │  Tableau de bord           [●sync] [🔔2] [👤]    │  ← Top bar (64px)
│ 📊 ├───────────────────────────────────────────────────┤
│ 📅 │                                                   │
│ 📱 │  ┌─────────────────┐  ┌─────────────────┐        │
│ 💰 │  │ 👥 12 employés  │  │ 📋 3 demandes   │        │  ← 2-col KPI
│ 📝 │  │   actifs        │  │   en attente    │        │
│ 🏢 │  └─────────────────┘  └─────────────────┘        │
│ 💼 │                                                   │
│ 📊 │  ┌─────────────────┐  ┌─────────────────┐        │
│    │  │ 📊 Budget:      │  │ 📝 5 engage-    │        │  ← 2-col KPI
│ ·· │  │   68% utilisé   │  │   ments ce mois │        │
│    │  └─────────────────┘  └─────────────────┘        │
│    │                                                   │
│ ⚙️ │  ── Actions rapides ────────────────────          │
│    │  ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐    │
│    │  │ Congé  │ │Approuv.│ │Pointer │ │ Budget │    │
│    │  └────────┘ └────────┘ └────────┘ └────────┘    │
│    │                                                   │
└────┴───────────────────────────────────────────────────┘
 68px                    Remaining width
(icons)

3.3 Desktop — 1024px

┌──────────────┬──────────────────────────────────────────────────────┐
│              │  Tableau de bord                [●sync] [🔔2] [🌙] [👤 Menu]│
│  🦋 Papillon ├──────────────────────────────────────────────────────┤
│  Acme Corp   │                                                      │
│              │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐│
│ ─QUOTIDIEN── │  │👥 12     │ │📋 3      │ │📊 68%    │ │📝 5      ││
│ 📊 Tableau   │  │employés  │ │demandes  │ │budget    │ │engagements│
│    de bord   │  │actifs    │ │en attente│ │utilisé   │ │ce mois   ││
│ 📅 Congés &  │  └──────────┘ └──────────┘ └──────────┘ └──────────┘│
│    Absences  │                                                      │
│ 📱 Pointage  │  ── Actions rapides ──────────────────────           │
│              │  ┌──────────┐ ┌──────────┐ ┌──────────┐             │
│ ─FINANCE──── │  │🏖 Nouveau│ │✅ Approu-│ │📍 Pointer│             │
│ 💰 Lignes    │  │  congé   │ │ver (3)   │ │arrivée   │             │
│    budgét.   │  └──────────┘ └──────────┘ └──────────┘             │
│ 📝 Engage-   │                                                      │
│    ments     │  ── Activité récente ─────────────────               │
│ 💳 Paie      │  ┌──────────────────────────────────────────┐       │
│ 🧾 Notes*    │  │ • Moussa Koné — congé approuvé (il y a 2h)│      │
│              │  │ • Paie février — en cours de validation    │      │
│ ─RH───────── │  │ • 2 nouveaux employés ajoutés             │      │
│ 👥 Employés  │  └──────────────────────────────────────────┘       │
│ 🎯 Perf.*    │                                                      │
│ 🧠 Compét.*  │                                                      │
│ 📚 Format.*  │                                                      │
│ 🔍 Recrut.*  │                                                      │
│              │                                                      │
│ ─COMMERCIAL─ │                                                      │
│ 💼 CRM       │                                                      │
│              │                                                      │
│ ─ADMIN────── │                                                      │
│ ⚙️ Paramètr. │                                                      │
│              │                                                      │
│ ──────────── │                                                      │
│ 👤 Éric B.   │                                                      │
│    DG        │                                                      │
└──────────────┴──────────────────────────────────────────────────────┘
  260px                          Remaining width (max 1200px content)

3.4 Large Desktop — 1440px

Same structure as 1024px. Content area centers within max-width 1200px. Extra horizontal space becomes equal left/right margins within the content zone. Dashboard KPI grid remains 4 columns. Activity feed may use a 2-column layout (feed left, quick stats right) if content justifies it.


4. Authentication Screens

4.1 Login Screen

Layout — Mobile (360px)

┌──────────────────────────────────────┐
│            (warm bg #FFFDF7)         │
│                                      │
│           🦋                         │
│       Papillon                       │
│  Votre assistant RH de confiance     │
│                                      │
│  ┌──────────────────────────────┐    │
│  │                              │    │
│  │  Adresse e-mail              │    │
│  │  ┌──────────────────────┐    │    │
│  │  │ [email protected]   │    │    │
│  │  └──────────────────────┘    │    │
│  │                              │    │
│  │  Mot de passe                │    │
│  │  ┌──────────────────────┐    │    │
│  │  │ ••••••••        [👁]  │    │    │
│  │  └──────────────────────┘    │    │
│  │                              │    │
│  │  ┌──────────────────────┐    │    │
│  │  │    Se connecter      │    │    │  ← Primary button, full width
│  │  └──────────────────────┘    │    │
│  │                              │    │
│  │  Mot de passe oublié ?       │    │  ← Text link, centered
│  │                              │    │
│  └──────────────────────────────┘    │
│                                      │
│      © 2026 ALTARYS ENTERPRISE       │
└──────────────────────────────────────┘

Layout — Desktop (1024px+)

┌────────────────────────────┬─────────────────────────────────┐
│                            │                                 │
│     (Deep teal panel)      │      (White card surface)       │
│     #0D6B6E                │                                 │
│                            │    🦋 Papillon                  │
│                            │                                 │
│     [Geometric SVG         │    Connectez-vous à votre       │
│      illustration:         │    espace RH                    │
│      warm amber circles    │                                 │
│      + teal arcs           │    Adresse e-mail               │
│      suggesting growth     │    ┌───────────────────────┐    │
│      and connection]       │    │ [email protected]    │    │
│                            │    └───────────────────────┘    │
│                            │                                 │
│                            │    Mot de passe                 │
│     "Votre assistant RH    │    ┌───────────────────────┐    │
│      de confiance"         │    │ ••••••••         [👁]  │    │
│                            │    └───────────────────────┘    │
│     Simplifiez la gestion  │                                 │
│     de vos ressources      │    ┌───────────────────────┐    │
│     humaines.              │    │    Se connecter        │    │
│                            │    └───────────────────────┘    │
│                            │                                 │
│                            │    Mot de passe oublié ?        │
│                            │                                 │
│     © 2026 ALTARYS         │                                 │
│       ENTERPRISE           │                                 │
└────────────────────────────┴─────────────────────────────────┘
        50% width                      50% width

States

Empty (initial): - Email field: empty, placeholder "[email protected]" - Password field: empty, no placeholder - Button: enabled (validation happens on submit)

Loading (submitting): - Button text changes to spinner + "Connexion…" - Both inputs disabled - No other UI change

Error — invalid credentials: - Inputs retain values (never clear the password on error — user may have mistyped one char) - Error toast appears at top: "Adresse e-mail ou mot de passe incorrect" - Error toast auto-dismisses after 5 seconds - No field-level error indicators (we don't reveal which field is wrong — security)

Error — network failure: - Toast: "Impossible de se connecter. Vérifiez votre connexion Internet." - Button re-enabled for retry

Error — account locked: - Toast: "Votre compte est temporairement verrouillé. Réessayez dans 15 minutes ou réinitialisez votre mot de passe." - "Mot de passe oublié ?" link pulses subtly to draw attention

Success: - Brief green checkmark animation on button (150ms) - Redirect to dashboard - First-time user: confetti + welcome toast (see §1 Q9)

Validation rules: - Email: validate format on blur. If invalid: "Veuillez saisir une adresse e-mail valide" below the field - Password: no client-side validation (server validates) - Submit: disabled only while request is in-flight

Accessibility: - aria-label="Formulaire de connexion" on form - aria-describedby linking error messages to inputs - Password visibility toggle: aria-label="Afficher le mot de passe" / "Masquer le mot de passe" - Focus order: email → password → submit → forgot password link - Skip link not needed (no navigation on login page)

4.2 Password Recovery Screen

Layout — Mobile (360px)

┌──────────────────────────────────────┐
│            (warm bg)                 │
│                                      │
│     ← Retour à la connexion         │  ← Back link with arrow
│                                      │
│           🦋                         │
│     Mot de passe oublié              │
│                                      │
│  Saisissez votre adresse e-mail.     │
│  Si un compte existe, vous           │
│  recevrez un lien de                 │
│  réinitialisation.                   │
│                                      │
│  Adresse e-mail                      │
│  ┌──────────────────────────────┐    │
│  │ [email protected]           │    │
│  └──────────────────────────────┘    │
│                                      │
│  ┌──────────────────────────────┐    │
│  │  Réinitialiser mon mot       │    │
│  │  de passe                    │    │
│  └──────────────────────────────┘    │
│                                      │
└──────────────────────────────────────┘

States

Empty (initial): Email field empty with placeholder.

Loading: Button shows spinner + "Envoi en cours…"

Success (always shown, regardless of whether the email exists — security): - Form is replaced by a success card:

✉️
E-mail envoyé !

Si l'adresse [email protected] est
associée à un compte, vous recevrez
un e-mail avec un lien de
réinitialisation.

Vérifiez aussi vos courriers
indésirables.

[Retour à la connexion]

Error — network failure: Toast: "Impossible d'envoyer la demande. Vérifiez votre connexion."

Offline: Toast: "Vous êtes hors ligne. Connectez-vous à Internet pour réinitialiser votre mot de passe."


5. App Shell Layout

5.1 Zone Architecture

The app shell consists of 3 persistent zones that wrap all module content:

┌─────────────────────────────────────────────────────┐
│                    ZONE 2: TOP BAR                   │
├──────────┬──────────────────────────────────────────┤
│          │                                          │
│  ZONE 1  │           ZONE 3: CONTENT                │
│  SIDEBAR │           (module pages render here)     │
│          │                                          │
│          │                                          │
│          │                                          │
└──────────┴──────────────────────────────────────────┘

On mobile, Zone 1 becomes the bottom navigation bar:

┌──────────────────────────────────────┐
│           ZONE 2: TOP BAR            │
├──────────────────────────────────────┤
│                                      │
│        ZONE 3: CONTENT               │
│                                      │
│                                      │
├──────────────────────────────────────┤
│       ZONE 1: BOTTOM NAV            │
└──────────────────────────────────────┘

5.2 Zone 1 — Sidebar (Desktop/Tablet)

Width: 260px expanded, 68px collapsed (icon-only) Background: --color-sidebar-bg (#0D6B6E) Behavior: - Desktop (≥1024px): Always expanded - Tablet (768px–1023px): Collapsed by default. Tap hamburger in top bar or swipe right from left edge to expand as an overlay (with backdrop). - Phone (<768px): Hidden. Replaced by bottom navigation.

Structure (top to bottom):

┌──────────────────────┐
│  🦋 Papillon         │  ← Brand logo + product name
│  ─────────────────── │
│  🏢 Acme Corp        │  ← Tenant name + logo (or initials)
│     Abidjan, CI      │     Tenant city + country code
├──────────────────────┤
│  QUOTIDIEN           │  ← Group label (--font-overline, uppercase)
│  📊 Tableau de bord  │
│  📅 Congés & Absences│
│  📱 Pointage QR      │
│                      │
│  FINANCE             │
│  💰 Lignes budgét.   │
│  📝 Engagements      │
│  💳 Paie             │
│  🧾 Notes de frais ✦ │  ← Locked item with "Bientôt" badge
│                      │
│  RESSOURCES HUMAINES │
│  👥 Employés         │
│  🎯 Performance  ✦   │
│  🧠 Compétences  ✦   │
│  📚 Formation    ✦   │
│  🔍 Recrutement  ✦   │
│                      │
│  COMMERCIAL          │
│  💼 CRM Interne      │
├──────────────────────┤
│  ADMINISTRATION      │  ← Only for admin roles
│  ⚙️ Paramètres       │
│  👥 Utilisateurs     │
│  📋 Journal d'audit  │
│  💳 Abonnement       │
├──────────────────────┤
│  ─────────────────── │
│  👤 Éric Bonville    │  ← User avatar/initials + name
│     Directeur Général│     Role label
│     [Se déconnecter] │     Logout link (subtle)
└──────────────────────┘

Nav item dimensions: - Height: 44px (with 4px vertical gap between items) - Icon: 20px, left-aligned with 16px left padding - Label: --font-body-medium, 12px left of icon - Active indicator: 3px amber left border + --color-sidebar-bg-active background - Hover: --color-sidebar-bg-hover background, 100ms transition

Collapsed state (68px): - Only icons visible, centered - Tooltip on hover showing the full label - Active indicator: amber dot below icon - Tenant section: logo/initials only - User section: avatar only

5.3 Zone 1 — Bottom Navigation (Phone)

Height: 64px + safe area inset bottom (for phones with home indicator) Background: --color-surface (#FFFFFF) with --shadow-lg upward

Position Icon Label Tap action
1 home (filled when active) Accueil Go to dashboard
2 calendar Congés Go to leave module
3 qr-code Pointage Go to QR attendance
4 menu (grid) Plus Open module bottom sheet

Item dimensions: - Touch target: 90px wide × 64px tall (exceeds 48px minimum) - Icon: 24px - Label: --font-caption (12px) - Active state: icon fills, label becomes --color-primary, subtle 2px top border amber

"Plus" bottom sheet: On tap, slides up a bottom sheet listing ALL modules (same groups as sidebar). The sheet has a drag handle, can be dismissed by swipe-down or tapping outside. Max height: 80vh. Scrollable if needed. Locked modules show ✦ Bientôt badge inline.

5.4 Zone 2 — Top Bar

Height: 56px (mobile), 64px (desktop) Background: --color-surface (#FFFFFF) Border: 1px bottom --color-border-light

Mobile layout (360px)

┌──────────────────────────────────────┐
│ [☰]    Papillon 🦋    [●] [🔔2]    │
└──────────────────────────────────────┘
  48px    centered         sync  bell
  • Hamburger [☰]: only on tablet (opens sidebar overlay). On phone, no hamburger (bottom nav handles it).
  • On phone: Left side shows "Papillon" brand mark. Center is implicit.
  • Right side: sync dot (16px) + notification bell (24px icon, with badge).

Desktop layout (1024px+)

┌──────────────────────────────────────────────────────────────────┐
│  Tableau de bord                    [● Synchronisé] [🔔2] [🌙] [👤▾]│
└──────────────────────────────────────────────────────────────────┘
   Page title / breadcrumb                sync label   bell  dark  user
  • Left: Page title (--font-h2). If within a sub-page, shows breadcrumb: Employés > Moussa Koné
  • Right (left-to-right): Sync status with label, notification bell with count, dark mode toggle, user menu dropdown trigger (avatar + name + chevron)

User menu dropdown (desktop, triggered by clicking avatar/name):

┌──────────────────────┐
│  👤 Éric Bonville    │
[email protected]│  ──────────────────  │
│  Mon profil          │
│  Préférences         │
│  ──────────────────  │
│  Se déconnecter      │
└──────────────────────┘
Width: 220px. Appears below the avatar, right-aligned. Shadow: --shadow-lg.

5.5 Zone 3 — Content Area

Behavior: - Scrolls independently from sidebar and top bar (sidebar and top bar are fixed/sticky) - Padding: 16px (mobile), 24px (tablet), 32px (desktop) - Max content width: 1200px, centered with auto margins on screens wider than 1200px + sidebar width - Background: --color-bg-primary (#FFFDF7)

Module loading: When navigating between modules (React.lazy code splitting): 1. Content area shows skeleton loader matching the target module's layout 2. Skeleton fades in immediately (no delay) 3. When module loads, skeleton fades out and content fades in (200ms crossfade) 4. If loading takes >3s (slow 3G), add subtle pulsing text below skeleton: "Chargement du module…"

Empty state (when a module has no data): - Centered vertically in content area - SVG illustration (geometric, warm) - Title: explains what this module does - Subtitle: guides user to first action - Primary CTA button - Example for Employés: "Aucun employé enregistré — Ajoutez votre premier employé pour commencer"


6. Dashboard

6.1 Structure Overview

The dashboard is the landing page after login. It provides an at-a-glance summary and quick access to common actions. In Sprint 0, it displays placeholder data and static layout. The structure is designed for future role-aware content.

6.2 Layout Zones

┌──────────────────────────────────────────────────┐
│  ZONE A: KPI Cards (summary metrics)             │
│  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐            │
│  │ KPI1 │ │ KPI2 │ │ KPI3 │ │ KPI4 │            │
│  └──────┘ └──────┘ └──────┘ └──────┘            │
├──────────────────────────────────────────────────┤
│  ZONE B: Quick Actions (shortcuts)               │
│  ┌──────┐ ┌──────┐ ┌──────┐                     │
│  │ Act1 │ │ Act2 │ │ Act3 │                     │
│  └──────┘ └──────┘ └──────┘                     │
├──────────────────────────────────────────────────┤
│  ZONE C: Recent Activity (feed)                  │
│  ┌──────────────────────────────────────┐        │
│  │ Activity list (scrollable)           │        │
│  └──────────────────────────────────────┘        │
└──────────────────────────────────────────────────┘

6.3 KPI Cards

Each KPI card follows a consistent structure:

┌──────────────────────────────┐
│  [icon]                      │
│                              │
│  12                          │  ← Metric value (--font-display, 32px bold)
│  employés actifs             │  ← Metric label (--font-small, secondary text)
│                              │
│  +2 ce mois  ↑              │  ← Trend indicator (--font-caption, green/red)
└──────────────────────────────┘

Card specs: - Background: --color-bg-secondary - Border: 1px --color-border - Border-radius: --radius-lg (12px) - Padding: --space-5 (20px) on mobile, --space-6 (24px) on desktop - Shadow: --shadow-sm - Icon: 24px, --color-primary tint - Hover (desktop): --shadow-md, translate Y -2px, 200ms transition

Sprint 0 KPI cards (placeholder data):

# Icon Value Label Trend
1 users 12 employés actifs +2 ce mois ↑
2 calendar-clock 3 demandes de congé en attente
3 pie-chart 68% du budget utilisé +12% vs mois dernier
4 file-text 5 engagements ce mois

Responsive grid: - 360px: 1 column, cards stack vertically. First 2 visible above fold. - 768px: 2 columns - 1024px: 4 columns - 1440px: 4 columns (cards don't grow beyond ~280px; extra space is margin)

Gap between cards: --space-4 (16px) on mobile, --space-6 (24px) on desktop.

6.4 Quick Actions

Quick actions are pill-shaped buttons that shortcut to common tasks.

┌──────────────────────┐
│  🏖  Nouvelle         │
│     demande de congé  │
└──────────────────────┘

Specs: - Background: --color-surface with --color-primary-light left border (4px) - Border-radius: --radius-md (8px) - Padding: --space-3 (12px) vertical, --space-4 (16px) horizontal - Icon: 20px, --color-primary - Text: --font-body-medium - Touch target: min 48px tall - Hover: background shifts to --color-primary-light

Sprint 0 quick actions:

# Icon Label Target route
1 palm-tree Nouvelle demande de congé /conges/nouvelle
2 check-circle Approuver les demandes (3) /conges/approbations
3 map-pin Pointer mon arrivée /pointage

Responsive layout: - 360px: 1 column, full-width buttons stacked - 768px+: horizontal row, wrapping if needed - Section title: "Actions rapides" (--font-h3)

6.5 Recent Activity Feed

A chronological list of recent events across all modules.

Item structure:

┌──────────────────────────────────────────────────┐
│  [avatar]  Moussa Koné a soumis une demande      │
│            de congé (15/03 – 22/03)              │
│            il y a 2 heures                       │
└──────────────────────────────────────────────────┘

Specs: - Avatar: 32px circle (user initials or icon for system events) - Title: --font-body, --color-text-primary - Timestamp: --font-caption, --color-text-tertiary - Divider: 1px --color-border-light between items - Max items visible: 5 (with "Voir toute l'activité" link at bottom)

Sprint 0: Show 3 static placeholder items. Design the empty state:

  📭
  Aucune activité récente

  L'activité de votre équipe
  apparaîtra ici.

6.6 Role-Aware Variants (Future Implementation)

Designed now, implemented when role system is connected.

P4 — Employee Dashboard

KPI Cards:
- Solde de congés: "12 jours restants" (with mini progress bar)
- Prochain congé: "15/03 – 22/03" or "Aucun congé planifié"
- Dernier bulletin: "Février 2026 — 450 000 XOF"

Quick Actions:
- Demander un congé
- Pointer mon arrivée
- Voir mes bulletins de paie

Activity: Own actions only

P2 — RH Manager Dashboard

KPI Cards:
- Effectif: "48 employés actifs" (+2 ce mois)
- Demandes en attente: "5" (clickable, goes to approvals)
- Absences aujourd'hui: "3 employés absents"
- Masse salariale: "22 500 000 XOF" (current month)

Quick Actions:
- Approuver les demandes (5)
- Ajouter un employé
- Voir le planning des absences

Activity: Team actions

P3 — Accountant Dashboard

KPI Cards:
- Budget consommé: "68%" (gauge visualization)
- Engagements en attente: "3" (pending approval)
- Paie en cours: "Février 2026 — en validation"
- Écart budgétaire: "+5%" (warning if over threshold)

Quick Actions:
- Valider la paie
- Nouveau engagement
- Exporter le journal budgétaire

Activity: Finance-related actions

P1 — DG Dashboard

KPI Cards:
- Effectif total: "48"
- Masse salariale: "22 500 000 XOF"
- Budget restant: "32%" (with gauge)
- Demandes à approuver: "2"

Quick Actions:
- Approuver (2)
- Voir le tableau de bord financier
- Exporter le rapport mensuel

Activity: All company actions

6.7 Dashboard Offline Behavior

  • All KPI data is cached in IndexedDB on every successful fetch
  • When offline, dashboard shows cached data
  • Timestamp below KPI section: "Dernière mise à jour il y a X minutes"
  • If cached data is >1 hour old, add subtle warning banner: "Les données affichées datent de plus d'une heure. Connectez-vous pour actualiser."
  • Banner style: --color-warning-light background, --color-warning left border, --font-small text
  • Quick actions that require connectivity (e.g., submit new leave) still navigate to the form — offline queueing handles the rest

7. Navigation

7.1 Module Registry

Complete list of all modules with their navigation metadata:

# Key Icon Label (FR) Group Status Route
1 dashboard layout-dashboard Tableau de bord Quotidien active /
2 absence calendar Congés & Absences Quotidien active /conges
3 attendance qr-code Pointage QR Quotidien active /pointage
4 budget wallet Lignes budgétaires Finance active /budget
5 commitment file-signature Engagements Finance active /engagements
6 payroll banknote Paie Finance active /paie
7 expense receipt Notes de frais Finance locked
8 employee users Employés Ressources Humaines active /employes
9 performance target Performance & Objectifs Ressources Humaines locked
10 skills brain Compétences & GPEC Ressources Humaines locked
11 training book-open Formation Ressources Humaines locked
12 recruitment search Recrutement Ressources Humaines locked
13 crm briefcase CRM Interne Commercial active /crm
14 time clock Temps & Activités locked
15 hse shield-check HSE locked

Icon library recommendation: Lucide Icons (open-source, consistent, supports all icons listed above, tree-shakeable). 24px size for sidebar, 20px for bottom nav labels.

7.2 Group Headers (Sidebar)

Group headers are NOT clickable, NOT collapsible. They are visual separators only.

Style: - Text: --font-overline (11px, weight 600, letter-spacing 0.08em, uppercase) - Color: --color-sidebar-group-label - Margin: --space-6 (24px) top, --space-2 (8px) bottom - No background, no border — just text with spacing

7.3 Active Module Indicator

The currently active module is highlighted in the sidebar:

Expanded sidebar: - Left border: 3px solid --color-primary (#F59E0B) - Background: --color-sidebar-bg-active - Icon color: --color-sidebar-icon-active (amber) - Text color: --color-sidebar-text-active (white) - Text weight: 600 (medium → semibold shift)

Collapsed sidebar: - Small amber dot (6px) below the icon - Icon color: amber

Bottom navigation (mobile): - Icon: filled variant (not outline) - Label color: --color-primary - Top border: 2px solid --color-primary on the active tab

7.4 Locked Module ("Bientôt") State

Sidebar appearance: - Icon: same icon as active module, but at 50% opacity - Label: 50% opacity - Badge: small pill "Bientôt" to the right of the label - Background: rgba(245,158,11,0.15) (amber tint) - Text: --color-primary, --font-caption, weight 600 - Border-radius: --radius-full - Padding: 2px 8px - Cursor: pointer (it IS clickable — opens preview)

On click — Desktop (popover):

┌──────────────────────────────────────┐
│                                      │
│  📚  Formation                       │
│                                      │
│  Gérez les plans de formation,       │
│  suivez les certifications et        │
│  développez les compétences de       │
│  votre équipe.                       │
│                                      │
│  ┌──────────────────────────────┐    │
│  │  ✦ Bientôt disponible       │    │  ← Amber badge, centered
│  └──────────────────────────────┘    │
│                                      │
│  ☐ Me notifier à la sortie          │  ← Toggle/checkbox
│                                      │
└──────────────────────────────────────┘

Popover specs: - Width: 300px - Background: --color-surface - Shadow: --shadow-lg - Border-radius: --radius-lg - Positioned: to the right of the sidebar item, vertically centered - Dismiss: click outside, Escape key, or click X - Animation: fade in + scale from 0.95 to 1.0, 200ms

On click — Mobile (bottom sheet): Same content as popover, displayed in a bottom sheet. Sheet height: auto (fits content). Drag handle at top. Dismiss: swipe down or tap backdrop.

7.5 Admin Section

Visible only when user has TENANT_ADMIN or PLATFORM_ADMIN role.

Sidebar placement: Below all module groups, separated by a thicker divider (2px --color-sidebar-divider).

Items:

Icon Label Route
settings Paramètres entreprise /admin/parametres
users Utilisateurs & Rôles /admin/utilisateurs
scroll-text Journal d'audit /admin/audit
credit-card Abonnement /admin/abonnement

Style: Same as regular nav items. Group header: "ADMINISTRATION" in --font-overline.

Non-admin users: These items are completely absent from the DOM (not hidden, not greyed — absent). Security by exclusion.

7.6 Keyboard Navigation (Desktop)

For P3 (Comptable) and power users:

Shortcut Action
Alt + 1 through Alt + 9 Navigate to module 1–9 in the active list
Alt + D Go to Dashboard
Alt + S Focus search (future — not in Sprint 0)
/ Focus search when not in an input (future)
Ctrl + K Command palette (future — designed here, built later)

Sprint 0 implements Alt + D (dashboard) and Alt + 1..9 (module shortcuts). The shortcuts are listed in the user menu under "Raccourcis clavier."


8. Sync Status Indicator

8.1 States

State Icon Label (desktop) Color Animation
Synced Filled circle (8px) Synchronisé --color-sync-synced (green) None — static
Pending Filled circle (8px) + count badge 3 en attente --color-sync-pending (amber) None — static
Syncing Filled circle (8px) Synchronisation… --color-sync-syncing (blue) Gentle pulse (opacity 0.4→1.0, 1500ms ease-in-out, infinite)
Offline Filled circle (8px) Hors ligne --color-sync-offline (warm grey) None — static

8.2 Placement & Size

Mobile (top bar): Circle dot only (8px). No label. Count badge (if pending) overlaps the dot as a mini number (like notification badges). Total touch target area: 40px × 40px (allows tapping to expand).

Desktop (top bar): Dot (8px) + label text (--font-small). Total clickable area: fits content + 8px padding.

8.3 Expanded Sync Panel

Triggered by tapping/clicking the sync indicator. Appears as a dropdown panel below the indicator (desktop) or bottom sheet (mobile).

Desktop Dropdown

┌──────────────────────────────────────────┐
│  ● Synchronisation                       │
│                                          │
│  Dernière synchronisation :              │
│  il y a 12 minutes                       │
│                                          │
│  ── 3 opérations en attente ──           │
│                                          │
│  📅  Demande de congé                    │
│      Moussa Koné — 15/03 au 22/03        │
│      En attente de synchronisation       │
│                                          │
│  📍  Pointage                            │
│      Arrivée — 08:15                     │
│      En attente de synchronisation       │
│                                          │
│  📝  Engagement n°2024-031               │
│      Modification du montant             │
│      En attente de synchronisation       │
│                                          │
│  ┌──────────────────────────────────┐    │
│  │    Synchroniser maintenant       │    │  ← Secondary button
│  └──────────────────────────────────┘    │
│                                          │
└──────────────────────────────────────────┘

Specs: - Width: 360px - Max-height: 400px (scrollable if more items) - Background: --color-surface - Shadow: --shadow-lg - Border-radius: --radius-lg - Positioned: below the sync indicator, right-aligned with it

Queue item: - Icon: 20px, module-specific icon - Title: --font-body-medium, --color-text-primary - Subtitle: --font-small, --color-text-secondary - Status: --font-caption, --color-text-tertiary - Divider: 1px --color-border-light between items - Height: ~72px per item

"Synchroniser maintenant" button: - Secondary button style (outlined) - Disabled when already syncing or when offline - When offline, replaced by text: "Connexion requise pour synchroniser"

States in the Panel

When synced (no pending):

┌──────────────────────────────────────────┐
│  ● Tout est à jour                       │
│                                          │
│  Dernière synchronisation :              │
│  il y a 2 minutes                        │
│                                          │
│  ✓ Toutes les données sont              │
│    synchronisées avec le serveur.        │
└──────────────────────────────────────────┘

When offline:

┌──────────────────────────────────────────┐
│  ● Hors ligne                            │
│                                          │
│  Dernière synchronisation :              │
│  il y a 45 minutes                       │
│                                          │
│  Vos modifications sont sauvegardées     │
│  localement. La synchronisation          │
│  reprendra automatiquement dès que       │
│  la connexion sera rétablie.             │
│                                          │
│  ── 2 opérations en attente ──           │
│  [operation items...]                    │
└──────────────────────────────────────────┘

8.4 Sync Indicator UX Principles

  1. CALM, not alarming: "Hors ligne" is stated as a fact, not a warning. No red, no exclamation marks. Warm grey color conveys "we're handling this."
  2. Reassuring: "Vos modifications sont sauvegardées localement" — the user knows nothing is lost.
  3. Automatic: "La synchronisation reprendra automatiquement" — no user action required. The manual sync button is a power-user option, not a necessity.
  4. Transparent: Every queued operation is listed. No black box.

9. Responsive Behavior

9.1 Breakpoint Matrix

Component 360px (Phone) 768px (Tablet) 1024px (Desktop) 1440px (Large)
Navigation Bottom nav (4 tabs) Collapsed sidebar (68px) Expanded sidebar (260px) Expanded sidebar (260px)
Top bar 56px, compact 64px, page title 64px, breadcrumb + all controls 64px, same as 1024
Content padding 16px 24px 32px 32px
Content max-width 100% 100% 100% 1200px (centered)
KPI grid 1 column 2 columns 4 columns 4 columns
Quick actions 1 column stack 4 column row 3–4 column row 3–4 column row
Activity feed Full width Full width Full width 2/3 width (with sidebar widget)
Notification panel Bottom sheet (full width) Right slide-in (360px) Right slide-in (360px) Right slide-in (360px)
Sync panel Bottom sheet Dropdown Dropdown Dropdown
Login layout Centered card Centered card Split (50/50) Split (50/50)
Modals Full screen Centered (max 600px) Centered (max 600px) Centered (max 600px)
Tables Card list view Scrollable table Full table Full table
Forms 1 column 2 columns 2 columns 2 columns

9.2 Transition Behavior

When the viewport crosses a breakpoint boundary (e.g., rotating a tablet from portrait to landscape):

  • Layout changes are CSS-driven (media queries), not JS-driven
  • Sidebar expansion/collapse: 200ms ease-in-out transition on width
  • Bottom nav to sidebar: no animation (distinct layout modes, not morphing)
  • Content re-flow: instant (grid columns snap, no animation on grid changes)
  • Modals: if a full-screen modal is open on phone and user rotates to tablet width, it smoothly transitions to centered card (300ms)

9.3 Touch Considerations

  • All interactive elements: minimum 48×48px touch target (even if visually smaller, pad with transparent hit area)
  • Sidebar nav items: 44px tall + 4px gap = 48px effective touch target
  • Bottom nav items: 64px tall × 90px wide (exceeds minimum)
  • Swipe gestures:
  • Swipe right from left edge (tablet): open sidebar overlay
  • Swipe down on bottom sheet: dismiss
  • Swipe down on content area: pull-to-refresh (triggers sync)
  • NO swipe-to-navigate-back (conflicts with OS gesture)
  • Long press: not used in Sprint 0 (reserved for future context menus on list items)

9.4 Orientation Handling

  • Phone landscape: top bar stays, bottom nav stays. Content area gets wider but shorter. Not optimized for landscape — most phone usage is portrait. No special layout.
  • Tablet portrait (768px): collapsed sidebar mode
  • Tablet landscape (~1024px): expanded sidebar mode (matches desktop breakpoint)

10. Dark Mode

10.1 Toggle Behavior

  • Location: top bar (desktop — moon/sun icon), user menu (mobile — toggle row)
  • Default: follows OS prefers-color-scheme setting
  • Manual override: persisted in localStorage under key papillon-theme ("light" | "dark" | "system")
  • Toggle: 3-state cycle: System → Light → Dark → System
  • Icon: ☀️ (sun) when in dark mode (clicking switches to light), 🌙 (moon) when in light mode
  • Transition: 200ms CSS transition on background-color, color, border-color. No flash of unstyled content.

10.2 Dark Mode Token Overrides

All tokens below are set on [data-theme="dark"] or @media (prefers-color-scheme: dark).

Background Colors

Token Light Value Dark Value Notes
--color-bg-primary #FFFDF7 #1A1614 Warm dark brown (not cold grey)
--color-bg-secondary #FFF9EE #231F1B Card surfaces
--color-bg-tertiary #F5F0E8 #2D2824 Input backgrounds
--color-surface #FFFFFF #2D2824 Floating surfaces
--color-border #E8E0D4 #3D3530 Borders
--color-border-light #F0EBE3 #332D28 Subtle dividers

Text Colors

Token Light Value Dark Value
--color-text-primary #1C1917 #F5F0E8
--color-text-secondary #57534E #A8A29E
--color-text-tertiary #A8A29E #78716C
--color-text-inverse #FFFDF7 #1C1917

Brand Colors (Adjusted for Dark)

Token Light Value Dark Value Notes
--color-primary #F59E0B #FBBF24 Slightly brighter amber for contrast
--color-primary-hover #D97706 #F59E0B
--color-primary-light #FEF3C7 #3D2E0A Dark amber tint
--color-primary-subtle #FFFBEB #2D2410 Very dark amber wash
--color-secondary #0D6B6E #14B8A6 Brighter teal for dark backgrounds
--color-secondary-hover #0A5456 #0D9488
Token Light Value Dark Value
--color-sidebar-bg #0D6B6E #0A3D3F
--color-sidebar-bg-hover #0A5456 #0D4F4F
--color-sidebar-bg-active #083F41 #0D6B6E
--color-sidebar-text #CCFBF1 #99F6E4

Semantic Colors (Dark)

Token Light Value Dark Value
--color-success #16A34A #4ADE80
--color-success-light #DCFCE7 #14532D
--color-warning #F59E0B #FBBF24
--color-warning-light #FEF9C3 #3D2E0A
--color-error #DC2626 #F87171
--color-error-light #FEE2E2 #450A0A
--color-info #2563EB #60A5FA
--color-info-light #DBEAFE #1E3A5F

Shadow Overrides (Dark)

In dark mode, shadows are less visible. Increase opacity and use darker values:

Token Light Value Dark Value
--shadow-sm 0 1px 2px rgba(28,25,23,0.05) 0 1px 2px rgba(0,0,0,0.2)
--shadow-md 0 4px 12px rgba(28,25,23,0.08) 0 4px 12px rgba(0,0,0,0.3)
--shadow-lg 0 8px 24px rgba(28,25,23,0.12) 0 8px 24px rgba(0,0,0,0.4)
--shadow-xl 0 16px 48px rgba(28,25,23,0.16) 0 16px 48px rgba(0,0,0,0.5)

10.3 Dark Mode Design Principles

  1. Warm, not cold: Background is warm dark brown (#1A1614), not cool grey (#1a1a1a). This maintains the Papillon warmth.
  2. Reduce, don't invert: Colors are adjusted to work on dark backgrounds, not mathematically inverted.
  3. Elevate with lightness: In dark mode, higher-elevation surfaces are slightly lighter (cards lighter than page bg). This replaces the shadow-based hierarchy of light mode.
  4. Primary stays amber: The amber/gold never shifts to a different hue. It only adjusts brightness for contrast.
  5. OLED-friendly: The page background (#1A1614) is dark enough to save battery on OLED screens while being warm enough to not feel like a void.

11. Notification Panel

11.1 Trigger

The notification bell icon in the top bar. When unread notifications exist, a count badge is displayed.

Bell icon specs: - Icon: bell (Lucide), 24px - Color: --color-text-secondary (default), --color-text-primary (when has unread) - Badge: red circle with white count text - Position: top-right of bell icon, offset -4px, -4px - Size: 18px circle (for 1 digit), pill for 2+ digits - Background: --color-error - Text: white, --font-caption (12px), weight 700 - Max display: "9+" for 10+ notifications - Animation on new notification: badge scales from 0 to 1 (150ms spring)

11.2 Panel Layout — Desktop (Slide-in)

Triggered by clicking the bell. Slides in from the right edge.

┌──────────────────────────────────────┐
│  Notifications          [Tout lu] ✕  │  ← Header
├──────────────────────────────────────┤
│                                      │
│  AUJOURD'HUI                         │  ← Date group header
│                                      │
│  ┌──────────────────────────────┐    │
│  │ ● 📋 Demande de congé       │    │  ← Unread (● blue dot)
│  │    Moussa Koné a demandé un  │    │
│  │    congé du 15/03 au 22/03   │    │
│  │    Il y a 2 heures           │    │
│  └──────────────────────────────┘    │
│                                      │
│  ┌──────────────────────────────┐    │
│  │   ✅ Congé approuvé         │    │  ← Read (no dot)
│  │    Votre demande de congé    │    │
│  │    a été approuvée           │    │
│  │    Il y a 5 heures           │    │
│  └──────────────────────────────┘    │
│                                      │
│  HIER                                │
│                                      │
│  ┌──────────────────────────────┐    │
│  │   ⚙️ Système                 │    │
│  │    La paie de février est    │    │
│  │    prête à être validée      │    │
│  │    Hier à 14:30              │    │
│  └──────────────────────────────┘    │
│                                      │
│  ── Voir toutes les notifications ── │
│                                      │
└──────────────────────────────────────┘

Panel specs: - Width: 380px - Max-height: 100vh - topbar height - Position: fixed, right: 0, top: topbar height - Background: --color-surface - Shadow: --shadow-xl (left-side shadow since it's right-aligned) - Animation: slide in from right, 300ms --easing-enter - Backdrop: semi-transparent overlay on content (mobile only) - Close: ✕ button, Escape key, click outside

Header: - "Notifications" — --font-h3 (18px, semibold) - "Tout marquer comme lu" — text button, --color-primary, --font-small - ✕ close button: 24px icon, --color-text-secondary

11.3 Notification Item

┌──────────────────────────────────────┐
│ [●] [icon]  Title text               │
│             Description text, up to   │
│             2 lines max               │
│             Timestamp                 │
└──────────────────────────────────────┘

Specs: - Padding: --space-4 (16px) - Unread indicator: 8px blue dot (--color-info), left-aligned - Icon: 20px, colored by notification type - Title: --font-body-medium, --color-text-primary - Description: --font-small, --color-text-secondary, max 2 lines (line-clamp) - Timestamp: --font-caption, --color-text-tertiary - Hover (desktop): --color-bg-tertiary background - Tap: navigates to the related item + marks as read - Unread background: --color-primary-subtle (very light amber wash) - Read background: transparent

Notification types and their icons/colors:

Type Icon Icon Color Example
Approval request clock --color-warning "Moussa Koné a demandé un congé"
Status change (positive) check-circle --color-success "Votre congé a été approuvé"
Status change (negative) x-circle --color-error "Votre congé a été refusé"
System alert info --color-info "La paie est prête à valider"
Mention at-sign --color-secondary "Vous avez été mentionné dans…"

11.4 Empty State (Sprint 0 Default)

┌──────────────────────────────────────┐
│  Notifications                    ✕  │
├──────────────────────────────────────┤
│                                      │
│                                      │
│            🔔                        │
│                                      │
│    Aucune notification               │
│    pour le moment                    │
│                                      │
│    Vous serez notifié lorsque        │
│    quelque chose nécessite           │
│    votre attention.                  │
│                                      │
│                                      │
└──────────────────────────────────────┘

Style: - Icon: 48px, --color-text-tertiary, 50% opacity - Title: --font-h3, --color-text-primary - Subtitle: --font-body, --color-text-secondary, centered, max 240px width

11.5 Mobile Layout (Bottom Sheet)

On phone (<768px), the notification panel opens as a bottom sheet instead of a side panel.

  • Height: 70vh (expandable to 90vh by dragging up)
  • Drag handle: 32px × 4px rounded bar, centered, --color-text-tertiary
  • Full-width
  • Same content layout as desktop panel
  • Dismiss: swipe down or tap backdrop

11.6 Date Grouping Logic

Condition Group Label
Today "Aujourd'hui"
Yesterday "Hier"
Within 7 days "Cette semaine"
Older "Plus ancien"

Group label style: --font-overline, uppercase, --color-text-tertiary, --space-4 top margin.


12. PWA Spec

12.1 Install Banner

A non-intrusive banner encouraging PWA installation. Shown ONCE per device/session when the browser's beforeinstallprompt event fires.

┌──────────────────────────────────────────────────────────────┐
│  🦋  Installer Papillon sur votre      [Installer] [✕]      │
│      téléphone pour un accès rapide                          │
└──────────────────────────────────────────────────────────────┘

Specs: - Position: fixed, bottom: --bottomnav-height + 8px (above bottom nav on phone), bottom: 16px on desktop - Width: 100% - 32px (mobile), max 480px (desktop), centered - Background: --color-surface - Shadow: --shadow-xl - Border-radius: --radius-lg - Padding: --space-3 (12px) vertical, --space-4 (16px) horizontal - Layout: flex row — icon (butterfly) | text | Install button | dismiss X - "Installer" button: Primary style, small size - "✕" dismiss: icon button, --color-text-tertiary - Animation: slides up from below, 300ms

Behavior: - Only shows when beforeinstallprompt fires (browser supports PWA install) - On "Installer": trigger native install prompt - On "✕": dismiss banner, store papillon-pwa-dismissed: true in localStorage - Never show again after dismissal (respect the user) - Never show if PWA is already installed (check display-mode: standalone)

12.2 Splash Screen

Shown briefly when launching the PWA from the home screen.

Design:

┌──────────────────────────────────────┐
│                                      │
│                                      │
│                                      │
│              🦋                      │  ← Butterfly logo, 64px
│                                      │
│           Papillon                   │  ← Brand name, --font-display
│                                      │
│    Votre assistant RH de confiance   │  ← Tagline, --font-small
│                                      │
│                                      │
│                                      │
│                                      │
│                                      │
│      © 2026 ALTARYS ENTERPRISE       │  ← Footer, --font-caption
│                                      │
└──────────────────────────────────────┘

Implementation: Configured in manifest.json: - background_color: #FFFDF7 (light mode) — matches --color-bg-primary - theme_color: #0D6B6E (matches sidebar teal) - icons: 192px and 512px app icons (butterfly logo on amber/gold circle background) - The actual splash is browser-generated from manifest fields. The design above guides icon/color choices.

Dark mode splash: If user's OS is in dark mode, background_color should ideally be #1A1614. Since manifest doesn't support dark mode, the JS splash (displayed between manifest splash and app load) handles this: - Brief JS-rendered splash (500ms max) that checks theme preference and renders accordingly - Crossfades into the app

12.3 Offline Landing Page

Shown when user opens the app (or navigates to it) while offline AND has no cached session (not logged in, or JWT expired).

┌──────────────────────────────────────┐
│                                      │
│                                      │
│                                      │
│     [Geometric SVG illustration:     │
│      warm amber/teal circles and     │
│      arcs, suggesting connection     │
│      with a gentle "disconnected"    │
│      visual — e.g., two circles      │
│      almost touching but not quite]  │
│                                      │
│      Vous êtes hors ligne            │  ← --font-h1
│                                      │
│   Connectez-vous à Internet pour     │  ← --font-body
│   accéder à Papillon.                │
│                                      │
│   Dès que la connexion sera          │  ← --font-small, secondary text
│   rétablie, cette page se            │
│   rechargera automatiquement.        │
│                                      │
│                                      │
│              🦋                      │
│           Papillon                   │
│                                      │
└──────────────────────────────────────┘

Specs: - Full screen, centered content - Background: --color-bg-primary - Illustration: simple inline SVG (no external file — must be available offline) - The page registers a navigator.onLine listener and auto-reloads when connectivity returns - No "retry" button needed (auto-reload is sufficient), but include one for user agency: "Réessayer" subtle text button below the main text

Important: This page is cached by the Service Worker on first load. It MUST be available offline. All assets (SVG, fonts, CSS) must be in the SW cache.

12.4 Manifest Configuration

{
  "name": "Papillon HR Suite",
  "short_name": "Papillon",
  "description": "Votre assistant RH de confiance — Gestion des ressources humaines pour les PME",
  "start_url": "/",
  "display": "standalone",
  "orientation": "any",
  "background_color": "#FFFDF7",
  "theme_color": "#0D6B6E",
  "lang": "fr",
  "categories": ["business", "productivity"],
  "icons": [
    { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" },
    { "src": "/icons/icon-maskable-192.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" },
    { "src": "/icons/icon-maskable-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
  ]
}

App icon design: Butterfly silhouette (🦋) in white on an amber/gold (#F59E0B) circle background. Maskable versions include extra padding per Android adaptive icon guidelines. The icon should be simple enough to be recognizable at 48px on a home screen.


13. Shared Component Specs

These components live in packages/shared-components/ and are reused by both frontends. All components accept theme tokens via CSS custom properties — no hardcoded colors.

13.1 Button

The most-used interactive element. Five variants, three sizes.

Variants

Variant Background Text Border Usage
primary --color-primary --color-text-on-primary none Primary actions: "Se connecter", "Enregistrer", "Soumettre"
secondary transparent --color-secondary 1px --color-secondary Secondary actions: "Annuler", "Synchroniser"
ghost transparent --color-text-secondary none Tertiary actions: "Voir tout", "Plus tard"
danger --color-error white none Destructive: "Supprimer" (with undo, never confirm dialogs)
success --color-success white none Positive confirmation: "Approuver"

Sizes

Size Height Padding H Font Icon size Usage
sm 32px 12px --font-small (14px) 16px Inline actions, table rows
md 44px 16px --font-body (16px) 20px Default — most buttons
lg 52px 20px --font-body (16px, 600) 20px Full-width mobile CTAs

States

State Visual Change
default As specified per variant
hover Background darkens 10% (use --color-primary-hover etc.)
active/pressed Background darkens 15%, scale(0.98) for 100ms
focused --shadow-focus ring (3px amber glow)
loading Text replaced by spinner (16px). Button width locked (no layout shift). Disabled.
disabled 50% opacity. cursor: not-allowed. No hover effects.

Layout Options

  • Icon + text: icon left of text, --space-2 (8px) gap
  • Text only: centered text
  • Icon only: square button (same height as width based on size)
  • Full width: width: 100% — used for mobile CTAs

Accessibility

  • role="button" (implicit for <button>)
  • aria-disabled="true" when disabled (not just disabled attr for screen readers)
  • aria-busy="true" when loading
  • Focus indicator: visible on keyboard focus (:focus-visible), hidden on mouse click
  • Minimum touch target: 48×48px (even for sm — pad with invisible hit area)

13.2 Input

Text input fields with labels, helper text, and validation states.

Structure

  Label text                    (optional badge)
  ┌──────────────────────────────────────┐
  │ [icon]  Placeholder text       [⟐]  │
  └──────────────────────────────────────┘
  Helper text or error message

Specs

Property Value
Height 48px (touch-friendly)
Padding 12px horizontal, centered vertical
Background --color-bg-tertiary
Border 1px --color-border
Border-radius --radius-md (8px)
Font --font-body (16px) — prevents iOS zoom on focus
Label --font-small (14px), --font-body-medium weight, --color-text-primary
Label gap --space-1 (4px) below label
Placeholder --color-text-tertiary
Helper text --font-caption (12px), --color-text-secondary

Types

Type Specifics
text Standard single-line text
email inputmode="email", email keyboard on mobile
password Visibility toggle button (eye icon) inside input, right-aligned
number inputmode="numeric", no browser spinners (CSS: appearance: none)
date Native date picker on mobile, custom picker on desktop. Format display: DD/MM/YYYY
tel inputmode="tel", phone keyboard. Country code prefix select (see below)
select Custom styled dropdown (not native <select>). Searchable for lists >7 items
textarea Multi-line. Min-height: 96px. Auto-resize up to 240px, then scroll

States

State Border Background Label Icon
default --color-border --color-bg-tertiary --color-text-primary --color-text-tertiary
hover --color-border darkened same same same
focused --color-border-focus (amber) + --shadow-focus --color-surface --color-primary --color-primary
filled --color-border --color-bg-tertiary --color-text-primary --color-text-secondary
error --color-error --color-error-light --color-error --color-error
disabled --color-border-light --color-bg-tertiary 50% opacity --color-text-tertiary --color-text-tertiary
read-only none transparent --color-text-secondary hidden

Validation

  • Validate on blur (not on every keystroke — avoids premature errors)
  • Error message appears with a subtle slide-down animation (150ms)
  • Error message: --font-caption, --color-error, 4px below input
  • Success indicator: green checkmark icon inside input (right side) when valid after previous error
  • Required fields: asterisk (*) after label text, --color-error

Phone Input Variant

┌─────┬──────────────────────────────┐
│ +225│  07 00 00 00 00              │
│  ▾  │                              │
└─────┴──────────────────────────────┘
  • Country code selector: 72px wide, left section
  • Default: +225 (CI), also shows 🇨🇮 flag
  • Options: +225 (CI), +229 (BJ), +237 (CM)
  • Format mask auto-applied based on country

13.3 Card

Container component for grouping related content.

Variants

Variant Usage Specs
default KPI cards, content sections --color-bg-secondary bg, --color-border border, --shadow-sm
elevated Floating panels, popovers --color-surface bg, --shadow-md
interactive Clickable cards (module previews) Same as default + hover: --shadow-md, translateY(-2px)
outlined Subtle grouping without elevation transparent bg, --color-border 1px border

Structure

┌──────────────────────────────────────┐
│  [Header area — optional]            │  ← Card.Header
│  Title            [Action button]    │
├──────────────────────────────────────┤
│                                      │
│  [Content area]                      │  ← Card.Content
│                                      │
├──────────────────────────────────────┤
│  [Footer area — optional]            │  ← Card.Footer
└──────────────────────────────────────┘

Specs: - Border-radius: --radius-lg (12px) - Padding: --space-5 (20px) mobile, --space-6 (24px) desktop - Header/footer separation: 1px --color-border-light divider - Full-bleed content option: negative margins to touch card edges (for tables/images inside cards)

13.4 Modal / Dialog

Overlay dialog for focused interactions. Full-screen on mobile, centered card on tablet+.

Layout

Mobile (<768px): Full screen

┌──────────────────────────────────────┐
│  ← Titre du modal             [✕]   │  ← Sticky header, 56px
├──────────────────────────────────────┤
│                                      │
│  [Scrollable content area]           │
│                                      │
│                                      │
├──────────────────────────────────────┤
│  [Annuler]          [Action primaire]│  ← Sticky footer
└──────────────────────────────────────┘

Tablet+ (≥768px): Centered card

         ┌──────────────────────────┐
         │  Titre du modal     [✕]  │  ← Header
         ├──────────────────────────┤
         │                          │
         │  [Content area]          │  ← Max-height: 70vh, scrollable
         │                          │
         ├──────────────────────────┤
         │  [Annuler]    [Action]   │  ← Footer, right-aligned buttons
         └──────────────────────────┘
         Backdrop: rgba(0,0,0,0.5)

Specs: - Desktop width: 480px (small), 600px (medium), 800px (large) - Background: --color-surface - Border-radius: --radius-xl (16px) — desktop only (mobile is full-screen) - Shadow: --shadow-xl - Backdrop: rgba(0,0,0,0.5) with blur (4px) - Animation open: backdrop fades in (200ms), modal scales from 0.95 + fades in (200ms) - Animation close: reverse (150ms — faster close feels snappy) - Close triggers: ✕ button, Escape key, backdrop click (unless persistent prop) - Focus trap: Tab cycles within modal. First focusable element auto-focused on open. - aria-modal="true", role="dialog", aria-labelledby pointing to title

13.5 Toast / Snackbar

Brief feedback messages that appear at screen edge and auto-dismiss.

Variants

Variant Icon Background Border-left
success check-circle --color-success-light 4px --color-success
error alert-circle --color-error-light 4px --color-error
warning alert-triangle --color-warning-light 4px --color-warning
info info --color-info-light 4px --color-info

Layout

┌──────────────────────────────────────┐
│  [icon]  Message text          [✕]   │
│          Optional action link        │
└──────────────────────────────────────┘

Specs: - Position: fixed, bottom-center (mobile), top-right (desktop) - Mobile: full width - 32px margin, 16px from bottom nav - Desktop: 400px max-width, 16px from top-right corner - Border-radius: --radius-md (8px) - Shadow: --shadow-lg - Padding: --space-3 (12px) vertical, --space-4 (16px) horizontal - Icon: 20px - Text: --font-body, --color-text-primary - Action link: --font-body-medium, --color-primary, underline on hover - Auto-dismiss: 5 seconds (success/info), 8 seconds (warning), persistent until dismissed (error) - Animation: slide in from bottom (mobile) or right (desktop), 200ms - Stack: multiple toasts stack vertically with 8px gap, max 3 visible - Z-index: --z-toast (600)

Accessibility: - role="alert" for error/warning, role="status" for success/info - aria-live="polite" (success/info) or aria-live="assertive" (error)

13.6 Loading Skeleton

Placeholder shapes shown while content loads. ALWAYS use skeletons, never spinners (skeletons feel faster and show expected layout).

Variants

Variant Shape Usage
text Rounded rectangle, height 16px Body text placeholder
title Rounded rectangle, height 24px, width 60% Heading placeholder
avatar Circle, 40px diameter User avatar placeholder
card Rounded rectangle matching card size KPI card, content card
button Rounded rectangle matching button size Action button placeholder
table-row Full-width rectangle, height 48px Table row placeholder

Animation: Shimmer effect — gradient sweep from left to right, 1.5s ease-in-out infinite. - Light mode shimmer: --color-bg-tertiary--color-bg-secondary--color-bg-tertiary - Dark mode shimmer: --color-bg-tertiary → slightly lighter → --color-bg-tertiary

Specs: - Border-radius: --radius-sm (6px) for text/table, --radius-lg for cards, --radius-full for avatars - Background: --color-bg-tertiary - No border - Opacity: 0.7 (subtle, not aggressive)

Accessibility: aria-hidden="true" on skeletons, aria-busy="true" on the container being loaded.

Usage rule: The skeleton must match the shape of the content it's replacing. Never use a generic "loading bar" — use shaped skeletons that preview the layout.

13.7 Empty State

Displayed when a list, table, or section has no data.

Structure

        [SVG illustration]        ← 120px, themed geometric
                                     shapes (amber + teal)

        Title text                ← --font-h2, --color-text-primary

        Description text that     ← --font-body, --color-text-secondary
        explains what this area      max-width: 320px, centered
        is for and what to do.

        [Primary CTA button]      ← Primary button, md size

Specs: - Centered vertically and horizontally in the parent container - SVG illustration: unique per context (different shape compositions for different modules) - Padding: --space-12 (48px) around the entire block - Gap between elements: --space-4 (16px) - CTA is optional (some empty states are informational only)

Sprint 0 empty states needed:

Context Illustration hint Title Subtitle CTA
Dashboard activity Circles connected by arcs Aucune activité récente L'activité de votre équipe apparaîtra ici.
Notifications Bell with gentle waves Aucune notification pour le moment Vous serez notifié lorsque quelque chose nécessite votre attention.
Module placeholder Shapes suggesting the module Bientôt disponible Ce module est en cours de développement. Me notifier
Generic list Dotted circle with plus Aucun élément Commencez par ajouter votre premier élément. Ajouter

13.8 Data Table

Basic table for Sprint 0. Enhanced with sort, filter, and pagination in Sprint 1.

Desktop Layout (≥768px)

┌──────────────────────────────────────────────────────┐
│  Nom           │ Poste          │ Statut   │ Actions │  ← Header row
├──────────────────────────────────────────────────────┤
│  Moussa Koné   │ Commercial     │ ● Actif  │ [⋮]    │  ← Data row
│  Awa Diallo    │ Comptable      │ ● Actif  │ [⋮]    │
│  Ibrahim Touré │ Développeur    │ ○ Congé  │ [⋮]    │
├──────────────────────────────────────────────────────┤
│  ◀  1  2  3  ...  12  ▶        │ 50 résultats       │  ← Footer (pagination)
└──────────────────────────────────────────────────────┘

Specs: - Container: --color-surface background, --radius-lg border-radius, --shadow-sm - Header row: --color-bg-tertiary background, --font-small weight 600, --color-text-secondary - Header height: 44px - Data row: --color-surface background, --font-body - Row height: 52px (touch-friendly) - Alternating rows: even rows get --color-bg-primary background (very subtle) - Row hover: --color-primary-subtle background - Cell padding: --space-4 (16px) horizontal - Border: 1px --color-border-light between rows - Action column: icon button (more actions), opens dropdown on click

Mobile Layout (<768px) — Card List View

Tables transform into card lists on mobile:

┌──────────────────────────────────────┐
│  👤 Moussa Koné                      │
│     Commercial             ● Actif   │
│                              [⋮]     │
├──────────────────────────────────────┤
│  👤 Awa Diallo                       │
│     Comptable              ● Actif   │
│                              [⋮]     │
└──────────────────────────────────────┘

Each row becomes a card with key data visible and secondary data available on tap (expand).

13.9 Badge / Tag

Small labels for status, counts, and categorization.

Variants

Variant Background Text Border Usage
default --color-bg-tertiary --color-text-secondary none Neutral categorization
primary --color-primary-light --color-primary-hover none Active/selected filter
success --color-success-light --color-success none "Actif", "Approuvé"
warning --color-warning-light --color-warning (darkened) none "En attente", "Bientôt"
error --color-error-light --color-error none "Refusé", "Expiré"
info --color-info-light --color-info none "Nouveau", informational

Sizes: - sm: height 20px, padding 0 6px, --font-caption (12px) - md: height 24px, padding 2px 8px, --font-caption (12px, weight 500)

Specs: - Border-radius: --radius-full (pill shape) - Optional leading dot (8px circle, same color as text) for status badges - Optional dismiss ✕ icon for removable tags (only on interactive variants)

13.10 Avatar

User/company identity display.

Sizes

Size Diameter Font Usage
xs 24px 10px Inline mentions, compact lists
sm 32px 12px Activity feed, notification items
md 40px 16px Sidebar user, table rows
lg 56px 20px User profile header
xl 80px 28px Profile page, large display

Variants

Variant Display Usage
image User photo (cropped circle) When photo available
initials 1-2 letter initials on colored background Default fallback
icon Generic user icon on neutral background Anonymous/system
company Company logo (square, rounded corners) Tenant logo

Initials variant colors: Generated from user name hash to ensure consistency. Palette of 8 warm/cool colors that work in both light and dark mode: #F59E0B, #0D6B6E, #7C3AED, #DC2626, #2563EB, #059669, #DB2777, #EA580C

Specs: - Border-radius: --radius-full (circle) - Border: 2px --color-surface (creates a white ring, useful when overlapping) - Initials: centered, white text on colored background, weight 600 - Online status dot (optional): 10px circle, bottom-right, --color-success with 2px white border - Company variant: --radius-md border-radius (not circle)

13.11 Breadcrumb

Navigation path indicator. Desktop only (hidden on mobile where screen title is sufficient).

Layout

Tableau de bord  /  Employés  /  Moussa Koné
   (link)            (link)       (current, not linked)

Specs: - Separator: / character, --color-text-tertiary, --space-2 (8px) horizontal padding - Link items: --font-small, --color-text-secondary, underline on hover, --color-primary on hover - Current (last item): --font-small, --color-text-primary, weight 500, not clickable - Truncation: on narrow viewports, early items collapse to with a dropdown on click - aria-label="Fil d'Ariane" on the nav element - Current item: aria-current="page"

Responsive: - ≥1024px: Full breadcrumb visible - 768px–1023px: Show last 2 items, earlier ones collapse to - <768px: Hidden (page title in top bar is sufficient)


14. French Micro-copy Document

Every user-facing string in the host shell. Organized by component/screen. These are the EXACT strings the DEVELOPER implements in the i18n JSON file.

14.1 Authentication

Key String
auth.login.title Connectez-vous à votre espace RH
auth.login.email.label Adresse e-mail
auth.login.email.placeholder [email protected]
auth.login.password.label Mot de passe
auth.login.password.show Afficher le mot de passe
auth.login.password.hide Masquer le mot de passe
auth.login.submit Se connecter
auth.login.submit.loading Connexion…
auth.login.forgot Mot de passe oublié ?
auth.login.error.credentials Adresse e-mail ou mot de passe incorrect
auth.login.error.network Impossible de se connecter. Vérifiez votre connexion Internet.
auth.login.error.locked Votre compte est temporairement verrouillé. Réessayez dans 15 minutes ou réinitialisez votre mot de passe.
auth.login.error.generic Une erreur est survenue. Veuillez réessayer.
auth.login.welcome Bienvenue sur Papillon ! 🦋
auth.recovery.title Mot de passe oublié
auth.recovery.description Saisissez votre adresse e-mail. Si un compte existe, vous recevrez un lien de réinitialisation.
auth.recovery.email.label Adresse e-mail
auth.recovery.submit Réinitialiser mon mot de passe
auth.recovery.submit.loading Envoi en cours…
auth.recovery.success.title E-mail envoyé !
auth.recovery.success.description Si l'adresse {email} est associée à un compte, vous recevrez un e-mail avec un lien de réinitialisation.
auth.recovery.success.spam Vérifiez aussi vos courriers indésirables.
auth.recovery.back Retour à la connexion
auth.recovery.error.network Impossible d'envoyer la demande. Vérifiez votre connexion.
auth.offline.title Vous êtes hors ligne
auth.offline.description Connectez-vous à Internet pour accéder à Papillon.
auth.offline.auto Dès que la connexion sera rétablie, cette page se rechargera automatiquement.
auth.offline.retry Réessayer
auth.token.expired Votre session a expiré. Veuillez vous reconnecter.

14.2 Navigation — Module Labels

Key String
nav.group.daily QUOTIDIEN
nav.group.finance FINANCE
nav.group.hr RESSOURCES HUMAINES
nav.group.commercial COMMERCIAL
nav.group.admin ADMINISTRATION
nav.dashboard Tableau de bord
nav.absence Congés & Absences
nav.attendance Pointage QR
nav.budget Lignes budgétaires
nav.commitment Engagements
nav.payroll Paie
nav.expense Notes de frais
nav.employee Employés
nav.performance Performance & Objectifs
nav.skills Compétences & GPEC
nav.training Formation
nav.recruitment Recrutement
nav.crm CRM Interne
nav.time Temps & Activités
nav.hse HSE
nav.settings Paramètres entreprise
nav.users Utilisateurs & Rôles
nav.audit Journal d'audit
nav.billing Abonnement

14.3 Navigation — States & Actions

Key String
nav.locked.badge Bientôt
nav.locked.status Bientôt disponible
nav.locked.notify Me notifier à la sortie
nav.locked.notified Vous serez notifié
nav.mobile.more Plus
nav.mobile.more.title Tous les modules
nav.skip Aller au contenu principal

14.4 Locked Module Descriptions

Key String
module.expense.desc Gérez les notes de frais, les justificatifs et les remboursements de votre équipe.
module.performance.desc Définissez des objectifs, réalisez les entretiens annuels et suivez la performance de vos collaborateurs.
module.skills.desc Cartographiez les compétences, planifiez la GPEC et identifiez les besoins en formation.
module.training.desc Gérez les plans de formation, suivez les certifications et développez les compétences de votre équipe.
module.recruitment.desc Publiez des offres, suivez les candidatures et gérez votre processus de recrutement.
module.time.desc Suivez le temps passé par projet, activité et collaborateur.
module.hse.desc Gérez la santé, la sécurité et l'environnement au travail.

14.5 Dashboard

Key String
dashboard.title Tableau de bord
dashboard.kpi.employees employés actifs
dashboard.kpi.employees.trend +{count} ce mois
dashboard.kpi.leaves demandes de congé en attente
dashboard.kpi.budget du budget utilisé
dashboard.kpi.budget.trend +{percent}% vs mois dernier
dashboard.kpi.commitments engagements ce mois
dashboard.actions.title Actions rapides
dashboard.actions.leave Nouvelle demande de congé
dashboard.actions.approve Approuver les demandes ({count})
dashboard.actions.clockin Pointer mon arrivée
dashboard.activity.title Activité récente
dashboard.activity.empty.title Aucune activité récente
dashboard.activity.empty.description L'activité de votre équipe apparaîtra ici.
dashboard.activity.viewall Voir toute l'activité
dashboard.stale.warning Les données affichées datent de plus d'une heure. Connectez-vous pour actualiser.
dashboard.lastupdated Dernière mise à jour il y a {time}

14.6 Sync Status

Key String
sync.synced Synchronisé
sync.synced.description Toutes les données sont synchronisées avec le serveur.
sync.pending {count} en attente
sync.pending.description {count} opérations en attente de synchronisation
sync.syncing Synchronisation…
sync.offline Hors ligne
sync.offline.description Vos modifications sont sauvegardées localement. La synchronisation reprendra automatiquement dès que la connexion sera rétablie.
sync.offline.required Connexion requise pour synchroniser
sync.lastsync Dernière synchronisation : il y a {time}
sync.panel.title Synchronisation
sync.panel.allclear Tout est à jour
sync.panel.manual Synchroniser maintenant
sync.item.pending En attente de synchronisation

14.7 Notifications

Key String
notifications.title Notifications
notifications.markallread Tout marquer comme lu
notifications.empty.title Aucune notification pour le moment
notifications.empty.description Vous serez notifié lorsque quelque chose nécessite votre attention.
notifications.viewall Voir toutes les notifications
notifications.group.today Aujourd'hui
notifications.group.yesterday Hier
notifications.group.thisweek Cette semaine
notifications.group.older Plus ancien

14.8 User Menu

Key String
user.profile Mon profil
user.preferences Préférences
user.shortcuts Raccourcis clavier
user.logout Se déconnecter
user.logout.success Vous avez été déconnecté avec succès.

14.9 Dark Mode

Key String
theme.system Système
theme.light Clair
theme.dark Sombre
theme.toggle.label Changer le thème

14.10 PWA

Key String
pwa.install.message Installer Papillon sur votre téléphone pour un accès rapide
pwa.install.button Installer
pwa.install.dismiss Plus tard
pwa.install.success Papillon est installé ! Accédez-y depuis votre écran d'accueil.

14.11 Time Formatting

Key String
time.now à l'instant
time.minutes il y a {count} minutes
time.hours il y a {count} heures
time.yesterday hier à {time}
time.date le {date}

14.12 Generic / Shared

Key String
generic.loading Chargement…
generic.loading.module Chargement du module…
generic.error.generic Une erreur est survenue. Veuillez réessayer.
generic.error.network Problème de connexion. Vérifiez votre accès Internet.
generic.retry Réessayer
generic.cancel Annuler
generic.save Enregistrer
generic.save.loading Enregistrement…
generic.save.success Modifications enregistrées
generic.delete Supprimer
generic.delete.undo Annuler la suppression
generic.confirm Confirmer
generic.close Fermer
generic.back Retour
generic.next Suivant
generic.previous Précédent
generic.search Rechercher…
generic.noResults Aucun résultat trouvé
generic.required Ce champ est obligatoire
generic.invalidEmail Veuillez saisir une adresse e-mail valide
generic.copyright © 2026 ALTARYS ENTERPRISE
generic.tagline Votre assistant RH de confiance
generic.empty.title Aucun élément
generic.empty.description Commencez par ajouter votre premier élément.
generic.empty.add Ajouter
generic.results {count} résultats
generic.selected {count} sélectionnés

14.13 Accessibility Labels (ARIA)

Key String
aria.login.form Formulaire de connexion
aria.nav.main Navigation principale
aria.nav.breadcrumb Fil d'Ariane
aria.nav.bottom Navigation rapide
aria.sync.indicator Indicateur de synchronisation
aria.notifications.bell Notifications
aria.notifications.unread {count} notifications non lues
aria.theme.toggle Changer le thème d'affichage
aria.user.menu Menu utilisateur
aria.sidebar.toggle Ouvrir le menu de navigation
aria.sidebar.collapse Réduire le menu
aria.modal.close Fermer la fenêtre
aria.toast.dismiss Fermer la notification

15. Brand Compliance Checklist

Papillon HR Suite ✓

  • [x] Amber/gold primary color used#F59E0B as --color-primary, used for buttons, active nav, accents, focus rings
  • [x] Mobile-first layout (360px designed first) — All wireframes start at 360px. Bottom navigation, single-column KPIs, full-screen modals on mobile
  • [x] Offline states specified for ALL write operations — Sync indicator (§8) covers all 4 states. Dashboard offline behavior (§6.7). Login offline (§4.1). PWA offline landing (§12.3). Sync panel shows queued operations
  • [x] Touch targets 48px minimum — Inputs: 48px height. Buttons (md): 44px + padding. Bottom nav: 64×90px. Sidebar items: 44px + 4px gap. All verified per spec
  • [x] French micro-copy warm and human — All strings in §14 use warm, conversational French. Errors are helpful, not technical. "Oops" avoided (too informal for professional context), replaced with empathetic phrasing
  • [x] Loading skeletons (not spinners) specified — §13.6 specifies skeleton variants for text, title, avatar, card, button, table-row. Shimmer animation specified. Only exception: button loading state uses inline spinner (contextually appropriate)
  • [x] Generous whitespace — not crowded — Spacing tokens range 4–64px. Cards use 20–24px padding. Content padding 16–32px per breakpoint. KPI grid has 16–24px gaps. Single-column mobile layout prevents crowding
  • [x] Celebration animation specified for milestone actions — §1 Q9: First login confetti + welcome toast. PWA install success toast with butterfly animation. Module-specific celebrations deferred to module design docs

Additional Compliance

  • [x] Deep teal/forest green secondary#0D6B6E sidebar, consistent throughout
  • [x] Warm off-white background#FFFDF7, not clinical white
  • [x] Dark mode warm#1A1614 base, warm brown tones, not cold charcoal
  • [x] Typography 16px body minimum--font-body: 16px. Smallest text: --font-overline: 11px (labels only, never body)
  • [x] French diacritics support — Inter font family specified, supports full Latin Extended
  • [x] Low density — One action per screen on mobile. Dashboard shows 2 KPI cards above fold, not 4
  • [x] Guided onboarding — First login welcome, contextual empty states with CTAs, locked module previews educate about upcoming features
  • [x] "Votre assistant RH de confiance" tone — Tagline in login, splash screen. Micro-copy is helpful and reassuring throughout
  • [x] WCAG AA compliance — Contrast ratios verified for all color pairs. Color never sole indicator. ARIA labels in French. Focus indicators specified. Skip navigation link included
  • [x] Design tokens (not hardcoded) — Complete token table in §2. All component specs reference tokens, not hex values
  • [x] Currency: XOF with zero decimals — Specified in dashboard KPI examples: "450 000 XOF" (space as thousands separator)
  • [x] Date format: DD/MM/YYYY — Specified in notification examples and input specs
  • [x] Number format: space thousands separator — "22 500 000 XOF" in dashboard specs
  • [x] prefers-reduced-motion respected — §1 Q8 animation philosophy: all animations respect reduced motion preference
  • [x] Performance budget compatible — SVG icons (not images), max 2 font families, code splitting, skeleton loading, minimal animations

Appendix A: Component File Mapping

For the DEVELOPER — where each component should be created:

Component Location Rationale
AppShell frontend/src/components/shell/AppShell.tsx Shell-only, not shared
Sidebar frontend/src/components/shell/Sidebar.tsx Shell-only
BottomNav frontend/src/components/shell/BottomNav.tsx Shell-only
TopBar frontend/src/components/shell/TopBar.tsx Shell-only
SyncIndicator frontend/src/components/shell/SyncIndicator.tsx Shell-only
SyncPanel frontend/src/components/shell/SyncPanel.tsx Shell-only
NotificationBell frontend/src/components/shell/NotificationBell.tsx Shell-only
NotificationPanel frontend/src/components/shell/NotificationPanel.tsx Shell-only
UserMenu frontend/src/components/shell/UserMenu.tsx Shell-only
DarkModeToggle frontend/src/components/shell/DarkModeToggle.tsx Shell-only
Dashboard frontend/src/pages/Dashboard.tsx Page-level
LoginPage frontend/src/pages/auth/LoginPage.tsx Page-level
RecoveryPage frontend/src/pages/auth/RecoveryPage.tsx Page-level
OfflineLanding frontend/src/pages/auth/OfflineLanding.tsx Page-level
Button packages/shared-components/src/Button.tsx Shared
Input packages/shared-components/src/Input.tsx Shared
Card packages/shared-components/src/Card.tsx Shared
Modal packages/shared-components/src/Modal.tsx Shared
Toast packages/shared-components/src/Toast.tsx Shared
Skeleton packages/shared-components/src/Skeleton.tsx Shared
EmptyState packages/shared-components/src/EmptyState.tsx Shared
DataTable packages/shared-components/src/DataTable.tsx Shared
Badge packages/shared-components/src/Badge.tsx Shared
Avatar packages/shared-components/src/Avatar.tsx Shared
Breadcrumb packages/shared-components/src/Breadcrumb.tsx Shared
theme.ts packages/shared-components/src/theme.ts Token system
theme-papillon.ts frontend/src/theme-papillon.ts Papillon overrides

Appendix B: Design Token Implementation Guide

For the DEVELOPER — how to implement the token system:

// packages/shared-components/src/theme.ts

// 1. Define the token interface (type-safe)
export interface ThemeTokens {
  colors: {
    primary: string;
    primaryHover: string;
    primaryLight: string;
    // ... all color tokens from §2.1
  };
  typography: {
    fontFamily: string;
    display: TypographyToken;
    h1: TypographyToken;
    // ... all type tokens from §2.2
  };
  spacing: Record<string, string>;  // from §2.3
  radius: Record<string, string>;   // from §2.4
  shadows: Record<string, string>;  // from §2.5
  animation: Record<string, string>; // from §2.6
  layout: Record<string, string>;   // from §2.7
  zIndex: Record<string, number>;   // from §2.8
}

// 2. Papillon theme implements this interface
// frontend/src/theme-papillon.ts
export const papillonTheme: ThemeTokens = {
  colors: {
    primary: '#F59E0B',
    primaryHover: '#D97706',
    // ... all values from §2.1
  },
  // ...
};

// 3. Theme is injected via CSS custom properties at the root
// This allows Enterprise frontend to inject different values
// at Month 12 without changing component code

End of document. This design spec is complete and self-contained for Sprint 0 implementation.