<!doctype html><html lang="fr"><head><meta charset="utf-8"><title></title><meta name="author" content="Le Comptoir Eolien - Groupe MADAULE"><meta name="rating" content="General"><meta name="copyright" content="All Rights Reserved - Le Comptoir Éolien ® - Groupe MADAULE"><meta name="robots" content="max-image-preview:large"><link rel="alternate" type="application/rss+xml" title="Flux RSS – Le Comptoir Éolien" href="https://www.comptoireolien.fr/rss.xml"><meta name="robots" content="noindex,nofollow,noarchive"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"><meta http-equiv="pragma" content="no-cache"><meta name="generator" content="Lauyan TOWeb 14.0.4.106"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link href="rss.xml" rel="alternate" type="application/rss+xml"><link href="_media/img/sq_icon/favicon1-32x32.webp" rel="shortcut icon" type="image/png"><link href="_media/img/thumb/favicon1-144x144.webp" rel="apple-touch-icon"><meta name="msapplication-TileColor" content="#5835b8"><meta name="msapplication-TileImage" content="_media/img/thumb/favicon1-144x144.webp"><link href="_scripts/bootstrap/css/bootstrap.min.css" rel="stylesheet"><link href="_frame/style.css" rel="stylesheet"><link rel="stylesheet" media="screen" href="_scripts/colorbox/colorbox.css"><link rel="stylesheet" href="_scripts/bootstrap/css/font-awesome.min.css"><style>.raty-comp{padding:8px 0;font-size:10px;color:#00B67A}.tw-blogbar{display:flex;align-items:center}@media (max-width:767px){.tw-blogbar{flex-direction:column;}}.ta-left{text-align:left}.ta-center{text-align:center}.ta-justify{text-align:justify}.ta-right{text-align:right}.float-l{float:left}.float-r{float:right}.flexobj{flex-grow:0;flex-shrink:0;margin-right:1em;margin-left:1em}.flexrow{display:flex !important;align-items:center}.flexrow-align-start{align-items:start}@media (max-width:767px){.flexrow{flex-direction:column}.flexrow-align-start{align-items:center}}</style><link href="_frame/print.css" rel="stylesheet" type="text/css" media="print"></head><body oncontextmenu="return false;"><div id="site"><div id="page"><header><nav id="toolbar1" class="navbar"><div class="navbar-inner"><div class="container-fluid"><ul id="toolbar1_l" class="nav"><li><a id="logo" href="./" aria-label="logo"><span id="logo-lt">Le Comptoir Éolien</span><span id="logo-rt">Depuis 2009 - Tél : 07.81.34.05.36</span><br><span id="logo-sl"><style>#assistant-virtuel-info,[id="assistant-virtuel-info"]{display:none!important}html{scrollbar-gutter:stable}</style></span></a></li></ul><button type="button" class="btn btn-navbar collapsed" aria-label="Menu" data-toggle="collapse" data-target=".nav-collapse"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><div class="nav-collapse collapse"><ul id="toolbar1_r" class="nav pull-right"><li><ul id="mainmenu" class="nav"><li><a href="./">Accueil</a></li><ul class="nav dc-btn"><li class="dropdown dc-btn"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Tous nos kits ▼&nbsp;<small>&#9660;</small></a><div class="dropdown-content"><div class="dc-row"><div class="dc-column"><p>⚡ Autoconsommation réseau</p><a href="kits-reseau-eolien-autoconsommation.html">› Kits éoliens autoconsommation 230V</a><a href="kits-reseau-solaire-autoconsommation.html">› Kits solaires autoconsommation 230V</a><a href="kits-hybrides-autoconsommation.html">› Kits hybrides autoconsommation (stockage)</a><a href="kits-eolien-reductions-factures-pour-reseau-triphase-380v-400v-060120242317.html">› Kits éoliens autoconsommation 400V</a></div><div class="dc-column"><p>🔋 Kits avec batteries</p><a href="kits-eoliens-sites-isoles.html">› Kits éoliens sur batteries</a><a href="kits-hybrides-site-isole.html">› Kits hybrides site isolé</a><a href="kits-solaires-sites-isoles.html">› Kits solaires site isolé</a><a href="kits-hybrides-autoconsommation.html">› Kits hybrides autoconsommation</a><a href="batteries-au-lithium.html">› Batteries de stockage</a></div><div class="dc-column"><p>⚙️ Générateurs pour éoliennes</p><a href="generatrices-eoliennes-12v.html">› Génératrices éoliennes 12V</a><a href="generatrices-eoliennes-24v.html">› Génératrices éoliennes 24V</a><a href="generatrices-eoliennes-48v.html">› Génératrices éoliennes 48V</a><a href="regulateur-controleur-de-charge-eolien.html">› Régulateurs / contrôleurs éoliens</a><a href="coupe-batterie-et-coupleur.html">› Commutateurs d’arrêt / freinage</a></div><div class="dc-column"><p>🧩 Compléter mon kit</p><a href="onduleurs.html">› Onduleurs réseau</a><a href="convertisseurs.html">› Convertisseurs 230V</a><a href="regulateurs-solaires-pwm-et-mppt.html">› Régulateurs / contrôleurs solaire</a><a href="mats-et-accessoires-de-fixations.html">› Mâts & accessoires de fixations</a><a href="coffret-de-protection-parafoudre-photovoltaique.html">› Coffrets de protections & parafoudre</a><a href="montage-et-fixations.html">› Câbles & connectique</a><a href="compteur-electrique.html">› Compteurs électriques / production</a><a href="outils-de-mesure.html">› Anémomètres / mesure du vent</a></div></div></div></li></ul><ul class="nav dc-btn"><li class="dropdown dc-btn"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Eoliennes ▼&nbsp;<small>&#9660;</small></a><div class="dropdown-content"><div class="dc-row"><div class="dc-column"><p>⚡ Kits & systèmes complets</p><a href="kits-reseau-eolien-erdf-autoconsommation-monophase-et-triphase-070120242112.html">› Kits réseau éolien autoconsommation</a><a href="kits-reseau-eolien-autoconsommation.html">› Kits éoliens monophasés 220V/230V</a><a href="kits-eolien-reductions-factures-pour-reseau-triphase-380v-400v-060120242317.html">› Kits éoliens triphasés 380V/400V</a><a href="kits-hybrides-autoconsommation.html">› Kits hybrides autoconsommation</a><a href="kits-eoliens-sites-isoles.html">› Kits éoliens sites isolés</a><a href="kits-hybrides-site-isole.html">› Kits hybrides pour sites isolés</a></div><div class="dc-column"><p>🌬 Éoliennes & équipements</p><a href="eoliennes-horizontales.html">› Éoliennes horizontales</a><a href="eoliennes-verticales.html">› Éoliennes verticales</a><a href="eoliennes-aerospiral-ultra-silencieuse-design.html">› Éoliennes AeroSpiral</a><a href="onduleurs-injection-reseau-eolien-230v.html">› Onduleurs injection réseau 230V</a><a href="onduleurs-injection-reseau-eolien-380v-400v-11072024162.html">› Onduleurs injection réseau 400V</a><a href="les-regulateurs-eoliens.html">› Régulateurs éoliens</a><a href="generatrice-eolienne.html">› Génératrice éolienne</a><a href="mats-et-accessoires-pour-eoliennes.html">› Mâts et accessoires de fixation</a></div><div class="dc-column"><p>🛠 Pièces détachées</p><a href="pieces-detachees-eoliennes.html">› Pièces détachées pour éoliennes</a><a href="pales-moyeux-et-nez.html">› Pales, moyeux & nez pour éoliennes</a><a href="roulements-pour-eoliennes.html">› Roulements</a><a href="visserie-pour-eoliennes.html">› Visserie</a><a href="pont-de-diode-redresseur.html">› Ponts de diodes</a><a href="resistances-de-decharge-dump-load.html">› Résistances de décharge</a><a href="poulies-pour-generatrices-eoliennes.html">› Poulies</a></div><div class="dc-column"><p>🛡️ Installation & sécurité</p><a href="coupe-batterie-et-coupleur.html">› Commutateurs d’arrêt / freinage</a><a href="coffret-de-protection-parafoudre-photovoltaique.html">› Coffrets de protection & parafoudre</a><a href="compteur-electrique.html">› Compteurs électriques</a><a href="montage-et-fixations.html">› Câbles / connectiques</a><a href="outils-de-mesure.html">› Anémomètres / mesure du vent</a><a href="accessoires-de-fixations-pour-eoliennes.html">› Fixations supports / platines</a><a href="schemas-de-branchement-solaire-et-eolien.html">› Schémas de branchement</a></div></div></div></li></ul><ul class="nav dc-btn"><li class="dropdown dc-btn"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Solaire ▼&nbsp;<small>&#9660;</small></a><div class="dropdown-content"><div class="dc-row"><div class="dc-column"><p>☀️ Kits & panneaux solaires</p><a href="kits-reseau-solaire-autoconsommation.html">› Kits réseau solaire autoconsommation</a><a href="kits-solaires-sites-isoles.html">› Kits solaires sites isolés</a><a href="panneaux-solaires.html">› Panneaux solaires</a><a href="panneaux-solaires-flexibles.html">› Panneaux solaires flexibles</a><a href="panneaux-solaires-pliables.html">› Panneaux solaires pliables</a></div><div class="dc-column"><p>🔌 Conversion & pilotage</p><a href="onduleurs-injection-reseau-solaire-230v.html">› Onduleurs injection réseau</a><a href="onduleurs-hybrides-230v.html">› Onduleurs hybrides</a><a href="regulateurs-solaires.html">› Régulateurs solaires</a><a href="batteries-au-lithium.html">› Batteries de stockage</a><a href="stations-energie-portables.html">› Stations d’énergie portables</a></div><div class="dc-column"><p>🛡️ Installation & protection</p><a href="coffret-de-protection-parafoudre-photovoltaique.html">› Coffrets de protection parafoudre</a><a href="montage-et-fixations.html">› Câbles & connectique</a><a href="montage-et-fixations.html">› Fixations / supports panneaux</a><a href="compteur-electrique.html">› Compteurs / suivi production</a></div><div class="dc-column"><p>💧 Pompes, fontaines & accessoires</p><a href="pompes-de-bassin-solaires.html">› Pompes de bassin solaires</a><a href="fontaines-solaires.html">› Fontaines solaires</a><a href="accessoires-pour-vos-ventilations.html">› Accessoires pour vos ventilations</a><a href="kits-de-ventilation.html">› Kits de ventilation</a></div></div></div></li></ul><ul class="nav dc-btn"><li class="dropdown dc-btn"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Accessoires ▼&nbsp;<small>&#9660;</small></a><div class="dropdown-content"><div class="dc-row"><div class="dc-column"><p>🧪 Mesure, commande & montage</p><a href="outils-de-mesure.html">› Outils de mesure</a><a href="compteur-electrique.html">› Compteur électrique</a><a href="programmateurs-electroniques.html">› Programmateurs électroniques</a><a href="relais-contacteurs.html">› Relais - contacteurs</a><a href="montage-et-fixations.html">› Montage et fixations</a></div><div class="dc-column"><p>🔋 Batteries & gestion de charge</p><a href="batteries-au-lithium.html">› Batteries lithium</a><a href="stations-energie-portables.html">› Stations d’énergie portables</a><a href="modules-de-protection-pour-batteries-au-lithium.html">› Modules de protection lithium</a><a href="chargeurs-de-batteries-lithium.html">› Chargeurs de batteries lithium</a><a href="batteries-au-gel.html">› Batteries gel</a><a href="chargeurs-de-batteries-au-plomb.html">› Chargeurs de batteries universel</a><a href="repartiteur-de-charge.html">› Répartiteur de charge</a><a href="coupe-batterie-et-coupleur.html">› Coupe-batterie et coupleur</a></div><div class="dc-column"><p>⚙️ Conversion</p><a href="onduleurs-hybrides-230v.html">› Onduleurs hybrides 230V</a><a href="convertisseurs.html">› Convertisseurs 230V</a><a href="convertisseurs-chargeurs.html">› Convertisseurs / chargeurs</a><a href="convertisseurs-basse-tension-dcdc.html">› Convertisseurs basse tension DC/DC</a><a href="convertisseur-allume-cigare.html">› Convertisseur allume-cigare</a><a href="accessoires-pour-onduleur.html">› Accessoires pour onduleurs</a></div><div class="dc-column"><p>🔌 Câblage, protection & éclairage</p><a href="montage-et-fixations.html">› Câbles & connectique</a><a href="coffret-de-protection-parafoudre-photovoltaique.html">› Coffrets de protection & parafoudre</a><a href="spots-projecteurs-lampadaires.html">› Spots / projecteurs / lampadaires</a><a href="ampoule-led-eclairage-led.html">› Ampoule LED / éclairage LED</a><a href="ampoules-basse-consommation.html">› Ampoules basse consommation</a><a href="piles-pour-torches-montres-calculatrices.html">› Piles pour torches / montres / calculatrices</a><a href="gadget-decoration.html">› Gadget / décoration</a></div></div></div></li></ul><ul class="nav dc-btn"><li class="dropdown dc-btn"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Conseils ▼&nbsp;<small>&#9660;</small></a><div class="dropdown-content"><div class="dc-row"><div class="dc-column"><p>📚 Guides & ressources</p><a href="infos-diverses.html">› Informations et ressources générales</a><a href="simulateur-hybride-eolien-solaire.html">› Simulateur hybride (kWh/an & ROI)</a><a href="infos-eoliennes.html">› Infos – éoliennes</a><a href="simulateur-eolien-production-rentabilite.html">› Simulateur éolien (kWh/an & ROI)</a><a href="infos-solaire.html">› Infos – solaire</a><a href="simulateur-solaire-production-roi.html">› Simulateur solaire (kWh/an & ROI)</a></div><div class="dc-column"><p>📐 Tutoriel & schémas</p><a href="videos-guides-demonstrations-le-comptoir-eolien.html">› Vidéos – Guides & démonstrations</a><a href="schemas-de-branchement-solaire-et-eolien.html">› Schémas de branchement éolien</a><a href="schema-de-montage-dun-panneau-solaire.html">› Schémas de branchement solaire</a><a href="comment-choisir-une-batterie-adaptee-a-votre-consommation.html">› Bien choisir sa batterie</a><a href="calcul-de-section-des-cables-electriques.html">› Calculer la section de câble</a><a href="infos-sur-les-batteries-le-montage-en-parallele-et-en-serie.html">› Brancher des batteries en parallèle ou en série</a><a href="installation-solaire-eolienne-comment-connecter-les-differents-equipements-entres-eux.html">› Raccorder les équipements en site isolé</a></div><div class="dc-column"><p>💡 Réalisations & mentions</p><a href="galerie-de-realisations-clients-eoliennes.html">› Galerie des réalisations clients – éoliennes</a><a href="galerie-de-realisations-clients-solaire.html">› Galerie des réalisations clients – solaire</a><a href="on-parle-de-nous-le-comptoir-eolien-210920231132.html" rel="nofollow">› Mentions du Comptoir Éolien sur le web</a></div><div class="dc-column"><p>❓ Questions fréquentes</p><a href="faq.html">› FAQ – Toutes les questions</a><a href="https://chatgpt.com/g/g-698b54ce7cc081918a741e5915772e79-assistant-le-comptoir-eolien?src=menu" target="_blank" rel="noopener">› Assistant conseil</a><a href="livraison.html">› Livraison</a><a href="moyens-de-paiements.html">› Moyens de paiements</a><a href="retours.html">› Retours</a><a href="service-client-contactez-nous.html">› Assistance & contact</a></div></div></div></li></ul></ul></li></ul></div></div></div></nav><nav id="toolbar2" class="navbar"><div class="navbar-inner"><div class="container-fluid"><ul id="toolbar2_r" class="nav pull-right"><li><form id="searchbox" class="navbar-search" action="_search2.html"><input type="text" name="req" id="searchbox-req" class="search-query" placeholder="Rechercher..."></form></li><li><a id="button-login" href="_accounts.php" title="Mon compte"><i class="fa fa-user fa-2x"></i></a></li><li><a id="button-cart" data-container="body" href="_checkout.html" title="Panier"><span id="sc_pcount"></span></a></li></ul></div></div></nav></header><main id="content" class="container-fluid"><div class="row-fluid"><div class="span12"></div></div><div id="topic" class="row-fluid"><div id="topic-inner"><div id="top-content" class="span12"></div></div></div></main><footer><div id="footerfat" class="row-fluid"><div class="row-fluid"><div  id="footerfat_s1" class="span3 tw-para"><p><strong><span style="font-size:22px;"><span style="font-family: inherit;">Aide &amp;&nbsp;information</span></span></strong></p><p><a href="avis-clients-et-temoignages.html?twtheme=no" class="  tos cboxElement" title="Avis clients ⭐⭐⭐⭐⭐" id="lnk2b5c76b9" data-cke-pa-onclick="javascript:return(doOpenLink(this.id))" data-cke-pa-ondblclick="javascript:doEditLink(this.id);">Avis clients</a> <span style="color:#00B87C"><i class="fa fa-star fa-lg"></i><i class="fa fa-star fa-lg"></i><i class="fa fa-star fa-lg"></i><i class="fa fa-star fa-lg"></i><i class="fa fa-star fa-lg"></i></span></p><p><a href="satisfait-ou-rembourse.html" title="Satisfait ou remboursé" id="lnke1291c97">Satisfait ou remboursé</a></p><p><a href="infos-eoliennes.html" title="Infos éoliennes" id="lnka0e50f29">Infos éoliennes</a></p><p><a href="infos-diverses.html" title="Infos diverses" id="lnk6d6c9355">Infos diverses</a></p><p><a href="infos-solaire.html" title="Infos solaire" id="lnkc00d44d8">Infos solaire</a></p><p><a href="livraison.html" title="Livraison" id="lnk0b30067c">Livraison</a></p><p><a href="retours.html" title="Retours" id="lnkca11d67f">Retours</a></p><p><a href="faq.html" title="FAQ" id="lnk71a55500">FAQ</a></p></div><div  id="footerfat_s2" class="span3 tw-para"><p><strong><span style="font-size:22px;">À propos &amp; contact</span></strong></p><p><a href="protection-des-donnees-personnelles.html" title="Protection des données" rel="nofollow" id="lnk78913e22">Protection des données</a></p><p><a href="_tos.html" title="Conditions de ventes" rel="nofollow" id="lnk03b1fcac">Conditions de ventes</a></p><p><a href="tel:+33781340536" title="Tél. : 07.81.34.05.36" id="lnk37dc3376">Tél. : 07.81.34.05.36</a></p><p><a href="qui-sommes-nous.html" title="Qui sommes-nous ?" id="lnk7e13d3bb">Qui sommes-nous ?</a></p><p><a href="mentions-legales.html" title="Mentions légales" id="lnka2fedd31">Mentions légales</a></p><p><span style="font-size:18px;"></span><a href="on-parle-de-nous-le-comptoir-eolien-210920231132.html" title="On parle de nous" rel="nofollow" id="lnk02ce5afd">On parle de nous</a></p><p><a href="a-propos-de-nous-le-comptoir-eolien.html" title="À propos" id="lnkf6949480">À propos</a></p><p><a href="service-client-contactez-nous.html" title="Contact" id="lnk53184d51">Contact</a></p></div><div  id="footerfat_s3" class="span3 tw-para"><p><strong><span style="font-size:22px;"><span style="font-family: inherit;">Moyens de paiement</span></span></strong></p><p><span style="font-size:18px;"></span><a href="moyens-de-paiements.html" id="lnkbdbbeeda" title="CB | PayPal | Stripe&nbsp;| SEPA">CB | PayPal | Stripe&nbsp;| SEPA</a></p><p><a href="moyens-de-paiements.html#xxLcgPD0" id="lnkfb7ba5b5" title="Facilités de paiement&nbsp;x3 x4">Facilités de paiement&nbsp;x3 x4</a></p><p><span style="font-size:18px;"></span><a href="moyens-de-paiements.html" id="lnk778c111b" title="En savoir plus">En savoir plus</a></p><br><p><strong><span style="font-size:22px;">Moyens de livraison</span></strong></p><div><p><a href="https://www.mondialrelay.fr/" target="_blank" title="Mondial Relay" id="lnkb13b607d" rel="noopener">Mondial Relay</a></p><p><a href="https://www.laposte.fr/colissimo" target="_blank" title="Colissimo" id="lnk2cc1a4f3" rel="noopener">Colissimo</a></p><p><a href="https://www.chronopost.fr/fr" target="_blank" title="Chronopost" id="lnkfb633b10" rel="noopener">Chronopost</a></p></div></div><div  id="footerfat_s4" class="span3 tw-para"><div><img src="_fields/entreprise-francaise.png" alt="Entreprise Française" title="Entreprise Française" height="146" width="316" loading="lazy" style="width: 60%; height: auto;"></div><div><br></div><div><br></div><div><a href="https://www.google.com/search?sca_esv=c2c3ea615d0b866b&rlz=1C1GCEA_enFR897FR897&tbm=lcl&sxsrf=ADLYWILNxYD2KBNIY1ojhLeq4v8ODphqKw:1733179103439&q=Le+Comptoir+Eolien+-+Groupe+MADAULE+Avis&rflfq=1&num=20&stick=H4sIAAAAAAAAAONgkxIxNDYxNjY0N7Q0MzIxNrU0MTI0NdnAyPiKUcMnVcE5P7egJD-zSME1PyczNU9BV8G9KL-0IFXB19HFMdTHVcGxLLN4ESvRSgEDCOcXcQAAAA&rldimm=13433171962435942154&hl=fr-FR&sa=X&ved=2ahUKEwiMo6umk4qKAxX7Q6QEHXe3DX0Q9fQKegQIQRAF" 
   target="_blank" 
   rel="noopener" 
   aria-label="Voir nos avis Google">
   <img data-src="_fields/png-google-notation.png"
        alt="Avis Google"
        class="lazy-load"
        title="Avis Google"
        width="300"
        height="auto"
        style="width: 60%; height:auto;">
</a>

<script>
document.addEventListener("DOMContentLoaded", function(){
    var lazyImages = document.querySelectorAll('img.lazy-load');
    if ('IntersectionObserver' in window) {
        var lazyImagesObserver = new IntersectionObserver(function(entries, observer){
            entries.forEach(function(entry){
                if(entry.isIntersecting){
                    var img = entry.target;
                    img.src = img.dataset.src;
                    observer.unobserve(img);
                }
            });
        });
        lazyImages.forEach(function(img){
            lazyImagesObserver.observe(img);
        });
    } else {
        // Fallback pour navigateurs plus anciens
        lazyImages.forEach(function(img){
            img.src = img.dataset.src;
        });
    }
});
</script></div><div><br></div><div><br></div><div><img src="_fields/the-green-web-foundation.png" alt="Le site ComptoirEolien.fr est classé en vert par The Green Web Foundation (association loi 1901)" title="Le site ComptoirEolien.fr est classé en vert par The Green Web Foundation (association loi 1901)" height="146" width="316" loading="lazy" style="width: 60%; height: auto;"></div></div></div></div><nav id="toolbar3" class="navbar"><div class="navbar-inner"><div class="container-fluid"><ul id="toolbar3_l" class="nav"><li></li></ul><ul id="toolbar3_r" class="nav pull-right"></ul></div></div></nav><div id="footersmall" class="row-fluid"><div id="foot-sec1" class="span6 ">🍪&nbsp;<a onclick="tarteaucitron.userInterface.openPanel()" id="lnk04bebef3" title="Gérer mes préférences cookies.;return(false);"><span style="color:#4D4D4D;">Gérer mes préférences cookies.</span></a><div><span style="font-size: 14.4px; color: rgb(77, 77, 77);">Le Comptoir Éolien®</span><a href="plan-du-site.html" style="font-size: 14.4px;" title="Plan du site"><span style="color:#4D4D4D;"></span></a><span style="font-size: 14.4px; color: rgb(77, 77, 77);">.&nbsp;</span><a href="https://www.comptoireolien.fr/_iserv/common/admin.php" id="lnk617569c2" style="font-size: 14.4px;" target="_blank" title="Groupe MADAULE" rel="noopener"><span style="color:#4D4D4D;">Groupe MADAULE</span></a><span style="font-size: 14.4px; color: rgb(77, 77, 77);">.</span></div><div><div><span style="color:#4D4D4D;"><span style="font-size: 14.4px;">Copyright © 2009-2026. Tous droits réservés.</span></span></div><div><a href="plan-du-site.html" id="lnkb119f042" title="Plan du site"><span style="color:#4D4D4D;">Plan du site</span></a>. <a href="https://www.comptoireolien.fr/_fields/agentic-catalog-v2.json" title="Catalogue IA" id="lnk4eb082b1"><span style="color:#4D4D4D;">Catalogue IA</span></a>. Mise à jour le&nbsp;<script type="text/javascript">
  var d = new Date()
  document.open() ;
  document.write(d.getDate())
  document.write("/")
  document.write(d.getMonth() + 1)
  document.write("/")
  document.write(d.getFullYear())
  document.close() ;
</script>.</div><div><span style="font-size:13px;">Blog partenaire :&nbsp;<a href="https://www.eoliennes-domestiques.fr/" id="lnkfcf466d9" target="_blank" title="Consulter notre blog partenaire sur l’éolien domestique" rel="noopener"><span style="color:#4D4D4D;">eoliennes-domestiques.fr</span></a></span></div><div><span style="font-size:13px;"><!-- ===================== CE – ORGANIZATION + ONLINESTORE JSON-LD ===================== -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": ["Organization", "OnlineStore"],
  "@id": "https://www.comptoireolien.fr/#organization",
  "name": "Le Comptoir Éolien",
  "alternateName": "Le Comptoir Éolien - Groupe MADAULE",
  "legalName": "Le Comptoir Éolien - Groupe MADAULE",
  "url": "https://www.comptoireolien.fr/",
  "logo": {
    "@type": "ImageObject",
    "url": "https://www.comptoireolien.fr/_media/img/medium/le-comptoir-eolien.webp"
  },
  "description": "Le Comptoir Éolien est une société française spécialisée dans les solutions éoliennes accessibles et durables pour particuliers et professionnels.",
  "foundingDate": "2009",
  "founder": {
    "@type": "Person",
    "name": "Jérôme Madaule"
  },
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "928, chemin du vignoble",
    "addressLocality": "Moissac",
    "postalCode": "82200",
    "addressCountry": "FR"
  },
  "email": "contact@comptoireolien.fr",
  "telephone": "+33781340536",
  "contactPoint": [
    {
      "@type": "ContactPoint",
      "telephone": "+33781340536",
      "email": "contact@comptoireolien.fr",
      "contactType": "customer support",
      "availableLanguage": ["fr"],
      "areaServed": "FR"
    }
  ],
  "vatID": "FR515355857",
  "sameAs": [
    "https://www.facebook.com/Le.Comptoir.Eolien",
    "https://twitter.com/ComptoirEolien",
    "https://www.pinterest.fr/le_comptoir_eolien",
    "https://www.instagram.com/le_comptoir_eolien",
    "https://www.tiktok.com/@le.comptoir.eolien",
    "https://www.youtube.com/@LeComptoirEolien",
    "https://www.linkedin.com/company/le-comptoir-eolien/",
    "https://fr.trustpilot.com/review/www.comptoireolien.fr",
    "https://g.page/r/CQo3u1O6Nmy6EAg/review",
    "https://linktr.ee/comptoireolien"
  ],
  "hasMerchantReturnPolicy": {
    "@type": "MerchantReturnPolicy",
    "@id": "https://www.comptoireolien.fr/satisfait-ou-rembourse.html#merchant-return-policy",
    "applicableCountry": "FR",
    "returnPolicyCountry": "FR",
    "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
    "merchantReturnDays": 90,
    "itemCondition": "https://schema.org/NewCondition",
    "returnMethod": "https://schema.org/ReturnByMail",
    "returnFees": "https://schema.org/ReturnFeesCustomerResponsibility",
    "refundType": "https://schema.org/FullRefund",
    "returnPolicyUrl": "https://www.comptoireolien.fr/satisfait-ou-rembourse.html"
  },
  "hasShippingService": {
    "@type": "ShippingService",
    "@id": "https://www.comptoireolien.fr/livraison.html#shipping-service-standard",
    "name": "Livraison standard France métropolitaine",
    "description": "Livraison offerte en France métropolitaine dès 49,90 €. Pour les commandes inférieures, les frais de livraison sont calculés selon l'adresse, le poids total et l'option choisie. Délai moyen d'acheminement : 2 à 4 jours ouvrés en France métropolitaine.",
    "fulfillmentType": "https://schema.org/FulfillmentTypeDelivery",
    "shippingConditions": [
      {
        "@type": "ShippingConditions",
        "shippingDestination": {
          "@type": "DefinedRegion",
          "addressCountry": "FR"
        },
        "orderValue": {
          "@type": "MonetaryAmount",
          "minValue": 49.90,
          "currency": "EUR"
        },
        "shippingRate": {
          "@type": "MonetaryAmount",
          "value": 0,
          "currency": "EUR"
        },
        "transitTime": {
          "@type": "ServicePeriod",
          "duration": {
            "@type": "QuantitativeValue",
            "minValue": 2,
            "maxValue": 4,
            "unitCode": "DAY"
          }
        }
      },
      {
        "@type": "ShippingConditions",
        "shippingDestination": {
          "@type": "DefinedRegion",
          "addressCountry": "FR"
        },
        "orderValue": {
          "@type": "MonetaryAmount",
          "minValue": 0,
          "maxValue": 49.89,
          "currency": "EUR"
        },
        "transitTime": {
          "@type": "ServicePeriod",
          "duration": {
            "@type": "QuantitativeValue",
            "minValue": 2,
            "maxValue": 4,
            "unitCode": "DAY"
          }
        }
      }
    ]
  }
}
</script>
<!-- ===================== /CE – ORGANIZATION + ONLINESTORE JSON-LD ===================== -->

<!-- ===================== CE – WEBSITE + SEARCHACTION JSON-LD ===================== -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "@id": "https://www.comptoireolien.fr/#website",
  "url": "https://www.comptoireolien.fr/",
  "name": "Le Comptoir Éolien",
  "inLanguage": "fr-FR",
  "publisher": {
    "@id": "https://www.comptoireolien.fr/#organization"
  },
  "potentialAction": {
    "@type": "SearchAction",
    "target": {
      "@type": "EntryPoint",
      "urlTemplate": "https://www.comptoireolien.fr/_search2.html?req={search_term_string}"
    },
    "query-input": "required name=search_term_string"
  }
}
</script>
<!-- ===================== /CE – WEBSITE + SEARCHACTION JSON-LD ===================== -->

<!-- ===================== CE – GLOBAL BREADCRUMB + PRODUCT JSON-LD FALLBACK v3 ===================== -->
<script id="ce-jsonld-global-clean-v3">
(function () {
  "use strict";

  const HOME_URL = "https://www.comptoireolien.fr/";
  const ORG_ID = "https://www.comptoireolien.fr/#organization";
  const BREADCRUMB_SCRIPT_ID = "ce-breadcrumb-jsonld";
  const PRODUCT_SCRIPT_ID = "ce-product-jsonld";

  const restrictedPages = [
    // "_checkout.html",
    // "_payment.html",
    // "_account.html"
  ];

  const productJsonLdExcludedPages = [
    // "exemple-produit-a-exclure.html"
  ];

  function q(sel, root) {
    return (root || document).querySelector(sel);
  }

  function qa(sel, root) {
    return Array.prototype.slice.call((root || document).querySelectorAll(sel));
  }

  function safeText(el) {
    return el ? (el.textContent || "").replace(/\s+/g, " ").trim() : "";
  }

  function currentPageFile() {
    return window.location.pathname.split("/").pop() || "";
  }

  function currentPageUrl() {
    return window.location.href.split("#")[0];
  }

  function currentPageTitle() {
    return safeText(q("h1")) || document.title || "Page";
  }

  function absUrl(url) {
    if (!url) return "";
    try {
      return new URL(url, window.location.href).href.split("#")[0];
    } catch (e) {
      return "";
    }
  }

  function uniqByUrl(items) {
    const out = [];
    const seen = {};
    items.forEach(function (item) {
      const key = String(item.url || "").trim();
      if (!key || seen[key]) return;
      seen[key] = true;
      out.push(item);
    });
    return out;
  }

  function getDomBreadcrumbTrail() {
    const container =
      q('nav[aria-label*="breadcrumb" i]') ||
      q(".breadcrumb") ||
      q('[itemtype*="BreadcrumbList"]') ||
      q("[data-breadcrumb]");

    if (!container) return [];

    const links = qa("a[href]", container).map(function (a) {
      return {
        url: absUrl(a.getAttribute("href") || a.href || ""),
        title: safeText(a)
      };
    }).filter(function (x) {
      return x.url && x.title;
    });

    let trail = uniqByUrl(links);

    if (!trail.length) return [];

    const pageUrl = currentPageUrl();
    const lastUrl = trail.length ? trail[trail.length - 1].url : "";

    if (lastUrl !== pageUrl) {
      trail.push({
        url: pageUrl,
        title: currentPageTitle()
      });
    }

    return uniqByUrl(trail);
  }

  function buildBreadcrumbJsonLd() {
    if (restrictedPages.indexOf(currentPageFile()) > -1) return;

    let trail = getDomBreadcrumbTrail();

    if (!trail.length) {
      trail = [
        { url: HOME_URL, title: "Accueil" },
        { url: currentPageUrl(), title: currentPageTitle() }
      ];
    } else {
      const hasHome = trail.some(function (item) {
        return item.url === HOME_URL;
      });
      if (!hasHome) {
        trail.unshift({ url: HOME_URL, title: "Accueil" });
      }
    }

    const old = document.getElementById(BREADCRUMB_SCRIPT_ID);
    if (old) old.remove();

    const data = {
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      "itemListElement": trail.map(function (item, index) {
        return {
          "@type": "ListItem",
          "position": index + 1,
          "name": item.title,
          "item": item.url
        };
      })
    };

    const s = document.createElement("script");
    s.type = "application/ld+json";
    s.id = BREADCRUMB_SCRIPT_ID;
    s.textContent = JSON.stringify(data, null, 2);
    document.head.appendChild(s);
  }

  function mapAvailability(raw) {
    const t = String(raw || "").trim().toLowerCase();
    if (!t) return "https://schema.org/InStock";
    if (/^https?:/.test(t)) return t;

    if (t === "in_stock" || t === "instock" || t === "in stock") return "https://schema.org/InStock";
    if (t === "out_of_stock" || t === "outofstock" || t === "out of stock" || t === "sold_out") return "https://schema.org/OutOfStock";

    if (/\b(non[-\s]*disponible|rupture|épuis[ée]?|epuis[ée]?|indispo(nible)?|sold\s*out)\b/.test(t)) {
      return "https://schema.org/OutOfStock";
    }

    if (/\blivraison\b|\bdelivery\b/.test(t)) return "https://schema.org/InStock";
    if (/\b(en\s*stock|dispo(nible)?|available|in\s*stock)\b/.test(t)) return "https://schema.org/InStock";

    return "https://schema.org/InStock";
  }

  function detectAvailability() {
    const pageText = (document.body && document.body.innerText ? document.body.innerText : "").toLowerCase();
    if (/\bnon\s*disponible\b/.test(pageText)) return "https://schema.org/OutOfStock";

    const ogAvail = q('meta[property="og:availability"]');
    if (ogAvail && ogAvail.content) return mapAvailability(ogAvail.content);

    const stockEl =
      q("#pstockRqRzIc") ||
      q('[id^="pstock"]') ||
      q(".availability, .stock");

    if (stockEl) return mapAvailability(stockEl.textContent || "");

    const addBtn = qa('a.btn,button[type="submit"],button').find(function (b) {
      return /ajouter au panier|acheter|add to cart|buy now/i.test(b.textContent || "");
    });

    return addBtn ? "https://schema.org/InStock" : "https://schema.org/OutOfStock";
  }

  function ensureOgAvailability(valueSchemaUrl) {
    const ogValue = String(valueSchemaUrl || "").indexOf("OutOfStock") > -1 ? "out_of_stock" : "in_stock";
    let m = q('meta[property="og:availability"]');
    if (!m) {
      m = document.createElement("meta");
      m.setAttribute("property", "og:availability");
      document.head.appendChild(m);
    }
    m.setAttribute("content", ogValue);
  }

  function isProductPage() {
    return !!(
      q("h1") &&
      q('span.tw-price:not(.striked)') &&
      q('div[id^="pref"]')
    );
  }

  function normUrl(u) {
    if (!u) return "";
    try {
      const url = new URL(u, window.location.href);
      url.hash = "";
      return url.href.replace(/^http:\/\//i, "https://").replace(/\/+$/, "");
    } catch (e) {
      return String(u).trim().replace(/#.*$/, "").replace(/\/+$/, "");
    }
  }

  function productMatchesCurrentPage(node, totalProductNodes) {
    const pageUrl = normUrl(currentPageUrl());
    const nodeUrl = normUrl(node && node.url);
    const nodeId = normUrl(node && node["@id"]);

    if (nodeUrl && nodeUrl === pageUrl) return true;
    if (nodeId && nodeId.indexOf(pageUrl) === 0) return true;

    return totalProductNodes === 1;
  }

  function hasGoodExistingProductJsonLd() {
    const scripts = qa('script[type="application/ld+json"]');

    for (let i = 0; i < scripts.length; i++) {
      let data;
      try {
        data = JSON.parse((scripts[i].textContent || "").trim());
      } catch (e) {
        continue;
      }

      const nodes = Array.isArray(data) ? data : (Array.isArray(data["@graph"]) ? data["@graph"] : [data]);
      const productNodes = nodes.filter(function (n) {
        const t = n && n["@type"];
        return t === "Product" || (Array.isArray(t) && t.indexOf("Product") > -1);
      });

      for (let j = 0; j < productNodes.length; j++) {
        const n = productNodes[j];
        if (!productMatchesCurrentPage(n, productNodes.length)) continue;

        const offers = n.offers ? (Array.isArray(n.offers) ? n.offers : [n.offers]) : [];
        const ok = offers.some(function (o) {
          return !!(
            o &&
            typeof o.availability === "string" &&
            o.availability.indexOf("https://schema.org/") > -1 &&
            (o.price !== undefined && o.price !== null && String(o.price) !== "") &&
            o.priceCurrency
          );
        });

        if (ok) return true;
      }
    }

    return false;
  }

  function getDomPrice() {
    const pp = q('[data-pp-message][data-pp-amount]');
    if (pp) {
      const raw = pp.getAttribute("data-pp-amount");
      const v = parseFloat(String(raw || "").replace(",", "."));
      if (isFinite(v)) return v.toFixed(2);
    }

    const el = q('span.tw-price:not(.striked)');
    if (!el) return null;

    const m = (el.textContent || "").trim().match(/([\d\s]+(?:[.,]\d{2})?)/);
    if (!m) return null;

    const val = parseFloat(m[1].replace(/\s/g, "").replace(",", "."));
    return isFinite(val) ? val.toFixed(2) : null;
  }

  function getProductImages() {
    const medium = [];
    const xlarge = [];
    const mediumByKey = {};
    const xlargeByKey = {};

    function normalizeProductImageUrl(url) {
      const u = absUrl(url);
      if (!u) return "";

      const clean = u.split("#")[0].split("?")[0].replace(/^http:\/\//i, "https://");

      if (!/^https:\/\/www\.comptoireolien\.fr\/_media\/img\/(medium|xlarge)\//i.test(clean)) {
        return "";
      }

      if (!/\.(webp|png|jpg|jpeg)$/i.test(clean)) {
        return "";
      }

      return clean;
    }

    function imageKey(url) {
      return String(url || "").toLowerCase().split("/").pop() || String(url || "").toLowerCase();
    }

    function add(url) {
      const u = normalizeProductImageUrl(url);
      if (!u) return;

      const key = imageKey(u);
      const isMedium = /\/_media\/img\/medium\//i.test(u);

      if (isMedium) {
        if (mediumByKey[key]) return;

        mediumByKey[key] = u;

        if (xlargeByKey[key]) {
          delete xlargeByKey[key];
          for (let i = xlarge.length - 1; i >= 0; i--) {
            if (imageKey(xlarge[i]) === key) xlarge.splice(i, 1);
          }
        }

        medium.push(u);
        return;
      }

      if (mediumByKey[key] || xlargeByKey[key]) return;

      xlargeByKey[key] = u;
      xlarge.push(u);
    }

    function addSrcset(srcset) {
      String(srcset || "").split(",").forEach(function (part) {
        const candidate = String(part || "").trim().split(/\s+/)[0];
        if (candidate) add(candidate);
      });
    }

    function collect(root) {
      if (!root) return;

      qa("a[href]", root).forEach(function (a) {
        add(a.getAttribute("href") || a.href || "");
      });

      qa("img[src]", root).forEach(function (img) {
        add(img.getAttribute("src") || img.src || "");
        add(img.getAttribute("data-zoom-image") || "");
        addSrcset(img.getAttribute("srcset") || "");
      });
    }

    const galleryRoot = q(".mpv") || q(".mpv_pics");
    if (galleryRoot) collect(galleryRoot);

    if (!medium.length && !xlarge.length) {
      qa('img.evzh_1[src], img[data-zoom-image], .img-wrapper a[href]').forEach(function (el) {
        const tag = String(el.tagName || "").toUpperCase();

        if (tag === "IMG") {
          add(el.getAttribute("src") || el.src || "");
          add(el.getAttribute("data-zoom-image") || "");
          addSrcset(el.getAttribute("srcset") || "");
        } else if (tag === "A") {
          add(el.getAttribute("href") || el.href || "");
        }
      });
    }

    const og = q('meta[property="og:image"]');
    if (og && og.content) add(og.content);

    const tw = q('meta[name="twitter:image"]');
    if (tw && tw.content) add(tw.content);

    return medium.concat(xlarge);
  }

  function buildProductJsonLd() {
    if (!isProductPage()) return;
    if (productJsonLdExcludedPages.indexOf(currentPageFile()) > -1) return;
    if (hasGoodExistingProductJsonLd()) return;

    const name = currentPageTitle();
    const sku = safeText(q('div[id^="pref"]')) || "";
    const desc = (q('meta[name="description"]') && q('meta[name="description"]').content) || "";
    const url = currentPageUrl();
    const price = getDomPrice();

    if (!price) return;

    const availability = detectAvailability();
    ensureOgAvailability(availability);

    const imgs = getProductImages();
    const weightMeta = (q('meta[name="product-weight"]') && q('meta[name="product-weight"]').getAttribute("content")) || "";
    const weightVal = parseFloat(String(weightMeta).replace(",", "."));

    const data = {
      "@context": "https://schema.org/",
      "@type": "Product",
      "@id": url + "#product",
      "mainEntityOfPage": { "@id": url + "#webpage" },
      "brand": { "@type": "Brand", "name": "Le Comptoir Éolien" },
      "sku": sku,
      "name": name,
      "image": imgs,
      "description": desc,
      "url": url,
      "offers": {
        "@type": "Offer",
        "@id": url + "#offer",
        "url": url,
        "priceCurrency": "EUR",
        "price": price,
        "availability": availability,
        "itemCondition": "https://schema.org/NewCondition",
        "seller": { "@id": ORG_ID }
      }
    };

    if (isFinite(weightVal) && weightVal > 0) {
      data.weight = {
        "@type": "QuantitativeValue",
        "value": Number(weightVal.toFixed(3)),
        "unitCode": "KGM",
        "unitText": "kg"
      };
    }

    const old = document.getElementById(PRODUCT_SCRIPT_ID);
    if (old) old.remove();

    const s = document.createElement("script");
    s.type = "application/ld+json";
    s.id = PRODUCT_SCRIPT_ID;
    s.textContent = JSON.stringify(data, null, 2);
    document.head.appendChild(s);
  }

  document.addEventListener("DOMContentLoaded", function () {
    buildBreadcrumbJsonLd();

    let tries = 0;
    const maxTries = 60;

    (function waitPriceAndBuild() {
      buildProductJsonLd();
      if (document.getElementById(PRODUCT_SCRIPT_ID)) return;
      if (hasGoodExistingProductJsonLd()) return;
      if (++tries >= maxTries) return;
      setTimeout(waitPriceAndBuild, 500);
    })();
  });
})();
</script>
<!-- ===================== /CE – GLOBAL BREADCRUMB + PRODUCT JSON-LD FALLBACK ===================== -->

<!-- ===================== CE – PATCH OFFER SHIPPING + RETURN POLICY v2 ===================== -->
<script id="ce-patch-offer-shipping-return-v2">
(function () {
  "use strict";

  const ORG_ID = "https://www.comptoireolien.fr/#organization";
  const RETURN_POLICY_URL = "https://www.comptoireolien.fr/satisfait-ou-rembourse.html";
  const TOS_URL = "https://www.comptoireolien.fr/_tos.html";
  const DEFAULT_DELIVERY_MIN_DAYS = 2;
  const DEFAULT_DELIVERY_MAX_DAYS = 4;
  const RETURN_WINDOW_DAYS = 90;
  const RETURN_FEES = "https://schema.org/ReturnFeesCustomerResponsibility";

  function q(sel, root) {
    return (root || document).querySelector(sel);
  }

  function safeJsonParse(txt) {
    try { return JSON.parse((txt || "").trim()); }
    catch (e) { return null; }
  }

  function flatten(root) {
    if (!root) return [];
    if (Array.isArray(root)) return root;
    if (Array.isArray(root["@graph"])) return root["@graph"];
    return [root];
  }

  function serialize(root, nodes) {
    if (Array.isArray(root)) return JSON.stringify(nodes, null, 2);
    if (root && Array.isArray(root["@graph"])) {
      root["@graph"] = nodes;
      return JSON.stringify(root, null, 2);
    }
    return JSON.stringify(nodes[0], null, 2);
  }

  function toArray(v) {
    if (!v) return [];
    return Array.isArray(v) ? v : [v];
  }

  function setBack(obj, key, arr) {
    if (!arr.length) return;
    obj[key] = (arr.length === 1) ? arr[0] : arr;
  }

  function hasType(node, typeName) {
    const t = node && node["@type"];
    return t === typeName || (Array.isArray(t) && t.indexOf(typeName) > -1);
  }

  function isProduct(node) {
    return hasType(node, "Product");
  }

  function normUrl(u) {
    if (!u) return "";
    try {
      const url = new URL(u, window.location.href);
      url.hash = "";
      return url.href.replace(/^http:\/\//i, "https://").replace(/\/+$/, "");
    } catch (e) {
      return String(u).trim().replace(/#.*$/, "").replace(/\/+$/, "");
    }
  }

  function currentPageUrl() {
    return window.location.href.split("#")[0];
  }

  function productMatchesCurrentPage(node, totalProductNodes) {
    const pageUrl = normUrl(currentPageUrl());
    const nodeUrl = normUrl(node && node.url);
    const nodeId = normUrl(node && node["@id"]);

    if (nodeUrl && nodeUrl === pageUrl) return true;
    if (nodeId && nodeId.indexOf(pageUrl) === 0) return true;

    return totalProductNodes === 1;
  }

  function readDeliveryDays() {
    const stockEl = q("#pstockRqRzIc") || q('[id^="pstock"]');
    const txt = (stockEl && stockEl.textContent ? stockEl.textContent : "").replace(/\s+/g, " ").trim();

    let m = txt.match(/livraison\s*[:\-]?\s*(\d+)\s*(?:à|\-)\s*(\d+)\s*jour/i);
    if (m) return { min: parseInt(m[1], 10), max: parseInt(m[2], 10) };

    m = txt.match(/livraison\s*[:\-]?\s*(\d+)\s*jour/i);
    if (m) {
      const d = parseInt(m[1], 10);
      return { min: d, max: d };
    }

    return { min: DEFAULT_DELIVERY_MIN_DAYS, max: DEFAULT_DELIVERY_MAX_DAYS };
  }

  function isFreeShippingMentioned() {
    const body = (document.body && document.body.innerText ? document.body.innerText : "").toLowerCase();
    return /\blivraison\s+(offerte|gratuite)\b/.test(body);
  }

  function patch() {
    const scripts = Array.from(document.querySelectorAll('script[type="application/ld+json"]'));
    const delivery = readDeliveryDays();
    const freeShip = isFreeShippingMentioned();

    scripts.forEach(function (scriptEl) {
      const root = safeJsonParse(scriptEl.textContent);
      if (!root) return;

      const nodes = flatten(root);
      const productNodes = nodes.filter(isProduct);
      if (!productNodes.length) return;

      let changed = false;

      nodes.forEach(function (node) {
        if (!isProduct(node)) return;
        if (!productMatchesCurrentPage(node, productNodes.length)) return;

        const offersArr = toArray(node.offers);
        if (!offersArr.length) return;

        offersArr.forEach(function (offer) {
          if (!offer || typeof offer !== "object") return;

          if (!offer.url) {
            offer.url = currentPageUrl();
            changed = true;
          }

          if (!offer["@id"]) {
            offer["@id"] = offer.url + "#offer";
            changed = true;
          }

          if (!offer.termsOfService) {
            offer.termsOfService = TOS_URL;
            changed = true;
          }

          if (!offer.seller) {
            offer.seller = { "@id": ORG_ID };
            changed = true;
          }

          const shippingDetailsArr = toArray(offer.shippingDetails).length
            ? toArray(offer.shippingDetails)
            : [{ "@type": "OfferShippingDetails" }];

          shippingDetailsArr.forEach(function (sd) {
            if (!sd || typeof sd !== "object") return;

            if (!sd["@type"]) {
              sd["@type"] = "OfferShippingDetails";
              changed = true;
            }

            if (!sd.shippingDestination || typeof sd.shippingDestination !== "object") {
              sd.shippingDestination = {
                "@type": "DefinedRegion",
                "addressCountry": "FR"
              };
              changed = true;
            } else {
              if (!sd.shippingDestination["@type"]) {
                sd.shippingDestination["@type"] = "DefinedRegion";
                changed = true;
              }
              if (!sd.shippingDestination.addressCountry) {
                sd.shippingDestination.addressCountry = "FR";
                changed = true;
              }
            }

            if (!sd.deliveryTime || typeof sd.deliveryTime !== "object") {
              sd.deliveryTime = { "@type": "ShippingDeliveryTime" };
              changed = true;
            }

            if (!sd.deliveryTime["@type"]) {
              sd.deliveryTime["@type"] = "ShippingDeliveryTime";
              changed = true;
            }

            const wantedTransit = {
              "@type": "QuantitativeValue",
              "minValue": Number(delivery.min),
              "maxValue": Number(delivery.max),
              "unitCode": "DAY"
            };

            if (JSON.stringify(sd.deliveryTime.transitTime || null) !== JSON.stringify(wantedTransit)) {
              sd.deliveryTime.transitTime = wantedTransit;
              changed = true;
            }

            if (freeShip && !sd.shippingRate) {
              sd.shippingRate = {
                "@type": "MonetaryAmount",
                "value": 0,
                "currency": "EUR"
              };
              changed = true;
            }
          });

          setBack(offer, "shippingDetails", shippingDetailsArr);

          const policies = toArray(offer.hasMerchantReturnPolicy).length
            ? toArray(offer.hasMerchantReturnPolicy)
            : [{
                "@type": "MerchantReturnPolicy"
              }];

          policies.forEach(function (rp) {
            if (!rp || typeof rp !== "object") return;

            if (!rp["@type"]) {
              rp["@type"] = "MerchantReturnPolicy";
              changed = true;
            }
            if (!rp.returnPolicyCountry) {
              rp.returnPolicyCountry = "FR";
              changed = true;
            }
            if (!rp.applicableCountry) {
              rp.applicableCountry = "FR";
              changed = true;
            }
            if (rp.returnPolicyCategory !== "https://schema.org/MerchantReturnFiniteReturnWindow") {
              rp.returnPolicyCategory = "https://schema.org/MerchantReturnFiniteReturnWindow";
              changed = true;
            }
            if (rp.merchantReturnDays !== RETURN_WINDOW_DAYS) {
              rp.merchantReturnDays = RETURN_WINDOW_DAYS;
              changed = true;
            }
            if (rp.returnMethod !== "https://schema.org/ReturnByMail") {
              rp.returnMethod = "https://schema.org/ReturnByMail";
              changed = true;
            }
            if (rp.returnFees !== RETURN_FEES) {
              rp.returnFees = RETURN_FEES;
              changed = true;
            }
            if (rp.returnPolicyUrl !== RETURN_POLICY_URL) {
              rp.returnPolicyUrl = RETURN_POLICY_URL;
              changed = true;
            }
          });

          setBack(offer, "hasMerchantReturnPolicy", policies);
        });

        setBack(node, "offers", offersArr);
      });

      if (changed) {
        scriptEl.textContent = serialize(root, nodes);
      }
    });
  }

  document.addEventListener("DOMContentLoaded", function () {
    let tries = 0;
    const maxTries = 60;

    (function loop() {
      patch();
      if (++tries >= maxTries) return;
      setTimeout(loop, 500);
    })();
  });
})();
</script>
<!-- ===================== /CE – PATCH OFFER SHIPPING + RETURN POLICY ===================== -->

<!-- ===================== CE – SEO AUTO JSON-LD (WebPage + BlogPosting + FAQPage) ===================== -->
<script id="seo-auto-jsonld">
(function(){
  'use strict';

  var LOAD_DELAY_MS = 300;
  var CONFIG = {
    orgId: "https://www.comptoireolien.fr/#organization",
    websiteId: "https://www.comptoireolien.fr/#website",
    orgName: "Le Comptoir Éolien",
    defaultLang: "fr-FR"
  };

  var D = document;

  function q(sel, root){ return (root || D).querySelector(sel); }
  function qa(sel, root){ return Array.prototype.slice.call((root || D).querySelectorAll(sel)); }
  function textOf(el){ return el ? (el.textContent || '').replace(/\s+/g, ' ').trim() : ''; }
  function valOf(el, prop){ return el && el[prop] ? el[prop] : undefined; }

  function firstNonEmpty(){
    for (var i = 0; i < arguments.length; i++){
      var v = arguments[i];
      if (v == null) continue;
      if (typeof v === 'string' && v.trim() === '') continue;
      if (Array.isArray(v) && !v.length) continue;
      return v;
    }
    return undefined;
  }

  function canon(){
    var can = q('link[rel="canonical"]');
    return (can && can.href) ? can.href.split('#')[0] : location.href.split('#')[0];
  }

  function absUrl(url){
    if (!url) return undefined;
    try { return new URL(url, location.href).href; }
    catch(e){ return undefined; }
  }

  function truncate(s, max){
    if (!s) return '';
    s = s.trim();
    if (s.length <= max) return s;
    var cut = s.slice(0, max);
    var lastDot = cut.lastIndexOf('.');
    return (lastDot > 100 ? cut.slice(0, lastDot + 1) : cut) + '…';
  }

  function hasExistingType(typeName){
    var scripts = qa('script[type="application/ld+json"]');

    for (var i = 0; i < scripts.length; i++){
      try{
        var raw = (scripts[i].textContent || '').trim();
        if (!raw) continue;

        var data = JSON.parse(raw);
        var list = Array.isArray(data)
          ? data
          : (Array.isArray(data['@graph']) ? data['@graph'] : [data]);

        for (var j = 0; j < list.length; j++){
          var node = list[j];
          if (!node) continue;

          var t = node['@type'];
          if (!t) continue;

          if (t === typeName) return true;
          if (Array.isArray(t) && t.indexOf(typeName) > -1) return true;
        }
      } catch(e){}
    }

    return false;
  }

  function isArticlePage(){
    return !!(
      q('meta[property="og:type"][content*="article"]') ||
      q('article, .single-post, .post-content, .blog-post') ||
      q('meta[name="article:published_time"], meta[property="article:published_time"]') ||
      q('time[datetime]')
    );
  }

  function isLikelyQuestion(txt){
    txt = (txt || '').replace(/\s+/g, ' ').trim();
    if (!txt) return false;
    if (txt.length < 8 || txt.length > 180) return false;

    return /(\?|^Comment\b|^Pourquoi\b|^Quel(?:le|s)?\b|^Combien\b|^Où\b|^Quand\b|^Peut-?on\b|^Est-?ce\b|^Faut-?il\b|^Doit-?on\b|^Que\b|^Qui\b)/i.test(txt);
  }

  function extractFaqPairs(container){
    if (!container) return [];

    var headings = qa('h2, h3', container);
    var pairs = [];

    for (var i = 0; i < headings.length; i++){
      var h = headings[i];
      var qText = textOf(h);

      if (!isLikelyQuestion(qText)) continue;

      var ansParts = [];
      var n = h.nextElementSibling;
      var blockCount = 0;

      while (n && !/H2|H3/.test(n.tagName) && blockCount < 12){
        var tag = (n.tagName || '').toUpperCase();

        if (/^(P|DIV|UL|OL|TABLE|SECTION|ARTICLE|SPAN)$/.test(tag)){
          var t = textOf(n);
          if (t) ansParts.push(t);
        }

        n = n.nextElementSibling;
        blockCount++;
      }

      var aText = truncate(ansParts.join(' ').replace(/\s+/g, ' ').trim(), 1000);

      if (qText && aText && aText.length >= 20){
        pairs.push({
          q: qText.replace(/\?*\s*$/, '?'),
          a: aText
        });
      }
    }

    var seen = {};
    return pairs.filter(function(p){
      var key = (p.q + '||' + p.a).toLowerCase();
      if (seen[key]) return false;
      seen[key] = true;
      return true;
    });
  }

  function buildAndInject(){
    var pageUrl = canon();
    var pageId = pageUrl + "#webpage";
    var info = D.getElementById('assistant-virtuel-info');
    var infoText = info ? textOf(info) : '';
    var metaDesc = valOf(q('meta[name="description"]'), 'content') || '';
    var graph = [];

    if (!hasExistingType('WebPage')){
      var pageNode = {
        "@type": "WebPage",
        "@id": pageId,
        "url": pageUrl,
        "name": firstNonEmpty(
          valOf(q('meta[property="og:title"]'), 'content'),
          textOf(q('h1')),
          D.title
        ),
        "description": truncate(firstNonEmpty(metaDesc, infoText, ''), 300),
        "isPartOf": { "@id": CONFIG.websiteId },
        "about": { "@id": CONFIG.orgId },
        "inLanguage": CONFIG.defaultLang
      };

      Object.keys(pageNode).forEach(function(k){
        if (pageNode[k] === undefined) delete pageNode[k];
      });

      graph.push(pageNode);
    }

    if (isArticlePage() && !hasExistingType('Article') && !hasExistingType('BlogPosting')){
      var headline = firstNonEmpty(
        valOf(q('meta[property="og:title"]'), 'content'),
        textOf(q('h1')),
        D.title
      );

      var hero = firstNonEmpty(
        absUrl(valOf(q('meta[property="og:image"]'), 'content')),
        absUrl(valOf(q('article img'), 'src'))
      );

      var desc = firstNonEmpty(
        metaDesc,
        truncate(infoText, 750)
      );

      var datePub = firstNonEmpty(
        valOf(q('meta[property="article:published_time"]'), 'content'),
        valOf(q('meta[name="article:published_time"]'), 'content'),
        (function(){
          var t = q('time[datetime]');
          return t ? t.getAttribute('datetime') : undefined;
        })()
      );

      var dateMod = firstNonEmpty(
        valOf(q('meta[property="article:modified_time"]'), 'content'),
        valOf(q('meta[name="article:modified_time"]'), 'content')
      );

      var rawAuthorName = firstNonEmpty(
        valOf(q('meta[name="author"]'), 'content'),
        textOf(q('a[rel="author"]')),
        CONFIG.orgName
      );

      var authorEntity = (rawAuthorName === CONFIG.orgName || rawAuthorName === "Le Comptoir Éolien - Groupe MADAULE")
        ? { "@type": "Organization", "@id": CONFIG.orgId, "name": CONFIG.orgName }
        : { "@type": "Person", "name": rawAuthorName };

      var articleNode = {
        "@type": "BlogPosting",
        "@id": pageUrl + "#article",
        "mainEntityOfPage": { "@id": pageId },
        "headline": headline ? headline.trim() : undefined,
        "image": hero ? [hero] : undefined,
        "description": desc,
        "datePublished": datePub || undefined,
        "dateModified": dateMod || undefined,
        "author": authorEntity,
        "publisher": { "@id": CONFIG.orgId },
        "inLanguage": CONFIG.defaultLang
      };

      Object.keys(articleNode).forEach(function(k){
        if (articleNode[k] === undefined) delete articleNode[k];
      });

      graph.push(articleNode);
    }

    var faqPairs = extractFaqPairs(info);

    if (faqPairs.length && !hasExistingType('FAQPage')){
      graph.push({
        "@type": "FAQPage",
        "mainEntity": faqPairs.map(function(p){
          return {
            "@type": "Question",
            "name": p.q,
            "acceptedAnswer": {
              "@type": "Answer",
              "text": p.a
            }
          };
        })
      });
    }

    if (!graph.length) return;

    var prev = D.getElementById('seo-auto-jsonld-output');
    if (prev && prev.parentNode) prev.parentNode.removeChild(prev);

    var s = D.createElement('script');
    s.type = 'application/ld+json';
    s.id = 'seo-auto-jsonld-output';
    s.text = JSON.stringify({
      "@context": "https://schema.org",
      "@graph": graph
    }, null, 2);

    (D.head || q('head')).appendChild(s);
  }

  function start(){
    var go = function(){ setTimeout(buildAndInject, LOAD_DELAY_MS); };
    if (D.readyState === 'complete') go();
    else window.addEventListener('load', go, { once: true });
  }

  start();
})();
</script>
<!-- ===================== /CE – SEO AUTO JSON-LD ===================== -->

<!-- ===================== CE – COLLECTIONPAGE + ITEMLIST + PRODUCT NORMALIZER v2 ===================== -->
<script id="ce-jsonld-enhancer-clean-v2">
(function () {
  "use strict";

  var D = document;
  var ORG_ID = "https://www.comptoireolien.fr/#organization";
  var WEBSITE_ID = "https://www.comptoireolien.fr/#website";

  function q(sel, root){ return (root || D).querySelector(sel); }
  function qa(sel, root){ return Array.prototype.slice.call((root || D).querySelectorAll(sel)); }
  function txt(el){ return el ? (el.textContent || "").replace(/\s+/g, " ").trim() : ""; }

  function canon(){
    var can = q('link[rel="canonical"]');
    return (can && can.href) ? can.href.split("#")[0] : location.href.split("#")[0];
  }

  function absUrl(url){
    if (!url) return "";
    try { return new URL(url, location.href).href.split("#")[0]; }
    catch(e){ return ""; }
  }

  function safeJsonParse(raw){
    try { return JSON.parse((raw || "").trim()); }
    catch(e){ return null; }
  }

  function flattenJsonLd(data){
    if (!data) return [];
    if (Array.isArray(data)) return data;
    if (Array.isArray(data["@graph"])) return data["@graph"];
    return [data];
  }

  function getAllJsonLdScripts(){
    return qa('script[type="application/ld+json"]');
  }

  function getAllJsonLdNodes(){
    var nodes = [];
    getAllJsonLdScripts().forEach(function(s){
      var data = safeJsonParse(s.textContent);
      if (!data) return;
      nodes = nodes.concat(flattenJsonLd(data));
    });
    return nodes;
  }

  function hasType(typeName){
    var nodes = getAllJsonLdNodes();
    for (var i = 0; i < nodes.length; i++){
      var t = nodes[i] && nodes[i]["@type"];
      if (!t) continue;
      if (t === typeName) return true;
      if (Array.isArray(t) && t.indexOf(typeName) > -1) return true;
    }
    return false;
  }

  function isProductType(t){
    return t === "Product" || (Array.isArray(t) && t.indexOf("Product") > -1);
  }

  function normalizeOffers(offers){
    if (!offers) return [];
    return Array.isArray(offers) ? offers : [offers];
  }

  function setOffersBack(node, offersArr){
    if (!offersArr.length) return;
    node.offers = offersArr.length === 1 ? offersArr[0] : offersArr;
  }

  function parsePriceFromText(raw){
    var m = (raw || "").match(/([\d\s]+(?:[.,]\d{2})?)/);
    if (!m) return null;
    var n = parseFloat(m[1].replace(/\s/g, "").replace(",", "."));
    return isFinite(n) ? n.toFixed(2) : null;
  }

  function isProductPage(){
    return !!(q("h1") && q('span.tw-price:not(.striked)') && q('div[id^="pref"]'));
  }

  function detectCategoryName(){
    return txt(q("h1")) || D.title || "Collection";
  }

  function detectCategoryDescription(){
    var md = q('meta[name="description"]');
    return md && md.content ? md.content.trim() : "";
  }

  function detectListCards(){
    var links = qa('.caption h3 a, .product h3 a, .thumbnail h3 a, .card h3 a');
    if (!links.length) {
      links = qa('.caption a[href$=".html"], .product a[href$=".html"], .thumbnail a[href$=".html"], .card a[href$=".html"]');
    }
    return links;
  }

  function isLikelyListingPage(){
    if (isProductPage()) return false;
    return detectListCards().length >= 3;
  }

  function buildItemListElements(){
    var links = detectListCards();
    var out = [];
    var seen = {};

    for (var i = 0; i < links.length; i++){
      var a = links[i];
      var href = absUrl(a.getAttribute("href") || a.href || "");
      var name = txt(a);

      if (!href || !name || seen[href]) continue;
      seen[href] = true;

      var card = a.closest('.caption, .product, .thumbnail, .card, .item') || a.parentElement;
      var priceEl = card ? q('span.tw-price:not(.striked)', card) : null;
      var imgEl = card ? (q('img', card.parentElement || card) || q('img', card)) : null;

      var itemNode = {
        "@type": "ListItem",
        "position": out.length + 1,
        "url": href,
        "name": name
      };

      if (imgEl && imgEl.src) itemNode.image = absUrl(imgEl.src);

      if (priceEl) {
        var price = parsePriceFromText(priceEl.textContent || "");
        if (price) {
          itemNode.item = {
            "@type": "Product",
            "name": name,
            "url": href,
            "offers": {
              "@type": "Offer",
              "priceCurrency": "EUR",
              "price": price
            }
          };
        }
      }

      out.push(itemNode);
      if (out.length >= 24) break;
    }

    return out;
  }

  function injectCollectionPageAndItemList(){
    if (!isLikelyListingPage()) return;
    if (hasType("CollectionPage") || hasType("ItemList")) return;

    var pageUrl = canon();
    var graph = [];

    graph.push({
      "@type": "CollectionPage",
      "@id": pageUrl + "#collectionpage",
      "url": pageUrl,
      "name": detectCategoryName(),
      "description": detectCategoryDescription() || undefined,
      "isPartOf": { "@id": WEBSITE_ID },
      "about": { "@id": ORG_ID },
      "inLanguage": "fr-FR"
    });

    var items = buildItemListElements();
    if (items.length) {
      graph.push({
        "@type": "ItemList",
        "@id": pageUrl + "#itemlist",
        "url": pageUrl,
        "name": detectCategoryName() + " – liste produits",
        "numberOfItems": items.length,
        "itemListOrder": "https://schema.org/ItemListOrderAscending",
        "itemListElement": items
      });
    }

    graph = graph.map(function(n){
      Object.keys(n).forEach(function(k){
        if (n[k] === undefined) delete n[k];
      });
      return n;
    });

    if (!graph.length) return;

    var old = D.getElementById("ce-collection-itemlist-jsonld");
    if (old) old.remove();

    var s = D.createElement("script");
    s.type = "application/ld+json";
    s.id = "ce-collection-itemlist-jsonld";
    s.textContent = JSON.stringify({
      "@context": "https://schema.org",
      "@graph": graph
    }, null, 2);

    (D.head || q("head")).appendChild(s);
  }

  function findTargetProductScript(){
    if (!isProductPage()) return null;

    var mine = D.getElementById("ce-product-jsonld");
    if (mine && mine.type === "application/ld+json") return mine;

    var scripts = getAllJsonLdScripts();
    for (var i = 0; i < scripts.length; i++){
      var data = safeJsonParse(scripts[i].textContent);
      if (!data) continue;

      var nodes = flattenJsonLd(data);
      for (var j = 0; j < nodes.length; j++){
        var node = nodes[j];
        if (node && isProductType(node["@type"]) && node.offers) {
          return scripts[i];
        }
      }
    }

    return null;
  }

  function patchExistingProductJsonLd(){
    if (!isProductPage()) return;

    var targetScript = findTargetProductScript();
    if (!targetScript) return;

    var data = safeJsonParse(targetScript.textContent);
    if (!data) return;

    var isGraph = !!data["@graph"];
    var nodes = flattenJsonLd(data);
    var changed = false;
    var pageUrl = canon();
    var patchedOne = false;

    nodes.forEach(function(node){
      if (patchedOne) return;
      if (!node || !isProductType(node["@type"]) || !node.offers) return;

      patchedOne = true;

      if (!node["@id"]) {
        node["@id"] = pageUrl + "#product";
        changed = true;
      }

      if (!node.url) {
        node.url = pageUrl;
        changed = true;
      }

      if (!node.mainEntityOfPage) {
        node.mainEntityOfPage = { "@id": pageUrl + "#webpage" };
        changed = true;
      }

      if (!node.brand) {
        node.brand = { "@type": "Brand", "name": "Le Comptoir Éolien" };
        changed = true;
      }

      if (!node.category) {
        var h1 = txt(q("h1"));
        if (h1) {
          node.category = h1;
          changed = true;
        }
      }

      var offers = normalizeOffers(node.offers);
      offers.forEach(function(offer){
        if (!offer || typeof offer !== "object") return;

        if (!offer["@id"]) {
          offer["@id"] = pageUrl + "#offer";
          changed = true;
        }

        if (!offer.url) {
          offer.url = pageUrl;
          changed = true;
        }

        if (!offer.seller) {
          offer.seller = { "@id": ORG_ID };
          changed = true;
        }

        if (!offer.priceSpecification && offer.price) {
          offer.priceSpecification = {
            "@type": "PriceSpecification",
            "price": offer.price,
            "priceCurrency": offer.priceCurrency || "EUR"
          };
          changed = true;
        }
      });

      setOffersBack(node, offers);
    });

    if (!changed) return;

    if (Array.isArray(data)) {
      targetScript.textContent = JSON.stringify(nodes, null, 2);
    } else if (isGraph) {
      data["@graph"] = nodes;
      targetScript.textContent = JSON.stringify(data, null, 2);
    } else {
      targetScript.textContent = JSON.stringify(nodes[0], null, 2);
    }
  }

  function start(){
    setTimeout(function(){
      patchExistingProductJsonLd();
      injectCollectionPageAndItemList();
    }, 700);
  }

  if (D.readyState === "complete") start();
  else window.addEventListener("load", start, { once: true });
})();
</script>
<!-- ===================== /CE – COLLECTIONPAGE + ITEMLIST + PRODUCT NORMALIZER ===================== -->

<!-- ===================== CE – CLEANUP PRODUCT JSON-LD v2 ===================== -->
<script id="ce-fix-product-rich-results-errors-v2">
(function () {
  "use strict";

  if (window.__CE_FIX_PRODUCT_RICH_RESULTS_ERRORS_V2__) return;
  window.__CE_FIX_PRODUCT_RICH_RESULTS_ERRORS_V2__ = true;

  var D = document;

  function q(sel, root) {
    return (root || D).querySelector(sel);
  }

  function canon() {
    var c = q('link[rel="canonical"]');
    return ((c && c.href) ? c.href : window.location.href).split("#")[0];
  }

  function normUrl(u) {
    if (!u) return "";
    try {
      var url = new URL(u, window.location.href);
      url.hash = "";
      return url.href.replace(/^http:\/\//i, "https://").replace(/\/+$/, "");
    } catch (e) {
      return String(u).trim().replace(/#.*$/, "").replace(/\/+$/, "");
    }
  }

  function isProductPage() {
    return !!(
      q("h1") &&
      (
        q('span.tw-price:not(.striked)') ||
        q('div[id^="pref"]') ||
        /\.html$/i.test(window.location.pathname)
      )
    );
  }

  function safeParse(raw) {
    try {
      return JSON.parse((raw || "").trim());
    } catch (e) {
      return null;
    }
  }

  function flatten(root) {
    if (!root) return [];
    if (Array.isArray(root)) return root;
    if (Array.isArray(root["@graph"])) return root["@graph"];
    return [root];
  }

  function serialize(root, nodes) {
    if (Array.isArray(root)) return JSON.stringify(nodes, null, 2);
    if (root && Array.isArray(root["@graph"])) {
      root["@graph"] = nodes;
      return JSON.stringify(root, null, 2);
    }
    return JSON.stringify(nodes[0], null, 2);
  }

  function hasType(node, typeName) {
    var t = node && node["@type"];
    return t === typeName || (Array.isArray(t) && t.indexOf(typeName) > -1);
  }

  function isProduct(node) {
    return hasType(node, "Product");
  }

  function isReview(node) {
    return hasType(node, "Review");
  }

  function isAggregateRating(node) {
    return hasType(node, "AggregateRating");
  }

  function productMatchesCurrentPage(node, totalProductNodes) {
    var pageUrl = normUrl(canon());
    var nodeUrl = normUrl(node && node.url);
    var nodeId = normUrl(node && node["@id"]);

    if (nodeUrl && nodeUrl === pageUrl) return true;
    if (nodeId && nodeId.indexOf(pageUrl) === 0) return true;

    return totalProductNodes === 1;
  }

  function productScore(node) {
    var score = 0;
    if (node && node.offers) score += 20;
    if (node && node.weight) score += 10;
    if (node && node.sku) score += 5;
    if (node && node.image) score += 3;
    if (node && node.brand) score += 2;
    if (node && node["@id"]) score += 1;
    return score;
  }

  function cleanProductNode(node) {
    var changed = false;
    if (!node || typeof node !== "object") return false;

    if (node.aggregateRating !== undefined) {
      delete node.aggregateRating;
      changed = true;
    }

    if (node.review !== undefined) {
      delete node.review;
      changed = true;
    }

    if (node.shippingDetails !== undefined) {
      delete node.shippingDetails;
      changed = true;
    }

    if (node.additionalProperty) {
      var arr = Array.isArray(node.additionalProperty) ? node.additionalProperty : [node.additionalProperty];

      var filtered = arr.filter(function (p) {
        var key = String((p && (p.propertyID || p.name)) || "").toLowerCase();
        return !/^shipping_(weight|length|width|height)$/.test(key);
      });

      if (filtered.length !== arr.length) {
        changed = true;
        if (!filtered.length) delete node.additionalProperty;
        else node.additionalProperty = (filtered.length === 1 ? filtered[0] : filtered);
      }
    }

    return changed;
  }

  function run() {
    if (!isProductPage()) return;

    var scriptEls = Array.from(D.querySelectorAll('script[type="application/ld+json"]'));
    var parsed = [];

    scriptEls.forEach(function (scriptEl) {
      var root = safeParse(scriptEl.textContent);
      if (!root) return;

      parsed.push({
        scriptEl: scriptEl,
        root: root,
        nodes: flatten(root)
      });
    });

    if (!parsed.length) return;

    var candidates = [];

    parsed.forEach(function (ps) {
      var productNodes = ps.nodes.filter(isProduct);

      ps.nodes.forEach(function (node, idx) {
        if (!isProduct(node)) return;
        if (!productMatchesCurrentPage(node, productNodes.length)) return;

        candidates.push({
          ps: ps,
          idx: idx,
          score: productScore(node)
        });
      });
    });

    var keep = null;
    if (candidates.length) {
      candidates.sort(function (a, b) {
        return b.score - a.score;
      });
      keep = candidates[0];
    }

    parsed.forEach(function (ps) {
      var productNodes = ps.nodes.filter(isProduct);
      var changed = false;
      var out = [];

      ps.nodes.forEach(function (node, idx) {
        if (!node) return;

        if (isReview(node) || isAggregateRating(node)) {
          changed = true;
          return;
        }

        if (isProduct(node) && productMatchesCurrentPage(node, productNodes.length)) {
          var isKept = keep && keep.ps === ps && keep.idx === idx;

          if (!isKept) {
            changed = true;
            return;
          }

          changed = cleanProductNode(node) || changed;
          out.push(node);
          return;
        }

        out.push(node);
      });

      if (!changed) return;

      if (!out.length) {
        if (ps.scriptEl.parentNode) ps.scriptEl.parentNode.removeChild(ps.scriptEl);
        return;
      }

      ps.scriptEl.textContent = serialize(ps.root, out);
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", function () {
      setTimeout(run, 1200);
    }, { once: true });
  } else {
    setTimeout(run, 1200);
  }

  window.addEventListener("load", function () {
    setTimeout(run, 300);
  }, { once: true });
})();
</script>
<!-- ===================== /CE – CLEANUP PRODUCT JSON-LD ===================== -->

<!-- ===================== CE – OPTIONAL OFFER FIELDS PATCH v2 ===================== -->
<script id="ce-product-jsonld-optional-fields-patch-v2">
(function () {
  "use strict";

  if (window.__CE_PRODUCT_JSONLD_OPTIONAL_FIELDS_PATCH_V2__) return;
  window.__CE_PRODUCT_JSONLD_OPTIONAL_FIELDS_PATCH_V2__ = true;

  var d = new Date();
  d.setDate(d.getDate() + 30);

  function pad(n) {
    return String(n).padStart(2, "0");
  }

  var localPriceValidUntil =
    d.getFullYear() + "-" +
    pad(d.getMonth() + 1) + "-" +
    pad(d.getDate());

  var CFG = {
    priceValidUntil: localPriceValidUntil,
    defaultHandlingTimeMinDays: null,
    defaultHandlingTimeMaxDays: null,
    applicableCountry: "FR"
  };

  var D = document;

  function q(sel, root) {
    return (root || D).querySelector(sel);
  }

  function canon() {
    var c = q('link[rel="canonical"]');
    return ((c && c.href) ? c.href : window.location.href).split("#")[0];
  }

  function normUrl(u) {
    if (!u) return "";
    try {
      var url = new URL(u, window.location.href);
      url.hash = "";
      return url.href.replace(/^http:\/\//i, "https://").replace(/\/+$/, "");
    } catch (e) {
      return String(u).trim().replace(/#.*$/, "").replace(/\/+$/, "");
    }
  }

  function isProductPage() {
    return !!(
      q("h1") &&
      (
        q('span.tw-price:not(.striked)') ||
        q('div[id^="pref"]') ||
        /\.html$/i.test(window.location.pathname)
      )
    );
  }

  function safeParse(raw) {
    try {
      return JSON.parse((raw || "").trim());
    } catch (e) {
      return null;
    }
  }

  function flatten(root) {
    if (!root) return [];
    if (Array.isArray(root)) return root;
    if (Array.isArray(root["@graph"])) return root["@graph"];
    return [root];
  }

  function serialize(root, nodes) {
    if (Array.isArray(root)) return JSON.stringify(nodes, null, 2);
    if (root && Array.isArray(root["@graph"])) {
      root["@graph"] = nodes;
      return JSON.stringify(root, null, 2);
    }
    return JSON.stringify(nodes[0], null, 2);
  }

  function toArray(v) {
    if (!v) return [];
    return Array.isArray(v) ? v : [v];
  }

  function setBack(obj, key, arr) {
    if (!arr.length) return;
    obj[key] = (arr.length === 1) ? arr[0] : arr;
  }

  function hasType(node, typeName) {
    var t = node && node["@type"];
    return t === typeName || (Array.isArray(t) && t.indexOf(typeName) > -1);
  }

  function isProduct(node) {
    return hasType(node, "Product");
  }

  function productMatchesCurrentPage(node, totalProductNodes) {
    var pageUrl = normUrl(canon());
    var nodeUrl = normUrl(node && node.url);
    var nodeId = normUrl(node && node["@id"]);

    if (nodeUrl && nodeUrl === pageUrl) return true;
    if (nodeId && nodeId.indexOf(pageUrl) === 0) return true;

    return totalProductNodes === 1;
  }

  function getMetaContent(name) {
    var el = q('meta[name="' + name + '"]');
    return el ? String(el.getAttribute("content") || "").trim() : "";
  }

  function toIntOrNull(v) {
    if (v == null || v === "") return null;
    var n = parseInt(String(v).trim(), 10);
    return Number.isFinite(n) ? n : null;
  }

  function getHandlingTimeValues() {
    var metaMin = toIntOrNull(getMetaContent("ce-handling-time-min"));
    var metaMax = toIntOrNull(getMetaContent("ce-handling-time-max"));

    var min = (metaMin !== null) ? metaMin : CFG.defaultHandlingTimeMinDays;
    var max = (metaMax !== null) ? metaMax : CFG.defaultHandlingTimeMaxDays;

    if (min === null && max === null) return null;
    if (min !== null && max === null) max = min;
    if (max !== null && min === null) min = max;

    if (min > max) {
      var tmp = min;
      min = max;
      max = tmp;
    }

    return { min: min, max: max };
  }

  function patch() {
    if (!isProductPage()) return;

    var handlingTime = getHandlingTimeValues();
    var scripts = Array.from(D.querySelectorAll('script[type="application/ld+json"]'));

    scripts.forEach(function (scriptEl) {
      var root = safeParse(scriptEl.textContent);
      if (!root) return;

      var nodes = flatten(root);
      if (!nodes.length) return;

      var productNodes = nodes.filter(isProduct);
      if (!productNodes.length) return;

      var changed = false;

      nodes.forEach(function (node) {
        if (!isProduct(node)) return;
        if (!productMatchesCurrentPage(node, productNodes.length)) return;

        var offers = toArray(node.offers);
        if (!offers.length) return;

        offers.forEach(function (offer) {
          if (!offer || typeof offer !== "object") return;

          if (
            CFG.priceValidUntil &&
            !offer.priceValidUntil &&
            offer.price !== undefined &&
            offer.price !== null &&
            String(offer.price) !== ""
          ) {
            offer.priceValidUntil = CFG.priceValidUntil;
            changed = true;
          }

          var shippingDetailsArr = toArray(offer.shippingDetails);
          if (shippingDetailsArr.length) {
            shippingDetailsArr.forEach(function (sd) {
              if (!sd || typeof sd !== "object") return;

              if (!sd.deliveryTime || typeof sd.deliveryTime !== "object") {
                sd.deliveryTime = { "@type": "ShippingDeliveryTime" };
                changed = true;
              }

              if (!sd.deliveryTime["@type"]) {
                sd.deliveryTime["@type"] = "ShippingDeliveryTime";
                changed = true;
              }

              if (handlingTime && sd.deliveryTime.handlingTime === undefined) {
                sd.deliveryTime.handlingTime = {
                  "@type": "QuantitativeValue",
                  "minValue": Number(handlingTime.min),
                  "maxValue": Number(handlingTime.max),
                  "unitCode": "DAY"
                };
                changed = true;
              }
            });

            setBack(offer, "shippingDetails", shippingDetailsArr);
          }

          var policies = toArray(offer.hasMerchantReturnPolicy);
          if (policies.length) {
            policies.forEach(function (policy) {
              if (!policy || typeof policy !== "object") return;

              if (!policy.applicableCountry && CFG.applicableCountry) {
                policy.applicableCountry = CFG.applicableCountry;
                changed = true;
              }
            });

            setBack(offer, "hasMerchantReturnPolicy", policies);
          }
        });

        setBack(node, "offers", offers);
      });

      if (changed) {
        scriptEl.textContent = serialize(root, nodes);
      }
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", function () {
      setTimeout(patch, 1600);
    }, { once: true });
  } else {
    setTimeout(patch, 1600);
  }

  window.addEventListener("load", function () {
    setTimeout(patch, 400);
  }, { once: true });
})();
</script>
<!-- ===================== /CE – OPTIONAL OFFER FIELDS PATCH ===================== -->

<!-- ===================== CE – PRODUCT WEIGHT FROM CATALOG + INTERNAL SHIPPING METAS v3 ===================== -->
<script id="ce-product-weight-from-catalog-v3">
(function () {
  "use strict";

  if (window.__CE_PRODUCT_WEIGHT_FROM_CATALOG_V3__) return;
  window.__CE_PRODUCT_WEIGHT_FROM_CATALOG_V3__ = true;

  var CFG = {
    catalogUrl: "https://www.comptoireolien.fr/_fields/agentic-catalog-v2.json",
    cacheKey: "ce_agentic_catalog_product_weight_v3",
    cacheTtlMs: 6 * 60 * 60 * 1000,
    retryCount: 20,
    retryDelayMs: 700,
    debug: false
  };

  var D = document;
  var payloadCache = null;

  function log() {
    if (!CFG.debug || !window.console) return;
    var args = Array.prototype.slice.call(arguments);
    args.unshift("[CE product weight v3]");
    console.log.apply(console, args);
  }

  function q(sel, root) {
    return (root || D).querySelector(sel);
  }

  function qa(sel, root) {
    return Array.prototype.slice.call((root || D).querySelectorAll(sel));
  }

  function txt(el) {
    return el ? (el.textContent || "").replace(/\s+/g, " ").trim() : "";
  }

  function stripDiacritics(s) {
    s = String(s || "");
    try {
      return s.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
    } catch (e) {
      return s;
    }
  }

  function cleanText(s) {
    return stripDiacritics(String(s || "").toLowerCase().replace(/\s+/g, " ").trim());
  }

  function canon() {
    var can = q('link[rel="canonical"]');
    return ((can && can.href) ? can.href : window.location.href).split("#")[0];
  }

  function normUrl(u) {
    if (!u) return "";
    try {
      var url = new URL(u, window.location.href);
      url.hash = "";
      return url.href.replace(/^http:\/\//i, "https://").replace(/\/+$/, "");
    } catch (e) {
      return String(u).trim().replace(/#.*$/, "").replace(/\/+$/, "");
    }
  }

  function pathOf(u) {
    try {
      return new URL(u, window.location.href).pathname.replace(/\/+$/, "");
    } catch (e) {
      return "";
    }
  }

  function uniq(arr) {
    var out = [];
    var seen = {};
    arr.forEach(function (v) {
      var k = String(v);
      if (!k || seen[k]) return;
      seen[k] = true;
      out.push(v);
    });
    return out;
  }

  function toNum(v) {
    if (v == null || v === "") return null;
    var s = String(v).replace(",", ".").replace(/[^\d.]+/g, "");
    var n = parseFloat(s);
    return isFinite(n) ? n : null;
  }

  function isProductPage() {
    return !!(
      q("h1") &&
      (
        q('span.tw-price:not(.striked)') ||
        q('div[id^="pref"]') ||
        /\.html$/i.test(window.location.pathname)
      )
    );
  }

  function currentSku() {
    var domSku = txt(q('div[id^="pref"]'));
    if (domSku) return domSku;
    return "";
  }

  function currentIds() {
    var out = [];
    var sku = currentSku();
    if (sku) out.push(String(sku));

    var nums = (window.location.pathname.match(/\d+/g) || []);
    nums.forEach(function (n) { out.push(String(n)); });

    return uniq(out.filter(Boolean));
  }

  function currentTitle() {
    return cleanText(txt(q("h1")));
  }

  function upsertMeta(name, content) {
    if (content == null || content === "") return;

    var m = q('meta[name="' + name + '"]');
    if (!m) {
      m = D.createElement("meta");
      m.setAttribute("name", name);
      (D.head || q("head")).appendChild(m);
    }
    m.setAttribute("content", String(content));
  }

  function getCachedCatalog() {
    try {
      var raw = sessionStorage.getItem(CFG.cacheKey);
      if (!raw) return null;
      var parsed = JSON.parse(raw);
      if (!parsed || !parsed.ts || !parsed.data) return null;
      if ((Date.now() - parsed.ts) > CFG.cacheTtlMs) return null;
      return parsed.data;
    } catch (e) {
      return null;
    }
  }

  function setCachedCatalog(data) {
    try {
      sessionStorage.setItem(CFG.cacheKey, JSON.stringify({
        ts: Date.now(),
        data: data
      }));
    } catch (e) {}
  }

  function loadCatalog() {
    var cached = getCachedCatalog();
    if (cached) return Promise.resolve(cached);

    return fetch(CFG.catalogUrl, {
      credentials: "same-origin",
      cache: "no-store"
    })
      .then(function (res) {
        if (!res.ok) throw new Error("Catalogue HTTP " + res.status);
        return res.json();
      })
      .then(function (data) {
        setCachedCatalog(data);
        return data;
      });
  }

  function getItems(catalog) {
    if (catalog && Array.isArray(catalog.items)) return catalog.items;
    return [];
  }

  function findBestCatalogItem(items) {
    var pageUrl = normUrl(canon());
    var pagePath = pathOf(pageUrl);
    var pageSku = currentSku();
    var pageIds = currentIds();
    var pageTitle = currentTitle();

    var best = null;
    var bestScore = -1;

    items.forEach(function (item) {
      if (!item || typeof item !== "object") return;

      var candidateWeight = toNum(
        item.productWeightKg != null ? item.productWeightKg :
        item.weightKg != null ? item.weightKg :
        item.product_weight != null ? item.product_weight :
        item.weight != null ? item.weight :
        item.shippingWeightKg != null ? item.shippingWeightKg :
        null
      );

      if (!(candidateWeight > 0)) return;

      var itemUrl = normUrl(item.url || item.productUrl || item.canonicalUrl || item.link || item.href || "");
      var itemPath = pathOf(itemUrl);

      var ids = uniq([
        item.sku,
        item.reference,
        item.ref,
        item.id,
        item.offerId,
        item.productId,
        item.itemId
      ].filter(function (v) {
        return v != null && v !== "";
      }).map(function (v) {
        return String(v).trim();
      }));

      var title = cleanText(item.name || item.title || item.label || "");
      var score = -1;

      if (itemUrl && itemUrl === pageUrl) score = Math.max(score, 100);
      if (itemPath && itemPath === pagePath) score = Math.max(score, 95);
      if (pageSku && ids.indexOf(String(pageSku)) > -1) score = Math.max(score, 90);

      if (pageIds.some(function (id) { return ids.indexOf(id) > -1; })) {
        score = Math.max(score, 80);
      }

      if (pageTitle && title && pageTitle === title) score = Math.max(score, 60);
      if (pageTitle && title && pageTitle.indexOf(title) > -1) score = Math.max(score, 50);

      if (score > bestScore) {
        bestScore = score;
        best = item;
      }
    });

    return bestScore >= 50 ? best : null;
  }

  function makeQuantitativeValue(n, unitCode, unitText) {
    n = Number(n);
    if (!isFinite(n) || n <= 0) return null;

    return {
      "@type": "QuantitativeValue",
      "value": Math.round(n * 1000) / 1000,
      "unitCode": unitCode,
      "unitText": unitText
    };
  }

  function extractWeightQv(v) {
    if (!v) return null;

    if (Object.prototype.toString.call(v) === "[object Object]") {
      var objVal = toNum(v.value);
      var objUnitCode = String(v.unitCode || "").trim().toUpperCase();
      var objUnitText = String(v.unitText || "").trim().toLowerCase();

      if (objVal > 0) {
        if (!objUnitCode && objUnitText) {
          objUnitCode = (
            objUnitText === "kg" ? "KGM" :
            objUnitText === "g" ? "GRM" :
            objUnitText === "lb" ? "LBR" :
            objUnitText === "oz" ? "ONZ" : ""
          );
        }

        if (!objUnitText && objUnitCode) {
          objUnitText = (
            objUnitCode === "KGM" ? "kg" :
            objUnitCode === "GRM" ? "g" :
            objUnitCode === "LBR" ? "lb" :
            objUnitCode === "ONZ" ? "oz" : ""
          );
        }

        return {
          "@type": "QuantitativeValue",
          "value": objVal,
          "unitCode": objUnitCode || "KGM",
          "unitText": objUnitText || "kg"
        };
      }
    }

    var s = String(v).toLowerCase();
    var n = toNum(s);
    if (!(n > 0)) return null;

    var unitText =
      /\bkg\b/.test(s) ? "kg" :
      /\bg\b/.test(s) ? "g" :
      /\blb\b/.test(s) ? "lb" :
      /\boz\b/.test(s) ? "oz" : "kg";

    var unitCode =
      unitText === "kg" ? "KGM" :
      unitText === "g" ? "GRM" :
      unitText === "lb" ? "LBR" : "ONZ";

    return makeQuantitativeValue(n, unitCode, unitText);
  }

  function sameWeightQv(a, b) {
    var qa = extractWeightQv(a);
    var qb = extractWeightQv(b);
    if (!qa || !qb) return false;

    return (
      Math.abs(Number(qa.value) - Number(qb.value)) < 0.0001 &&
      (
        String(qa.unitCode || "") === String(qb.unitCode || "") ||
        String(qa.unitText || "") === String(qb.unitText || "")
      )
    );
  }

  function buildPayload(item) {
    if (!item) return null;

    var productWeightKg = toNum(
      item.productWeightKg != null ? item.productWeightKg :
      item.weightKg != null ? item.weightKg :
      item.product_weight != null ? item.product_weight :
      item.weight != null ? item.weight :
      null
    );

    var shippingWeightKg = toNum(
      item.shippingWeightKg != null ? item.shippingWeightKg :
      item.packageWeightKg != null ? item.packageWeightKg :
      item.shipping_weight != null ? item.shipping_weight :
      null
    );

    var shippingLengthCm = toNum(
      item.shippingLengthCm != null ? item.shippingLengthCm :
      item.shipping_length != null ? item.shipping_length :
      null
    );

    var shippingWidthCm = toNum(
      item.shippingWidthCm != null ? item.shippingWidthCm :
      item.shipping_width != null ? item.shipping_width :
      null
    );

    var shippingHeightCm = toNum(
      item.shippingHeightCm != null ? item.shippingHeightCm :
      item.shipping_height != null ? item.shipping_height :
      null
    );

    if (!(productWeightKg > 0) && shippingWeightKg > 0) {
      productWeightKg = shippingWeightKg;
    }

    if (!(productWeightKg > 0)) return null;

    return {
      sku: String(item.sku || currentSku() || ""),
      name: String(item.name || item.title || txt(q("h1")) || ""),
      url: canon(),
      productWeightKg: productWeightKg,
      productWeightQv: makeQuantitativeValue(productWeightKg, "KGM", "kg"),
      shippingWeightKg: shippingWeightKg,
      shippingLengthCm: shippingLengthCm,
      shippingWidthCm: shippingWidthCm,
      shippingHeightCm: shippingHeightCm
    };
  }

  function safeParse(raw) {
    try {
      return JSON.parse((raw || "").trim());
    } catch (e) {
      return null;
    }
  }

  function flatten(root) {
    if (!root) return [];
    if (Array.isArray(root)) return root;
    if (Array.isArray(root["@graph"])) return root["@graph"];
    return [root];
  }

  function serialize(root, nodes) {
    if (Array.isArray(root)) return JSON.stringify(nodes, null, 2);
    if (root && Array.isArray(root["@graph"])) {
      root["@graph"] = nodes;
      return JSON.stringify(root, null, 2);
    }
    return JSON.stringify(nodes[0], null, 2);
  }

  function toArray(v) {
    if (!v) return [];
    return Array.isArray(v) ? v : [v];
  }

  function setBack(obj, key, arr) {
    if (!arr.length) return;
    obj[key] = (arr.length === 1) ? arr[0] : arr;
  }

  function hasType(node, typeName) {
    var t = node && node["@type"];
    return t === typeName || (Array.isArray(t) && t.indexOf(typeName) > -1);
  }

  function isProduct(node) {
    return hasType(node, "Product");
  }

  function productMatchesCurrentPage(node, totalProductNodes) {
    var pageUrl = normUrl(canon());
    var nodeUrl = normUrl(node && node.url);
    var nodeId = normUrl(node && node["@id"]);

    if (nodeUrl && nodeUrl === pageUrl) return true;
    if (nodeId && nodeId.indexOf(pageUrl) === 0) return true;

    return totalProductNodes === 1;
  }

  function patchJsonLd(payload) {
    var scripts = qa('script[type="application/ld+json"]');
    var foundProduct = false;

    scripts.forEach(function (scriptEl) {
      var root = safeParse(scriptEl.textContent);
      if (!root) return;

      var nodes = flatten(root);
      if (!nodes.length) return;

      var productNodes = nodes.filter(isProduct);
      if (!productNodes.length) return;

      var changed = false;

      nodes.forEach(function (node) {
        if (!isProduct(node)) return;
        if (!productMatchesCurrentPage(node, productNodes.length)) return;

        foundProduct = true;

        var offers = toArray(node.offers);

        offers.forEach(function (offer) {
          if (!offer || typeof offer !== "object") return;

          var priceSpecs = toArray(offer.priceSpecification);
          priceSpecs.forEach(function (ps) {
            if (!ps || typeof ps !== "object") return;

            if (ps.weight) {
              if (!node.weight) {
                var extracted = extractWeightQv(ps.weight);
                if (extracted) {
                  node.weight = extracted;
                }
              }
              delete ps.weight;
              changed = true;
            }
          });
          setBack(offer, "priceSpecification", priceSpecs);

          var shippingDetailsArr = toArray(offer.shippingDetails);
          shippingDetailsArr.forEach(function (sd) {
            if (!sd || typeof sd !== "object") return;

            ["weight", "depth", "width", "height"].forEach(function (badKey) {
              if (Object.prototype.hasOwnProperty.call(sd, badKey)) {
                delete sd[badKey];
                changed = true;
              }
            });
          });
          setBack(offer, "shippingDetails", shippingDetailsArr);
        });

        setBack(node, "offers", offers);

        if (payload.productWeightQv && !sameWeightQv(node.weight, payload.productWeightQv)) {
          node.weight = payload.productWeightQv;
          changed = true;
        }
      });

      if (changed) {
        scriptEl.textContent = serialize(root, nodes);
      }
    });

    return { foundProduct: foundProduct };
  }

  function applyMeta(payload) {
    if (!payload) return;

    upsertMeta("product-weight", Number(payload.productWeightKg).toFixed(3));
    if (payload.shippingWeightKg > 0) upsertMeta("shipping-weight", Number(payload.shippingWeightKg).toFixed(3));
    if (payload.shippingLengthCm > 0) upsertMeta("shipping-length", Number(payload.shippingLengthCm).toFixed(0));
    if (payload.shippingWidthCm > 0) upsertMeta("shipping-width", Number(payload.shippingWidthCm).toFixed(0));
    if (payload.shippingHeightCm > 0) upsertMeta("shipping-height", Number(payload.shippingHeightCm).toFixed(0));
  }

  function runPatchLoop(payload) {
    var tries = 0;

    function tick() {
      applyMeta(payload);

      var res = patchJsonLd(payload);
      if (res.foundProduct) {
        log("Product weight patch appliqué", payload);
        return;
      }

      if (tries >= CFG.retryCount) {
        log("Aucun Product JSON-LD trouvé après retries.");
        return;
      }

      tries += 1;
      setTimeout(tick, CFG.retryDelayMs);
    }

    tick();
  }

  function boot() {
    if (!isProductPage()) return;

    loadCatalog()
      .then(function (catalog) {
        var items = getItems(catalog);
        var item = findBestCatalogItem(items);

        if (!item) {
          log("Aucun produit trouvé dans le catalogue pour cette fiche.");
          return;
        }

        var payload = buildPayload(item);
        if (!payload) {
          log("Poids produit introuvable pour le produit trouvé.");
          return;
        }

        payloadCache = payload;
        applyMeta(payload);
        runPatchLoop(payload);
      })
      .catch(function (err) {
        log("Erreur :", err);
      });
  }

  if (D.readyState === "loading") {
    D.addEventListener("DOMContentLoaded", boot, { once: true });
  } else {
    boot();
  }

  window.addEventListener("load", function () {
    if (payloadCache) runPatchLoop(payloadCache);
  }, { once: true });
})();
</script>
<!-- ===================== /CE – PRODUCT WEIGHT FROM CATALOG + INTERNAL SHIPPING METAS ===================== -->
<!-- ===================== CE – PRODUCT IMAGE SANITIZER FOR MERCHANT CENTER v1 ===================== -->
<script id="ce-product-jsonld-image-sanitizer-v1">
(function () {
  "use strict";

  if (window.__CE_PRODUCT_JSONLD_IMAGE_SANITIZER_V1__) return;
  window.__CE_PRODUCT_JSONLD_IMAGE_SANITIZER_V1__ = true;

  var D = document;

  function q(sel, root) {
    return (root || D).querySelector(sel);
  }

  function qa(sel, root) {
    return Array.prototype.slice.call((root || D).querySelectorAll(sel));
  }

  function canon() {
    var c = q('link[rel="canonical"]');
    return ((c && c.href) ? c.href : window.location.href).split("#")[0];
  }

  function absUrl(url) {
    if (!url) return "";
    try {
      return new URL(url, window.location.href).href.split("#")[0];
    } catch (e) {
      return "";
    }
  }

  function normUrl(u) {
    if (!u) return "";
    try {
      var url = new URL(u, window.location.href);
      url.hash = "";
      return url.href.replace(/^http:\/\//i, "https://").replace(/\/+$/, "");
    } catch (e) {
      return String(u).trim().replace(/#.*$/, "").replace(/\/+$/, "");
    }
  }

  function isProductPage() {
    return !!(
      q("h1") &&
      (
        q('span.tw-price:not(.striked)') ||
        q('div[id^="pref"]') ||
        /\.html$/i.test(window.location.pathname)
      )
    );
  }

  function normalizeProductImageUrl(url) {
    var u = absUrl(url);
    if (!u) return "";

    var clean = u.split("?")[0].replace(/^http:\/\//i, "https://");

    if (!/^https:\/\/www\.comptoireolien\.fr\/_media\/img\/(medium|xlarge)\//i.test(clean)) {
      return "";
    }

    if (!/\.(webp|png|jpg|jpeg)$/i.test(clean)) {
      return "";
    }

    return clean;
  }

  function imageKey(url) {
    return String(url || "").toLowerCase().split("/").pop() || String(url || "").toLowerCase();
  }

  function addSrcset(srcset, add) {
    String(srcset || "").split(",").forEach(function (part) {
      var candidate = String(part || "").trim().split(/\s+/)[0];
      if (candidate) add(candidate);
    });
  }

  function collectStrictProductImages() {
    var medium = [];
    var xlarge = [];
    var mediumByKey = {};
    var xlargeByKey = {};

    function add(url) {
      var u = normalizeProductImageUrl(url);
      if (!u) return;

      var key = imageKey(u);
      var isMedium = /\/_media\/img\/medium\//i.test(u);

      if (isMedium) {
        if (mediumByKey[key]) return;

        mediumByKey[key] = u;

        if (xlargeByKey[key]) {
          delete xlargeByKey[key];
          for (var i = xlarge.length - 1; i >= 0; i--) {
            if (imageKey(xlarge[i]) === key) xlarge.splice(i, 1);
          }
        }

        medium.push(u);
        return;
      }

      if (mediumByKey[key] || xlargeByKey[key]) return;

      xlargeByKey[key] = u;
      xlarge.push(u);
    }

    function collect(root) {
      if (!root) return;

      qa("a[href]", root).forEach(function (a) {
        add(a.getAttribute("href") || a.href || "");
      });

      qa("img[src]", root).forEach(function (img) {
        add(img.getAttribute("src") || img.src || "");
        add(img.getAttribute("data-zoom-image") || "");
        addSrcset(img.getAttribute("srcset") || "", add);
      });
    }

    var galleryRoot = q(".mpv") || q(".mpv_pics");
    if (galleryRoot) collect(galleryRoot);

    if (!medium.length && !xlarge.length) {
      qa('img.evzh_1[src], img[data-zoom-image], .img-wrapper a[href]').forEach(function (el) {
        var tag = String(el.tagName || "").toUpperCase();

        if (tag === "IMG") {
          add(el.getAttribute("src") || el.src || "");
          add(el.getAttribute("data-zoom-image") || "");
          addSrcset(el.getAttribute("srcset") || "", add);
        } else if (tag === "A") {
          add(el.getAttribute("href") || el.href || "");
        }
      });
    }

    var og = q('meta[property="og:image"]');
    if (og && og.content) add(og.content);

    var tw = q('meta[name="twitter:image"]');
    if (tw && tw.content) add(tw.content);

    return medium.concat(xlarge);
  }

  function upsertMeta(attrName, attrValue, content) {
    if (!content) return;

    var m = q('meta[' + attrName + '="' + attrValue + '"]');
    if (!m) {
      m = D.createElement("meta");
      m.setAttribute(attrName, attrValue);
      (D.head || q("head")).appendChild(m);
    }
    m.setAttribute("content", content);
  }

  function safeParse(raw) {
    try {
      return JSON.parse((raw || "").trim());
    } catch (e) {
      return null;
    }
  }

  function flatten(root) {
    if (!root) return [];
    if (Array.isArray(root)) return root;
    if (Array.isArray(root["@graph"])) return root["@graph"];
    return [root];
  }

  function serialize(root, nodes) {
    if (Array.isArray(root)) return JSON.stringify(nodes, null, 2);
    if (root && Array.isArray(root["@graph"])) {
      root["@graph"] = nodes;
      return JSON.stringify(root, null, 2);
    }
    return JSON.stringify(nodes[0], null, 2);
  }

  function hasType(node, typeName) {
    var t = node && node["@type"];
    return t === typeName || (Array.isArray(t) && t.indexOf(typeName) > -1);
  }

  function isProduct(node) {
    return hasType(node, "Product");
  }

  function productMatchesCurrentPage(node, totalProductNodes) {
    var pageUrl = normUrl(canon());
    var nodeUrl = normUrl(node && node.url);
    var nodeId = normUrl(node && node["@id"]);

    if (nodeUrl && nodeUrl === pageUrl) return true;
    if (nodeId && nodeId.indexOf(pageUrl) === 0) return true;

    return totalProductNodes === 1;
  }

  function sameImageArray(a, b) {
    var left = Array.isArray(a) ? a : (a ? [a] : []);
    var right = Array.isArray(b) ? b : (b ? [b] : []);

    if (left.length !== right.length) return false;

    for (var i = 0; i < left.length; i++) {
      if (String(left[i]) !== String(right[i])) return false;
    }

    return true;
  }

  function patch() {
    if (!isProductPage()) return;

    var images = collectStrictProductImages();
    if (!images.length) return;

    upsertMeta("property", "og:image", images[0]);
    upsertMeta("name", "twitter:image", images[0]);

    var scripts = qa('script[type="application/ld+json"]');

    scripts.forEach(function (scriptEl) {
      var root = safeParse(scriptEl.textContent);
      if (!root) return;

      var nodes = flatten(root);
      if (!nodes.length) return;

      var productNodes = nodes.filter(isProduct);
      if (!productNodes.length) return;

      var changed = false;

      nodes.forEach(function (node) {
        if (!isProduct(node)) return;
        if (!productMatchesCurrentPage(node, productNodes.length)) return;

        if (!sameImageArray(node.image, images)) {
          node.image = (images.length === 1) ? images[0] : images.slice();
          changed = true;
        }
      });

      if (changed) {
        scriptEl.textContent = serialize(root, nodes);
      }
    });
  }

  function startLoop() {
    var tries = 0;
    var maxTries = 40;

    (function tick() {
      patch();
      if (++tries >= maxTries) return;
      setTimeout(tick, 500);
    })();
  }

  if (D.readyState === "loading") {
    D.addEventListener("DOMContentLoaded", function () {
      startLoop();
    }, { once: true });
  } else {
    startLoop();
  }

  window.addEventListener("load", function () {
    setTimeout(patch, 300);
    setTimeout(patch, 1200);
  }, { once: true });
})();
</script>
<!-- ===================== /CE – PRODUCT IMAGE SANITIZER FOR MERCHANT CENTER ===================== -->

<!-- ===================== CE – FINAL PRODUCT JSON-LD PATCH v2 ===================== -->
<script id="ce-product-jsonld-final-fix-v2">
(function () {
  "use strict";

  if (window.__CE_PRODUCT_JSONLD_FINAL_FIX_V2__) return;
  window.__CE_PRODUCT_JSONLD_FINAL_FIX_V2__ = true;

  var D = document;
  var ORG_ID = "https://www.comptoireolien.fr/#organization";
  var RETURN_POLICY_URL = "https://www.comptoireolien.fr/satisfait-ou-rembourse.html";
  var PRODUCT_SCRIPT_ID = "ce-product-jsonld-final-fallback-v2";
  var PRODUCT_ID_SUFFIX = "#product";
  var OFFER_ID_SUFFIX = "#offer";
  var WEBPAGE_ID_SUFFIX = "#webpage";
  var RETURN_DAYS = 90;

  function q(sel, root) {
    return (root || D).querySelector(sel);
  }

  function qa(sel, root) {
    return Array.prototype.slice.call((root || D).querySelectorAll(sel));
  }

  function txt(el) {
    return el ? String(el.textContent || "").replace(/\s+/g, " ").trim() : "";
  }

  function canon() {
    var c = q('link[rel="canonical"]');
    return ((c && c.href) ? c.href : window.location.href).split("#")[0];
  }

  function normUrl(u) {
    if (!u) return "";
    try {
      var url = new URL(String(u), window.location.href);
      url.hash = "";
      return url.href.replace(/^http:\/\//i, "https://").replace(/\/+$/, "");
    } catch (e) {
      return String(u).trim().replace(/#.*$/, "").replace(/\/+$/, "");
    }
  }

  function absUrl(u) {
    if (!u) return "";
    try {
      return new URL(String(u), window.location.href).href.split("#")[0];
    } catch (e) {
      return "";
    }
  }

  function safeParse(raw) {
    try {
      return JSON.parse(String(raw || "").trim());
    } catch (e) {
      return null;
    }
  }

  function flatten(root) {
    if (!root) return [];
    if (Array.isArray(root)) return root;
    if (Array.isArray(root["@graph"])) return root["@graph"];
    return [root];
  }

  function serialize(root, nodes) {
    if (Array.isArray(root)) return JSON.stringify(nodes, null, 2);
    if (root && Array.isArray(root["@graph"])) {
      root["@graph"] = nodes;
      return JSON.stringify(root, null, 2);
    }
    return JSON.stringify(nodes[0], null, 2);
  }

  function toArray(v) {
    if (!v) return [];
    return Array.isArray(v) ? v : [v];
  }

  function hasType(node, typeName) {
    var t = node && node["@type"];
    return t === typeName || (Array.isArray(t) && t.indexOf(typeName) > -1);
  }

  function isProduct(node) {
    return hasType(node, "Product");
  }

  function isReview(node) {
    return hasType(node, "Review");
  }

  function isAggregateRating(node) {
    return hasType(node, "AggregateRating");
  }

  function pageTitle() {
    return txt(q("h1")) || document.title || "Produit";
  }

  function numeric(v) {
    if (v == null || v === "") return null;
    var s = String(v).replace(/\s/g, "").replace(",", ".").replace(/[^\d.-]/g, "");
    var n = parseFloat(s);
    return isFinite(n) ? n : null;
  }

  function getPriceCurrencyFromDom() {
    var meta = q('meta[itemprop="priceCurrency"][content], meta[property="product:price:currency"][content], meta[property="og:price:currency"][content]');
    var raw = meta ? String(meta.getAttribute("content") || "").trim().toUpperCase() : "";
    return raw || "EUR";
  }

  function getPriceFromDom() {
    var pp = q('[data-pp-message][data-pp-amount]');
    if (pp) {
      var ppv = numeric(pp.getAttribute("data-pp-amount"));
      if (ppv !== null) return ppv.toFixed(2);
    }

    var meta = q('meta[itemprop="price"][content], meta[property="product:price:amount"][content]');
    if (meta) {
      var mv = numeric(meta.getAttribute("content"));
      if (mv !== null) return mv.toFixed(2);
    }

    var el = q('span.tw-price:not(.striked)');
    if (!el) return null;

    var m = txt(el).match(/([\d\s]+(?:[.,]\d{2})?)/);
    if (!m) return null;

    var v = numeric(m[1]);
    return v !== null ? v.toFixed(2) : null;
  }

  function getSkuFromDom() {
    return txt(q('div[id^="pref"]')) || "";
  }

  function getWeightFromMeta() {
    var m = q('meta[name="product-weight"]');
    if (!m) return null;

    var v = numeric(m.getAttribute("content"));
    if (v === null || v <= 0) return null;

    return {
      "@type": "QuantitativeValue",
      "value": Number(v.toFixed(3)),
      "unitCode": "KGM",
      "unitText": "kg"
    };
  }

  function mapAvailability(raw) {
    var t = String(raw || "").trim().toLowerCase();
    if (!t) return "https://schema.org/InStock";
    if (/^https?:/.test(t)) return t;

    if (/\b(non[-\s]*disponible|rupture|épuis[ée]?|epuis[ée]?|indispo|sold\s*out|out\s*of\s*stock)\b/.test(t)) {
      return "https://schema.org/OutOfStock";
    }

    if (/\b(en\s*stock|dispo|livraison|available|in\s*stock)\b/.test(t)) {
      return "https://schema.org/InStock";
    }

    return "https://schema.org/InStock";
  }

  function getAvailabilityFromDom() {
    var og = q('meta[property="og:availability"]');
    if (og && og.content) return mapAvailability(og.content);

    var stockEl = q("#pstockRqRzIc") || q('[id^="pstock"]') || q(".availability, .stock");
    if (stockEl) return mapAvailability(txt(stockEl));

    return q('a[href*="_checkout"], .btn, button')
      ? "https://schema.org/InStock"
      : "https://schema.org/OutOfStock";
  }

  function getDeliveryDays() {
    var stockEl = q("#pstockRqRzIc") || q('[id^="pstock"]');
    var t = txt(stockEl).toLowerCase();

    var m = t.match(/livraison\s*[:\-]?\s*(\d+)\s*(?:à|\-)\s*(\d+)\s*jour/);
    if (m) return { min: parseInt(m[1], 10), max: parseInt(m[2], 10) };

    m = t.match(/livraison\s*[:\-]?\s*(\d+)\s*jour/);
    if (m) {
      var d = parseInt(m[1], 10);
      return { min: d, max: d };
    }

    return { min: 2, max: 4 };
  }

  function isFreeShippingMentioned() {
    var body = String((document.body && document.body.innerText) || "").toLowerCase();
    return /\blivraison\s+(offerte|gratuite)\b/.test(body);
  }

  function addDaysIso(days) {
    var d = new Date();
    d.setDate(d.getDate() + days);
    var yyyy = d.getFullYear();
    var mm = String(d.getMonth() + 1).padStart(2, "0");
    var dd = String(d.getDate()).padStart(2, "0");
    return yyyy + "-" + mm + "-" + dd;
  }

  function getProductImages() {
    var out = [];
    var seen = {};

    function add(u) {
      var abs = absUrl(u);
      if (!abs || seen[abs]) return;
      seen[abs] = true;
      out.push(abs);
    }

    qa('.mpv img[src], .mpv_pics img[src], img[data-zoom-image], meta[property="og:image"], meta[name="twitter:image"]').forEach(function (el) {
      if (el.tagName === "META") {
        add(el.getAttribute("content"));
      } else {
        add(el.getAttribute("data-zoom-image") || el.getAttribute("src") || "");
      }
    });

    if (!out.length) {
      var og = q('meta[property="og:image"]');
      if (og && og.content) add(og.content);
    }

    return out;
  }

  function productPageStrict() {
    var hasTitle = !!q("h1");
    var price = getPriceFromDom();
    var priceCount = qa('span.tw-price:not(.striked)').length;

    var hasPref = !!q('div[id^="pref"]');
    var hasProductMeta = !!q(
      'meta[name="product-weight"], ' +
      'meta[name="shipping-weight"], ' +
      'meta[itemprop="price"][content], ' +
      'meta[property="product:price:amount"][content], ' +
      'meta[property="og:type"][content="product"]'
    );

    return !!(hasTitle && price !== null && (hasPref || hasProductMeta) && priceCount <= 6);
  }

  function hasValidOffer(offers) {
    return toArray(offers).some(function (o) {
      if (!o || typeof o !== "object") return false;

      var t = o["@type"];
      var isOfferType = (t === "Offer") || (Array.isArray(t) && t.indexOf("Offer") > -1) || !t;
      if (!isOfferType) return false;

      var price = numeric(o.price);
      var specPrice = o.priceSpecification ? numeric(o.priceSpecification.price) : null;
      var hasPrice = (price !== null) || (specPrice !== null);
      var hasCurrency = !!(o.priceCurrency || (o.priceSpecification && o.priceSpecification.priceCurrency));

      return hasPrice && hasCurrency;
    });
  }

  function buildOffer(existing) {
    var pageUrl = canon();
    var price = getPriceFromDom();
    var currency = getPriceCurrencyFromDom();
    var availability = getAvailabilityFromDom();
    var delivery = getDeliveryDays();
    var freeShip = isFreeShippingMentioned();

    var offer = (existing && typeof existing === "object") ? existing : {};

    offer["@type"] = "Offer";
    offer["@id"] = pageUrl + OFFER_ID_SUFFIX;
    offer.url = pageUrl;
    offer.priceCurrency = currency;
    if (price !== null) offer.price = price;
    if (price !== null && !offer.priceValidUntil) offer.priceValidUntil = addDaysIso(30);
    offer.availability = availability;
    offer.itemCondition = "https://schema.org/NewCondition";
    offer.seller = { "@id": ORG_ID };

    offer.shippingDetails = {
      "@type": "OfferShippingDetails",
      "shippingDestination": {
        "@type": "DefinedRegion",
        "addressCountry": "FR"
      },
      "deliveryTime": {
        "@type": "ShippingDeliveryTime",
        "transitTime": {
          "@type": "QuantitativeValue",
          "minValue": Number(delivery.min),
          "maxValue": Number(delivery.max),
          "unitCode": "DAY"
        }
      }
    };

    if (freeShip) {
      offer.shippingDetails.shippingRate = {
        "@type": "MonetaryAmount",
        "value": 0,
        "currency": currency
      };
    }

    offer.hasMerchantReturnPolicy = {
      "@type": "MerchantReturnPolicy",
      "applicableCountry": "FR",
      "returnPolicyCountry": "FR",
      "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
      "merchantReturnDays": RETURN_DAYS,
      "returnMethod": "https://schema.org/ReturnByMail",
      "returnFees": "https://schema.org/ReturnFeesCustomerResponsibility",
      "refundType": "https://schema.org/FullRefund",
      "returnPolicyUrl": RETURN_POLICY_URL
    };

    return offer;
  }

  function isCurrentPageProductNode(node, totalProducts) {
    var pageUrl = normUrl(canon());
    var nodeUrl = normUrl(node && node.url);
    var nodeId = normUrl(node && node["@id"]);
    var mainId = normUrl(node && node.mainEntityOfPage && node.mainEntityOfPage["@id"]);

    if (nodeUrl && nodeUrl === pageUrl) return true;
    if (nodeId && nodeId.indexOf(pageUrl) === 0) return true;
    if (mainId && mainId.indexOf(pageUrl) === 0) return true;

    return totalProducts === 1;
  }

  function isCurrentPageCategoryishProductNode(node) {
    var pageUrl = normUrl(canon());
    var nodeUrl = normUrl(node && node.url);
    var nodeId = normUrl(node && node["@id"]);
    var nodeName = String((node && node.name) || "").replace(/\s+/g, " ").trim().toLowerCase();
    var title = pageTitle().replace(/\s+/g, " ").trim().toLowerCase();

    if (nodeUrl && nodeUrl === pageUrl) return true;
    if (nodeId && nodeId.indexOf(pageUrl) === 0) return true;
    if (nodeName && title && nodeName === title) return true;

    return false;
  }

  function scoreProduct(node) {
    var s = 0;
    if (hasValidOffer(node && node.offers)) s += 100;
    else if (node && node.offers) s += 20;
    if (node && node.sku) s += 10;
    if (node && node.mainEntityOfPage) s += 8;
    if (node && node.url && normUrl(node.url) === normUrl(canon())) s += 20;
    if (node && node["@id"] && normUrl(node["@id"]).indexOf(normUrl(canon())) === 0) s += 10;
    if (node && node.weight) s += 3;
    if (node && node.image) s += 2;
    return s;
  }

  function cleanAndPatchProductNode(node) {
    var pageUrl = canon();
    if (!node || typeof node !== "object") return;

    node["@type"] = "Product";
    node["@id"] = pageUrl + PRODUCT_ID_SUFFIX;
    node.url = pageUrl;
    node.mainEntityOfPage = { "@id": pageUrl + WEBPAGE_ID_SUFFIX };

    if (!node.name) node.name = pageTitle();
    if (!node.brand) {
      node.brand = { "@type": "Brand", "name": "Le Comptoir Éolien" };
    }

    var sku = getSkuFromDom();
    if (sku && !node.sku) node.sku = sku;

    var imgs = getProductImages();
    if (imgs.length) node.image = (imgs.length === 1 ? imgs[0] : imgs.slice());

    var weight = getWeightFromMeta();
    if (weight) node.weight = weight;

    delete node.aggregateRating;
    delete node.review;
    delete node.shippingDetails;

    node.offers = buildOffer(toArray(node.offers)[0] || null);
  }

  function injectFallbackProductJsonLd() {
    var pageUrl = canon();
    var price = getPriceFromDom();
    if (price === null) return;

    var existing = q("#" + PRODUCT_SCRIPT_ID);
    if (existing) existing.parentNode.removeChild(existing);

    var data = {
      "@context": "https://schema.org",
      "@type": "Product",
      "@id": pageUrl + PRODUCT_ID_SUFFIX,
      "url": pageUrl,
      "mainEntityOfPage": { "@id": pageUrl + WEBPAGE_ID_SUFFIX },
      "name": pageTitle(),
      "brand": { "@type": "Brand", "name": "Le Comptoir Éolien" },
      "description": (q('meta[name="description"]') && q('meta[name="description"]').getAttribute("content")) || "",
      "offers": buildOffer(null)
    };

    var sku = getSkuFromDom();
    if (sku) data.sku = sku;

    var imgs = getProductImages();
    if (imgs.length) data.image = (imgs.length === 1 ? imgs[0] : imgs.slice());

    var weight = getWeightFromMeta();
    if (weight) data.weight = weight;

    var s = D.createElement("script");
    s.type = "application/ld+json";
    s.id = PRODUCT_SCRIPT_ID;
    s.textContent = JSON.stringify(data, null, 2);
    (D.head || q("head")).appendChild(s);
  }

  function processScripts() {
    var scriptEls = qa('script[type="application/ld+json"]');
    if (!scriptEls.length) return;

    var parsed = [];

    scriptEls.forEach(function (scriptEl) {
      var root = safeParse(scriptEl.textContent);
      if (!root) return;
      parsed.push({
        scriptEl: scriptEl,
        root: root,
        nodes: flatten(root)
      });
    });

    if (!parsed.length) return;

    var strictProduct = productPageStrict();

    var hasArticleJsonLd = parsed.some(function (ps) {
      return ps.nodes.some(function (node) {
        return hasType(node, "Article") || hasType(node, "BlogPosting");
      });
    });

    /* 1) Pages article / blog : on supprime uniquement les Product parasites */
    if (hasArticleJsonLd && !strictProduct) {
      parsed.forEach(function (ps) {
        var productNodes = ps.nodes.filter(isProduct);
        var out = [];
        var changed = false;

        ps.nodes.forEach(function (node) {
          if (!node) return;

          if (isReview(node) || isAggregateRating(node)) {
            changed = true;
            return;
          }

          if (isProduct(node) && isCurrentPageProductNode(node, productNodes.length)) {
            changed = true;
            return;
          }

          out.push(node);
        });

        if (!changed) return;

        if (!out.length) {
          if (ps.scriptEl.parentNode) ps.scriptEl.parentNode.removeChild(ps.scriptEl);
        } else {
          ps.scriptEl.textContent = serialize(ps.root, out);
        }
      });

      return;
    }

    /* 2) Vraies fiches produit : on garde un seul Product et on force offers */
    if (strictProduct) {
      var candidates = [];

      parsed.forEach(function (ps) {
        var productNodes = ps.nodes.filter(isProduct);

        ps.nodes.forEach(function (node, idx) {
          if (!isProduct(node)) return;
          if (!isCurrentPageProductNode(node, productNodes.length)) return;

          candidates.push({
            ps: ps,
            idx: idx,
            score: scoreProduct(node)
          });
        });
      });

      if (!candidates.length) {
        injectFallbackProductJsonLd();
        return;
      }

      candidates.sort(function (a, b) {
        return b.score - a.score;
      });

      var keep = candidates[0];

      parsed.forEach(function (ps) {
        var productNodes = ps.nodes.filter(isProduct);
        var out = [];
        var changed = false;

        ps.nodes.forEach(function (node, idx) {
          if (!node) return;

          if (isReview(node) || isAggregateRating(node)) {
            changed = true;
            return;
          }

          if (isProduct(node) && isCurrentPageProductNode(node, productNodes.length)) {
            var isKept = (keep.ps === ps && keep.idx === idx);

            if (!isKept) {
              changed = true;
              return;
            }

            cleanAndPatchProductNode(node);
            out.push(node);
            changed = true;
            return;
          }

          out.push(node);
        });

        if (!changed) return;

        if (!out.length) {
          if (ps.scriptEl.parentNode) ps.scriptEl.parentNode.removeChild(ps.scriptEl);
        } else {
          ps.scriptEl.textContent = serialize(ps.root, out);
        }
      });

      return;
    }

    /* 3) Pages catégorie / index / hub : on enlève les faux Product top-level */
    parsed.forEach(function (ps) {
      var out = [];
      var changed = false;

      ps.nodes.forEach(function (node) {
        if (!node) return;

        if (isReview(node) || isAggregateRating(node)) {
          changed = true;
          return;
        }

        if (isProduct(node) && isCurrentPageCategoryishProductNode(node)) {
          changed = true;
          return;
        }

        out.push(node);
      });

      if (!changed) return;

      if (!out.length) {
        if (ps.scriptEl.parentNode) ps.scriptEl.parentNode.removeChild(ps.scriptEl);
      } else {
        ps.scriptEl.textContent = serialize(ps.root, out);
      }
    });
  }

  function startLoop() {
    var tries = 0;
    var maxTries = 30;

    (function tick() {
      processScripts();
      tries += 1;
      if (tries >= maxTries) return;
      setTimeout(tick, 400);
    })();
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", function () {
      setTimeout(startLoop, 500);
    }, { once: true });
  } else {
    setTimeout(startLoop, 500);
  }

  window.addEventListener("load", function () {
    setTimeout(processScripts, 300);
    setTimeout(processScripts, 1200);
    setTimeout(processScripts, 2500);
  }, { once: true });

})();
</script>
<!-- ===================== /CE – FINAL PRODUCT JSON-LD PATCH v2 ===================== --><!-- ===================== CE – EDITORIAL ITEMLIST PRODUCT TO LISTITEM v1 ===================== -->
<script id="ce-editorial-itemlist-product-to-listitem-v1">
(function () {
  "use strict";

  if (window.__CE_EDITORIAL_ITEMLIST_PRODUCT_TO_LISTITEM_V1__) return;
  window.__CE_EDITORIAL_ITEMLIST_PRODUCT_TO_LISTITEM_V1__ = true;

  var D = document;

  function q(sel, root) {
    return (root || D).querySelector(sel);
  }

  function qa(sel, root) {
    return Array.prototype.slice.call((root || D).querySelectorAll(sel));
  }

  function txt(el) {
    return el ? String(el.textContent || "").replace(/\s+/g, " ").trim() : "";
  }

  function canon() {
    var c = q('link[rel="canonical"]');
    return ((c && c.href) ? c.href : window.location.href).split("#")[0];
  }

  function safeParse(raw) {
    try {
      return JSON.parse(String(raw || "").trim());
    } catch (e) {
      return null;
    }
  }

  function flatten(root) {
    if (!root) return [];
    if (Array.isArray(root)) return root;
    if (Array.isArray(root["@graph"])) return root["@graph"];
    return [root];
  }

  function serialize(root, nodes) {
    if (Array.isArray(root)) return JSON.stringify(nodes, null, 2);
    if (root && Array.isArray(root["@graph"])) {
      root["@graph"] = nodes;
      return JSON.stringify(root, null, 2);
    }
    return JSON.stringify(nodes[0], null, 2);
  }

  function toArray(v) {
    if (!v) return [];
    return Array.isArray(v) ? v : [v];
  }

  function setBack(obj, key, arr) {
    if (!arr.length) return;
    obj[key] = (arr.length === 1) ? arr[0] : arr;
  }

  function hasType(node, typeName) {
    var t = node && node["@type"];
    return t === typeName || (Array.isArray(t) && t.indexOf(typeName) > -1);
  }

  function isStrictProductPage() {
    var hasTitle = !!q("h1");
    var hasPrice = !!(
      q('[data-pp-message][data-pp-amount]') ||
      q('span.tw-price:not(.striked)') ||
      q('meta[itemprop="price"][content]') ||
      q('meta[property="product:price:amount"][content]')
    );
    var hasProductSignals = !!(
      q('div[id^="pref"]') ||
      q('meta[name="product-weight"]') ||
      q('meta[property="og:type"][content="product"]')
    );

    return !!(hasTitle && hasPrice && hasProductSignals);
  }

  function isEditorialLikePage() {
    if (isStrictProductPage()) return false;

    if (
      q('meta[property="og:type"][content*="article"]') ||
      q('meta[name="article:published_time"], meta[property="article:published_time"], meta[name="article:modified_time"], meta[property="article:modified_time"]') ||
      q('article, .single-post, .post-content, .blog-post, .entry-content, .post, .article') ||
      q('time[datetime]') ||
      q('#assistant-virtuel-info')
    ) {
      return true;
    }

    var bodyClass = (D.body && D.body.className ? D.body.className : "").toLowerCase();
    if (/\b(post|article|blog|single)\b/.test(bodyClass)) return true;

    return false;
  }

  function isHashOnlyUrl(u) {
    return /^#/.test(String(u || "").trim());
  }

  function toAbsoluteUrl(u) {
    var raw = String(u || "").trim();
    if (!raw) return "";

    if (isHashOnlyUrl(raw)) {
      return canon() + raw;
    }

    try {
      var url = new URL(raw, window.location.href);

      if (
        url.origin === window.location.origin &&
        url.pathname === window.location.pathname &&
        url.hash
      ) {
        return canon() + url.hash;
      }

      return url.href;
    } catch (e) {
      return "";
    }
  }

  function looksLikeEditorialProductList(itemListNode) {
    var arr = toArray(itemListNode && itemListNode.itemListElement);
    if (!arr.length) return false;

    var productCount = 0;
    var hashCount = 0;

    arr.forEach(function (li) {
      if (!li || typeof li !== "object") return;
      if (!hasType(li, "ListItem")) return;

      var item = li.item;
      if (item && typeof item === "object" && hasType(item, "Product")) {
        productCount += 1;

        var candidateUrl = item.url || item["@id"] || li.url || "";
        if (isHashOnlyUrl(candidateUrl)) hashCount += 1;
      }
    });

    if (!productCount) return false;
    if (isEditorialLikePage()) return true;

    return hashCount > 0;
  }

  function transformListItem(li, index) {
    if (!li || typeof li !== "object") return li;

    var item = li.item;
    if (!(item && typeof item === "object" && hasType(item, "Product"))) {
      if (!li.position && typeof index === "number") li.position = index + 1;
      if (!li["@type"]) li["@type"] = "ListItem";
      if (li.url && isHashOnlyUrl(li.url)) li.url = canon() + li.url;
      return li;
    }

    if (!li["@type"]) li["@type"] = "ListItem";
    if (!li.position && typeof index === "number") li.position = index + 1;

    var bestName =
      String(li.name || item.name || "").replace(/\s+/g, " ").trim();

    var bestUrl =
      li.url ||
      item.url ||
      item["@id"] ||
      item.itemid ||
      "";

    var abs = toAbsoluteUrl(bestUrl);

    if (bestName) li.name = bestName;
    if (abs) li.url = abs;

    delete li.item;

    return li;
  }

  function patchJsonLd() {
    if (isStrictProductPage()) return;

    var scripts = qa('script[type="application/ld+json"]');
    if (!scripts.length) return;

    scripts.forEach(function (scriptEl) {
      var root = safeParse(scriptEl.textContent);
      if (!root) return;

      var nodes = flatten(root);
      if (!nodes.length) return;

      var changed = false;

      nodes.forEach(function (node) {
        if (!node || typeof node !== "object") return;
        if (!hasType(node, "ItemList")) return;
        if (!looksLikeEditorialProductList(node)) return;

        var arr = toArray(node.itemListElement);
        if (!arr.length) return;

        arr = arr.map(function (li, idx) {
          var before = JSON.stringify(li);
          var afterNode = transformListItem(li, idx);
          var after = JSON.stringify(afterNode);
          if (before !== after) changed = true;
          return afterNode;
        });

        setBack(node, "itemListElement", arr);

        if (!node.itemListOrder) {
          node.itemListOrder = "https://schema.org/ItemListOrderAscending";
          changed = true;
        }

        if (node.numberOfItems !== arr.length) {
          node.numberOfItems = arr.length;
          changed = true;
        }

        if (!node.url) {
          node.url = canon();
          changed = true;
        }

        if (!node["@id"]) {
          node["@id"] = canon() + "#itemlist";
          changed = true;
        }

        if (!node.name) {
          node.name = txt(q("h1")) || document.title || "Liste";
          changed = true;
        }
      });

      if (changed) {
        scriptEl.textContent = serialize(root, nodes);
      }
    });
  }

  function startLoop() {
    var tries = 0;
    var maxTries = 30;

    (function tick() {
      patchJsonLd();
      tries += 1;
      if (tries >= maxTries) return;
      setTimeout(tick, 500);
    })();
  }

  if (D.readyState === "loading") {
    D.addEventListener("DOMContentLoaded", function () {
      setTimeout(startLoop, 300);
    }, { once: true });
  } else {
    setTimeout(startLoop, 300);
  }

  window.addEventListener("load", function () {
    setTimeout(patchJsonLd, 300);
    setTimeout(patchJsonLd, 1200);
    setTimeout(patchJsonLd, 2500);
  }, { once: true });

})();
</script>
<!-- ===================== /CE – EDITORIAL ITEMLIST PRODUCT TO LISTITEM v1 ===================== --><!-- CE – PRODUCT VIDEO JSON-LD PATCH v10 (AUTO YOUTUBE MATCHING STRICT + SHORTS/WATCH) -->
<script id="ce-product-jsonld-video-patch-v10">
(function(){
  "use strict";

  if(window.__CE_PRODUCT_JSONLD_VIDEO_PATCH_V10__) return;
  window.__CE_PRODUCT_JSONLD_VIDEO_PATCH_V10__ = true;

  var CE_VIDEOS = [

    /* ===================== SHORTS 2026 / 2024 / 2023 ===================== */
    {kind:"short", title:"Génératrice 48V 2000W à Faible Tours/Min – Idéale pour Éolienne", id:"xKYrwSpVIBw", date:"2026-04-26T00:00:00+00:00", kw:["generatrice","génératrice","48v","2000w","aimant permanent","faible tours","alternateur","hydrolienne"]},
    {kind:"short", title:"Optimisez votre éolienne avec ce régulateur MPPT 12V !", id:"VsILmffGjkI", date:"2026-04-25T00:00:00+00:00", kw:["regulateur mppt","régulateur mppt","mppt","12v","ip67","charge batterie","eolienne triphasee","éolienne triphasée"]},
    {kind:"short", title:"Régulateur Éolien 12V / 24V Automatique – Triphasé 400W", id:"8yYw5xF3-H0", date:"2026-04-23T00:00:00+00:00", kw:["regulateur","régulateur","12v","24v","400w","triphasé","pwm","ip67"]},
    {kind:"short", title:"Éolien + Solaire : Passez en Hybride MPPT 24V / 48V !", id:"j69uleu1UwY", date:"2026-04-21T00:00:00+00:00", kw:["controleur hybride","contrôleur hybride","hybride mppt","eolien solaire","éolien solaire","24v","48v","dump load","freinage eolien"]},
    {kind:"short", title:"Passez à la LED 12V / 24V / 230V – Éclairage basse consommation, économique et durable", id:"oD-EhiG9XOM", date:"2026-04-19T00:00:00+00:00", kw:["led","eclairage","éclairage","12v","24v","230v","ruban led","ampoule"]},
    {kind:"short", title:"Kit Autonomie 48V Solaire + Éolien | Stockage Lithium & Onduleur Hybride", id:"ucwfHG0Od74", date:"2026-04-18T00:00:00+00:00", kw:["kit autonomie","48v","solaire eolien","solaire éolien","stockage lithium","lifepo4","onduleur hybride"]},
    {kind:"short", title:"Réduisez votre facture avec une éolienne verticale 230V !", id:"Z-3o5Lufv3M", date:"2026-04-16T00:00:00+00:00", kw:["eolienne verticale 230v","éolienne verticale 230v","spirale","230v","linky","autoconsommation"]},
    {kind:"short", title:"Réduisez votre facture avec une éolienne verticale !", id:"5BtWhXFLIAM", date:"2026-04-14T00:00:00+00:00", kw:["eolienne verticale","éolienne verticale","24v","batterie lifepo4","linky","injection reseau"]},
    {kind:"short", title:"Produisez Votre Électricité Jour & Nuit : Kit Hybride Solaire + Éolien", id:"wGdOv2AW8s4", date:"2026-04-12T00:00:00+00:00", kw:["kit hybride","solaire eolien","éolien solaire","jour nuit","autonomie energetique","site isolé"]},
    {kind:"short", title:"Stop aux surtensions : protégez votre installation éolienne & solaire !", id:"v7lGLDMrr4s", date:"2026-04-11T00:00:00+00:00", kw:["surtension","parafoudre","coffret parafoudre","sectionneur","protection electrique"]},
    {kind:"short", title:"Batterie LiFePO4 12V 100Ah : Boostez Votre Autonomie !", id:"2A0Q6v_cmsw", date:"2026-04-09T00:00:00+00:00", kw:["batterie lifepo4","12v 100ah","100ah","lithium","bluetooth","bms"]},
    {kind:"short", title:"Éolienne 1000W pour maison ⚡ Kit complet autoconsommation avec mât", id:"t2BXtdr6QkM", date:"2026-04-07T00:00:00+00:00", kw:["eolienne 1000w","éolienne 1000w","1000w","mat","mât","triphasé","400v","380v"]},
    {kind:"short", title:"Éolien + Solaire : Le Kit pour Produire Votre Électricité", id:"54_YP0aF4Uw", date:"2026-04-05T00:00:00+00:00", kw:["kit hybride","12v 230v","convertisseur pur sinus","site isolé","chalet","camping"]},
    {kind:"short", title:"Réduisez votre facture avec ce kit éolien 350W ⚡", id:"UOSJMgsXT2I", date:"2026-04-04T00:00:00+00:00", kw:["kit eolien 350w","kit éolien 350w","350w","sans batterie","linky","plug and play"]},
    {kind:"short", title:"Passez en autonomie avec un kit éolien + solaire !", id:"mMgV2XVQYaE", date:"2026-04-02T00:00:00+00:00", kw:["kit eolien solaire","kit éolien solaire","site isolé","hors reseau","autonomie","bateau"]},
    {kind:"short", title:"Optimisez votre ventilation avec ces adaptateurs !", id:"L-p1_78oTSE", date:"2026-03-31T00:00:00+00:00", kw:["ventilation","ventilateur","adaptateur","5v","12v","24v"]},
    {kind:"short", title:"Mini Batterie Lithium 12V 🔋 Parfaite pour Camping, Bateau & Vanlife", id:"SXWPzLuFqmI", date:"2026-03-29T00:00:00+00:00", kw:["mini batterie","lithium 12v","20ah","camping","bateau","vanlife"]},
    {kind:"short", title:"Éolienne Verticale 12V 500W : Idéale pour Faible Vent & Site Isolé", id:"T9RJpf-3miE", date:"2026-03-28T00:00:00+00:00", kw:["eolienne verticale 12v 500w","éolienne verticale 12v 500w","windside","faible vent","500w","site isolé"]},
    {kind:"short", title:"Kit Éolien Sydney 600W : Passez à l’autoconsommation dès aujourd’hui !", id:"u183iN6Pq6A", date:"2026-03-26T00:00:00+00:00", kw:["sydney","kit eolien 600w","kit éolien 600w","600w","48v","230v"]},
    {kind:"short", title:"Mini-générateur 3V à 24V ⚡ Idéal pour maquettes & projets scolaires", id:"kT4taS4nDKA", date:"2026-03-24T00:00:00+00:00", kw:["mini generateur","mini générateur","3v","12v","24v","maquette","projet scolaire"]},
    {kind:"short", title:"Éolienne 12V 500W – Démarre dès 2 m/s | Idéale Sites Isolés", id:"cPLt7NJOosw", date:"2026-03-22T00:00:00+00:00", kw:["vector 500w","eolienne 12v 500w","éolienne 12v 500w","demarre 2 m/s","site isolé"]},
    {kind:"short", title:"Solaire : Les 3 bases pour bien commencer en 30 secondes", id:"4OrlmB9cEaQ", date:"2026-03-21T00:00:00+00:00", kw:["solaire","panneau solaire","photovoltaique","photovoltaïque","regulateur solaire","orientation"]},
    {kind:"short", title:"Coupure de courant ? Passez en hybride !", id:"AK0J8vNYsgs", date:"2026-03-15T00:00:00+00:00", kw:["coupure courant","secours","ups","hybride","batterie","onduleur hybride"]},
    {kind:"short", title:"Batterie LiFePO4 12V 100Ah Connectée – Bluetooth & WiFi | Autonomie Intelligente", id:"QWmqWwri0xk", date:"2026-03-14T00:00:00+00:00", kw:["batterie connectee","batterie connectée","bluetooth wifi","lifepo4 12v 100ah","soc"]},
    {kind:"short", title:"Kit Hybride 48V : Autonomie Solaire + Éolienne en 1 Solution !", id:"WEoMFQpazDc", date:"2026-03-12T00:00:00+00:00", kw:["kit hybride 48v","autonomie solaire eolienne","sydney","2580wc","onduleur pur sinus"]},
    {kind:"short", title:"Votre éolienne est-elle rentable ? Test en 30 secondes", id:"XTBoDFe-zRk", date:"2026-03-10T00:00:00+00:00", kw:["simulateur eolien","simulateur éolien","rentable","rentabilite","roi","production kwh"]},
    {kind:"short", title:"Pack Autonomie 10,24 kWh : Énergie garantie même en coupure !", id:"v-9vzCg9lVA", date:"2026-03-07T00:00:00+00:00", kw:["pack autonomie","10,24 kwh","1024 kwh","ups","basculement automatique","48v"]},

    {kind:"short", title:"Égaliseur de Batterie 24V : Le Secret pour Doubler la Vie de votre Parc !", id:"a439PYsy45k", date:"2026-01-30T00:00:00+00:00", kw:["egaliseur batterie","égaliseur batterie","repartiteur de charge","répartiteur de charge","24v","48v"]},
    {kind:"short", title:"Alternateur 400W sur Socle : La Base Idéale pour votre Éolienne Maison !", id:"esoLT1kjD3Q", date:"2026-01-29T00:00:00+00:00", kw:["alternateur 400w","alternateur sur socle","12v 400w","aimant permanent"]},
    {kind:"short", title:"Wattmètre 200A : Le Mouchard de votre Installation !", id:"vaLKRBO602s", date:"2026-01-28T00:00:00+00:00", kw:["wattmetre","wattmètre","analyseur","200a","ampere","tension","puissance"]},
    {kind:"short", title:"Kit Hybride 48V Ultime : Solaire + Éolien + 10kWh de Stockage !", id:"tHjT6zyjMjI", date:"2026-01-27T00:00:00+00:00", kw:["kit hybride 48v ultime","2580wc","2000w","10kwh","10,24 kwh","air-side"]},
    {kind:"short", title:"Panneau Solaire Flexible 130W : L'Énergie Invisible pour Bateau & Van !", id:"W21XT4GdDb8", date:"2026-01-27T00:00:00+00:00", kw:["panneau solaire flexible","130w","bateau","van","camping car"]},
    {kind:"short", title:"Convertisseur 12V/230V 1100W : Le Courant Parfait pour Frigo & Café !", id:"C1eQS3ajYdM", date:"2026-01-27T00:00:00+00:00", kw:["convertisseur","onduleur pur sinus","12v 230v","1100w","2200w","frigo"]},
    {kind:"short", title:"Connecteur Rapide 50A : Branchez/Débranchez vos Batteries en 1 seconde !", id:"VvfrmeYQzMQ", date:"2026-01-26T00:00:00+00:00", kw:["connecteur rapide","connecteur bipolaire","50a","8 awg","batterie amovible"]},
    {kind:"short", title:"Génératrice 12V 800W : Le Cœur de vos Projets DIY", id:"A8fcJImccWs", date:"2026-01-26T00:00:00+00:00", kw:["generatrice 12v 800w","génératrice 12v 800w","pmg","800w","12v","diy"]},
    {kind:"short", title:"Éolienne trop bruyante ? Découvrez l'amortisseur anti-vibrations !", id:"XIM1uIkMhNM", date:"2026-01-26T00:00:00+00:00", kw:["amortisseur","anti vibration","anti-vibration","silent bloc","bruit eolienne"]},
    {kind:"short", title:"Régulateur Solaire 30A PWM : Simple, Efficace et Connecté !", id:"C9HtZ3FXSGM", date:"2026-01-25T00:00:00+00:00", kw:["regulateur solaire 30a","régulateur solaire 30a","pwm 30a","lcd","usb"]},
    {kind:"short", title:"Voltmètre LCD 8–100V : Surveillez vos batteries avec précision !", id:"rYZZQgvXqhs", date:"2026-01-25T00:00:00+00:00", kw:["voltmetre","voltmètre","8-100v","lcd","indicateur batterie"]},
    {kind:"short", title:"Interrupteur 3 Phases : Le Frein de Sécurité pour votre Éolienne !", id:"U6zoe1ZchzE", date:"2026-01-25T00:00:00+00:00", kw:["interrupteur 3 phases","commutateur arret","commutateur arrêt","frein eolienne","freinage dynamique"]},
    {kind:"short", title:"Chargeur Intelligent 5A : L'Allié de vos Batteries Lithium & Plomb !", id:"FjLxF1ToalI", date:"2026-01-24T00:00:00+00:00", kw:["chargeur batterie","chargeur intelligent","5a","lithium plomb","lifepo4"]},
    {kind:"short", title:"Éolien Triphasé 400V : Réduisez vos Factures Pro & Domestiques !", id:"l6iRTas4BsU", date:"2026-01-24T00:00:00+00:00", kw:["eolien triphase","éolien triphasé","400v","380v","triphasé","facture pro"]},
    {kind:"short", title:"Éolienne Verticale 100W : Le Silence Absolu pour votre Énergie !", id:"CFR_hCIkCEY", date:"2026-01-23T00:00:00+00:00", kw:["eolienne verticale 100w","éolienne verticale 100w","100w","silencieuse","30 db"]},
    {kind:"short", title:"Batterie Lithium 100Ah : Bluetooth, WiFi & Alarme Intégrée !", id:"_dBiug2SOp0", date:"2026-01-23T00:00:00+00:00", kw:["batterie lithium 100ah","bluetooth wifi","alarme","led","lifepo4"]},
    {kind:"short", title:"Kit Solaire Balcon 1720W + Stockage : Effacez votre Facture !", id:"FqgNzres91o", date:"2026-01-23T00:00:00+00:00", kw:["kit solaire balcon","1720w","stockage","plug and play","5120wh"]},
    {kind:"short", title:"Batterie Lithium 280Ah Bluetooth : L'Autonomie XXL Connectée !", id:"KHUzofuACYM", date:"2026-01-22T00:00:00+00:00", kw:["batterie lithium 280ah","280ah","3584wh","bluetooth","autonomie xxl"]},
    {kind:"short", title:"Kit Éolienne Air-Prospeed 500W + Mât : L'Autonomie Tout Compris !", id:"mdEs7Q1-g9c", date:"2026-01-22T00:00:00+00:00", kw:["air-prospeed","air prospeed","500w","mat 4m","mât 4m","site isolé"]},
    {kind:"short", title:"Batterie Lithium Solaire : Plus de Puissance, Plus Longtemps !", id:"zClO5m7XRpw", date:"2026-01-22T00:00:00+00:00", kw:["batteries lithium","batterie solaire","stockage lithium","lithium solaire"]},
    {kind:"short", title:"Mini Éolienne Domestique : L'Énergie au Jardin !", id:"kN5vGCdQWrs", date:"2026-01-21T00:00:00+00:00", kw:["mini eolienne","mini éolienne","eolienne domestique","jardin","pignon"]},
    {kind:"short", title:"Coupe-Batterie & Interrupteur Éolien : La Sécurité Avant Tout !", id:"hl1J4-VAptI", date:"2026-01-21T00:00:00+00:00", kw:["coupe batterie","coupleur","interrupteur eolien","sécurité électrique","securite electrique"]},
    {kind:"short", title:"Kit Éolien Vector 350W : Réduisez votre Facture sans Batterie !", id:"3s2iGjH8JM0", date:"2026-01-21T00:00:00+00:00", kw:["kit eolien vector 350w","kit éolien vector 350w","vector 350w","sans batterie","plug and play"]},

    {kind:"short", title:"Éolienne Triphasée 380V/400V : La Puissance pour votre Réseau !", id:"ueVvSmrSNi0", date:"2026-01-20T00:00:00+00:00", kw:["eolienne triphasee","éolienne triphasée","380v","400v","reseau triphase","réseau triphasé","kits eoliens 380v","kits éoliens 400v"]},
    {kind:"short", title:"Comment faire durer vos batteries ? Le Chargeur Intelligent 5A", id:"TTCjfLr0IMo", date:"2026-01-20T00:00:00+00:00", kw:["chargeur intelligent 5a","chargeur batterie","hivernage batterie","entretien batterie","lithium plomb","lifepo4","sulfatation"]},
    {kind:"short", title:"Kit Hybride Complet 520W : L'Autonomie Totale dans un Carton !", id:"1vgre6XV2qk", date:"2026-01-20T00:00:00+00:00", kw:["kit hybride 520w","kit hybride complet","520w","eolienne 400w","panneau solaire 120w","batterie 50ah","site isolé","autonomie"]},
    {kind:"short", title:"Barre Omnibus 150A : Le Secret d'un Câblage Pro et Propre !", id:"LlfSVhE_nHs", date:"2026-01-19T00:00:00+00:00", kw:["barre omnibus","bus bar","150a","cablage batterie","câblage batterie","12v 48v","connexion batterie"]},
    {kind:"short", title:"Éolienne Horizontale 12V/24V/48V : L'Indépendance Énergétique !", id:"K9hUjTJc_4g", date:"2026-01-19T00:00:00+00:00", kw:["eolienne horizontale","éolienne horizontale","12v","24v","48v","independance energetique","site isolé","bateau","camping-car"]},
    {kind:"short", title:"Génératrice Éolienne 12V/24V/48V : Comment bien choisir ?", id:"nfB0aNK0B6A", date:"2026-01-18T00:00:00+00:00", kw:["generatrice eolienne","génératrice éolienne","alternateur","12v","24v","48v","aimant permanent","ac dc"]},
    {kind:"short", title:"Mâts pour Éoliennes : Stabilité & Performance en Hauteur", id:"ilWQHVB36lY", date:"2026-01-17T00:00:00+00:00", kw:["mat eolienne","mât éolienne","mats pour eoliennes","mâts pour éoliennes","support eolienne","hauteur","stabilité","fixation mat"]},
    {kind:"short", title:"Pont de Diode Redresseur : Convertir le courant Éolien AC vers DC", id:"eVD6SGo6oYg", date:"2026-01-16T00:00:00+00:00", kw:["pont de diode","redresseur","ac dc","courant alternatif","courant continu","triphasé","3 fils","batterie"]},
    {kind:"short", title:"Éolienne Sydney 800W : La Puissance Verticale en Milieu Urbain !", id:"oerzGReW5Tc", date:"2026-01-16T00:00:00+00:00", kw:["sydney 800w","eolienne sydney","éolienne sydney","48v 800w","verticale","milieu urbain","spirale"]},
    {kind:"short", title:"Pales & Moyeux Éoliennes Horizontales : Un Stock Mondial !", id:"x5vt6_yyS1M", date:"2026-01-16T00:00:00+00:00", kw:["pales eolienne horizontale","pales éolienne horizontale","moyeux","nez","pieces detachees","pièces détachées","sav eolienne"]},
    {kind:"short", title:"Éolienne Domestique 230V : Réduisez votre Facture Jour & Nuit !", id:"h7ysb2QZCIY", date:"2026-01-15T00:00:00+00:00", kw:["eolienne domestique 230v","éolienne domestique 230v","kits reseau eolien","kits réseau éolien","autoconsommation","linky","maison"]},
    {kind:"short", title:"Fontaine Solaire : Créez un Coin Zen sans Câble Électrique !", id:"LXmgVluDB1c", date:"2026-01-15T00:00:00+00:00", kw:["fontaine solaire","fontaines solaires","jardin","bassin","terrasse","solaire decoratif","décoratif"]},
    {kind:"short", title:"Éolienne Pro Air-Side 2000W : La Puissance Haute Résistance !", id:"2y5ItuGwGfU", date:"2026-01-14T00:00:00+00:00", kw:["air-side","air side","eolienne pro","éolienne pro","2000w","48v","230v","protection tempete","tempête"]},
    {kind:"short", title:"Régulateur Solaire MPPT : Boostez votre Production de 30% !", id:"SnNhjNTWCjs", date:"2026-01-14T00:00:00+00:00", kw:["regulateur solaire mppt","régulateur solaire mppt","mppt solaire","controleur solaire","contrôleur solaire","photovoltaïque","production solaire"]},
    {kind:"short", title:"Kit Ventilation Solaire : Aérez vos Espaces sans Fil !", id:"DUlT_3DBDj4", date:"2026-01-14T00:00:00+00:00", kw:["kit ventilation solaire","ventilation solaire","extracteur solaire","aeration","aération","serre","abri de jardin","camping-car"]},
    {kind:"short", title:"Pales & Moyeux pour Éoliennes Verticales : Créez votre Turbine !", id:"amPbRIFiaiI", date:"2026-01-13T00:00:00+00:00", kw:["pales eolienne verticale","pales éolienne verticale","moyeux verticale","sydney","windside","low-speed","autoconstruction"]},
    {kind:"short", title:"Fixations & Montage : Sécurisez votre Installation Éolienne & Solaire !", id:"1O6c0sSeSCo", date:"2026-01-13T00:00:00+00:00", kw:["montage fixation","montage et fixations","fixation eolienne","fixation solaire","haubans","tendeurs","support panneau"]},
    {kind:"short", title:"Programmateurs Électroniques : Automatisez votre Énergie !", id:"bLZBbvy1wlU", date:"2026-01-13T00:00:00+00:00", kw:["programmateur electronique","programmateur électronique","minuterie","automatisation","pilotage energie","éclairage","pompage","ventilation"]},
    {kind:"short", title:"Kits Solaires Autoconsommation : Réduisez votre Facture !", id:"RX3ri5FqrHk", date:"2026-01-12T00:00:00+00:00", kw:["kit solaire autoconsommation","kits solaires autoconsommation","plug and play solaire","600w","1200w","stockage solaire","facture solaire"]},
    {kind:"short", title:"Onduleur d'Injection Éolien : Synchronisez votre Énergie !", id:"vvmg2xM6FEc", date:"2026-01-11T00:00:00+00:00", kw:["onduleur injection eolien","onduleur injection éolien","onduleur reseau eolien","injection reseau","230v","400v","synchronisation reseau"]},
    {kind:"short", title:"Kit Éolien Autoconsommation : Monophasé ou Triphasé ?", id:"SaLOkNv8KPQ", date:"2026-01-11T00:00:00+00:00", kw:["kit eolien autoconsommation","kit éolien autoconsommation","monophasé","triphase","triphasé","enedis","230v","400v"]},
    {kind:"short", title:"Kit Solaire Site Isolé : Votre Électricité en Toute Autonomie !", id:"qd5NvpUKF_s", date:"2026-01-11T00:00:00+00:00", kw:["kit solaire site isolé","kits solaires sites isolés","site isolé","offgrid","autonomie solaire","hors reseau","hors réseau"]},
    {kind:"short", title:"Régulateurs Éoliens & Hybrides : Protégez vos Batteries !", id:"IZKtTReTXtA", date:"2026-01-10T00:00:00+00:00", kw:["regulateur eolien","régulateur éolien","controleur de charge","contrôleur de charge","regulateur hybride","protection batterie","charge batterie"]},
    {kind:"short", title:"Roue Pelton Haute Performance : L'Énergie Hydroélectrique", id:"nZHqqcbnp0I", date:"2026-01-10T00:00:00+00:00", kw:["roue pelton","turbine pelton","hydroelectricite","hydroélectricité","helice pelton","hélice pelton","centrale hydroelectrique"]},
    {kind:"short", title:"Kits Hybrides Éolien + Solaire : L'Autonomie Totale !", id:"1NurlJzdiQM", date:"2026-01-10T00:00:00+00:00", kw:["kits hybrides site isolé","kit hybride site isolé","eolien solaire","éolien solaire","offgrid","autonomie totale","chalet"]},
    {kind:"short", title:"Résistances de Décharge Dump Load : Protégez votre Éolienne !", id:"dtstxNlDDcY", date:"2026-01-09T00:00:00+00:00", kw:["resistance de decharge","résistance de décharge","dump load","protection eolienne","surcharge batterie","freinage","debordement"]},
    {kind:"short", title:"Pales & Pièces de Rechange : Gardez votre Éolienne Performante !", id:"DnLR6HpLsSQ", date:"2026-01-09T00:00:00+00:00", kw:["pieces detachees eoliennes","pièces détachées éoliennes","pales","moyeux","roulements","visserie","sav"]},
    {kind:"short", title:"Anémomètres & Outils de Mesure : Optimisez votre installation !", id:"tQTZbtjxUGU", date:"2026-01-09T00:00:00+00:00", kw:["anemometre","anémomètre","outils de mesure","mesure vent","vitesse du vent","potentiel eolien","wattmetre"]},
    {kind:"short", title:"Éoliennes Verticales Domestiques : Choisir entre 12V, 24V ou 48V", id:"NouJeC8dAMs", date:"2026-01-09T00:00:00+00:00", kw:["eoliennes verticales","éoliennes verticales","verticale domestique","12v","24v","48v","axe vertical"]},
    {kind:"short", title:"Éolienne AeroSpiral : Silence & Performance", id:"B0jVcM8fSdM", date:"2026-01-09T00:00:00+00:00", kw:["aerospiral","aero spiral","éolienne aerospiral","eolienne aerospiral","ultra silencieuse","24v","48v","verticale"]},
    {kind:"short", title:"Kit Éolien Autoconsommation 220V Sans Mât", id:"vTxAHQtWYnE", date:"2026-01-08T00:00:00+00:00", kw:["kit eolien autoconsommation sans mat","kit éolien autoconsommation sans mât","sans mat","sans mât","220v","230v"]},
    {kind:"short", title:"Kit Éolien Autoconsommation avec Mât 220V", id:"WsD-cxNZeOo", date:"2026-01-08T00:00:00+00:00", kw:["kit eolien autoconsommation avec mat","kit éolien autoconsommation avec mât","avec mat","avec mât","220v","230v"]},
    {kind:"short", title:"Découvrez les Éoliennes Tulip Breeze et Flower en rotation !", id:"m2VMgdNYP5U", date:"2024-09-24T00:00:00+00:00", kw:["tulip breeze","tulip flower","flower turbines","eolienne tulip","éolienne tulip","breeze","flower","48v"]},
    {kind:"short", title:"Découvrez notre toute nouvelle Hydro Turbine Turbo Pelton en action !", id:"bwNaneb4Ncs", date:"2024-03-11T00:00:00+00:00", kw:["hydro turbine","turbo pelton","turbine pelton","energie hydraulique","énergie hydraulique","hydroelectrique"]},
    {kind:"short", title:"Éolienne Verticale Spirale Sydney - Production d'Énergie Innovante", id:"KzS18T9LsPA", date:"2024-02-27T00:00:00+00:00", kw:["sydney","eolienne sydney","éolienne sydney","verticale spirale","48v","650w","milieu urbain"]},
    {kind:"short", title:"Découvrez nos génératrices éoliennes haut de gamme sur socle et sans socle", id:"hR98JOmnlvM", date:"2023-06-27T00:00:00+00:00", kw:["generatrice eolienne","génératrice éolienne","generatrices","génératrices","sur socle","sans socle","ndfeb"]},
    {kind:"short", title:"Découvrez le fonctionnement du kit éolien i-1000w sur le toit d'un immeuble de bureau !", id:"YgexYXMOQkc", date:"2023-06-23T00:00:00+00:00", kw:["i-1000w","kit eolien 1000w","kit éolien 1000w","1000w","immeuble","mât 4m","48v 230v"]},
    {kind:"short", title:"Transformez votre Bureau en une Source d'Énergie Éolienne avec notre Kit 800W !", id:"Yo2PvLPnbCs", date:"2023-06-23T00:00:00+00:00", kw:["kit eolien 800w","kit éolien 800w","800w","storage","vertical","48v","immeuble"]},
    {kind:"short", title:"Contrôleur-Régulateur Éolien 1000W/1500W", id:"i92USflIkCc", date:"2023-06-15T00:00:00+00:00", kw:["controleur regulateur eolien","contrôleur régulateur éolien","1000w","1500w","triphasé","charge batterie"]},
    {kind:"short", title:"Eolienne VERTICALE + régulateur externe", id:"Thx08eDMDIc", date:"2023-06-14T00:00:00+00:00", kw:["eolienne verticale","éolienne verticale","regulateur externe","régulateur externe","urbain","axe vertical"]},
    {kind:"short", title:"Kit 3 pales et moyeu Silence Air - Vents faibles", id:"AapZCDcIkFM", date:"2023-06-13T00:00:00+00:00", kw:["kit 3 pales","moyeu silence air","pales silence air","vents faibles","air breeze","air x","diametre 89cm"]},
    {kind:"short", title:"Découvrez l'éolienne LOW-SPEED verticale du type Darrieus", id:"ig8b_ohXMG0", date:"2023-06-13T00:00:00+00:00", kw:["low-speed","low speed","darrieus","eolienne verticale","éolienne verticale","pales en h","aluminium"]},
    {kind:"short", title:"Kit 6 pales et moyeu Silence Air - Vents faibles", id:"3pP-2Y8xut0", date:"2023-06-11T00:00:00+00:00", kw:["kit 6 pales","moyeu silence air","pales silence air","vents faibles","diametre 89cm","air breeze","air x"]},
    {kind:"short", title:"Découvrez l'éolienne Sydney Verticale : Captez l'énergie du vent dans toutes les directions !", id:"KOxifqh3gLI", date:"2023-06-09T00:00:00+00:00", kw:["sydney verticale","éolienne sydney","eolienne sydney","lames incurvées","spirale","milieu urbain"]},

    /* ===================== VIDEOS CLASSIQUES YOUTUBE ===================== */
    {kind:"watch", title:"Éolienne 2000W 5 pales en 48V — rotation sur mât", id:"Ds_Vxiuxb74", date:"2025-08-24T00:00:00+00:00", kw:["eolienne 2000w","éolienne 2000w","2000w","48v","5 pales","rotation sur mat","pylontech"]},
    {kind:"watch", title:"Éoliennes horizontales 500W – Découvrez leur puissance en action !", id:"DENLmmYptaM", date:"2025-07-03T00:00:00+00:00", kw:["eolienne horizontale 500w","éolienne horizontale 500w","500w","12v","horizontale","air prospeed"]},
    {kind:"watch", title:"Passez à l’autoconsommation 100 % renouvelable !", id:"1RFzFf38mOY", date:"2025-07-01T00:00:00+00:00", kw:["kit eolienne mat 2000w","kit éolienne mât 2000w","i2000 breeze","2000w","48v 230v","autoconsommation"]},
    {kind:"watch", title:"Injection 380V : démo 3 éoliennes Air-Side en action", id:"F7YO1Qj7bBY", date:"2025-06-12T00:00:00+00:00", kw:["air-side triphasé","air side triphasé","3 eoliennes","3 éoliennes","380v","400v","injection triphasé"]},
    {kind:"watch", title:"Éoliennes en Plein Désert de Neige : Une Installation Hors du Commun !", id:"jbEOjIJRvmo", date:"2024-09-25T00:00:00+00:00", kw:["desert de neige","désert de neige","pro-hisper","air-side","site isolé","eoliennes horizontales 48v"]},
    {kind:"watch", title:"Découvrez la Windside : Éolienne à Axe Vertical", id:"GcwAeNl6F7Y", date:"2024-07-26T00:00:00+00:00", kw:["windside","éolienne windside","eolienne windside","axe vertical","12v","24v","faible vent"]},
    {kind:"watch", title:"Éolienne Air-Prospeed 500w en Action : Énergie Verte en Montagne", id:"9ymgReaUJB8", date:"2024-06-06T00:00:00+00:00", kw:["air-prospeed 500w","air prospeed 500w","500w","montagne","site isolé","kits eoliens sites isolés"]},
    {kind:"watch", title:"Réduisez Votre Facture Électrique avec une Éolienne en Autoconsommation !", id:"_km0xkBF85k", date:"2024-05-14T00:00:00+00:00", kw:["eolienne autoconsommation","éolienne autoconsommation","réduire facture","monophasé","triphasé","enedis"]},
    {kind:"watch", title:"Maximisez vos économies d'énergie avec notre Onduleur 1000W pour Éoliennes 24V !", id:"0Q3VrY3J5xw", date:"2024-02-08T00:00:00+00:00", kw:["onduleur 1000w","onduleur eolienne 24v","onduleur éolienne 24v","injection reseau","resistance debordement"]},
    {kind:"watch", title:"Découvrez notre Éolienne à Axe Vertical : Puissance et Design de l'Énergie Éolienne Urbaine !", id:"pyedxgMgIW0", date:"2024-01-10T00:00:00+00:00", kw:["eolienne axe vertical 700w","éolienne axe vertical 700w","700w","urbaine","verticale","design"]},
    {kind:"watch", title:"Découvrez l'Éolienne Air-Side : Votre Solution Énergétique Fiable", id:"3DMfZZk_q8U", date:"2023-11-05T00:00:00+00:00", kw:["air-side","air side","eolienne professionnelle","éolienne professionnelle","tempête","vents violents"]},
    {kind:"watch", title:"Montage de l'Éolienne Air-Side 2000W", id:"0IQMNWmrUIE", date:"2023-11-01T00:00:00+00:00", kw:["montage air-side","montage air side","air-side 2000w","2000w","48v 230v","kit eolienne mat pro"]},
    {kind:"watch", title:"Découvrez notre Générateur Vertical Révolutionnaire !", id:"3rV9n_EepZQ", date:"2023-08-26T00:00:00+00:00", kw:["generateur vertical","générateur vertical","sydney","low-speed","basse vitesse","ampoules led"]},
    {kind:"watch", title:"Éoliennes en autoconsommation pour réduire votre facture énergétique !", id:"82rko_dol-Q", date:"2023-07-18T00:00:00+00:00", kw:["eoliennes autoconsommation","éoliennes autoconsommation","kit 1000w","kit 800w","immeuble","reduction facture"]},
    {kind:"watch", title:"Guide d'utilisation de l'onduleur réseau spécial éolienne", id:"nQXrz0NeZRQ", date:"2023-07-03T00:00:00+00:00", kw:["onduleur reseau special eolienne","onduleur réseau spécial éolienne","onduleur 350w","injection reseau","generatrice 12v"]},
    {kind:"watch", title:"Découvrez le Kit Éolien Vertical Storage avec l'éolienne Sydney en action !", id:"2vKxOXdnHhg", date:"2023-06-29T00:00:00+00:00", kw:["kit eolien vertical storage","kit éolien vertical storage","sydney","storage","batteries","panneaux solaires"]},
    {kind:"watch", title:"Découvrez notre échantillon de génératrices éoliennes à petite puissance", id:"ZunKMqngn70", date:"2023-06-27T00:00:00+00:00", kw:["generatrices petite puissance","génératrices petite puissance","alternateur","petite puissance","12v","24v"]},
    {kind:"watch", title:"Découvrez notre sélection de génératrices éoliennes de qualité supérieure !", id:"dTTameB66kM", date:"2023-06-27T00:00:00+00:00", kw:["selection generatrices","sélection génératrices","generatrice eolienne","génératrice éolienne","sur socle","sans socle"]},
    {kind:"watch", title:"Éolienne 12V 400W AIR-WPS + Régulation", id:"0qNGchpRgek", date:"2023-06-23T00:00:00+00:00", kw:["air-wps","air wps","12v 400w","400w","regulation","régulation","site isolé"]},
    {kind:"watch", title:"Installation d'un système éolien couplé à des panneaux solaires avec l'Air-X 400", id:"jzZKQqw68xo", date:"2023-06-20T00:00:00+00:00", kw:["air-x 400","air x 400","air 400","panneaux solaires","systeme hybride","système hybride"]},
    {kind:"watch", title:"Montage de l'éolienne 12V 15W VERTICALE avec régulateur externe", id:"kY5z6Fmjzb4", date:"2023-06-19T00:00:00+00:00", kw:["eolienne 12v 15w","éolienne 12v 15w","verticale 15w","regulateur externe","régulateur externe"]},
    {kind:"watch", title:"Alternateur sur Socle 12V 400W à Aimant Permanent", id:"CqwmaIonDH0", date:"2023-06-07T00:00:00+00:00", kw:["alternateur sur socle","12v 400w","aimant permanent","85 tr/min","electricite gratuite"]}
  ];

  function cleanText(t){
    return String(t || "")
      .toLowerCase()
      .normalize("NFD")
      .replace(/[\u0300-\u036f]/g,"")
      .replace(/[’']/g," ")
      .replace(/[^a-z0-9\s\-\/,.]/g," ")
      .replace(/\s+/g," ")
      .trim();
  }

  function canon(){
    var c = document.querySelector('link[rel="canonical"]');
    return ((c && c.href) ? c.href : location.href).split("#")[0];
  }

  function isLikelyProductPage(){
    return !!(
      document.querySelector("h1") &&
      (
        document.querySelector('span.tw-price:not(.striked)') ||
        document.querySelector('[data-pp-message][data-pp-amount]') ||
        document.querySelector('meta[itemprop="price"][content]') ||
        document.querySelector('meta[property="product:price:amount"][content]') ||
        document.querySelector('div[id^="pref"]')
      )
    );
  }

  function pageFields(){
    return {
      h1: cleanText(document.querySelector("h1")?.textContent || ""),
      title: cleanText(document.title || ""),
      desc: cleanText(document.querySelector('meta[name="description"]')?.content || ""),
      keywords: cleanText(document.querySelector('meta[name="keywords"]')?.content || ""),
      url: cleanText(canon())
    };
  }

  function youtubeUrl(v){
    if(!v || !v.id) return "";
    if(v.url) return v.url;
    if(v.kind === "watch" || v.kind === "video") return "https://www.youtube.com/watch?v=" + v.id;
    return "https://www.youtube.com/shorts/" + v.id;
  }

  function youtubeThumb(v){
    return "https://i.ytimg.com/vi/" + v.id + "/hqdefault.jpg";
  }

  function youtubeEmbed(v){
    return "https://www.youtube.com/embed/" + v.id;
  }

  function bestVideo(){
    var f = pageFields();
    var best = null;
    var bestScore = 0;

    CE_VIDEOS.forEach(function(v){
      var score = 0;

      (v.kw || []).forEach(function(k){
        var ck = cleanText(k);
        if(!ck) return;

        if(f.h1.includes(ck)) score += 30;
        if(f.title.includes(ck)) score += 20;
        if(f.url.includes(ck.replace(/\s+/g,"-"))) score += 18;
        if(f.desc.includes(ck)) score += 10;
        if(f.keywords.includes(ck)) score += 8;
      });

      cleanText(v.title).split(" ").forEach(function(w){
        if(w.length > 4 && f.h1.includes(w)) score += 3;
      });

      if(score > bestScore){
        bestScore = score;
        best = v;
      }
    });

    return bestScore >= 20 ? best : null;
  }

  function parseJson(raw){
    try { return JSON.parse(String(raw || "").trim()); }
    catch(e){ return null; }
  }

  function flatten(root){
    return Array.isArray(root)
      ? root
      : (root && Array.isArray(root["@graph"]) ? root["@graph"] : [root]);
  }

  function hasType(n,t){
    var x = n && n["@type"];
    return x === t || (Array.isArray(x) && x.indexOf(t) > -1);
  }

  function serialize(root,nodes){
    if(Array.isArray(root)) return JSON.stringify(nodes,null,2);
    if(root && Array.isArray(root["@graph"])){
      root["@graph"] = nodes;
      return JSON.stringify(root,null,2);
    }
    return JSON.stringify(nodes[0],null,2);
  }

  function isCurrentProduct(n,total){
    var page = canon().replace(/\/+$/,"");
    var url = String(n.url || "").split("#")[0].replace(/\/+$/,"");
    var id = String(n["@id"] || "");
    var main = String((n.mainEntityOfPage && n.mainEntityOfPage["@id"]) || "");

    return (
      url === page ||
      id.indexOf(page) === 0 ||
      main.indexOf(page) === 0 ||
      total === 1
    );
  }

  function patch(){
    if(!isLikelyProductPage()) return;

    var video = bestVideo();
    if(!video) return;

    document.querySelectorAll('script[type="application/ld+json"]').forEach(function(s){
      var root = parseJson(s.textContent);
      if(!root) return;

      var nodes = flatten(root);
      var products = nodes.filter(function(n){ return hasType(n,"Product"); });
      if(!products.length) return;

      var changed = false;

      nodes.forEach(function(n){
        if(!hasType(n,"Product")) return;
        if(!isCurrentProduct(n, products.length)) return;

        n.video = {
          "@type": "VideoObject",
          "name": video.title,
          "description": video.title,
          "thumbnailUrl": [youtubeThumb(video)],
          "uploadDate": video.date,
          "contentUrl": youtubeUrl(video),
          "embedUrl": youtubeEmbed(video)
        };

        changed = true;
      });

      if(changed) {
        s.textContent = serialize(root,nodes);
      }
    });
  }

  function loop(){
    var tries = 0;

    (function tick(){
      patch();
      if(++tries >= 25) return;
      setTimeout(tick, 500);
    })();
  }

  if(document.readyState === "loading"){
    document.addEventListener("DOMContentLoaded", loop, {once:true});
  } else {
    loop();
  }

})();
</script>
<!-- /CE – PRODUCT VIDEO JSON-LD PATCH v10 --></span><span style="font-size:13px;"><!-- 
  Script maintenance : Normalisation des icônes de stock
  Objet :
  - Remplacer toutes les icônes stock.ltd.svg / stock.out1-4.svg
    par l’icône unique stock.ok.svg
-->

<script>
document.addEventListener("DOMContentLoaded", function () {
  /*
    Script maintenance : Normalisation des icônes de stock
    Objet :
    - Remplacer toutes les icônes stock.ltd.svg / stock.out1-4.svg
      par l’icône unique stock.ok.svg
  */

  // 🔵 Icône correcte (toujours la même)
  const URL_OK = "_twsc/stock.ok.svg";

  // 🧩 Table de correspondance : ancien fichier → nouvelle URL
  const ICON_MAP = {
    "stock.ltd.svg":  URL_OK,
    "stock.out1.svg": URL_OK,
    "stock.out2.svg": URL_OK,
    "stock.out3.svg": URL_OK,
    "stock.out4.svg": URL_OK
  };

  // Remplacement des icônes dans un conteneur donné
  function remplacerIcones(root = document) {
    const imgs = root.querySelectorAll("img[src]");
    imgs.forEach(function (img) {
      const src = img.getAttribute("src");
      if (!src) return;

      Object.keys(ICON_MAP).forEach(function (oldName) {
        // On teste la fin de l'URL : fonctionne pour src="_twsc/stock.out2.svg"
        // comme pour src="https://www.comptoireolien.fr/_twsc/stock.out2.svg"
        if (src.endsWith(oldName)) {
          img.src = ICON_MAP[oldName];
        }
      });
    });
  }

  // Observer les ajouts dynamiques (chargements JS, etc.)
  const observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      mutation.addedNodes.forEach(function (node) {
        if (node.nodeType !== 1) return; // pas un élément
        if (node.tagName === "IMG") {
          remplacerIcones(node.parentNode || document);
        } else {
          remplacerIcones(node);
        }
      });
    });
  });

  // ⏱️ Petit délai pour laisser TOWeb finir le rendu
  setTimeout(function () {
    // 1) Premier passage sur toute la page
    remplacerIcones();

    // 2) On surveille les changements du DOM
    observer.observe(document.documentElement, {
      childList: true,
      subtree: true
    });
  }, 300); // tu peux monter à 500 ms si besoin
});
</script></span><span style="color:#4D4D4D;"><span style="font-size:13px;"><!-- 🍪 Tarteaucitron.js -->
<!-- 1️⃣  Consent Mode Google (v2)  – à placer ABSOLUMENT en tout premier -->
<!-- gtag.js est chargé dès l’arrivée sur la page pour envoyer le ping cookieless “default” -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-X0KSJDCR9Y" crossorigin="anonymous"></script>

<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){ dataLayer.push(arguments); }

  /* Default : tout est refusé jusqu’à choix de l’internaute */
  gtag('consent', 'default', {
    ad_storage:        'denied',
    analytics_storage: 'denied',
    ad_user_data:      'denied',
    ad_personalization:'denied'
  }, {
    /* Laisse 500 ms à la CMP pour surclasser le statut avant d’envoyer un ping */
    wait_for_update: 500
  });
</script>

<!-- 2️⃣  tarteaucitron.js  (≥ 1.13.0) -->
<link rel="preload" href="https://www.comptoireolien.fr/tarteaucitron/tarteaucitron.min.js" as="script">
<script src="https://www.comptoireolien.fr/tarteaucitron/tarteaucitron.min.js"></script>

<script>
  window.tarteaucitronCustomText = {
    alertBigPrivacy:
      "🍪 Ce site utilise des cookies. Vous gardez le contrôle."
  };
</script>

<script src="https://www.comptoireolien.fr/tarteaucitron/tarteaucitron.services.min.js"></script>

<style>
#tarteaucitronPersonalize2 {
  all: unset !important;
  display: inline-block !important;
  background-color: #009900 !important; /* VERT */
  color: #fff !important;
  border: none !important;
  border-radius: 4px !important;
  padding: 12px 28px !important;
  font-weight: bold !important;
  font-size: 14px !important;
  cursor: pointer !important;
  text-align: center !important;
  line-height: 1.2 !important;
  box-shadow: none !important;
  transition: background-color 0.3s ease !important;
  margin-right: 10px !important; 
}

#tarteaucitronAllDenied2 {
  all: unset !important;
  display: inline-block !important;
  background-color: #CC0000 !important; /* ROUGE */
  color: #fff !important;
  border: none !important;
  border-radius: 4px !important;
  padding: 12px 28px !important;
  font-weight: bold !important;
  font-size: 14px !important;
  cursor: pointer !important;
  text-align: center !important;
  line-height: 1.2 !important;
  box-shadow: none !important;
  transition: background-color 0.3s ease !important;
  margin-right: 10px !important; 
}

#tarteaucitronCloseAlert {
  all: unset !important;
  display: inline-block !important;
  background-color: #2fb5d2 !important; /* BLEU */
  color: #fff !important;
  border: none !important;
  border-radius: 4px !important;
  padding: 12px 28px !important;
  font-weight: bold !important;
  font-size: 14px !important;
  cursor: pointer !important;
  text-align: center !important;
  line-height: 1.2 !important;
  box-shadow: none !important;
  transition: background-color 0.3s ease !important;
  margin-right: 10px !important; 
}

/* ─── Override icône décorative de la bannière tarteaucitron ─── */
#tarteaucitronAlertBig.tarteaucitronAlertBigTop::before,
#tarteaucitronAlertBig.tarteaucitronAlertBigMiddle::before,
#tarteaucitronAlertBig.tarteaucitronAlertBigBottom::before {
  /* on neutralise toutes les orientations possibles */
  display: none !important;     /* retire complètement le pseudo‑élément   */
  content: '' !important;       /* élimine le contenu éventuel             */
  background: none !important;  /* supprime l’image de fond (emoji sprite) */
}
</style>

<script>
/* Initialisation CMP après chargement complet du DOM */
window.addEventListener('load', () => {
  tarteaucitron.init({
    privacyUrl:            'https://www.comptoireolien.fr/protection-des-donnees-personnelles.html',
    bodyPosition: 'top',         // ✅ CORRECTION PRINCIPALE : évite le scroll vers le footer
    orientation:           'middle',
    highPrivacy:           true,
    DenyAllCta:            true,
    AcceptAllCta:          true,
    showIcon:              false,
    groupServices:         true,
    showDetailsOnClick:    true,
    serviceDefaultState:   'wait',
    googleConsentMode:     true,    // active les 4 services GCM v2
    cookieName:            'tarteaucitron',
    cookieExpire:          365
  });

  /* ——— Services Google ——— */
  tarteaucitron.user.gtagUa          = 'G-X0KSJDCR9Y';
  (tarteaucitron.job = tarteaucitron.job || []).push('gtag');

  tarteaucitron.user.googleadsId     = 'AW-1003642734';
  (tarteaucitron.job = tarteaucitron.job || []).push('googleads');

  /* Signaux Consent Mode v2 (managed automatiquement par tarteaucitron) */
  (tarteaucitron.job = tarteaucitron.job || []).push('gcmanalyticsstorage');
  (tarteaucitron.job = tarteaucitron.job || []).push('gcmadstorage');
  (tarteaucitron.job = tarteaucitron.job || []).push('gcmaduserdata');
  (tarteaucitron.job = tarteaucitron.job || []).push('gcmadpersonalization');

  /* ——— Services additionnels ——— */
  tarteaucitron.user.facebookpixelId = '992820939367938';
  (tarteaucitron.job = tarteaucitron.job || []).push('facebookpixel');

  tarteaucitron.user.googletagmanagerId = 'GTM-NGGVG7P9';
  (tarteaucitron.job = tarteaucitron.job || []).push('googletagmanager');

  /* ——— Google AdSense (annonces automatiques) ——— */
  tarteaucitron.user.adsensecapub = 'ca-pub-1399300145672369';  // <-- ton vrai ca-pub
  (tarteaucitron.job = tarteaucitron.job || []).push('adsenseauto');

  /* ——— Youtube (videos) ——— */
  tarteaucitron.user.youtubeNoCookie = true;
  (tarteaucitron.job = tarteaucitron.job || []).push('youtube');
});
</script>
<!-- / CMP tarteaucitron -->
<!-- 🍪 Tarteaucitron.js -->

<!-- ===================== CE YouTube CMP Gate (tarteaucitron) ===================== -->
<script>
/* CE YouTube CMP Gate (tarteaucitron)
   Objectif : bloquer les iframes YouTube (src=about:blank) tant que le service YouTube n’est pas accepté,
   puis réinjecter le src en youtube-nocookie après consentement.
*/
(function () {

  var lastConsent = null;

  function findYouTubeIframes() {
    return Array.from(document.querySelectorAll(
      'iframe[src*="youtube.com/embed/"], iframe[src*="youtube-nocookie.com/embed/"], iframe[data-yt-src]'
    ));
  }

  function toNoCookie(url) {
    if (!url) return url;
    return url
      .replace('https://www.youtube.com/embed/', 'https://www.youtube-nocookie.com/embed/')
      .replace('http://www.youtube.com/embed/',  'https://www.youtube-nocookie.com/embed/');
  }

  function blockIframes() {
    findYouTubeIframes().forEach(function (ifr) {
      if (ifr.dataset.ytBlocked === '1') return;

      var src = ifr.getAttribute('src') || '';
      if (src && src !== 'about:blank') {
        ifr.dataset.ytSrc = toNoCookie(src);
      }

      if (ifr.dataset.ytSrc) {
        ifr.dataset.ytBlocked = '1';
        ifr.setAttribute('src', 'about:blank');
        ifr.setAttribute('loading', 'lazy');
        ifr.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');
      }
    });
  }

  function unblockIframes() {
    findYouTubeIframes().forEach(function (ifr) {
      var desired = toNoCookie(ifr.dataset.ytSrc || ifr.getAttribute('data-yt-src') || '');
      if (!desired) return;

      var current = ifr.getAttribute('src') || '';

      // ✅ si déjà débloqué + bon src => NE RIEN FAIRE (sinon reload -> boucle)
      if (ifr.dataset.ytBlocked === '0' && current === desired) return;

      if (current !== desired) {
        ifr.setAttribute('src', desired);
      }
      ifr.dataset.ytBlocked = '0';
    });
  }

  function hasYouTubeConsent() {
    try {
      if (!window.tarteaucitron) return false;

      if (tarteaucitron.state && (tarteaucitron.state.youtube === true || tarteaucitron.state.youtube === "true")) {
        return true;
      }

      if (tarteaucitron.services && tarteaucitron.services.youtube) {
        var s = tarteaucitron.services.youtube;
        if (s.status === true || s.status === "allow" || s.status === "accepted") return true;
      }

      var c = document.cookie.match(/(?:^|;\s*)tarteaucitron=([^;]+)/);
      if (c && decodeURIComponent(c[1]).indexOf('youtube=true') !== -1) return true;

    } catch (e) {}
    return false;
  }

  function apply(force) {
    var consent = hasYouTubeConsent();

    // ✅ si rien n’a changé, on ne touche à rien
    if (!force && consent === lastConsent) return;
    lastConsent = consent;

    if (consent) unblockIframes();
    else blockIframes();
  }

  document.addEventListener('DOMContentLoaded', function(){ apply(true); });
  window.addEventListener('load', function(){ setTimeout(function(){ apply(true); }, 800); });

  window.addEventListener('tac.open_alert',  function(){ setTimeout(function(){ apply(true); }, 50); });
  window.addEventListener('tac.close_alert', function(){ setTimeout(function(){ apply(true); }, 50); });
  window.addEventListener('tac.accepted',    function(){ setTimeout(function(){ apply(true); }, 50); });
  window.addEventListener('tac.denied',      function(){ setTimeout(function(){ apply(true); }, 50); });

  // Fallback léger, mais sans casser la lecture
  setInterval(function(){ apply(false); }, 3000);

})();
</script>
<!-- ===================== /CE YouTube CMP Gate ===================== -->

<!-- 🛡️ Masquage de la console en production -->
<script>
(function() {
    const isLocal = window.location.protocol === "file:";

    if (!isLocal) {
        if (typeof console === "undefined") {
            window.console = {};
        }
        const noop = function() {};
        console.log = noop;
        console.warn = noop;
        console.error = noop;
        console.info = noop;
        console.debug = noop;
    } else {
        console.info("Console active (mode local).");
    }
})();
</script>
<!-- 🛡️ Masquage de la console en production -->

<!-- === Barre bénéfices sticky === -->
<style>
  #ce-benefits{ position: sticky; top: 0; z-index: 1; }
  #ce-benefits .bleed{
    position:relative; left:50%; width:100vw; transform:translateX(-50%);
    background:#fff; border-bottom:1px solid rgba(0,0,0,.08); box-shadow:0 1px 0 rgba(0,0,0,.03);
  }
  #ce-benefits .inner{
    max-width:1440px; margin:0 auto; padding:8px 16px;
    display:flex; gap:14px; align-items:center; justify-content:center; flex-wrap:wrap;
    font:500 14px/1.25 system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;
  }
  #ce-benefits .item{display:inline-flex;align-items:center;gap:8px;white-space:nowrap}
  #ce-benefits .sep{opacity:.35}
  #ce-benefits b{color:#00B67A}

  /* Icônes */
  #ce-benefits .icon{width:16px;height:16px;flex:0 0 16px}
  #ce-benefits .icon--trust{color:#00B67A}
  #ce-benefits .icon--truck{color:#00559E}
  #ce-benefits .icon--shield{color:#E53935}
  #ce-benefits .icon--lock{color:#2E7D32}
  #ce-benefits .icon--flag{color:#0D47A1}

  #ce-benefits .tpr-link{ color: inherit; text-decoration:none; display:inline-flex; align-items:center; gap:8px; }
  #ce-benefits .tpr-link:hover{ text-decoration:underline; }

  @media (max-width:768px){
    #ce-benefits{display:none!important} /* Masquer entièrement sur mobile */
  }
</style>

<!-- Sprite SVG -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
  <symbol id="ico-star" viewBox="0 0 24 24">
    <path fill="currentColor" d="M12 2l3.09 6.26L22 9.27l-5 4.88L18.18 22 12 18.6 5.82 22 7 14.15 2 9.27l6.91-1.01L12 2z"/>
  </symbol>
  <symbol id="ico-truck" viewBox="0 0 24 24">
    <path fill="currentColor" d="M3 5h12v8h2.5l2.5 3V13h2v5h-2.5l-2 2H17a2 2 0 1 1-4 0H9a2 2 0 1 1-4 0H3V5zm4 12a2 2 0 0 1 2 2H5a2 2 0 0 1 2-2zm8 0a2 2 0 0 1 2 2h-4a2 2 0 0 1 2-2zM5 7v4h8V7H5z"/>
  </symbol>
  <symbol id="ico-shield" viewBox="0 0 24 24">
    <path fill="currentColor" d="M12 2l7 3v6c0 5-3.5 9.74-7 11-3.5-1.26-7-6-7-11V5l7-3z"/>
  </symbol>
  <symbol id="ico-lock" viewBox="0 0 24 24">
    <path fill="currentColor" d="M12 2a5 5 0 0 1 5 5v3h1a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h1V7a5 5 0 0 1 5-5zm3 8V7a3 3 0 0 0-6 0v3h6z"/>
  </symbol>
  <symbol id="ico-flag-fr" viewBox="0 0 24 24">
    <rect width="24" height="16" y="4" fill="#fff" rx="2"/>
    <rect width="8" height="16" y="4" fill="#0055A4" rx="2"/>
    <rect x="16" width="8" height="16" y="4" fill="#EF4135" rx="2"/>
  </symbol>
</svg>

<script>
(function(){
  if (document.getElementById('ce-benefits')) return;
  var html = `
  <div id="ce-benefits" role="region" aria-label="Avantages Comptoir Éolien">
    <div class="bleed">
      <div class="inner">
        <a class="item tpr-link" href="https://fr.trustpilot.com/review/www.comptoireolien.fr" target="_blank" rel="noopener noreferrer" title="Lire nos avis sur Trustpilot">
          <svg class="icon icon--trust" aria-hidden="true"><use xlink:href="#ico-star"></use></svg>
          Avis vérifiés <b>4.5★</b> sur Trustpilot
        </a>
        <span class="sep">|</span>
        <span class="item">
          <svg class="icon icon--truck" aria-hidden="true"><use xlink:href="#ico-truck"></use></svg>
          Livraison offerte dès 49,90&nbsp;€
        </span>
        <span class="sep">|</span>
        <span class="item">
          <svg class="icon icon--shield" aria-hidden="true"><use xlink:href="#ico-shield"></use></svg>
          Garantie 2&nbsp;ans
        </span>
        <span class="sep">|</span>
        <span class="item">
          <svg class="icon icon--lock" aria-hidden="true"><use xlink:href="#ico-lock"></use></svg>
          Paiement sécurisé
        </span>
        <span class="sep">|</span>
        <span class="item">
          <svg class="icon icon--flag" aria-hidden="true"><use xlink:href="#ico-flag-fr"></use></svg>
          16 ans d’expertise
        </span>
      </div>
    </div>
  </div>`;

  var header = document.querySelector('header');
  if (header && header.parentNode) header.insertAdjacentHTML('afterend', html);
  else document.body.insertAdjacentHTML('afterbegin', html);
})();
</script>
<!-- === /Barre bénéfices sticky === -->

<!-- Couleurs texte et fond des boutons d’action -->
<style>
a.btn.btn-primary,
a.tw-formfield.btn.btn-primary {
    color: #0C1A3B !important;
    background-color: #58D5BF !important;
}

a.btn.btn-primary:hover,
a.tw-formfield.btn.btn-primary:hover {
    background-color: #7BEACD !important;  /* couleur au survol */
}
</style>
<!-- /Couleurs texte et fond des boutons d’action -->

<!-- Couleurs texte et fond des boutons groupes de rubriques btn btn-info -->
<style>
a.btn.btn-info,
a.tw-formfield.btn.btn-info {
    color: #fff !important;
    background-color: var(--ce-blue, #00559E) !important;
}

a.btn.btn-info:hover,
a.tw-formfield.btn.btn-info:hover {
    background-color: #2F8DEE !important;  /* couleur au survol */
    color: #fff !important;
}
</style>
<!-- Couleurs texte et fond des boutons groupes de rubriques btn btn-info -->

<!-- Correction de l'erreur du moteur de recherche sur Firefox -->
<script>
document.addEventListener("DOMContentLoaded", function() {
  var searchbox = document.getElementById("searchbox");
  var modalSearch = document.getElementById("modal-search");
  
  if (searchbox && modalSearch) {
    // Utilisation de la phase de capture pour intercepter avant l'exécution du href inline
    searchbox.addEventListener("click", function(e) {
      e.preventDefault();              // Empêche l'action par défaut
      e.stopImmediatePropagation();    // Arrête la propagation immédiate (empêche l'exécution du javascript: dans le href)
      modalSearch.style.visibility = "visible";
    }, true); // "true" active la phase de capture
  }

  // Gestion du clic sur le bouton de fermeture
  var closeBtn = document.getElementById("close-btn");
  if (closeBtn && modalSearch) {
    closeBtn.addEventListener("click", function(e) {
      e.preventDefault();
      modalSearch.style.visibility = "hidden";
    });
  }

  // Gestion de la soumission de la recherche via l'icône
  var dosearchButtons = document.querySelectorAll(".dosearch");
  dosearchButtons.forEach(function(btn) {
    btn.addEventListener("click", function(e) {
      e.preventDefault();
      var form = this.closest("form");
      if (form) {
        form.submit();
      }
    });
  });
});
</script>
<!-- Correction de l'erreur du moteur de recherche sur Firefox -->

<!-- Optimisation moteur de recherche -->
<script>
document.addEventListener("DOMContentLoaded", function() {
    let url = new URL(window.location.href);
    let searchParams = url.searchParams;
    let query = searchParams.get("req");

    if (query) {
        let cleanedQuery = query.trim(); // Supprime les espaces en début et fin
        if (cleanedQuery !== query) {
            searchParams.set("req", cleanedQuery); 
            window.location.replace(url.pathname + "?" + searchParams.toString()); // Recharge la page avec la requête nettoyée
        }

        // Convertir le mot en singulier s'il finit par 's'
        let normalizedQuery = query.toLowerCase();
        if (normalizedQuery.endsWith("s") && normalizedQuery.length > 3) {
            let singularQuery = normalizedQuery.slice(0, -1);
            searchParams.set("req", singularQuery);
            window.location.replace(url.pathname + "?" + searchParams.toString()); // Recharge avec le mot au singulier
        }
    }
});

function normalizeKeyword(keyword) {
    const accentsMap = {
        'é': 'e', 'è': 'e', 'ê': 'e', 'ë': 'e',
        'à': 'a', 'â': 'a', 'ä': 'a',
        'ô': 'o', 'ö': 'o',
        'î': 'i', 'ï': 'i',
        'ù': 'u', 'û': 'u', 'ü': 'u',
        'ç': 'c'
    };

    const removeAccents = (str) => str.split('').map(char => accentsMap[char] || char).join('');

    return removeAccents(keyword.toLowerCase());
}

function searchProducts() {
    let url = new URL(window.location.href);
    let searchParams = url.searchParams;
    let query = searchParams.get("req");
    
    if (!query) return;
    
    let keyword = normalizeKeyword(query);
    
    let productElements = document.querySelectorAll(".product-name"); // Sélectionner les noms des produits sur la page
    
    productElements.forEach(element => {
        let productText = normalizeKeyword(element.textContent);
        
        if (!productText.includes(keyword)) {
            element.closest(".product-item").style.display = "none"; // Cacher les produits non correspondants
        }
    });
}

document.addEventListener("DOMContentLoaded", searchProducts);
</script>
<!-- Optimisation moteur de recherche -->

<!-- SEO-SearchResults – Troncature des titres produits dans les résultats de recherche sur desktop -->
<style>
  @media (min-width: 768px) {
    /* On cible tout b dans un h4 dans un a pointant sur .html */
    a[href$=".html"] h4 b {
      display: inline-block !important;    /* pour text-overflow */
      max-width: 30ch !important;          /* ≃ 30 caractères */
      white-space: nowrap !important;      /* pas de retour à la ligne */
      overflow: hidden !important;         /* coupe le surplus */
      text-overflow: ellipsis !important;  /* ajoute les "…" */
    }
  }
</style>

<script>
(function() {
  function truncate() {
    if (window.innerWidth < 768) return;
    document.querySelectorAll('a[href$=".html"] h4 b').forEach(function(el) {
      var txt = el.textContent.trim();
      if (txt.length > 30) {
        el.textContent = txt.slice(0, 30) + '…';
      }
    });
  }
  // Exécute au chargement et si la fenêtre est redimensionnée
  window.addEventListener('load', truncate);
  window.addEventListener('resize', truncate);
})();
</script>
<!-- SEO-SearchResults – Troncature des titres produits dans les résultats de recherche sur desktop -->

<!-- Script Correction Leaflet Checkout - Début -->
<script>
  (function() {
    if (window.location.pathname.includes('_checkout.html')) {
      // Supprime les liens Leaflet défaillants
      document.querySelectorAll('link[href*="unpkg.com/leaflet"]').forEach(el => el.remove());
      document.querySelectorAll('script[src*="unpkg.com/leaflet"]').forEach(el => el.remove());

      // Ajoute les fichiers locaux (modifie les chemins si besoin)
      const leafletCSS = document.createElement('link');
      leafletCSS.rel = 'stylesheet';
      leafletCSS.href = '/_fields/leaflet.css';  // <-- adapte ce chemin
      document.head.appendChild(leafletCSS);

      const leafletJS = document.createElement('script');
      leafletJS.src = '/_fields/leaflet.js';  // <-- adapte ce chemin
      leafletJS.defer = true;
      document.body.appendChild(leafletJS);
    }
  })();
</script>
<!-- Script Correction Leaflet Checkout - Fin -->

<!-- Supprimer le pied de page dans la partie panier checkout -->
<script> 
document.addEventListener("DOMContentLoaded", function() {
  // Vérifie si le chemin de la page contient "_checkout.html"
  if (window.location.pathname.indexOf('_checkout.html') !== -1) {
    // Supprime l'élément avec l'ID "footerfat"
    var footerfat = document.getElementById('footerfat');
    if (footerfat) {
      footerfat.remove();
    }
  }
});
</script>
<!-- Supprimer le pied de page dans la partie panier checkout -->

<!-- Effet zoom au survol des images -->
<style>
/* Cible les divs avec des images de background commençant par _media/img/small, _media/img/medium ou _media/img/sq_icon */
/* Dans les conteneurs .pobj.obj-before */
.pobj.obj-before div[style*="_media/img/small"],
.pobj.obj-before div[style*="_media/img/medium"],
.pobj.obj-before div[style*="_media/img/sq_icon"] {
    transition: transform 0.3s ease, filter 0.3s ease; /* Effet fluide */
}

/* Effets au survol */
.pobj.obj-before div[style*="_media/img/small"]:hover,
.pobj.obj-before div[style*="_media/img/medium"]:hover,
.pobj.obj-before div[style*="_media/img/sq_icon"]:hover {
    transform: scale(1.05); /* Zoom léger */
    filter: brightness(1.1); /* Augmente la luminosité */
}   

/* Effet zoom au survol des images */
/* Cible l'effet sur l'image et la bordure de l'élément thumbnail lors du survol */
.thumbnail:hover {
    box-shadow: 0 0 20px rgba(100, 100, 100, 0.5);
    transition: box-shadow 0.3s ease; /* Ajoute une transition douce */
}

/* Transition initiale pour la bordure et l'ombre */
.thumbnail {
    position: relative; /* Assurez-vous que la position est relative pour utiliser z-index */
    transition: border 0.3s ease, box-shadow 0.3s ease;
}

/* Effet de zoom sur l'image */
.thumbnail:hover .img-wrapper img {
    transform: scale(1.05); /* Agrandit l'image lors du survol */
    transition: transform 0.3s ease; /* Ajoute une transition douce */
}

.thumbnail .img-wrapper img {
    transition: transform 0.3s ease; /* Transition pour le retour à la normale */
}

/* Désactive les événements de la souris sur les éléments ribbon-wrapper */
.thumbnail .ribbon-wrapper {
    pointer-events: none;
}

/* Assurez-vous que le prix est visible même lors du zoom */
.thumbnail .tw-price {
    position: relative;
    z-index: 10; /* Place le prix au-dessus de l'image zoomée */
}

/* Désactive le zoom sur les appareils mobiles */
@media (max-width: 768px) {
    .thumbnail:hover {
        box-shadow: none; /* Pas d'ombre supplémentaire */
    }
    .thumbnail:hover .img-wrapper img {
        transform: none; /* Aucun zoom */
    }
    .pobj.obj-before div[style*="_media/img/small"]:hover,
    .pobj.obj-before div[style*="_media/img/medium"]:hover,
    .pobj.obj-before div[style*="_media/img/sq_icon"]:hover {
        transform: none; /* Aucun zoom */
        filter: none; /* Pas de modification de luminosité */
    }
}
</style>
<!-- Effet zoom au survol des images -->

<!-- Script correction mega-menu (alignement à gauche) -->
<script>
document.addEventListener('DOMContentLoaded', function () {
  // On récupère tous les mega-menus (ceux qui ont .dc-row dedans)
  var megaMenus = Array.from(document.querySelectorAll('.dropdown-content'))
    .filter(function (el) {
      return el.querySelector('.dc-row') !== null;
    });

  if (!megaMenus.length) return;

  function alignMegaMenusLeft() {
    megaMenus.forEach(function (menu) {
      // On remet à zéro avant de recalculer
      menu.style.transform = 'none';

      var computed = window.getComputedStyle(menu);
      var oldDisplay = menu.style.display;
      var oldVisibility = menu.style.visibility;
      var forcedOpen = false;

      // Si le menu est caché (hover), on l’affiche "en invisible" pour mesurer
      if (computed.display === 'none') {
        menu.style.visibility = 'hidden';
        menu.style.display = 'block';
        forcedOpen = true;
      }

      // Position actuelle par rapport au bord gauche de l’écran
      var rect = menu.getBoundingClientRect();
      var offset = rect.left - 0; // px depuis le bord gauche du viewport

      // On décale pour que le bord gauche soit à 0 (bord gauche de l'écran)
      menu.style.transform = 'translateX(' + (-offset) + 'px)';

      // On remet l’état comme avant
      if (forcedOpen) {
        menu.style.display = oldDisplay;
        menu.style.visibility = oldVisibility;
      }
    });
  }

  alignMegaMenusLeft();
  window.addEventListener('resize', alignMegaMenusLeft);
});
</script>
<!-- Script correction mega-menu (alignement à gauche) -->

<!-- Newsletter Popup Adaptatif -->
<div id="newsletterOverlay" 
    style="opacity: 0.5; cursor: pointer; visibility: visible; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: black; z-index: 9999; display: none;" 
    onclick="closeNewsletterPopup()"
    aria-hidden="true">
</div>

<div id="newsletterPopup" role="dialog" aria-labelledby="newsletterTitle" aria-hidden="true"
    style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 20px; background: white; border: 1px solid #DEDEDE; border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); z-index: 100000; text-align: center; display: none; max-width: 600px; width: 90%;">

    <!-- Bouton de fermeture -->
    <button onclick="closeNewsletterPopup()" 
            aria-label="Fermer la popup"
            style="position: absolute; top: 10px; right: 10px; background: none; border: none; font-size: 20px; cursor: pointer;">&times;</button>
    
    <h2 id="newsletterTitle" style="color: #00559E;">💌 Abonnez-vous à notre newsletter !</h2>
    <p style="font-size: 18px;">Recevez nos dernières nouveautés, offres exclusives et conseils pratiques directement dans votre boîte mail !</p>
    
    <!-- Formulaire sécurisé et optimisé -->
    <form class="form-horizontal" id="subscribe_popup_form" method="POST" action="_iserv/mailinglist/mailinglist.php" 
        onsubmit="closeNewsletterPopup(true)">
        <input type="hidden" name="mlconfaction" value="sub">
        <label for="mlemail">Renseignez votre e-mail :</label>
        <input type="email" name="mlemail" id="mlemail" required placeholder="Votre adresse email" class="input-normal" style="margin-bottom:10px;width:80%;">
        <button type="submit" class="btn btn-success nowrap-phone">✔ S'abonner</button>
    </form>

    <p id="subscribe_policy" style="font-size:90%;margin-top:6px;">
        En envoyant mes informations, j'accepte votre 
    <a href="protection-des-donnees-personnelles.html?twtheme=no" target="_blank" class="tos cboxElement" rel="noopener nofollow" style="color: #00559E;">Politique de confidentialité</a>
    </p>
</div>

<script>
/* ===== Cookies helpers ===== */
function setCookie(name, value, maxAgeSeconds) {
  const secure = (location.protocol === 'https:') ? '; Secure' : '';
  document.cookie =
    name + '=' + encodeURIComponent(value) +
    '; Max-Age=' + maxAgeSeconds +
    '; Path=/' +
    '; SameSite=Lax' +
    secure;
}

function getCookie(name) {
  const parts = ('; ' + document.cookie).split('; ' + name + '=');
  if (parts.length === 2) return decodeURIComponent(parts.pop().split(';').shift());
  return null;
}

document.addEventListener('DOMContentLoaded', function () {

  // --- Réglages ---
  const POPUP_DELAY_MS = 30000;                  // 30 sec
  const SHOW_EVERY_MS  = 24 * 60 * 60 * 1000;    // 1 jour
  const ONE_YEAR_SEC   = 365 * 24 * 60 * 60;     // 1 an

  // --- Cookies ---
  const CK_LAST_SHOWN  = 'nl_last_shown';        // timestamp ms
  const CK_SUBSCRIBED  = 'nl_subscribed';        // "1"

  const now = Date.now();

  /* ======================================================
     1) Détection page confirmation d'abonnement _message.html
     (contenu injecté après coup par TOWeb => observer)
  ====================================================== */
  const isMessagePage = /\/_message\.html$/i.test(window.location.pathname);

  if (isMessagePage) {
    const TARGET_SNIPPET = "Votre demande d'abonnement a été enregistrée.";

    const norm = (s) => (s || '')
      .replace(/\u00A0/g, ' ') // NBSP -> espace
      .replace(/\s+/g, ' ')
      .trim();

    function isNewsletterConfirmationPresent() {
      const scope = document.getElementById('top-content') || document;

      // anti faux-positif si _message.html sert à autre chose
      const h1 = norm(scope.querySelector('h1')?.textContent);
      const looksLikeNewsletter = /newsletter/i.test(h1) || /inscription/i.test(h1);

      const found = Array.from(scope.querySelectorAll('p'))
        .some(p => norm(p.textContent).includes(TARGET_SNIPPET));

      return looksLikeNewsletter && found;
    }

    function markSubscribedAndExit() {
      setCookie(CK_SUBSCRIBED, '1', ONE_YEAR_SEC);
      setCookie(CK_LAST_SHOWN, String(Date.now()), ONE_YEAR_SEC);
      closeNewsletterPopup(false);
    }

    // Tentative immédiate
    if (isNewsletterConfirmationPresent()) {
      markSubscribedAndExit();
      return;
    }

    // Attente de l’injection Ajax / decode.php
    const watchRoot = document.getElementById('top-content') || document.body;
    if (watchRoot) {
      const obs = new MutationObserver(() => {
        if (isNewsletterConfirmationPresent()) {
          obs.disconnect();
          markSubscribedAndExit();
        }
      });

      obs.observe(watchRoot, { childList: true, subtree: true, characterData: true });

      // sécurité : stop au bout de 10s
      setTimeout(() => obs.disconnect(), 10000);
    }

    // Sur _message.html on ne déclenche pas la popup
    return;
  }

  // 2) Si déjà abonné => jamais de popup (pendant 1 an)
  if (getCookie(CK_SUBSCRIBED) === '1') return;

  // 3) Fréquence : max 1 fois par jour
  const lastShown = parseInt(getCookie(CK_LAST_SHOWN) || '0', 10);
  if (lastShown && (now - lastShown) < SHOW_EVERY_MS) return;

  // --- Affichage popup ---
  function showNewsletterPopup() {
    const overlay = document.getElementById('newsletterOverlay');
    const popup = document.getElementById('newsletterPopup');
    if (!overlay || !popup) return;

    overlay.style.display = 'block';
    popup.style.display = 'block';
    popup.setAttribute('aria-hidden', 'false');

    // On marque "vu"
    setCookie(CK_LAST_SHOWN, String(Date.now()), ONE_YEAR_SEC);

    const email = document.getElementById('mlemail');
    if (email) email.focus();
  }

  setTimeout(showNewsletterPopup, POPUP_DELAY_MS);

  // Optionnel : fermer avec ESC
  document.addEventListener('keydown', function (e) {
    if (e.key === 'Escape') closeNewsletterPopup(false);
  });
});

// Fonction globale appelée par tes onclick
function closeNewsletterPopup(subscribed = false) {
  const overlay = document.getElementById('newsletterOverlay');
  const popup = document.getElementById('newsletterPopup');

  if (overlay) overlay.style.display = 'none';
  if (popup) {
    popup.style.display = 'none';
    popup.setAttribute('aria-hidden', 'true');
  }

  // On stocke la date de fermeture (1 an)
  const ONE_YEAR_SEC = 365 * 24 * 60 * 60;
  setCookie('nl_last_shown', String(Date.now()), ONE_YEAR_SEC);

  // Ne PAS marquer abonné ici (on le fait uniquement via /_message.html)
}
</script>

<!-- CSS pour l'adaptation mobile -->
<style>
@media screen and (max-width: 768px) {
    #newsletterPopup {
        padding: 15px;
        font-size: 16px;
    }
}
</style>
<!-- Newsletter Popup Adaptatif -->

<!-- Style du bandeau en haut de la page -->
<style>
    div.alert-success {
        z-index: 5 !important;
        position: relative !important;
        background-color: #00B87C;
        color: #FFFFFF;
        border-bottom: 1px solid #00B87C;
        font-weight: bold;
        text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
    }
</style>
<!-- Style du bandeau en haut de la page -->

<!-- Socle commun CSS + JS global pour les carrousels produits -->
<style>
.ceh-product-block,
.ceh-product-block * {
  box-sizing: border-box;
}

.ceh-product-block {
  width: 100%;
  margin: 0;
  padding: 0;
  font-family: inherit;
  color: #0c193a;
}

.ceh-product-block .ceh-section {
  background: #fff;
  border: 1px solid #d8e1ed;
  border-radius: 16px;
  box-shadow: 0 3px 12px rgba(12, 25, 58, 0.06);
  padding: 14px;
  overflow: hidden;
}

.ceh-product-block .ceh-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.ceh-product-block .ceh-title {
  margin: 0;
  color: #0f5ea8;
  font-size: clamp(19px, 2.2vw, 28px);
  line-height: 1.08;
  font-weight: 700;
}

.ceh-product-block .ceh-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

.ceh-product-block .ceh-nav {
  appearance: none;
  width: 56px;
  height: 56px;
  border: 1px solid #e1e7ef;
  border-radius: 999px;
  background: #f5f6f8;
  color: #9aa4b2;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 34px;
  line-height: 1;
  transition: background .2s ease, color .2s ease, transform .2s ease, opacity .2s ease;
}

.ceh-product-block .ceh-nav:hover:not(:disabled) {
  background: #eef3f8;
  color: #6e7b8f;
  transform: translateY(-1px);
}

.ceh-product-block .ceh-nav:disabled {
  opacity: .45;
  cursor: not-allowed;
}

.ceh-product-block .ceh-track {
  display: flex;
  align-items: stretch;
  gap: 14px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: smooth;
  scroll-snap-type: x mandatory;
  padding-bottom: 2px;
  scrollbar-width: none;
}

.ceh-product-block .ceh-track::-webkit-scrollbar {
  display: none;
}

.ceh-product-block .ceh-card {
  flex: 0 0 272px;
  min-width: 272px;
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid #d8e1ed;
  border-radius: 18px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  scroll-snap-align: start;
  transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}

.ceh-product-block .ceh-card:hover {
  transform: translateY(-2px);
  border-color: #c7d3e3;
  box-shadow: 0 8px 22px rgba(12, 25, 58, 0.10);
  text-decoration: none;
}

.ceh-product-block .ceh-media {
  position: relative;
  height: 220px;
  background:
    radial-gradient(circle at 15% 18%, rgba(87, 126, 255, .08), transparent 28%),
    linear-gradient(180deg, #fafcff 0%, #f3f7fc 100%);
  border-bottom: 1px solid #e1e7ef;
  overflow: hidden;
}

.ceh-product-block .ceh-media img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
  object-position: center;
  transform: scale(1.03);
}

.ceh-product-block .ceh-badge {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 7px 14px;
  border-radius: 999px;
  background: rgba(48, 65, 123, .96);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: .01em;
  box-shadow: 0 6px 14px rgba(12, 25, 58, .14);
}

.ceh-product-block .ceh-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px;
  flex: 1 1 auto;
}

.ceh-product-block .ceh-name {
  margin: 0;
  font-size: 17px;
  line-height: 1.28;
  font-weight: 700;
  color: #10255c;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 66px;
}

.ceh-product-block .ceh-pricebox {
  display: grid;
  gap: 2px;
}

.ceh-product-block .ceh-price {
  font-size: 28px;
  line-height: 1;
  font-weight: 800;
  letter-spacing: -0.03em;
  color: #10255c;
}

.ceh-product-block .ceh-stock {
  font-size: 12px;
  font-weight: 700;
  line-height: 1.3;
  color: #167a4d;
}

.ceh-product-block .ceh-stock.ceh-out {
  color: #b03535;
}

.ceh-product-block .ceh-stock.ceh-unknown {
  color: #69778b;
}

.ceh-product-block .ceh-cta {
  margin-top: auto;
  min-height: 54px;
  border-radius: 16px;
  background: #0a1d59;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px 14px;
  text-align: center;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.2;
}

.ceh-product-block .ceh-loading,
.ceh-product-block .ceh-error,
.ceh-product-block .ceh-empty {
  background: #fff;
  border: 1px solid #d8e1ed;
  border-radius: 16px;
  box-shadow: 0 3px 12px rgba(12, 25, 58, 0.06);
  padding: 18px;
  color: #5f6c82;
  font-size: 14px;
  line-height: 1.5;
}

@media (max-width: 991px) {
  .ceh-product-block .ceh-card {
    flex-basis: 238px;
    min-width: 238px;
  }

  .ceh-product-block .ceh-media {
    height: 190px;
  }

  .ceh-product-block .ceh-price {
    font-size: 24px;
  }

  .ceh-product-block .ceh-nav {
    width: 48px;
    height: 48px;
    font-size: 28px;
  }
}

@media (max-width: 767px) {
  .ceh-product-block .ceh-section {
    padding: 12px;
    border-radius: 14px;
  }

  .ceh-product-block .ceh-head {
    margin-bottom: 10px;
  }

  .ceh-product-block .ceh-title {
    font-size: 20px;
  }

  .ceh-product-block .ceh-actions {
    display: none;
  }

  .ceh-product-block .ceh-card {
    flex-basis: 210px;
    min-width: 210px;
  }

  .ceh-product-block .ceh-media {
    height: 170px;
  }

  .ceh-product-block .ceh-name {
    font-size: 15px;
    min-height: 58px;
  }

  .ceh-product-block .ceh-price {
    font-size: 22px;
  }

  .ceh-product-block .ceh-cta {
    min-height: 48px;
    font-size: 13px;
    border-radius: 14px;
  }
}
</style>

<script>
(function () {
  function init() {
    var blocks = Array.prototype.slice.call(
      document.querySelectorAll(".ceh-product-block[data-ceh-block]")
    );
    if (!blocks.length) return;

    var SITE_ORIGIN = "https://www.comptoireolien.fr";
    var CATALOG_URLS = [
      "/_fields/agentic-catalog-v2.json",
      SITE_ORIGIN + "/_fields/agentic-catalog-v2.json"
    ];

    for (var i = 0; i < blocks.length; i++) {
      blocks[i].innerHTML = '<div class="ceh-loading">Chargement des produits…</div>';
    }

    loadCatalog();

    async function loadCatalog() {
      var lastError = null;

      for (var i = 0; i < CATALOG_URLS.length; i++) {
        try {
          var response = await fetch(CATALOG_URLS[i], { credentials: "same-origin" });
          if (!response.ok) throw new Error("HTTP " + response.status);

          var data = await response.json();
          var items = normalizeItems(extractItems(data));
          renderAllBlocks(items);
          return;
        } catch (error) {
          lastError = error;
        }
      }

      console.warn("Catalogue non chargé", lastError);

      for (var j = 0; j < blocks.length; j++) {
        blocks[j].innerHTML =
          '<div class="ceh-error">Impossible de charger le catalogue produit. Sur le site publié, ce bloc doit lire <code>/_fields/agentic-catalog-v2.json</code>. En aperçu local <code>file://</code>, le navigateur peut bloquer la requête.</div>';
      }
    }

    function extractItems(data) {
      if (Array.isArray(data)) return data;
      if (data && Array.isArray(data.items)) return data.items;
      if (data && Array.isArray(data.products)) return data.products;
      if (data && Array.isArray(data.catalog)) return data.catalog;

      if (data && typeof data === "object") {
        for (var key in data) {
          if (Object.prototype.hasOwnProperty.call(data, key) && Array.isArray(data[key])) {
            return data[key];
          }
        }
      }

      return [];
    }

    function normalizeItems(items) {
      return (items || [])
        .map(function (item) {
          return {
            sku: String(item.sku || item.id || "").trim(),
            name: String(item.name || item.title || "").trim(),
            url: toAbsoluteUrl(String(item.url || item.link || "").trim()),
            image: normalizeImageUrl(String(item.image || item.image_url || item.img || "").trim()),
            price: parsePrice(item.price),
            oldPrice: parsePrice(item.oldPrice),
            currency: String(item.currency || item.priceCurrency || "").trim(),
            availability: String(item.availability || "").trim(),
            inStock: typeof item.inStock === "boolean" ? item.inStock : null,
            weightKg: parseNumber(item.weightKg),
            packageRule: String(item.packageRule || "").trim()
          };
        })
        .filter(function (item) {
          return item.name && item.url && item.image;
        });
    }

    function renderAllBlocks(allItems) {
      var catalog = prepareCatalog(allItems);
      var weekSeed = getWeekSeed();
      var used = {};

      for (var index = 0; index < blocks.length; index++) {
        var root = blocks[index];
        var blockId = String(root.getAttribute("data-ceh-block") || "").trim().toLowerCase();
        var title = String(root.getAttribute("data-ceh-title") || getDefaultTitle(blockId)).trim();
        var maxItems = parseInt(root.getAttribute("data-ceh-max-items"), 10);

        if (!isFinite(maxItems) || maxItems < 1) maxItems = 10;

        var ranked = rankForBlock(catalog, blockId, weekSeed + (index * 97));
        var selected = [];

        for (var i = 0; i < ranked.length && selected.length < maxItems; i++) {
          var item = ranked[i];
          var key = item.sku || item.url;
          if (!key || used[key]) continue;

          used[key] = true;
          selected.push({
            name: item.name,
            badge: getBadge(blockId, item, selected.length),
            url: item.url,
            image: item.image,
            price: item.price,
            currency: item.currency,
            availability: item.availability,
            inStock: item.inStock,
            weightKg: item.weightKg
          });
        }

        if (!selected.length) {
          root.innerHTML = '<div class="ceh-empty">Aucun produit n’a été retenu pour ce carrousel.</div>';
          continue;
        }

        var trackId = "ceh-track-" + safeId(blockId || "block") + "-" + index;
        root.innerHTML = renderSection({
          id: blockId || ("block-" + index),
          title: title,
          trackId: trackId
        }, selected);

        bindNav(root);
      }
    }

    function prepareCatalog(items) {
      var seen = {};
      var result = [];

      (items || []).forEach(function (item) {
        var key = item.sku || item.url;
        if (!key || seen[key]) return;
        seen[key] = true;
        result.push(item);
      });

      return result;
    }

    function rankForBlock(items, blockId, seed) {
      return items
        .map(function (item) {
          return {
            item: item,
            score: getMerchantScore(blockId, item) + seededJitter(seed, item.sku || item.url)
          };
        })
        .sort(function (a, b) {
          if (a.score !== b.score) return b.score - a.score;
          return a.item.name.localeCompare(b.item.name, "fr");
        })
        .map(function (entry) {
          return entry.item;
        });
    }

    function getMerchantScore(blockId, item) {
      var score = baseScore(item);

      if (blockId === "selection") {
        if (item.weightKg !== null && item.weightKg >= 30) score += 220;
        else if (item.weightKg !== null && item.weightKg >= 10) score += 180;
        else if (item.weightKg !== null && item.weightKg >= 5) score += 35;
        else score -= 20;

        if (item.packageRule && /weight_gt_30|solar_fallback_weight_gt_30|complete_wind_turbine/i.test(item.packageRule)) {
          score += 50;
        }

        if (item.price !== null && item.price >= 500) score += 20;
        if (item.price !== null && item.price < 25) score -= 20;

        return score;
      }

      if (blockId === "featured") {
        if (item.oldPrice !== null && item.price !== null && item.oldPrice > item.price) score += 55;

        if (item.weightKg !== null && item.weightKg >= 10) score += 70;
        else if (item.weightKg !== null && item.weightKg >= 1) score += 20;

        if (item.price !== null && item.price >= 50 && item.price <= 2500) score += 10;

        return score;
      }

      if (blockId === "essentials") {
        if (item.weightKg !== null && item.weightKg >= 10) score += 40;
        else if (item.weightKg !== null && item.weightKg < 0.2) score -= 10;

        if (item.price !== null && item.price >= 10 && item.price <= 500) score += 35;
        if (item.price !== null && item.price < 5) score -= 15;

        return score;
      }

      return score;
    }

    function baseScore(item) {
      var score = 0;

      if (isInStock(item)) score += 80;
      else if (!isOutOfStock(item)) score += 25;
      else score -= 120;

      if (item.image) score += 25;
      if (item.price !== null && item.currency) score += 20;
      if (item.name && item.name.length > 8) score += 5;

      return score;
    }

    function seededJitter(seed, key) {
      var random = mulberry32(hashSeed(String(seed) + "|" + String(key)));
      return random() * 24;
    }

    function getBadge(blockId, item, position) {
      if (blockId === "selection") {
        if (item.weightKg !== null && item.weightKg >= 30) return "Notre sélection";
        if (item.weightKg !== null && item.weightKg >= 10) return "Sélection";
        return position < 3 ? "Notre sélection" : "Sélection";
      }

      if (blockId === "featured") {
        return "À la une";
      }

      if (blockId === "essentials") {
        if (item.weightKg !== null && item.weightKg >= 10) return "Incontournable";
        return "Essentiel";
      }

      return "Produit";
    }

    function getDefaultTitle(blockId) {
      if (blockId === "selection") return "Notre sélection";
      if (blockId === "featured") return "À la une";
      if (blockId === "essentials") return "Nos incontournables";
      return "Produits";
    }

    function getWeekSeed() {
      var now = new Date();
      var date = new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()));
      var dayNum = date.getUTCDay() || 7;
      date.setUTCDate(date.getUTCDate() + 4 - dayNum);
      var yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
      var weekNum = Math.ceil((((date - yearStart) / 86400000) + 1) / 7);
      return date.getUTCFullYear() * 100 + weekNum;
    }

    function hashSeed(seed) {
      var str = String(seed);
      var h = 1779033703 ^ str.length;

      for (var i = 0; i < str.length; i++) {
        h = Math.imul(h ^ str.charCodeAt(i), 3432918353);
        h = (h << 13) | (h >>> 19);
      }

      h = Math.imul(h ^ (h >>> 16), 2246822507);
      h = Math.imul(h ^ (h >>> 13), 3266489909);

      return (h ^ (h >>> 16)) >>> 0;
    }

    function mulberry32(a) {
      return function () {
        var t = a += 0x6D2B79F5;
        t = Math.imul(t ^ (t >>> 15), t | 1);
        t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
        return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
      };
    }

    function safeId(value) {
      return String(value || "")
        .toLowerCase()
        .replace(/[^a-z0-9_-]+/g, "-")
        .replace(/^-+|-+$/g, "") || "block";
    }

    function toAbsoluteUrl(value) {
      if (!value) return "";
      if (/^https?:\/\//i.test(value)) return value;
      if (value.indexOf("//") === 0) return "https:" + value;
      return SITE_ORIGIN + (value.charAt(0) === "/" ? "" : "/") + value;
    }

    function normalizeImageUrl(value) {
      var url = toAbsoluteUrl(value);
      return url.replace(/\/sq_icon\//g, "/medium/");
    }

    function parsePrice(value) {
      if (value === null || value === undefined || value === "") return null;
      if (typeof value === "number") return isFinite(value) ? value : null;

      var cleaned = String(value)
        .replace(/\s/g, "")
        .replace(/,/g, ".")
        .replace(/[^0-9.\-]/g, "");

      var parsed = parseFloat(cleaned);
      return isFinite(parsed) ? parsed : null;
    }

    function parseNumber(value) {
      if (value === null || value === undefined || value === "") return null;
      if (typeof value === "number") return isFinite(value) ? value : null;

      var cleaned = String(value)
        .replace(/\s/g, "")
        .replace(/,/g, ".")
        .replace(/[^0-9.\-]/g, "");

      var parsed = parseFloat(cleaned);
      return isFinite(parsed) ? parsed : null;
    }

    function isInStock(item) {
      return item.inStock === true || /instock/i.test(String(item.availability || ""));
    }

    function isOutOfStock(item) {
      return item.inStock === false || /outofstock/i.test(String(item.availability || ""));
    }

    function getStockMeta(item) {
      if (isInStock(item)) return { label: "En stock", className: "" };
      if (isOutOfStock(item)) return { label: "Indisponible", className: " ceh-out" };
      return { label: "Disponibilité à confirmer", className: " ceh-unknown" };
    }

    function formatPrice(value, currency) {
      if (value === null || !currency) return "";

      try {
        return new Intl.NumberFormat("fr-FR", {
          style: "currency",
          currency: currency,
          minimumFractionDigits: 2,
          maximumFractionDigits: 2
        }).format(value);
      } catch (error) {
        return value + " " + currency;
      }
    }

    function escapeHtml(str) {
      return String(str)
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#39;");
    }

    function renderCard(item) {
      var stock = getStockMeta(item);
      var priceHtml = "";

      if (item.price !== null && item.currency) {
        priceHtml = '<div class="ceh-price">' + escapeHtml(formatPrice(item.price, item.currency)) + '</div>';
      }

      return [
        '<a class="ceh-card" href="' + escapeHtml(item.url) + '" target="_self" rel="noopener">',
          '<div class="ceh-media">',
            '<span class="ceh-badge">' + escapeHtml(item.badge) + '</span>',
            '<img src="' + escapeHtml(item.image) + '" alt="' + escapeHtml(item.name) + '" loading="lazy">',
          '</div>',
          '<div class="ceh-body">',
            '<h3 class="ceh-name">' + escapeHtml(item.name) + '</h3>',
            '<div class="ceh-pricebox">',
              priceHtml,
              '<div class="ceh-stock' + stock.className + '">' + escapeHtml(stock.label) + '</div>',
            '</div>',
            '<div class="ceh-cta">Voir la fiche produit</div>',
          '</div>',
        '</a>'
      ].join("");
    }

    function renderSection(block, items) {
      return [
        '<section class="ceh-section">',
          '<div class="ceh-head">',
            '<h2 class="ceh-title">' + escapeHtml(block.title) + '</h2>',
            '<div class="ceh-actions">',
              '<button class="ceh-nav" type="button" data-ceh-prev="' + escapeHtml(block.trackId) + '" aria-label="Précédent">‹</button>',
              '<button class="ceh-nav" type="button" data-ceh-next="' + escapeHtml(block.trackId) + '" aria-label="Suivant">›</button>',
            '</div>',
          '</div>',
          '<div class="ceh-track" id="' + escapeHtml(block.trackId) + '">',
            items.map(renderCard).join(""),
          '</div>',
        '</section>'
      ].join("");
    }

    function bindNav(root) {
      var tracks = root.querySelectorAll(".ceh-track");

      for (var i = 0; i < tracks.length; i++) {
        (function (track) {
          updateNav(root, track);

          track.addEventListener("scroll", function () {
            updateNav(root, track);
          }, { passive: true });

          window.addEventListener("resize", function () {
            updateNav(root, track);
          });
        })(tracks[i]);
      }

      var prevBtns = root.querySelectorAll("[data-ceh-prev]");
      for (var j = 0; j < prevBtns.length; j++) {
        prevBtns[j].addEventListener("click", function () {
          scrollTrack(root, this.getAttribute("data-ceh-prev"), -1);
        });
      }

      var nextBtns = root.querySelectorAll("[data-ceh-next]");
      for (var k = 0; k < nextBtns.length; k++) {
        nextBtns[k].addEventListener("click", function () {
          scrollTrack(root, this.getAttribute("data-ceh-next"), 1);
        });
      }
    }

    function updateNav(root, track) {
      var prev = root.querySelector('[data-ceh-prev="' + track.id + '"]');
      var next = root.querySelector('[data-ceh-next="' + track.id + '"]');
      if (!prev || !next) return;

      var maxScroll = Math.max(0, track.scrollWidth - track.clientWidth - 2);
      prev.disabled = track.scrollLeft <= 4;
      next.disabled = track.scrollLeft >= maxScroll;
    }

    function scrollTrack(root, trackId, direction) {
      var track = root.querySelector("#" + cssEscape(trackId));
      if (!track) return;

      var card = track.querySelector(".ceh-card");
      var gap = 14;
      var step = (card ? card.getBoundingClientRect().width : 272) + gap;
      var visible = Math.max(1, Math.floor(track.clientWidth / step));

      track.scrollBy({
        left: direction * step * visible,
        behavior: "smooth"
      });
    }

    function cssEscape(value) {
      return String(value).replace(/([ #;?%&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1');
    }
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();
</script>
<!-- Socle commun CSS + JS global pour les carrousels produits -->

<!-- Script : flèche sur images cliquables des rubriques -->
<script>
(function () {
  var STYLE_ID = 'ce-rubrique-arrow-style';
  var BADGE_CLASS = 'ce-rubrique-arrow-badge';
  var HOVER_CLASS = 'ce-rubrique-arrow-hover';
  var READY_ATTR = 'data-ce-rubrique-arrow-ready';
  var CLICK_ATTR = 'data-ce-rubrique-arrow-clickbound';

  function injectStyle() {
    if (document.getElementById(STYLE_ID)) return;

    var style = document.createElement('style');
    style.id = STYLE_ID;
    style.textContent =
      '.' + BADGE_CLASS + '{' +
        'position:absolute;' +
        'top:10px;' +
        'left:10px;' +
        'z-index:5;' +
        'width:30px;' +
        'height:30px;' +
        'display:flex;' +
        'align-items:center;' +
        'justify-content:center;' +
        'border-radius:999px;' +
        'background:rgba(255,255,255,0.96);' +
        'border:1px solid rgba(31,94,168,0.18);' +
        'box-shadow:0 2px 8px rgba(0,0,0,0.14);' +
        'color:#1f5ea8;' +
        'font-size:18px;' +
        'font-weight:700;' +
        'line-height:1;' +
        'pointer-events:none;' +
        'user-select:none;' +
        'transition:transform .18s ease, box-shadow .18s ease, background .18s ease;' +
      '}' +

      '.' + HOVER_CLASS + '{' +
        'transition:box-shadow .18s ease;' +
      '}' +

      '@media (hover:hover){' +
        '.' + HOVER_CLASS + ':hover .' + BADGE_CLASS + '{' +
          'transform:translate(1px,1px);' +
          'box-shadow:0 4px 12px rgba(0,0,0,0.16);' +
        '}' +
      '}' +

      '.' + HOVER_CLASS + '[tabindex="0"]:focus{' +
        'outline:2px solid rgba(31,94,168,0.35);' +
        'outline-offset:2px;' +
      '}' +

      '@media (max-width:767px){' +
        '.' + BADGE_CLASS + '{' +
          'top:8px;' +
          'left:8px;' +
          'width:28px;' +
          'height:28px;' +
          'font-size:16px;' +
        '}' +
      '}';

    document.head.appendChild(style);
  }

  function isValidHref(href) {
    if (!href) return false;
    href = String(href).trim();

    return !!href &&
      href !== '#' &&
      !/^javascript:/i.test(href) &&
      !/^mailto:/i.test(href) &&
      !/^tel:/i.test(href) &&
      !/^sms:/i.test(href);
  }

  function toAbsoluteUrl(href) {
    try {
      return new URL(href, window.location.href).href;
    } catch (e) {
      return '';
    }
  }

  function cleanText(str) {
    return String(str || '').replace(/\s+/g, ' ').trim();
  }

  function isTargetImageDiv(el) {
    if (!el || el.tagName !== 'DIV') return false;

    var s = el.getAttribute('style') || '';

    return s.indexOf('_media/img/small/') !== -1 &&
           /background\s*:/i.test(s) &&
           /padding-top\s*:\s*100%/i.test(s);
  }

  function collectUniqueAnchors(scope) {
    if (!scope || !scope.querySelectorAll) return [];

    var anchors = scope.querySelectorAll('a[href]');
    var seen = {};
    var list = [];

    for (var i = 0; i < anchors.length; i++) {
      var rawHref = anchors[i].getAttribute('href');
      if (!isValidHref(rawHref)) continue;

      var absHref = toAbsoluteUrl(rawHref);
      if (!absHref || seen[absHref]) continue;

      seen[absHref] = true;
      list.push({
        href: absHref,
        text: cleanText(anchors[i].textContent)
      });
    }

    return list;
  }

  function findTarget(el) {
    if (!el) return null;

    var directAnchor = el.closest ? el.closest('a[href]') : null;

    if (directAnchor && isValidHref(directAnchor.getAttribute('href'))) {
      var directHref = toAbsoluteUrl(directAnchor.getAttribute('href'));
      var scope = directAnchor.parentElement;

      for (var d = 0; d < 4 && scope; d++, scope = scope.parentElement) {
        var scopeLinks = collectUniqueAnchors(scope);
        if (scopeLinks.length === 1 && scopeLinks[0].href === directHref) {
          return {
            type: 'direct',
            href: directHref,
            text: scopeLinks[0].text || cleanText(directAnchor.textContent)
          };
        }
      }
    }

    var node = el.parentElement;

    for (var depth = 0; depth < 4 && node; depth++, node = node.parentElement) {
      var dataHref = node.getAttribute && node.getAttribute('data-href');
      if (isValidHref(dataHref)) {
        return {
          type: 'datahref',
          href: toAbsoluteUrl(dataHref),
          text: ''
        };
      }

      var role = node.getAttribute && node.getAttribute('role');
      if ((node.hasAttribute && node.hasAttribute('onclick')) || role === 'link' || role === 'button') {
        return {
          type: 'nodeclick',
          node: node,
          text: ''
        };
      }

      var links = collectUniqueAnchors(node);
      if (links.length === 1) {
        return {
          type: 'nearby',
          href: links[0].href,
          text: links[0].text
        };
      }
    }

    return null;
  }

  function makeDivClickable(el, target) {
    if (!el || !target) return;
    if (target.type === 'direct') return;
    if (el.getAttribute(CLICK_ATTR) === '1') return;

    el.setAttribute('tabindex', '0');
    el.setAttribute('role', 'link');
    el.setAttribute('aria-label', target.text || 'Ouvrir le lien');

    el.addEventListener('click', function (e) {
      if (e.target && e.target.closest && e.target.closest('a[href]')) return;

      if (target.type === 'nodeclick' && target.node && typeof target.node.click === 'function') {
        target.node.click();
        return;
      }

      if (target.href) {
        window.location.href = target.href;
      }
    });

    el.addEventListener('keydown', function (e) {
      var key = e.key || e.code;

      if (key === 'Enter' || key === ' ' || key === 'Spacebar') {
        e.preventDefault();

        if (target.type === 'nodeclick' && target.node && typeof target.node.click === 'function') {
          target.node.click();
          return;
        }

        if (target.href) {
          window.location.href = target.href;
        }
      }
    });

    el.setAttribute(CLICK_ATTR, '1');
  }

  function addArrow(el) {
    if (!el || el.getAttribute(READY_ATTR) === '1') return;

    var cs = window.getComputedStyle(el);

    if (cs.position === 'static') {
      el.style.position = 'relative';
    }

    if (cs.overflow === 'visible') {
      el.style.overflow = 'hidden';
    }

    el.style.cursor = 'pointer';
    el.classList.add(HOVER_CLASS);

    var badge = document.createElement('span');
    badge.className = BADGE_CLASS;
    badge.setAttribute('aria-hidden', 'true');
    badge.textContent = '↘';

    el.appendChild(badge);
    el.setAttribute(READY_ATTR, '1');
  }

  function getCandidates(context) {
    var nodes = [];

    if (!context || context === document) {
      return document.querySelectorAll('div[style*="_media/img/small/"]');
    }

    if (context.nodeType === 1 && context.matches && context.matches('div[style*="_media/img/small/"]')) {
      nodes.push(context);
    }

    if (context.querySelectorAll) {
      var found = context.querySelectorAll('div[style*="_media/img/small/"]');
      for (var i = 0; i < found.length; i++) nodes.push(found[i]);
    }

    return nodes;
  }

  function process(context) {
    var candidates = getCandidates(context);

    for (var i = 0; i < candidates.length; i++) {
      var el = candidates[i];

      if (!isTargetImageDiv(el)) continue;
      if (el.getAttribute(READY_ATTR) === '1') continue;

      var target = findTarget(el);
      if (!target) continue;

      addArrow(el);
      makeDivClickable(el, target);
    }
  }

  function init() {
    injectStyle();
    process(document);

    var timer = null;
    var observer = new MutationObserver(function (mutations) {
      var hasAddedNodes = false;

      for (var i = 0; i < mutations.length; i++) {
        if (mutations[i].addedNodes && mutations[i].addedNodes.length) {
          hasAddedNodes = true;
          break;
        }
      }

      if (!hasAddedNodes) return;

      clearTimeout(timer);
      timer = setTimeout(function () {
        process(document);
      }, 120);
    });

    observer.observe(document.documentElement, {
      childList: true,
      subtree: true
    });

    window.addEventListener('load', function () {
      process(document);
    });
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();
</script>
<!-- Script : flèche sur images cliquables des rubriques -->

<!-- Maintenance panier – purge unique des anciennes données locales 4e2c -->
<script>
(function () {
  try {
    var FLAG = "ce-cart-clean-once-v1";
    if (localStorage.getItem(FLAG)) return;

    [
      "4e2c-cart",
      "4e2c-cart-ts",
      "4e2c-restored",
      "4e2c-cart-reminder",
      "4e2c-popover"
    ].forEach(function (k) {
      localStorage.removeItem(k);
      sessionStorage.removeItem(k);
    });

    localStorage.setItem(FLAG, "1");
  } catch (e) {}
})();
</script>
<!-- Maintenance panier – purge unique des anciennes données locales 4e2c -->

<!-- ===================== CE – CRÉDIT FIDÉLITÉ PANIER CHECKOUT ===================== -->
<script>
(function () {
  var CE_FIDELITE_CART = {
    seuil: 100,
    bonusParSeuil: 5,
    urlCompte: "https://www.comptoireolien.fr/_accounts.php",
    urlExplication: "https://www.comptoireolien.fr/credit-fidelite-compte-client.html",
    locale: "fr-FR",
    devise: "EUR",

    // null | "connected" | "guest" | "unknown"
    forceEtat: null,

    checkoutRootSelector: "#div_co",

    selectorsTotal: [
      "span.total.ta-right",
      ".total.ta-right",
      "span.total",
      ".total"
    ]
  };

  var STYLE_ID = "ce-fidelite-cart-style-v6";
  var BOX_ID = "ce-fidelite-cart-box-v6";
  var ROW_ID = "ce-fidelite-cart-row-v6";
  var renderTimer = null;
  var observerStarted = false;

  function isCheckoutPage() {
    var path = (window.location.pathname || "").toLowerCase();
    var h1 = document.querySelector("h1");
    var h1Text = h1 ? (h1.textContent || "") : "";
    return path.indexOf("_checkout.html") !== -1 || /votre commande/i.test(h1Text);
  }

  function getRoot() {
    return document.querySelector(CE_FIDELITE_CART.checkoutRootSelector) || document.body || document;
  }

  function formatEuro(value) {
    return new Intl.NumberFormat(CE_FIDELITE_CART.locale, {
      style: "currency",
      currency: CE_FIDELITE_CART.devise,
      minimumFractionDigits: 2,
      maximumFractionDigits: 2
    }).format(value);
  }

  function parsePrix(text) {
    if (!text) return null;

    var s = String(text).replace(/\u00A0/g, " ");
    var matches = s.match(/-?\d[\d\s]*(?:[.,]\d{2})/g);

    if (matches && matches.length) {
      s = matches[matches.length - 1];
    }

    s = s
      .replace(/\s+/g, "")
      .replace(/[^\d,.\-]/g, "");

    if (!s) return null;

    if (s.indexOf(",") !== -1 && s.indexOf(".") !== -1) {
      if (s.lastIndexOf(",") > s.lastIndexOf(".")) {
        s = s.replace(/\./g, "").replace(",", ".");
      } else {
        s = s.replace(/,/g, "");
      }
    } else if (s.indexOf(",") !== -1) {
      s = s.replace(",", ".");
    }

    var value = parseFloat(s);
    return isFinite(value) ? value : null;
  }

  function isVisible(el) {
    return !!(el && (el.offsetWidth || el.offsetHeight || el.getClientRects().length));
  }

  function nodeText(el) {
    return el ? String(el.textContent || "").replace(/\s+/g, " ").trim() : "";
  }

  function matchesSelector(el, selector) {
    if (!el || el.nodeType !== 1) return false;
    var fn = el.matches || el.msMatchesSelector || el.webkitMatchesSelector || el.mozMatchesSelector;
    return fn ? fn.call(el, selector) : false;
  }

  function closest(el, selector) {
    while (el && el.nodeType === 1) {
      if (matchesSelector(el, selector)) return el;
      el = el.parentElement;
    }
    return null;
  }

  function isInsideInjectedBox(el) {
    return !!closest(el, "#" + BOX_ID) || !!closest(el, "#" + ROW_ID);
  }

  function normalizeState(value) {
    var v = String(value || "").toLowerCase().trim();
    if (v === "connected" || v === "guest" || v === "unknown") return v;
    return "";
  }

  function hasGuestCouponPrompt(root) {
    if (!root) return false;

    var text = nodeText(root);

    if (/si vous avez un code personnel/i.test(text) && /connectez-vous/i.test(text)) {
      return true;
    }

    var links = root.querySelectorAll("a");
    for (var i = 0; i < links.length; i++) {
      var a = links[i];
      var aText = nodeText(a);
      var parentText = nodeText(a.parentElement || a);
      var onclick = a.getAttribute("onclick") || "";
      var href = a.getAttribute("href") || "";

      if (
        /connectez-vous/i.test(aText) &&
        (
          /si vous avez un code personnel/i.test(parentText) ||
          /_accounts\.php\?email=/i.test(onclick + " " + href) ||
          /sc2_return_step/i.test(onclick)
        )
      ) {
        return true;
      }
    }

    return false;
  }

  function hasCouponArea(root) {
    if (!root) return false;
    var text = nodeText(root);
    return /coupon de réduction/i.test(text) || /code personnel/i.test(text);
  }

  function getConnectionState() {
    if (
      CE_FIDELITE_CART.forceEtat === "connected" ||
      CE_FIDELITE_CART.forceEtat === "guest" ||
      CE_FIDELITE_CART.forceEtat === "unknown"
    ) {
      return CE_FIDELITE_CART.forceEtat;
    }

    var root = getRoot();
    if (!root) return "unknown";

    if (hasGuestCouponPrompt(root)) {
      return "guest";
    }

    if (hasCouponArea(root) && !hasGuestCouponPrompt(root)) {
      return "connected";
    }

    return "unknown";
  }

  function injectStyle() {
    if (document.getElementById(STYLE_ID)) return;

    var style = document.createElement("style");
    style.id = STYLE_ID;
    style.textContent =
      "#" + BOX_ID + "{" +
        "display:block;" +
        "width:100%;" +
        "max-width:none;" +
        "margin:6px 0 24px 0;" +
        "padding:12px 14px;" +
        "border:1px solid rgba(0,182,122,.18);" +
        "border-left:4px solid #00B67A;" +
        "border-radius:12px;" +
        "background:#f7fdf9;" +
        "font-size:13px;" +
        "line-height:1.5;" +
        "color:#183247;" +
        "box-sizing:border-box;" +
      "}" +
      "#" + BOX_ID + " .ce-fidelite-badge-link{" +
        "display:inline-block;" +
        "text-decoration:none !important;" +
        "margin-bottom:7px;" +
      "}" +
      "#" + BOX_ID + " .ce-fidelite-badge-link:focus{" +
        "outline:2px solid #008559;" +
        "outline-offset:2px;" +
        "border-radius:999px;" +
      "}" +
      "#" + BOX_ID + " .ce-fidelite-badge{" +
        "display:inline-block;" +
        "padding:4px 9px;" +
        "border-radius:999px;" +
        "background:#00B67A;" +
        "color:#fff;" +
        "font-size:11px;" +
        "font-weight:700;" +
        "text-transform:uppercase;" +
        "letter-spacing:.2px;" +
        "transition:background .2s ease;" +
      "}" +
      "#" + BOX_ID + " .ce-fidelite-badge-link:hover .ce-fidelite-badge{" +
        "background:#008559;" +
      "}" +
      "#" + BOX_ID + " .ce-fidelite-main{" +
        "display:block;" +
        "font-weight:600;" +
      "}" +
      "#" + BOX_ID + " .ce-fidelite-main strong{" +
        "color:#008559;" +
        "font-weight:800;" +
      "}" +
      "#" + BOX_ID + " .ce-fidelite-sub{" +
        "display:block;" +
        "margin-top:5px;" +
        "font-size:12px;" +
        "color:#5a6f80;" +
      "}" +
      "#" + BOX_ID + " a{" +
        "color:#008559;" +
        "text-decoration:underline;" +
        "font-weight:700;" +
      "}" +
      "#" + ROW_ID + " td{" +
        "border:none !important;" +
        "background:transparent !important;" +
        "padding:6px 0 0 0 !important;" +
      "}";

    document.head.appendChild(style);
  }

  function calculBonus(total) {
    return Math.floor(total / CE_FIDELITE_CART.seuil) * CE_FIDELITE_CART.bonusParSeuil;
  }

  function calculManque(total) {
    var reste = total % CE_FIDELITE_CART.seuil;
    return reste === 0 ? 0 : (CE_FIDELITE_CART.seuil - reste);
  }

  function findTotalInfo() {
    var root = getRoot();
    if (!root) return null;

    var labels = root.querySelectorAll("td, th, div, p, span, strong, b, small");

    for (var i = 0; i < labels.length; i++) {
      var el = labels[i];
      if (isInsideInjectedBox(el)) continue;
      if (!isVisible(el)) continue;

      var txt = nodeText(el);
      if (!/total du panier/i.test(txt)) continue;

      var row = closest(el, "tr") ||
                closest(el, ".row, .row-fluid, .flexrow, .flexrow-align-start") ||
                el.parentElement;

      if (!row) continue;

      var amountNode = row.querySelector(CE_FIDELITE_CART.selectorsTotal.join(","));
      var total = amountNode ? parsePrix(nodeText(amountNode)) : null;

      if (!total || total <= 0) {
        total = parsePrix(nodeText(row));
      }

      if (total && total > 0) {
        return {
          total: total,
          anchor: row
        };
      }
    }

    var best = null;

    for (var s = 0; s < CE_FIDELITE_CART.selectorsTotal.length; s++) {
      var nodes = root.querySelectorAll(CE_FIDELITE_CART.selectorsTotal[s]);

      for (var n = 0; n < nodes.length; n++) {
        var node = nodes[n];
        if (isInsideInjectedBox(node)) continue;
        if (!isVisible(node)) continue;

        var value = parsePrix(nodeText(node));
        if (!value || value <= 0) continue;

        var anchor = closest(node, "tr") ||
                     closest(node, ".row, .row-fluid, .flexrow, .flexrow-align-start") ||
                     node.parentElement;

        if (!best || value > best.total) {
          best = {
            total: value,
            anchor: anchor
          };
        }
      }
    }

    return best;
  }

  function getTableColspan(tr) {
    var max = (tr && tr.children && tr.children.length) ? tr.children.length : 1;
    var table = closest(tr, "table");

    if (table && table.rows) {
      for (var i = 0; i < table.rows.length; i++) {
        if (table.rows[i].cells && table.rows[i].cells.length > max) {
          max = table.rows[i].cells.length;
        }
      }
    }

    return max || 1;
  }

  function getBox() {
    var box = document.getElementById(BOX_ID);
    if (!box) {
      box = document.createElement("div");
      box.id = BOX_ID;
    }
    return box;
  }

  function removeRowContainer() {
    var row = document.getElementById(ROW_ID);
    if (row && row.parentNode) {
      row.parentNode.removeChild(row);
    }
  }

  function insertAfter(anchor, node) {
    if (!anchor || !anchor.parentNode) return;

    if (anchor.nextSibling) {
      anchor.parentNode.insertBefore(node, anchor.nextSibling);
    } else {
      anchor.parentNode.appendChild(node);
    }
  }

  function placeBox(anchor, box) {
    if (!anchor || !box) return;

    if ((anchor.tagName || "").toUpperCase() === "TR") {
      var row = document.getElementById(ROW_ID);
      if (!row) {
        row = document.createElement("tr");
        row.id = ROW_ID;
      }

      var td = row.querySelector("td");
      if (!td) {
        td = document.createElement("td");
        row.appendChild(td);
      }

      td.colSpan = getTableColspan(anchor);

      if (box.parentNode !== td) {
        td.innerHTML = "";
        td.appendChild(box);
      }

      if (row.parentNode !== anchor.parentNode || row.previousSibling !== anchor) {
        insertAfter(anchor, row);
      }

      return;
    }

    removeRowContainer();

    if (box.parentNode !== anchor.parentNode || box.previousSibling !== anchor) {
      insertAfter(anchor, box);
    }
  }

  function buildMessage(total) {
    var state = getConnectionState();
    var bonus = calculBonus(total);
    var manque = calculManque(total);
    var loginLink = '<a href="' + CE_FIDELITE_CART.urlCompte + '" target="_top">Connectez-vous</a>';
    var badgeLink =
      '<a class="ce-fidelite-badge-link" href="' + CE_FIDELITE_CART.urlExplication + '" target="_top" aria-label="En savoir plus sur le crédit fidélité">' +
        '<span class="ce-fidelite-badge">Crédit fidélité</span>' +
      '</a>';
    var html = badgeLink;

    if (bonus > 0) {
      if (state === "connected") {
        html += '<span class="ce-fidelite-main">Avec cette commande, vous cumulerez <strong>' + formatEuro(bonus) + '</strong> de crédit fidélité.</span>';
        html += '<span class="ce-fidelite-sub">Crédit fidélité utilisable sur votre prochaine commande via votre compte client.</span>';
      } else if (state === "guest") {
        html += '<span class="ce-fidelite-main">' + loginLink + ' pour cumuler <strong>' + formatEuro(bonus) + '</strong> de crédit fidélité avec cette commande.</span>';
        html += '<span class="ce-fidelite-sub">Crédit fidélité utilisable sur votre prochaine commande, réservé aux clients disposant d’un compte client.</span>';
      } else {
        html += '<span class="ce-fidelite-main">Associez cette commande à votre compte client pour cumuler <strong>' + formatEuro(bonus) + '</strong> de crédit fidélité.</span>';
        html += '<span class="ce-fidelite-sub">Crédit fidélité utilisable sur votre prochaine commande, réservé aux clients disposant d’un compte client.</span>';
      }

      html += '<span class="ce-fidelite-sub">' +
        formatEuro(CE_FIDELITE_CART.bonusParSeuil) +
        ' offerts par tranche complète de ' +
        formatEuro(CE_FIDELITE_CART.seuil) +
        ' d’achat.' +
      '</span>';

      return html;
    }

    if (state === "connected") {
      html += '<span class="ce-fidelite-main">Cumulez <strong>' + formatEuro(CE_FIDELITE_CART.bonusParSeuil) + '</strong> dès ' + formatEuro(CE_FIDELITE_CART.seuil) + ' d’achat.</span>';
      html += '<span class="ce-fidelite-sub">Crédit fidélité utilisable sur votre prochaine commande via votre compte client.</span>';
    } else if (state === "guest") {
      html += '<span class="ce-fidelite-main">' + loginLink + ' pour cumuler <strong>' + formatEuro(CE_FIDELITE_CART.bonusParSeuil) + '</strong> dès ' + formatEuro(CE_FIDELITE_CART.seuil) + ' d’achat.</span>';
      html += '<span class="ce-fidelite-sub">Crédit fidélité réservé aux clients disposant d’un compte client.</span>';
    } else {
      html += '<span class="ce-fidelite-main">Créez ou utilisez votre compte client pour cumuler <strong>' + formatEuro(CE_FIDELITE_CART.bonusParSeuil) + '</strong> dès ' + formatEuro(CE_FIDELITE_CART.seuil) + ' d’achat.</span>';
      html += '<span class="ce-fidelite-sub">Crédit fidélité réservé aux clients disposant d’un compte client.</span>';
    }

    html += '<span class="ce-fidelite-sub">Il vous manque ' + formatEuro(manque || CE_FIDELITE_CART.seuil) + ' pour débloquer le premier palier.</span>';

    return html;
  }

  function renderFidelityBox() {
    if (!isCheckoutPage()) return;

    injectStyle();

    var info = findTotalInfo();
    if (!info || !info.total || info.total <= 0 || !info.anchor) return;

    var box = getBox();
    var html = buildMessage(info.total);

    if (box.getAttribute("data-ce-html") !== html) {
      box.innerHTML = html;
      box.setAttribute("data-ce-html", html);
    }

    placeBox(info.anchor, box);
  }

  function scheduleRender() {
    window.clearTimeout(renderTimer);
    renderTimer = window.setTimeout(renderFidelityBox, 180);
  }

  function startObserver() {
    if (observerStarted || !window.MutationObserver) return;
    observerStarted = true;

    var target = getRoot();
    if (!target) target = document.body;
    if (!target) return;

    var observer = new MutationObserver(function () {
      scheduleRender();
    });

    observer.observe(target, {
      childList: true,
      subtree: true,
      characterData: true
    });
  }

  function init() {
    if (!isCheckoutPage()) return;

    scheduleRender();
    startObserver();
    window.addEventListener("load", scheduleRender);
    window.addEventListener("pageshow", scheduleRender);
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();
</script>
<!-- ===================== /CE – CRÉDIT FIDÉLITÉ PANIER CHECKOUT ===================== -->

<!-- Script ajout indication TTC automatique -->
<script>
document.addEventListener('DOMContentLoaded', function() {
  setTimeout(function () {
    var priceElements = document.querySelectorAll('.tw-price');
    priceElements.forEach(function(elem) {
      if (elem.classList.contains('striked')) return;
      if (elem.textContent.includes('TTC')) return;
      var ttcSpan = document.createElement('span');
      ttcSpan.textContent = ' TTC';
      ttcSpan.style.color = 'hsl(0, 0%, 0%)'; // noir, comme le prix
      ttcSpan.style.fontSize = '70%';
      ttcSpan.style.marginLeft = '0px';
      elem.appendChild(ttcSpan);
    });
  }, 300); // attend 300ms avant d’exécuter
});
</script>
<!-- Script ajout indication TTC automatique --><style>
/* ================== Toolbar & recherche — base ================== */
#toolbar2_r.nav.pull-right{
  float:none !important;
  display:flex !important;
  align-items:center;
  gap:8px;
  width:100%;
  margin:0;
  padding:0;
  list-style:none;
}

#toolbar2_r > li:first-child{
  flex:1 1 auto;
  min-width:0;
  margin-left:16px;
}

#searchbox{
  display:flex;
  align-items:center;
  width:100%;
}

#searchbox-req{
  flex:1 1 auto;
  min-width:0;
  width:100%;
}

@media (max-width:768px){
  #toolbar2_r{ gap:6px; }
}

/* ================== Hauteur & confort du champ ================== */
:root{ --search-height:34px; }

#searchbox-req{
  height:var(--search-height);
  line-height:var(--search-height);
  padding:0 14px;
  border-radius:5px;
}

/* ================== Desktop : barre = max 40% ================== */
@media (min-width:1024px){
  #toolbar2_r > li:first-child{
    flex:1 1 0;
    min-width:520px;
    max-width:40%;
  }

  #searchbox{
    width:100%;
    max-width:100%;
  }
}
@media (min-width:1920px){
  #toolbar2_r > li:first-child{ max-width:40%; }
}
</style>

<style>
/* ================== Liens + compte + panier ================== */
@media (min-width: 992px) {
  /* Le bloc de liens pousse tout ce qui suit à droite */
  #toolbar2_r .toolbar-extra-links{
    display:flex;
    align-items:center;
    gap:16px;
    margin:0 14px 0 auto;
    white-space:nowrap;
    font-size:0.90rem;
    font-weight:300;
    letter-spacing:0.06em;
  }

  #toolbar2_r .toolbar-extra-links a{
    color:#FFFFFF;
    text-decoration:none;
    padding:0 2px;
  }

  #toolbar2_r .toolbar-extra-links a:hover{
    text-decoration:underline;
    text-decoration-color:#7BEACD;
  }

  #toolbar2_r .toolbar-extra-sep{
    color:#FFFFFF;
    opacity:0.7;
    margin:0 2px;
  }

  /* Harmonisation compte + panier */
  #toolbar2_r #button-login,
  #toolbar2_r #button-cart{
    display:inline-flex;
    align-items:center;
    justify-content:center;
    color:#FFFFFF;
    text-decoration:none;
    transition:color .18s ease, transform .18s ease;
  }

  #toolbar2_r #button-login:hover,
  #toolbar2_r #button-cart:hover{
    color:#7BEACD;
  }

  #toolbar2_r #button-login{
    margin-left:2px;
    margin-right:2px;
  }

  #toolbar2_r #button-cart{
    margin-left:2px;
  }
}

/* Cacher les liens texte sur mobile / petites tablettes */
@media (max-width: 991px) {
  #toolbar2_r .toolbar-extra-links{
    display:none !important;
  }
}
</style>

<script>
document.addEventListener('DOMContentLoaded', function () {
  var toolbar = document.getElementById('toolbar2_r');
  if (!toolbar) return;

  var loginLink = document.getElementById('button-login');
  var cartLink  = document.getElementById('button-cart');
  if (!cartLink) return;

  var cartLi  = cartLink.closest('li');
  var loginLi = loginLink ? loginLink.closest('li') : null;
  if (!cartLi) return;

  /* Crée ou récupère le bloc de liens */
  var extraLi = toolbar.querySelector('.toolbar-extra-links');
  if (!extraLi) {
    extraLi = document.createElement('li');
    extraLi.className = 'toolbar-extra-links';
    extraLi.innerHTML =
      '<a href="faq.html">Aide &amp; FAQ</a>' +
      '<span class="toolbar-extra-sep">|</span>' +
      '<a href="mentions-legales.html">Mentions légales</a>' +
      '<span class="toolbar-extra-sep">|</span>' +
      '<a href="_tos.html">CGV</a>' +
      '<span class="toolbar-extra-sep">|</span>' +
      '<a href="service-client-contactez-nous.html">Contact</a>';
  }

  /* Ordre final souhaité :
     Recherche / Liens / Compte / Panier */
  if (loginLi) {
    toolbar.insertBefore(extraLi, loginLi);
    toolbar.insertBefore(loginLi, cartLi);
  } else {
    toolbar.insertBefore(extraLi, cartLi);
  }
});
</script></span></span><span style="font-size:13px;"><!-- MEGA MENU PREMIUM : FLOU D'ARRIÈRE-PLAN + FOCUS NAVIGATION -->
<style>
/* =========================
   VERSION PREMIUM
   Flou plus doux + voile un peu plus sombre
   ========================= */

:root{
  --ce-blur-strength: 6px;              /* flou plus doux */
  --ce-overlay-speed: .24s;
  --ce-overlay-dark-top: rgba(10,18,30,.12);
  --ce-overlay-dark-mid: rgba(10,18,30,.16);
  --ce-overlay-dark-bottom: rgba(10,18,30,.22);
  --ce-overlay-fallback: rgba(10,18,30,.26);
}

header{
  position: relative;
  z-index: 11 !important;
}

#ce-menu-blur-overlay{
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  top: 0;
  opacity: 0;
  pointer-events: none;
  z-index: 10 !important;

  /* voile plus premium, légèrement plus sombre */
  background:
    linear-gradient(
      to bottom,
      var(--ce-overlay-dark-top) 0%,
      var(--ce-overlay-dark-mid) 38%,
      var(--ce-overlay-dark-bottom) 100%
    );

  /* focus plus haut de gamme : flou doux + légère baisse de luminosité */
  -webkit-backdrop-filter: blur(var(--ce-blur-strength)) saturate(92%) brightness(0.88) contrast(0.96);
  backdrop-filter: blur(var(--ce-blur-strength)) saturate(92%) brightness(0.88) contrast(0.96);

  transition: opacity var(--ce-overlay-speed) ease;
  will-change: opacity, backdrop-filter;
}

body.ce-menu-blur-open #ce-menu-blur-overlay{
  opacity: 1;
  pointer-events: auto;
}

/* Le menu reste bien au-dessus et gagne un rendu plus premium */
header .dropdown-content,
header .dropdown-menu{
  z-index: 100002 !important;
  box-shadow:
    0 22px 46px rgba(0,0,0,.18),
    0 8px 18px rgba(0,0,0,.08);
  border-top: 1px solid rgba(255,255,255,.28);
}

/* Fallback si backdrop-filter n'est pas bien pris en charge */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  #ce-menu-blur-overlay{
    background: var(--ce-overlay-fallback);
  }
}

/* Mobile : effet un peu allégé */
@media (max-width: 991px){
  :root{
    --ce-blur-strength: 4px;
  }

  #ce-menu-blur-overlay{
    background:
      linear-gradient(
        to bottom,
        rgba(10,18,30,.10) 0%,
        rgba(10,18,30,.14) 40%,
        rgba(10,18,30,.18) 100%
      );
  }
}
</style>

<script>
(function () {
  var header = document.querySelector('header');
  var menuItems = Array.prototype.slice.call(
    document.querySelectorAll('#mainmenu li.dropdown')
  );

  if (!header || !menuItems.length) return;

  var overlay = document.getElementById('ce-menu-blur-overlay');
  if (!overlay) {
    overlay = document.createElement('div');
    overlay.id = 'ce-menu-blur-overlay';
    overlay.setAttribute('aria-hidden', 'true');
    document.body.appendChild(overlay);
  }

  var closeTimer = null;

  function updateOverlayTop() {
    var rect = header.getBoundingClientRect();
    overlay.style.top = Math.max(0, Math.round(rect.bottom)) + 'px';
  }

  function isMenuActive() {
    return menuItems.some(function (item) {
      return item.matches(':hover') ||
             item.matches(':focus-within') ||
             item.classList.contains('open') ||
             item.classList.contains('show');
    });
  }

  function openBlur() {
    clearTimeout(closeTimer);
    updateOverlayTop();
    document.body.classList.add('ce-menu-blur-open');
  }

  function closeBlur(force) {
    clearTimeout(closeTimer);

    if (force) {
      document.body.classList.remove('ce-menu-blur-open');
      return;
    }

    closeTimer = setTimeout(function () {
      if (!isMenuActive()) {
        document.body.classList.remove('ce-menu-blur-open');
      }
    }, 40);
  }

  menuItems.forEach(function (item) {
    item.addEventListener('mouseenter', openBlur);
    item.addEventListener('mouseleave', function () {
      closeBlur(false);
    });

    item.addEventListener('focusin', openBlur);
    item.addEventListener('focusout', function () {
      closeBlur(false);
    });

    var toggle = item.querySelector('.dropdown-toggle');
    if (toggle) {
      toggle.addEventListener('click', function () {
        setTimeout(function () {
          if (isMenuActive()) openBlur();
          else closeBlur(true);
        }, 0);
      });
    }
  });

  overlay.addEventListener('click', function () {
    document.body.classList.remove('ce-menu-blur-open');

    menuItems.forEach(function (item) {
      item.classList.remove('open', 'show');
    });

    if (document.activeElement) {
      document.activeElement.blur();
    }
  });

  document.addEventListener('keydown', function (e) {
    if (e.key === 'Escape') {
      closeBlur(true);

      menuItems.forEach(function (item) {
        item.classList.remove('open', 'show');
      });

      if (document.activeElement) {
        document.activeElement.blur();
      }
    }
  });

  document.addEventListener('click', function (e) {
    if (!header.contains(e.target) && e.target !== overlay) {
      closeBlur(true);
    }
  });

  window.addEventListener('resize', function () {
    if (document.body.classList.contains('ce-menu-blur-open')) {
      updateOverlayTop();
    }
  });

  window.addEventListener('scroll', function () {
    if (document.body.classList.contains('ce-menu-blur-open')) {
      updateOverlayTop();
    }
  }, { passive: true });

  var observer = new MutationObserver(function () {
    if (isMenuActive()) openBlur();
    else closeBlur(true);
  });

  menuItems.forEach(function (item) {
    observer.observe(item, {
      attributes: true,
      attributeFilter: ['class']
    });
  });
})();
</script>
<!-- MEGA MENU PREMIUM : FLOU D'ARRIÈRE-PLAN + FOCUS NAVIGATION --></span></div></div></div><div id="foot-sec2" class="span6 "><span style="color:#4D4D4D;"><span style="font-size:13px;"><span style="background-color: transparent;">    <style>
    .flags {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        margin-top: 0px;
        }
        
        .flags img {
            margin: 5px;
            width: 35px;
            height: auto;
            box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);  /* Ombre portée */
        }
        
        /* Règles spécifiques pour les écrans mobiles */
        @media (max-width: 768px) {
        .flags {
            justify-content: flex-start; /* Aligne à gauche sur mobile */
        }
    }
    </style>
        <div class="flags">
<img src="_fields/flag_fr.png" alt="Drapeau de la France" title="France" />
<img src="_fields/flag_de.png" alt="Drapeau de l'Allemagne" title="Germany" />
<img src="_fields/flag_be2.png" alt="Drapeau de la Belgique" title="Belgium" />
<img src="_fields/flag_lu.png" alt="Drapeau du Luxembourg" title="Luxembourg" />
<img src="_fields/flag_it.png" alt="Drapeau de l'Italie" title="Italy" />
<img src="_fields/flag_es.png" alt="Drapeau de l'Espagne" title="Spain" />
<img src="_fields/flag_pt.png" alt="Drapeau du Portugal" title="Portugal" />
<img src="_fields/flag_mc.png" alt="Drapeau de Monaco" title="Monaco" />
<img src="_fields/flag_fi.png" alt="Drapeau de la Finlande" title="Finland" />
<img src="_fields/flag_ie.png" alt="Drapeau de l'Irlande" title="Ireland" />
<img src="_fields/flag_nl.png" alt="Drapeau des Pays-Bas" title="Netherlands" />
<img src="_fields/flag_se.png" alt="Drapeau de la Suède" title="Sweden" />
    </div></span></span></span><div><span style="font-size:13px;"><style>
    /* Conteneur pour les logos */
    .logos-color {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        margin-top: 10px;
    }
    /* Ajout d'un espacement entre chaque logo */
    .logos-color img {
        margin: 5px; /* Marge entre les logos */
    }
            
    /* Styles par logo */
    .logo-cb {
        width: 50px;
        height: auto;
    }

    .logo-visa {
        width: 50px;
        height: auto;
    }

    .logo-mastercard {
        width: 45px;
        height: auto;
    }

    .logo-klarna {
        width: 80px;
        height: auto;
    }

    .logo-paypal {
        width: 80px;
        height: auto;
    }

    .logo-colissimo {
        width: 90px;
        height: auto;
    }

    .logo-mondialrelay {
        width: 35px;
        height: auto;
    }

    .logo-chronopost {
        width: 100px;
        height: auto;
    }
    
    /* Règles spécifiques pour les écrans mobiles */
    @media (max-width: 768px) {
        .logos-color {
            justify-content: flex-start; /* Aligne à gauche sur mobile */
        }
    }  
</style>

<!-- Section des logos de paiement et livraison -->
<div class="logos-color">
    <img src="_fields/cb-color.svg" alt="CB Visa" title="Paiement par CB" class="logo-cb"/>
    <img src="_fields/visa-color.svg" alt="CB Visa" title="Paiement par CB Visa" class="logo-visa"/>
    <img src="_fields/mastercard-color.svg" alt="CB Mastercard" title="Paiement par CB Mastercard" class="logo-mastercard"/>
    <img src="_fields/klarna-color.svg" alt="Paiement Klarna" title="Paiement par Klarna" class="logo-klarna"/>
    <img src="_fields/paypal-color.svg" alt="Paiement PayPal" title="Paiement par PayPal" class="logo-paypal"/>
    <img src="_fields/colissimo-color.svg" alt="Livraison Colissimo" title="Livraison Colissimo" class="logo-colissimo"/>
    <img src="_fields/mondialRelay-color.svg" alt="Livraison Mondial Relay" title="Livraison Mondial Relay" class="logo-mondialrelay"/>
    <img src="_fields/chronopost-color.svg" alt="Livraison Chronopost" title="Livraison Chronopost" class="logo-chronopost"/>
</div></span></div></div></div></footer></div></div><script src="_scripts/jquery/jquery.min.js"></script><script src="_scripts/bootstrap/js/bootstrap.min.js"></script><script src="_scripts/colorbox/jquery.colorbox-min.js"></script><script>function _Ox404(e){var t={},n,r,i=[],s="",o=String.fromCharCode;var u=[[65,91],[97,123],[48,58],[43,44],[47,48]];for(z in u){for(n=u[z][0];n<u[z][1];n++){i.push(o(n))}}for(n=0;n<64;n++){t[i[n]]=n}for(n=0;n<e.length;n+=72){var a=0,f,l,c=0,h=e.substring(n,n+72);for(l=0;l<h.length;l++){f=t[h.charAt(l)];a=(a<<6)+f;c+=6;while(c>=8){s+=o((a>>>(c-=8))%256)}}}return s}function ucc(){var a=sessionStorage.getItem("4e2c-cart")||"";if(!a||a=="")b=0;else{var b=0;var c=0;do{c=a.indexOf(")",c);if(c>0){e=c-1;while(e>=0&&a[e]!="=")e--;b+=parseInt(a.substring(e+1,c));c++}}while(c>0)}$("#sc_pcount").text(b)}function showParag(id){if(id.length>1&&id[0]!="#")id="#"+id;var p=$(id).is("a")?$(id).parent().parent():$(id).parent();$("html,body").animate({scrollTop:p.offset().top},"slow");}function onChangeSiteLang(href){var i=location.href.indexOf("?");if(i>0)href+=location.href.substr(i);document.location.href=href;}</script><script>$(document).ready(function(){var params=window.location.search.substring(1).split("$");if(params.length==2){if(params[0]!=""){$.post("./_iserv/common/decode.php",{msg:params[0],code:params[1]},function(r){if(r.trim()!=""){$("#top-content").html(_Ox404(r));}else console.log("msg code error");}).fail(function(response){console.log("decode failure");});}else console.log("msg code empty");}else console.log("msg code missing");ucc();$("#button-cart").popover({placement:"bottom",html:true,content:function(){return sessionStorage.getItem("4e2c-popover")||"<small>VOTRE PANIER EST VIDE</small>"},trigger:"hover"});$("#searchbox>input").click(function(){$(this).select();});$("#searchbox").click(function(e){if(e.offsetX>e.target.width){}else $("#searchbox").submit()});var clickmessage="Avertissement : Ce contenu est protégé. Le Comptoir Eolien. Copyright ©. Tous droits réservés. INPI 12 3 921 088.";function disableclick(e){if(document.all){if(event.button==2||event.button==3){if(event.srcElement.tagName=="IMG"){if(clickmessage!="")alert(clickmessage);return false;}}}else if(document.layers){if(e.which==3){if(clickmessage!= "")alert(clickmessage);return false;}}else if(document.getElementById){if(e.which==3&&e.target.tagName=="IMG" ){if(clickmessage!="")alert(clickmessage);return false;}}}function associateimages(){for(i=0;i<document.images.length;i++)document.images[i].onmousedown=disableclick;}if(document.all){document.onmousedown=disableclick;} else if(document.getElementById){document.onmouseup=disableclick;}else if(document.layers)associateimages();if($(window.location.hash).length)showParag(window.location.hash);if(location.href.indexOf("?")>0&&location.href.indexOf("twtheme=no")>0){$("#toolbar1,#toolbar2,#toolbar3,#footersmall,#footerfat").hide();var idbmk=location.href;idbmk=idbmk.substring(idbmk.lastIndexOf("#")+1,idbmk.lastIndexOf("?"));if(idbmk!=""){idbmk=idbmk.split("?")[0];if($("#"+idbmk+"_container").length)idbmk+="_container";$("html,body").animate({scrollTop:$("#"+idbmk).offset().top},0);}}$(".tos").colorbox({width:"80%",height:"80%",iframe:true,transition:"none"});$(".dropdown-toggle").dropdown();{var html='<div id="topBanner" class="alert alert-success fill-available" style="margin:0;border-radius:0;position:relative;z-index:9998;padding-left:180% !important;padding-right:180% !important;margin-left:-180% !important;margin-right:-180% !important;font-size:90%;border-style:solid;border-width:0 0 1px;"><div class="alert-success" style="display:flex;justify-content:center;align-items:center;max-width:1320px;"><div style="text-align:center;">🎁 Cumulez 5 € de crédit fidélité par tranche de 100 € d’achat</div></div></div>';$("header").prepend(html);}if(typeof onTOWebPageLoaded=="function")onTOWebPageLoaded();});</script></body></html>