diff --git a/.impeccable/critique/2026-08-30T21-23-40Z__frontend-src.md b/.impeccable/critique/2026-08-30T21-23-40Z__frontend-src.md
new file mode 100644
index 0000000..1201125
--- /dev/null
+++ b/.impeccable/critique/2026-08-30T21-23-40Z__frontend-src.md
@@ -0,0 +1,65 @@
+---
+target: frontend/src (UI complète Wordly.art)
+total_score: 28
+max_score: 40
+na_heuristics:
+p0_count: 0
+p1_count: 2
+timestamp: 2026-08-30T21-23-40Z
+slug: frontend-src
+---
+# Évaluation de design — Wordly.art (`frontend/src`) — 3ᵉ passage
+
+Méthode : double agent isolé (A : agent_a56a818e · B : agent_fa9c4f90)
+
+## Score de santé (10 règles d'ergonomie, 0-4 chacune)
+
+| # | Règle | Note | Problème principal |
+|---|-------|------|--------------------|
+| 1 | L'utilisateur sait toujours où il en est | 3 | Aucun retour visuel quand on survole la zone de dépôt avec un fichier (`isDragOver` calculé dans `useFileUpload.ts:69-77` mais jamais affiché, `translate/page.tsx:359-415`) ; « Tout approuver » enchaîne les demandes sans progression (`reviews/[jobId]/page.tsx:159-167`). |
+| 2 | Le produit parle la langue de ses utilisateurs | 3 | Restes de jargon : « Le job a été arrêté » (`fr/translate.json:102`), « Segments », « Moteur contextuel » — globalement bien vulgarisé (XLIFF expliqué). |
+| 3 | L'utilisateur garde le contrôle | 3 | Retrait d'un membre d'équipe sans confirmation (`teams/page.tsx:195-205`) ; ailleurs excellent (annulation réelle, reprise après rafraîchissement). |
+| 4 | Cohérence de l'ensemble | 2 | Page Glossaires en couleurs brutes hors système (`glossaries/page.tsx:93,115,130`), n'utilise pas l'en-tête commun `page-header.tsx` ; émojis ⚠️🎯🌐 dans les avertissements (`GlossarySelector.tsx:342,352,379`) ; achat de crédits sans confirmation alors que les abonnements en ont une. |
+| 5 | Prévention des erreurs | 3 | Bouton bloqué sans explication quand langue source = langue cible (`useTranslationConfig.ts:237`, aides incomplètes `translate/page.tsx:617-622`). |
+| 6 | Reconnaissance plutôt que mémoire | 3 | Récapitulatif pendant et après le traitement, historique récent avec liens de relecture. |
+| 7 | Vitesse pour les utilisateurs intensifs | 3 | Ctrl+Entrée existe mais n'est jamais annoncé à l'écran ; pas de filtre « à relire uniquement » dans la table de relecture. |
+| 8 | Sobriété visuelle | 2 | Micro-textes 8,5-10 px par centaines (`ProviderSelector.tsx:201`, `landing-page.tsx:278,350`) ; 5 plans × 5-10 fonctions par carte. |
+| 9 | Récupération après erreur | 3 | Erreurs traduites en actions (`translate/page.tsx:91-112`), fichier conservé + Réessayer. |
+| 10 | Aide disponible | 3 | Aides contextuelles réelles ; pas de centre d'aide. |
+| **Total** | | **28/40** | **Palier « bonne interface » (28-35)** |
+
+## Verdict de spécificité
+
+**Revue** : l'accueil devient « parfois précieux » — le dessin animé du hero (`hero-visual.tsx`) est jugé « la meilleure pièce du site » : la promesse produit est dessinée, pas photographiée, avec le balayage doré « détail d'auteur ». L'outil Traduire est « la surface la plus authentique » (pipeline dédié, avertissements de glossaire, garde source = cible) ; la relecture parle « le vocabulaire de la localisation, pas du SaaS générique ». Restent deux plaques de modèle tout fait : le mur de 6 cartes de fonctionnalités de l'accueil, et les « signaux de confiance » de la page tarifs.
+
+**Scan automatique** : 3 constats inchangés — les 2 Inter (choix assumé « outil sobre ») et le faux positif du rond de chargement.
+
+## Ce qui marche
+
+1. **L'état d'attente comme pièce maîtresse** : progression, phases nommées, temps restant estimé honnêtement, annulation serveur réelle, survie au rafraîchissement. « Peu de produits d'IA assument l'attente avec cette précision. »
+2. **Le langage du métier assumé** : XLIFF expliqué, avertissements glossaire précis, garde anti source = cible.
+3. **Les garde-fous des gestes irréversibles** : approbation en deux clics, confirmation avant paiement, confirmation de purge.
+
+## Problèmes prioritaires
+
+1. **[P1] La zone de dépôt est muette au survol.** Le premier geste du produit n'a aucun retour. → Afficher un contour doré et un léger agrandissement pendant le survol (`translate/page.tsx:361`).
+2. **[P1] L'or des petits textes est illisible.** `#C5A17A` sur crème ≈ 2,3:1, et des textes à 8,5-10 px partout. → Assombrir l'or des textes à `#8B6F47`, plancher 11 px (`globals.css:196`, `ProviderSelector.tsx:201`).
+3. **[P2] « Tout approuver » sans progression.** Sur 500 segments : 500 demandes enchaînées sans compteur ni arrêt. → Compteur dans le bouton + arrêt possible (`reviews/[jobId]/page.tsx:151-168`).
+4. **[P2] Bouton bloqué sans raison quand source = cible.** → Ajouter l'explication manquante (`translate/page.tsx:617-622`).
+5. **[P2] Page Glossaires hors système + sélecteur de glossaire trop chargé.** Couleurs brutes, pas d'en-tête commun ; dans le flux de traduction, le sélecteur empile 6 décisions (choix, filtre, avertissements, aperçu, ajout de terme). → Migrer la page aux couleurs du système ; réduire le sélecteur au choix + avertissements, l'ajout de terme derrière un lien dépliable (`glossaries/page.tsx:107`, `GlossarySelector.tsx:578-614`).
+
+## Drapeaux rouges par persona
+
+**Alex (expert pressé)** : le raccourci Ctrl+Entrée n'est annoncé nulle part ; pas de filtre « à relire uniquement » sur 800 segments ; les icônes du pipeline et les libellés d'étapes suivent deux seuils contradictoires (`translate/page.tsx:660` vs `:42`).
+**Sam (accessibilité)** : or clair illisible + micro-textes ; sévérité des avertissements glossaire portée par des émojis et la seule couleur ; le bandeau d'annonce de la page tarifs n'est pas lu aux lecteurs d'écran (contrairement aux notifications).
+**Jordan (premier usage)** : la mention légale à l'inscription n'est pas cliquable ; l'annulation réussie d'une traduction s'affiche en rouge comme une erreur ; membres d'équipe en codes illisibles.
+
+## Observations mineures
+
+Restes de replis français codés en dur (`translate/page.tsx:861,868,881`) ; le lien tarifs de l'accueil construit l'adresse avec le nom traduit du plan (cassera le jour où le nom est traduit) ; l'accueil montre 3 plans, la page tarifs 5 sans le gratuit en haut ; « document réservé libéré » formulation opaque ; double barre de défilement dans la liste des langues ; page « Réglages » sans aucun réglage ; bouton d'échange de langues mort mais visible ; titres par défaut en Inter alors que la charte repose sur le serif posé à la main ; clé dupliquée preserveLayout.
+
+## Questions à se poser
+
+1. La grille tarifaire doit-elle vraiment montrer les 5 plans en même temps ? Free et Enterprise en lignes secondaires rendraient la décision binaire.
+2. Pourquoi l'ajout de termes existe-t-il à la fois dans le sélecteur de traduction ET dans la page glossaires ? Laquelle est la vraie maison du geste ?
+3. Que gagnerait l'écran d'attente à montrer le document lui-même, comme le dessin animé de l'accueil — une continuité entre la promesse et l'exécution ?
diff --git a/frontend/src/app/dashboard/DashboardSidebar.tsx b/frontend/src/app/dashboard/DashboardSidebar.tsx
index fcefd68..fbea933 100644
--- a/frontend/src/app/dashboard/DashboardSidebar.tsx
+++ b/frontend/src/app/dashboard/DashboardSidebar.tsx
@@ -39,7 +39,7 @@ export function DashboardSidebar() {
{t('dashboard.sidebar.upgradeToPro', { defaultValue: 'Passer Pro →' })}
@@ -64,7 +64,7 @@ export function DashboardSidebar() {
@@ -305,7 +305,7 @@ export function ProviderSelector({
{/* Pro upgrade banner when llm is active and user is not pro */}
{!isPro && activeTab === 'llm' && (
@@ -347,7 +402,7 @@ const PricingSection = () => {
diff --git a/frontend/src/lib/i18n/messages/en/landing.json b/frontend/src/lib/i18n/messages/en/landing.json
index b9f5d66..cef46a9 100644
--- a/frontend/src/lib/i18n/messages/en/landing.json
+++ b/frontend/src/lib/i18n/messages/en/landing.json
@@ -150,5 +150,23 @@
"landing.translate.processing": "Processing",
"landing.translate.preservingLayout": "Your layout is being preserved",
"landing.formats.pill": "COMPATIBILITY",
- "landing.hero.visualCaption": "Same layout, new language — nothing else moves"
+ "landing.hero.visualCaption": "Same layout, new language — nothing else moves",
+ "landing.beforeAfter.sourceTitle": "Cahier des charges — Traitement d'air",
+ "landing.beforeAfter.targetTitle": "Technical specification — Air handling",
+ "landing.beforeAfter.sourcePara1": "L'installation de ventilation doit être mise en service avant la fin du deuxième trimestre.",
+ "landing.beforeAfter.targetPara1": "The ventilation system must be commissioned before the end of the second quarter.",
+ "landing.beforeAfter.sourcePara2Before": "Le",
+ "landing.beforeAfter.sourceTerm": "groupe de traitement d'air",
+ "landing.beforeAfter.sourcePara2After": "doit respecter la classe de filtration F7 conformément au planning.",
+ "landing.beforeAfter.targetPara2Before": "The",
+ "landing.beforeAfter.targetTerm": "air handling unit",
+ "landing.beforeAfter.targetPara2After": "must comply with filter class F7 as specified in the schedule.",
+ "landing.beforeAfter.sourceItem1": "Charge thermique : 42 kW au débit nominal",
+ "landing.beforeAfter.targetItem1": "Thermal load: 42 kW at nominal flow",
+ "landing.beforeAfter.sourceItem2": "Niveau sonore inférieur à 45 dB(A) à 3 m",
+ "landing.beforeAfter.targetItem2": "Sound level below 45 dB(A) at 3 m",
+ "landing.beforeAfter.seal": "Same layout, word for word",
+ "landing.beforeAfter.proof1": "SmartArt diagrams rebuilt, not flattened",
+ "landing.beforeAfter.proof2": "Chart series and axes translated",
+ "landing.beforeAfter.proof3": "Tables of contents regenerated in the target language"
}
diff --git a/frontend/src/lib/i18n/messages/en/pricing.json b/frontend/src/lib/i18n/messages/en/pricing.json
index d80e49a..92853bb 100644
--- a/frontend/src/lib/i18n/messages/en/pricing.json
+++ b/frontend/src/lib/i18n/messages/en/pricing.json
@@ -159,5 +159,9 @@
"pricing.confirm.monthlyEquivalent": "Billed yearly — {price} € / month equivalent.",
"pricing.confirm.secureNote": "You can cancel anytime from your profile. Payment is processed by Stripe; your card details never touch our servers.",
"pricing.confirm.cancel": "Cancel",
- "pricing.confirm.cta": "Continue to payment"
+ "pricing.confirm.cta": "Continue to payment",
+ "pricing.freeBand.text": "Just want to try? Start free — 5 documents per month, no card required.",
+ "pricing.freeBand.cta": "Start free",
+ "pricing.enterpriseBand.text": "Volume, dedicated engines, on-premise options — let's talk.",
+ "pricing.enterpriseBand.cta": "Contact us"
}
diff --git a/frontend/src/lib/i18n/messages/fr/landing.json b/frontend/src/lib/i18n/messages/fr/landing.json
index b87fcf4..5836fbc 100644
--- a/frontend/src/lib/i18n/messages/fr/landing.json
+++ b/frontend/src/lib/i18n/messages/fr/landing.json
@@ -150,5 +150,23 @@
"landing.translate.processing": "Traitement en cours",
"landing.translate.preservingLayout": "Votre mise en page est en cours de préservation",
"landing.formats.pill": "COMPATIBILITÉ",
- "landing.hero.visualCaption": "Même mise en page, nouvelle langue — rien d'autre ne bouge"
+ "landing.hero.visualCaption": "Même mise en page, nouvelle langue — rien d'autre ne bouge",
+ "landing.beforeAfter.sourceTitle": "Cahier des charges — Traitement d'air",
+ "landing.beforeAfter.targetTitle": "Technical specification — Air handling",
+ "landing.beforeAfter.sourcePara1": "L'installation de ventilation doit être mise en service avant la fin du deuxième trimestre.",
+ "landing.beforeAfter.targetPara1": "The ventilation system must be commissioned before the end of the second quarter.",
+ "landing.beforeAfter.sourcePara2Before": "Le",
+ "landing.beforeAfter.sourceTerm": "groupe de traitement d'air",
+ "landing.beforeAfter.sourcePara2After": "doit respecter la classe de filtration F7 conformément au planning.",
+ "landing.beforeAfter.targetPara2Before": "The",
+ "landing.beforeAfter.targetTerm": "air handling unit",
+ "landing.beforeAfter.targetPara2After": "must comply with filter class F7 as specified in the schedule.",
+ "landing.beforeAfter.sourceItem1": "Charge thermique : 42 kW au débit nominal",
+ "landing.beforeAfter.targetItem1": "Thermal load: 42 kW at nominal flow",
+ "landing.beforeAfter.sourceItem2": "Niveau sonore inférieur à 45 dB(A) à 3 m",
+ "landing.beforeAfter.targetItem2": "Sound level below 45 dB(A) at 3 m",
+ "landing.beforeAfter.seal": "Même mise en page, mot pour mot",
+ "landing.beforeAfter.proof1": "Les SmartArt sont reconstruits, pas aplatis",
+ "landing.beforeAfter.proof2": "Séries et axes des graphiques traduits",
+ "landing.beforeAfter.proof3": "Tables des matières régénérées dans la langue cible"
}
diff --git a/frontend/src/lib/i18n/messages/fr/pricing.json b/frontend/src/lib/i18n/messages/fr/pricing.json
index 854a657..e24bba5 100644
--- a/frontend/src/lib/i18n/messages/fr/pricing.json
+++ b/frontend/src/lib/i18n/messages/fr/pricing.json
@@ -159,5 +159,9 @@
"pricing.confirm.monthlyEquivalent": "Facturation annuelle — soit {price} € / mois.",
"pricing.confirm.secureNote": "Résiliable à tout moment depuis votre profil. Paiement traité par Stripe ; vos données bancaires ne passent jamais par nos serveurs.",
"pricing.confirm.cancel": "Annuler",
- "pricing.confirm.cta": "Continuer vers le paiement"
+ "pricing.confirm.cta": "Continuer vers le paiement",
+ "pricing.freeBand.text": "Juste envie d'essayer ? Commencez gratuitement — 5 documents par mois, sans carte.",
+ "pricing.freeBand.cta": "Commencer gratuitement",
+ "pricing.enterpriseBand.text": "Volume, moteurs dédiés, hébergement spécifique — parlons-en.",
+ "pricing.enterpriseBand.cta": "Nous contacter"
}