diff --git a/SOLUTIONS_services_2.md b/SOLUTIONS_services_2.md
new file mode 100644
index 0000000..6b302f1
--- /dev/null
+++ b/SOLUTIONS_services_2.md
@@ -0,0 +1,263 @@
+# ✅ Solutions — rattrapage services (`PROCHAINE_ETAPE_services_2.md`)
+
+> 🛑 **À NE REGARDER QU'EN DERNIER RECOURS.**
+> Cherche d'abord par toi-même (au moins 10–15 min, et regarde la doc MDN). Recopier une solution sans l'avoir cherchée, ça ne s'apprend pas. Quand tu lis une réponse ici : lis-la, **ferme le fichier**, et réécris-la **de mémoire**. Si tu y arrives, c'est gagné.
+
+Le code ci-dessous est **un** exemple correct. Le tien peut être écrit autrement et être tout aussi bon.
+
+---
+
+## 🩹 Préambule — les 3 corrections de ton `devis.js`
+
+**1. L'attribut de la textarea** : c'est `rows` (pluriel), pas `row`.
+```html
+
+```
+
+**2. Bloquer AVANT d'afficher** : on teste la limite d'abord, on affiche ensuite.
+```js
+boutonPlus.addEventListener("click", function () {
+ if (nbVehicules < 100) { // on teste AVANT
+ nbVehicules = nbVehicules + 1;
+ }
+ mettreAJour(); // on affiche APRÈS (jamais 100 puis retour)
+});
+```
+
+**3. Le total se recalcule, il ne se stocke pas.** Supprime `totalargent` et `mettreAJourTOTAL`. Une seule fonction d'affichage suffit :
+```js
+function mettreAJour() {
+ affichageNb.textContent = nbVehicules;
+ affichageGeo.textContent = nbVehicules * PRIX_GPS;
+ affichageConso.textContent = nbVehicules * PRIX_CONSOMMATION;
+}
+```
+> 💬 *« Pourquoi pas une variable `totalargent` ? »* Parce qu'elle pourrait se désynchroniser de `nbVehicules`. Une valeur qui se déduit d'une autre, on la **calcule au moment de l'afficher** : impossible qu'elle soit fausse.
+
+---
+
+## 🟢 Exo 1 — Singulier / pluriel
+
+Dans le HTML, mets le mot dans son propre span, à côté du nombre :
+```html
+1véhicule
+```
+Dans `mettreAJour()` :
+```js
+motVehicule.textContent = nbVehicules === 1 ? "véhicule" : "véhicules";
+```
+(avec `const motVehicule = document.getElementById("mot_vehicule");` en haut.)
+
+> 💬 *« `=`, `==` ou `===` ? »* `=` **range** une valeur. `===` **compare** (et vérifie aussi le type). Dans un `if`/un test, utilise toujours `===`.
+
+---
+
+## 🟢 Exo 2 — Compteur de caractères
+
+HTML, sous la textarea :
+```html
+
Il vous reste 500 caractères.
+```
+JS :
+```js
+const zoneMsg = document.getElementById("msg");
+const restant = document.getElementById("restant");
+const MAX = 500;
+
+zoneMsg.addEventListener("input", function () {
+ const reste = MAX - zoneMsg.value.length;
+ restant.textContent = reste;
+ restant.style.color = reste < 50 ? "red" : "black"; // bonus
+});
+```
+> 💬 *« Pourquoi `input` et pas `click` ? »* `click` ne se déclenche qu'au clic de souris ; `input` se déclenche à **chaque modification** du champ (clavier, collage…). C'est ce qu'on veut pour un compteur.
+
+---
+
+## 🟢 Exo 3 — Bloquer l'envoi vide
+
+```js
+const formulaire = document.querySelector("form");
+
+formulaire.addEventListener("submit", function (evenement) {
+ if (zoneMsg.value.trim() === "") {
+ evenement.preventDefault();
+ alert("Merci d'écrire une suggestion avant d'envoyer !");
+ }
+});
+```
+> 💬 *« À quoi sert `trim()` ? »* Il enlève les espaces au début/à la fin. Sans lui, « 3 espaces » compterait comme un message valide.
+> 💬 *« `preventDefault`, c'est quoi ? »* Ça annule l'action par défaut du navigateur (ici : envoyer le formulaire et recharger la page).
+
+---
+
+## 🟡 Exo 4 — Tableau d'objets
+
+Dans un fichier `services.js` (ou en haut de `devis.js`) :
+```js
+const services = [
+ { nom: "Géolocalisation", description: "Suivi en temps réel", prix: "30€/véhicule/mois" },
+ { nom: "Odomètre", description: "Kilométrage précis", prix: "200€" },
+ { nom: "Consommation", description: "Carburant consommé", prix: "15€/véhicule/mois" },
+ { nom: "Impact carbone", description: "CO₂ rejeté", prix: "30€/véhicule/mois" }
+];
+
+for (const service of services) {
+ console.log(service.nom + " — " + service.prix);
+}
+```
+
+---
+
+## 🟡 Exo 5 — Générer les lignes du tableau
+
+HTML : garde le ``, vide le corps et donne-lui un id :
+```html
+
+```
+JS (version `innerHTML` + template literal) :
+```js
+const corps = document.getElementById("corps_services");
+let lignes = "";
+for (const s of services) {
+ lignes += `
${s.nom}
${s.description}
${s.prix}
`;
+}
+corps.innerHTML = lignes;
+```
+> 💬 *« Pourquoi mes `${}` ne marchent pas ? »* Vérifie que tu utilises bien les accents **graves** `` ` `` (touche AltGr+7), pas des guillemets simples `'`.
+
+---
+
+## 🟡 Exo 6 — Recherche
+
+Mets l'affichage dans une fonction réutilisable :
+```js
+function afficherServices(liste) {
+ let lignes = "";
+ for (const s of liste) {
+ lignes += `
${s.nom}
${s.description}
${s.prix}
`;
+ }
+ corps.innerHTML = lignes;
+}
+afficherServices(services);
+
+const champ = document.getElementById("recherche"); // dans le HTML
+champ.addEventListener("input", function () {
+ const mot = champ.value.toLowerCase();
+ const resultats = services.filter(function (s) {
+ return s.nom.toLowerCase().includes(mot);
+ });
+ afficherServices(resultats);
+});
+```
+> 💬 *« `filter` modifie-t-il `services` ? »* Non. `filter` renvoie une **nouvelle** liste ; l'originale reste intacte (c'est pour ça qu'effacer la recherche fait tout revenir).
+
+---
+
+## 🟡 Exo 7 — Se souvenir du nombre de véhicules
+
+```js
+// à la fin de mettreAJour(), on sauvegarde
+localStorage.setItem("nbVehicules", nbVehicules);
+
+// au chargement de la page, on relit
+const sauvegarde = localStorage.getItem("nbVehicules");
+if (sauvegarde !== null) {
+ nbVehicules = parseInt(sauvegarde); // ⚠️ reconvertir le TEXTE en NOMBRE
+ mettreAJour();
+}
+```
+> 💬 *« Pourquoi `parseInt` ? »* `localStorage` ne stocke que du **texte**. Sans conversion, `"12" + 1` donnerait `"121"`. `parseInt("12")` redonne le nombre `12`.
+
+---
+
+## 🟠 Exo 8 — Mode sombre
+
+CSS :
+```css
+body.sombre { background-color: #1d2733; color: white; }
+```
+JS (avec `` dans le HTML) :
+```js
+document.getElementById("theme").addEventListener("click", function () {
+ document.body.classList.toggle("sombre");
+});
+```
+> 💬 *« `toggle` fait quoi exactement ? »* Si la classe est présente il l'enlève, sinon il l'ajoute. Un seul appel gère l'aller **et** le retour.
+
+---
+
+## 🟠 Exo 9 — Horloge
+
+```html
+
+```
+```js
+const horloge = document.getElementById("horloge");
+function afficherHeure() {
+ horloge.textContent = new Date().toLocaleTimeString();
+}
+afficherHeure(); // tout de suite
+setInterval(afficherHeure, 1000); // puis chaque seconde
+```
+> 💬 *« Pourquoi appeler `afficherHeure()` avant le `setInterval` ? »* Sinon la page reste vide pendant la 1ʳᵉ seconde, le temps que `setInterval` se déclenche la première fois.
+
+---
+
+## 🔴 Exo 10 — `fetch` d'un fichier JSON
+
+`vehicules.json` (racine du projet) :
+```json
+[
+ { "modele": "Renault Kangoo", "immatriculation": "AB-123-CD", "km": 45200 },
+ { "modele": "Peugeot Partner", "immatriculation": "EF-456-GH", "km": 78900 }
+]
+```
+JS :
+```js
+async function chargerFlotte() {
+ const message = document.getElementById("message_flotte");
+ const corps = document.getElementById("corps_flotte");
+ try {
+ const reponse = await fetch("../vehicules.json");
+ const vehicules = await reponse.json();
+ for (const v of vehicules) {
+ const tr = document.createElement("tr");
+ tr.textContent = `${v.modele} — ${v.immatriculation} — ${v.km} km`;
+ corps.append(tr);
+ }
+ } catch (erreur) {
+ message.textContent = "Impossible de charger la flotte 😕";
+ console.error(erreur);
+ }
+}
+chargerFlotte();
+```
+> 💬 *« J'ai l'erreur "CORS" / "Failed to fetch" ! »* Tu as ouvert la page en double-cliquant (`file://`). Lance `python3 -m http.server 8000` dans le dossier du projet et ouvre `http://localhost:8000/pages/services.html`.
+> 💬 *« Mon JSON ne charge pas. »* Vérifie : guillemets **doubles** partout, et **pas** de virgule après le dernier élément.
+
+---
+
+## 🏁 Exo 11 — Navbar en composant
+
+```js
+function creerNavbar(pageActive) {
+ return `
+
+
FleetZen
+
+
+
+
+
+
`;
+}
+document.body.insertAdjacentHTML("afterbegin", creerNavbar("services"));
+```
+N'oublie pas d'**enlever** la navbar écrite en dur dans ton HTML, sinon tu en auras deux.
+> 💬 *« Pourquoi un paramètre `pageActive` ? »* Pour que la **même** fonction serve sur toutes les pages : sur services tu appelles `creerNavbar("services")`, sur contact `creerNavbar("contact")`, et c'est le bon bouton qui est mis en valeur.
+
+---
+
+### 🆘 Encore bloqué après avoir lu la solution ?
+Note précisément : *qu'est-ce que tu attendais, qu'est-ce qui se passe à la place, et qu'affiche la Console (F12) ?* Avec ces 3 infos, on débloque n'importe quoi en deux minutes.