diff --git a/SOLUTIONS_contact_4.md b/SOLUTIONS_contact_4.md
new file mode 100644
index 0000000..1bf9e8b
--- /dev/null
+++ b/SOLUTIONS_contact_4.md
@@ -0,0 +1,165 @@
+# ✅ Solutions — Niveau 5 contact (`PROCHAINE_ETAPE_contact_4.md`)
+
+> 🛑 **À NE REGARDER QU'EN DERNIER RECOURS.**
+> Cherche d'abord par toi-même (au moins 10–15 min, doc MDN à l'appui). Quand tu lis une réponse : lis-la, **ferme le fichier**, et réécris-la **de mémoire**. C'est comme ça que ça rentre.
+
+Le code ci-dessous est **un** exemple correct. Le tien peut être différent et tout aussi valable.
+
+---
+
+## 🧪 Exo 1 — `map`
+
+```js
+const noms = equipe.map(function (membre) {
+ return membre.nom;
+});
+console.log(noms); // ["Mélissa", "Guillaume"]
+```
+> 💬 *« `map` ou `filter` ? »* `filter` garde/jette des éléments (la liste rétrécit). `map` transforme chaque élément (la liste garde la même taille). Ici on veut transformer chaque objet en son nom → `map`.
+
+---
+
+## 🧪 Exo 2 — `find`
+
+```js
+const personne = equipe.find(function (membre) {
+ return membre.partie === "Page contact";
+});
+
+if (personne) {
+ console.log(personne.nom);
+} else {
+ console.log("Personne ne correspond.");
+}
+```
+> 💬 *« Pourquoi le `if (personne)` ? »* Si aucun élément ne correspond, `find` renvoie `undefined`. Faire `personne.nom` planterait. On vérifie d'abord. (Variante moderne : `personne?.nom` — cherche `optional chaining`.)
+
+---
+
+## 🧪 Exo 3 — `reduce`
+
+Avec une boucle (plus lisible pour commencer) :
+```js
+let totalKm = 0;
+for (const v of vehicules) {
+ totalKm = totalKm + v.km;
+}
+```
+La même chose en `reduce` :
+```js
+const totalKm = vehicules.reduce(function (somme, v) {
+ return somme + v.km;
+}, 0); // ← 0 = la valeur de départ
+console.log(totalKm);
+```
+> 💬 *« À quoi sert le `0` à la fin ? »* C'est la valeur de départ de l'accumulateur (`somme`). Pour une somme on part de 0 ; pour multiplier on partirait de 1.
+
+---
+
+## 🧪 Exo 4 — Délégation d'événements
+
+Quand tu génères les lignes, marque chaque ligne avec le nom (un attribut `data-…`) :
+```js
+function creerLigne(membre) {
+ const tr = document.createElement("tr");
+ tr.dataset.nom = membre.nom; // devient data-nom="..." dans le HTML
+ // ... (les
comme avant)
+ return tr;
+}
+```
+Puis **un seul** écouteur, sur le parent qui ne bouge pas :
+```js
+const corps = document.getElementById("corps_equipe");
+corps.addEventListener("click", function (event) {
+ const ligne = event.target.closest("tr"); // la | cliquée, peu importe la |
+ if (ligne) {
+ alert("Membre : " + ligne.dataset.nom);
+ }
+});
+```
+> 💬 *« Pourquoi ne pas mettre l'écouteur sur chaque ` |
` ? »* Parce que tes lignes sont recréées à chaque recherche/tri : il faudrait tout réattacher à chaque fois. En écoutant le **parent** (qui, lui, ne change pas), ça marche même pour les lignes créées plus tard.
+> 💬 *« À quoi sert `closest("tr")` ? »* Le clic peut tomber sur une `| ` ; `closest` remonte jusqu'à la ` |
` qui la contient.
+
+---
+
+## 🧪 Exo 5 — Debounce sur la recherche
+
+```js
+let minuteur; // garde la trace du minuteur en cours
+
+champRecherche.addEventListener("input", function () {
+ clearTimeout(minuteur); // on annule le précédent
+ minuteur = setTimeout(function () { // on en relance un
+ const mot = champRecherche.value.toLowerCase();
+ const resultats = equipe.filter(m => m.nom.toLowerCase().includes(mot));
+ afficherEquipe(resultats);
+ }, 300); // 300 ms après la DERNIÈRE frappe
+});
+```
+> 💬 *« Comment ça « attend » ? »* À chaque frappe, on **annule** le minuteur précédent (`clearTimeout`) et on en repart un de 300 ms. Tant que tu tapes, il est sans cesse annulé ; il ne se déclenche que quand tu fais une pause.
+
+---
+
+## 🧪 Exo 6 — Modules `export` / `import`
+
+`navbar.js` :
+```js
+export function creerNavbar(pageActive) {
+ return `... ton HTML de navbar ...`;
+}
+```
+`contact.js` (tout en haut) :
+```js
+import { creerNavbar } from "./navbar.js";
+document.body.insertAdjacentHTML("afterbegin", creerNavbar("contact"));
+```
+HTML :
+```html
+
+```
+> 💬 *« Depuis que j'utilise `type="module"`, mes autres scripts ne se voient plus ! »* Normal : chaque module a son **propre** espace. Une variable d'un fichier n'est plus visible ailleurs **sauf** si tu l'`export`es et l'`import`es. C'est justement le but : plus de variables globales qui se marchent dessus.
+> 💬 *« Erreur CORS au chargement du module. »* Comme `fetch`, les modules exigent un serveur : `python3 -m http.server` puis `http://localhost:8000/...` (pas `file://`).
+
+---
+
+## 🧪 Exo 7 — Vraie API en ligne
+
+```js
+async function chargerUtilisateurs() {
+ const liste = document.getElementById("liste_users");
+ try {
+ const reponse = await fetch("https://jsonplaceholder.typicode.com/users");
+ const users = await reponse.json();
+ for (const u of users) {
+ const li = document.createElement("li");
+ li.textContent = `${u.name} — ${u.email}`;
+ liste.append(li);
+ }
+ } catch (erreur) {
+ console.error(erreur);
+ }
+}
+chargerUtilisateurs();
+```
+> 💬 *« Comment je sais que les clés s'appellent `name` et `email` ? »* J'ai d'abord ouvert `https://jsonplaceholder.typicode.com/users` dans le navigateur pour **voir** la forme des données. Fais toujours ça avant d'afficher.
+> 💬 *« Ça marche sur le web mais mon fichier local non ? »* Une API en ligne autorise les requêtes externes (CORS) ; un fichier local ouvert en `file://` non. D'où le serveur local pour tes propres fichiers.
+
+---
+
+## 🧪 Exo 8 — `FormData`
+
+```js
+formulaire.addEventListener("submit", function (evenement) {
+ evenement.preventDefault();
+ const data = new FormData(formulaire);
+ const valeurs = Object.fromEntries(data);
+ console.log(valeurs); // { prenom: "...", email: "...", contacter: "..." }
+});
+```
+> 💬 *« `FormData` me renvoie du vide ! »* Vérifie que chaque champ a un attribut **`name`** (pas seulement `id`). `FormData` lit les champs par leur `name`.
+> 💬 *« C'est mieux que `getElementById` partout ? »* Pour lire **tout** un formulaire d'un coup, oui : une ligne au lieu d'un `getElementById` par champ. Pour un seul champ ponctuel, `getElementById` reste très bien.
+
+---
+
+### 🆘 Encore bloquée après la solution ?
+Note : *ce que tu attendais, ce qui se passe à la place, et ce qu'affiche la Console (F12)*. Avec ces 3 infos, on débloque vite.