diff --git a/templates/marketing/fonctionnalites.html b/templates/marketing/fonctionnalites.html
index 73d04ff..35031e0 100644
--- a/templates/marketing/fonctionnalites.html
+++ b/templates/marketing/fonctionnalites.html
@@ -408,6 +408,20 @@
.dictia-feat-btn { transition: transform 0.18s ease, background-color 0.2s ease, opacity 0.2s ease; will-change: transform; }
.dictia-feat-btn:hover { transform: scale(1.08); opacity: 1 !important; }
+ /* Process breadcrumb step buttons (top of section, light bg) */
+ .dictia-step-btn { transition: transform 0.2s ease, background-color 0.25s ease, border-color 0.25s ease; will-change: transform; }
+ .dictia-step-btn:hover { transform: translateY(-1px); }
+ .dictia-step-btn.is-past { opacity: 0.55; }
+ .dictia-step-btn.is-future { opacity: 0.40; }
+ .dictia-step-btn.is-active { transform: scale(1.03); }
+
+ /* Step navigator bottom (dark bg, inside phone) */
+ .dictia-step-bottom:hover { transform: translateY(-1px); }
+
+ /* Step section right panel (mini groups by stage) */
+ .dictia-step-section { transition: border-color 0.3s ease, background-color 0.3s ease, box-shadow 0.3s ease; }
+ .dictia-step-section.is-active { box-shadow: 0 0 24px rgba(0,0,0,0.25), inset 0 0 16px rgba(255,255,255,0.02); }
+
/* Hide scrollbar mobile pills */
.dictia-hide-scrollbar::-webkit-scrollbar { display: none; }
@@ -452,6 +466,7 @@
.dictia-phone-glow-ring, .dictia-rec-dot, .dictia-wave-bar,
.dictia-typing-dot, .dictia-lang-highlight, .dictia-connecting-line,
.dictia-auto-pulse, .dictia-countdown-fill { animation: none !important; }
+ .dictia-step-btn, .dictia-step-bottom, .dictia-step-section { transition: none !important; }
}
@@ -496,23 +511,93 @@
- {# ── DASHBOARD HOLOGRAPHIQUE — 2 colonnes (phone center + IA right) ── #}
-
+ {# ── DASHBOARD HOLOGRAPHIQUE — wrapper outer column (process breadcrumb + progress + 2-col layout) ── #}
+
- {# Connecting line SVG (phone -> IA panel, desktop only) #}
+ {# ─────────────── PROCESS BREADCRUMB — 4 étapes du flow utilisateur (refonte narrative 2026-04-29 v3) ─────────────── #}
+
+
+ {# ── 2 colonnes (phone center + IA right) ── #}
+
+
+ {# Connecting line SVG (phone -> IA panel, desktop only) — directional arrow with travelling dot #}
-
@@ -1200,27 +1285,28 @@
- {# BOTTOM : 6 boutons feature originaux (Trans / Diari / Lang / Exp / Users / Part) + Auto pill — hauteur fixe 90px #}
+ {# BOTTOM : Step navigator — 4 boutons étapes (au lieu de 6 features individuelles) + Auto pill — refonte narrative 2026-04-29 v3 #}
- {# 6 boutons features originaux (FEATURES indexes 1-6) — visible bottom tab bar #}
-
-
-
- Auto reprend bientôt
+ Manuel · Auto reprend bientôt
@@ -1247,20 +1333,26 @@
{# /dictia-phone-shell #}
{# /phone wrapper (glow ring) #}
- {# Feature info card sous le phone — fond bg-brand-navy SOLIDE (extension visuelle du phone, contraste WCAG AA garanti sur section claire) + accent border-left tab indicator #}
-
+ {# Feature info card sous le phone — affiche contexte processus (étape + sub-mode) — bg-brand-navy SOLIDE + accent border-left #}
+
{# Border-left 3px accent — style tab indicator #}
- {# Badge top-right #}
-
-
-
+ {# Process context header : ÉTAPE X/4 · TITRE — small breadcrumb pill #}
+
+
+ Étape /4 ·
+
+ {# Badge top-right (sub-mode) #}
+
+
+
+
{# Icon container 32×32 #}
-
+
@@ -1279,10 +1371,10 @@
- {# Mobile : pills features horizontales scrollables (12 fonctions, indexes 1-12) #}
+ {# Mobile : pills features horizontales scrollables — suivent PROCESS_ORDER (13 sub-modes) #}
{# IA Mistral 7B premium card — couleurs brand-b3 (fuchsia officiel) #}
@@ -1409,26 +1501,49 @@
- {# Feature grid 3×4 — 12 fonctions (FEATURES indexes 1-12, IA mode 0 accessible via Brain card ci-dessus) #}
-
-
-
-
-
-
-
-
+ {# Feature grid REFONTE NARRATIVE — 4 mini-sections par étape (12 boutons regroupés selon flow) #}
+
+
+
+ {# Mini header : badge numéro + titre #}
+
+
+
+ Étape ·
+
+
+ {# Mini buttons — flex wrap compact #}
+
+
+
+
+
+
+
+
+
+
+
-
+
{# /2-col flex layout #}
+
{# /dictiaDashboard wrapper outer column #}
@@ -1453,29 +1568,47 @@
{ idx: 11, title: 'Audit trail', subtitle: 'Traçabilité Loi 25 immutable', color: '#2563eb', badge: 'Loi 25' }, /* brand-b1 */
{ idx: 12, title: 'Conformité', subtitle: '9 ordres pros · EFVP CAI', color: '#c026d3', badge: 'MCN' } /* brand-b3 */
],
- selectedFeature: 1,
+ /* PROCESS NARRATIF — ordre canonique du flow utilisateur (refonte 2026-04-29 v3).
+ Cycle : Capture → Transformation IA → Distribution → Recherche & Gouvernance.
+ 13 sub-modes (mode 0 IA inclus) — auto-cycle ≈ 14.3s tour complet. */
+ PROCESS_ORDER: [7, 1, 2, 3, 9, 0, 4, 6, 5, 10, 8, 11, 12],
+ STEPS: [
+ { id: 1, title: 'Capture', short: 'Capture', subtitle: 'Audio in', subModes: [7, 1], color: '#06b6d4' }, /* brand-b2 */
+ { id: 2, title: 'Transformation IA', short: 'Transform.', subtitle: 'Le moteur', subModes: [2, 3, 9, 0], color: '#c026d3' }, /* brand-b3 */
+ { id: 3, title: 'Distribution', short: 'Distrib.', subtitle: 'Partage', subModes: [4, 6, 5, 10], color: '#2563eb' }, /* brand-b1 */
+ { id: 4, title: 'Recherche & Gouvernance', short: 'Gouv.', subtitle: 'Long terme',subModes: [8, 11, 12], color: '#06b6d4' } /* brand-b2 */
+ ],
+ processIdx: 0,
isManual: false,
autoCycleTimer: null,
manualResetTimer: null,
+ get selectedFeature() { return this.PROCESS_ORDER[this.processIdx]; },
get displayMode() { return this.selectedFeature; },
get activeColor() { return this.FEATURES[this.displayMode].color; },
+ get activeStep() {
+ const sf = this.selectedFeature;
+ const s = this.STEPS.find(st => st.subModes.includes(sf));
+ return s ? s.id : 1;
+ },
+ get progressPercent() {
+ return Math.round(((this.processIdx + 1) / this.PROCESS_ORDER.length) * 100);
+ },
init() {
if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
this.startAutoCycle();
},
- /* Auto-cycle logic : avance 1→12 (skip 0=IA mode, accessible via Brain card), 1100ms each.
- Cycle complet : 12 features × 1100ms ≈ 13.2s puis recommence à 1. */
+ /* Auto-cycle logic : suit PROCESS_ORDER (13 sub-modes), 1100ms each.
+ Cycle complet : 13 modes × 1100ms ≈ 14.3s puis recommence à processIdx=0. */
startAutoCycle() {
if (this.autoCycleTimer) clearInterval(this.autoCycleTimer);
this.autoCycleTimer = setInterval(() => {
- /* Avance 1→2→...→12, puis retour à 1 (skip 0=IA) */
- this.selectedFeature = this.selectedFeature >= 12 ? 1 : this.selectedFeature + 1;
- if (this.selectedFeature === 0) this.selectedFeature = 1;
+ this.processIdx = (this.processIdx + 1) % this.PROCESS_ORDER.length;
}, 1100);
},
- /* Click manuel sur un bouton feature : sélectionne ce mode + freeze auto 4500ms */
+ /* Click manuel sur un bouton feature : trouve son index dans PROCESS_ORDER + freeze auto 4500ms */
handleManualSelect(i) {
- this.selectedFeature = i;
+ const idx = this.PROCESS_ORDER.indexOf(i);
+ if (idx >= 0) this.processIdx = idx;
this.isManual = true;
if (this.autoCycleTimer) { clearInterval(this.autoCycleTimer); this.autoCycleTimer = null; }
if (this.manualResetTimer) clearTimeout(this.manualResetTimer);
@@ -1484,6 +1617,12 @@
this.startAutoCycle();
}, 4500);
},
+ /* Click sur une étape du breadcrumb / bottom step nav : jump au 1er sub-mode de l'étape */
+ goToStep(stepId) {
+ const step = this.STEPS.find(s => s.id === stepId);
+ if (!step || step.subModes.length === 0) return;
+ this.handleManualSelect(step.subModes[0]);
+ },
featureIconPath(i) {
const paths = {
0: '',
diff --git a/tests/test_marketing_secondary_pages.py b/tests/test_marketing_secondary_pages.py
index 38fa45a..b1c78e6 100644
--- a/tests/test_marketing_secondary_pages.py
+++ b/tests/test_marketing_secondary_pages.py
@@ -300,6 +300,42 @@ def test_fonctionnalites_how_it_works_reactor_section():
# Performance metrics : 3 cells with grad-text for 0ms / 24/7
assert 'grad-text' in body, "Missing grad-text on metrics"
+ # ── REFONTE NARRATIVE PROCESSUS 2026-04-29 v3 ──────────────────────────
+ # PROCESS_ORDER : ordre canonique du flow utilisateur (13 sub-modes, mode 0 inclus)
+ assert 'PROCESS_ORDER' in body, "Missing PROCESS_ORDER array (narrative refactor)"
+ assert '[7, 1, 2, 3, 9, 0, 4, 6, 5, 10, 8, 11, 12]' in body, \
+ "Missing canonical PROCESS_ORDER sequence (Capture → Transform IA → Distribution → Gouvernance)"
+ # 4 STEPS (étapes principales) + helpers
+ assert 'STEPS:' in body, "Missing STEPS array"
+ assert "'Capture'" in body, "Missing étape 1 Capture"
+ assert "'Transformation IA'" in body, "Missing étape 2 Transformation IA"
+ assert "'Distribution'" in body, "Missing étape 3 Distribution"
+ assert "'Recherche & Gouvernance'" in body, "Missing étape 4 Recherche & Gouvernance"
+ assert 'subModes:' in body, "Missing subModes mapping"
+ # Computed states + helpers
+ assert 'processIdx' in body, "Missing processIdx state"
+ assert 'activeStep' in body, "Missing activeStep getter"
+ assert 'goToStep' in body, "Missing goToStep helper"
+ assert 'progressPercent' in body, "Missing progressPercent getter"
+ # Process breadcrumb visible above phone
+ assert 'dictia-process-breadcrumb' in body, "Missing process breadcrumb wrapper"
+ assert 'Étapes du processus DictIA' in body, "Missing breadcrumb aria-label"
+ assert 'aria-current' in body, "Missing aria-current on active step"
+ # Progress bar
+ assert 'role="progressbar"' in body, "Missing progressbar role"
+ assert 'Progression du flow' in body, "Missing progress bar label"
+ # Bottom step navigator (4 buttons étapes au lieu de 6 features)
+ assert 'dictia-step-bottom' in body, "Missing bottom step navigator class"
+ assert 'Étapes du processus' in body, "Missing bottom tablist aria-label"
+ # Right panel : 4 mini-sections par étape
+ assert 'dictia-step-section' in body, "Missing right panel step sections"
+ # Feature info card : context processus (Étape X/4 · Titre)
+ assert 'STEPS[activeStep - 1]' in body, "Missing process context binding in feature card"
+ # Connecting line : travelling dot following processIdx
+ assert 'PROCESS_ORDER.length' in body, "Missing PROCESS_ORDER.length binding (travelling dot or progress)"
+ # Right panel header : updated badge
+ assert '12 fonctions · 4 étapes' in body, "Missing right panel updated badge"
+
def test_fonctionnalites_export_formats_section():
client = app.test_client()