{"id":1868,"date":"2026-03-25T17:03:34","date_gmt":"2026-03-25T16:03:34","guid":{"rendered":"https:\/\/spes.anivise.fr\/?page_id=1868"},"modified":"2026-06-08T14:53:33","modified_gmt":"2026-06-08T12:53:33","slug":"fiches-spes-test-modifs","status":"publish","type":"page","link":"https:\/\/spes.anivise.fr\/index.php\/fiches-spes-test-modifs\/","title":{"rendered":"Fiches SPES &#8211; TEST MODIFS"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"1868\" class=\"elementor elementor-1868\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e978140 e-flex e-con-boxed parallax_section_no qode_elementor_container_no e-con e-parent\" data-id=\"e978140\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-383d0ed e-con-full e-flex parallax_section_no qode_elementor_container_no e-con e-child\" data-id=\"383d0ed\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6a1a66a elementor-button-align-stretch elementor-widget elementor-widget-form\" data-id=\"6a1a66a\" data-element_type=\"widget\" id=\"search-espece\" data-settings=\"{&quot;step_next_label&quot;:&quot;Next&quot;,&quot;step_previous_label&quot;:&quot;Previous&quot;,&quot;button_width&quot;:&quot;100&quot;,&quot;step_type&quot;:&quot;number_text&quot;,&quot;step_icon_shape&quot;:&quot;circle&quot;}\" data-widget_type=\"form.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<form class=\"elementor-form\" method=\"post\" name=\"New Form\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"1868\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"6a1a66a\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Fiches SPES &#8211; TEST MODIFS\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"1868\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-above\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-searchespece elementor-col-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-searchespece\" class=\"elementor-field-label\">\n\t\t\t\t\t\t\t\tESPECE RECHERCHEE\t\t\t\t\t\t\t<\/label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<input size=\"1\" type=\"text\" name=\"form_fields[searchespece]\" id=\"form-field-searchespece\" class=\"elementor-field elementor-size-sm  elementor-field-textual\" placeholder=\"Ecrire ici\">\n\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-group elementor-column elementor-field-type-submit elementor-col-100 e-form__buttons\">\n\t\t\t\t\t<button class=\"elementor-button elementor-size-sm\" type=\"submit\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/button>\n\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/form>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ac9acb5 e-flex e-con-boxed parallax_section_no qode_elementor_container_no e-con e-parent\" data-id=\"ac9acb5\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-019c501 elementor-widget elementor-widget-html\" data-id=\"019c501\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script>\r\ndocument.addEventListener('DOMContentLoaded', () => {\r\n  console.log('shortcode fiches_rest_nonce exists?', (typeof window.wp !== 'undefined'));\r\n});\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-991917d elementor-widget elementor-widget-shortcode\" data-id=\"991917d\" data-element_type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">\n\n<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-794bd2b elementor-widget elementor-widget-shortcode\" data-id=\"794bd2b\" data-element_type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\"><script>window.FICHES_EXPORT = { canExportPdf: false };<\/script><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0122c1f elementor-widget elementor-widget-html\" data-id=\"0122c1f\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- Fonts -->\r\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;600&display=swap\" rel=\"stylesheet\">\r\n\r\n<!-- Librairies -->\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/papaparse@5.4.1\/papaparse.min.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/fuse.js@6.6.2\"><\/script>\r\n<script src=\"https:\/\/www.gstatic.com\/charts\/loader.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"><\/script>\r\n\r\n<style>\r\n\/* Masquer le logo du th\u00e8me Bridge *\/\r\n.q_logo,\r\n.header_logo,\r\n.logo_wrapper {\r\n  display: none !important;\r\n}\r\n\r\n\/* Police et base *\/\r\nbody {\r\n  font-family: 'Inter', sans-serif;\r\n  background-color: #f8f9fa;\r\n  color: #222;\r\n  margin: 0;\r\n  padding: 0;\r\n  line-height: 1.6;\r\n}\r\n\r\n\r\n\/* Conteneur du champ de recherche *\/\r\n#search-espece {\r\n  position: relative;\r\n  z-index: 999; \/* assure la superposition *\/\r\n}\r\n\r\n\/* Champ de recherche *\/\r\n#search-espece input[type=\"text\"] {\r\n  width: 100%;\r\n  max-width: 400px;\r\n  padding: 12px 16px;\r\n  font-size: 1rem;\r\n  border: 1px solid #ccc;\r\n  border-radius: 8px;\r\n  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);\r\n  outline: none;\r\n  transition: border-color 0.2s ease;\r\n  margin: 20px auto;\r\n  display: block;\r\n}\r\n\r\n\/* Focus *\/\r\n#search-espece input[type=\"text\"]:focus {\r\n  border-color: #4ECDC4;\r\n}\r\n\r\n\/* \u2705 Input d\u00e9sactiv\u00e9 pendant chargement *\/\r\n#search-espece input[type=\"text\"][disabled] {\r\n  opacity: 0.6;\r\n  cursor: not-allowed;\r\n}\r\n\r\n\/* Liste des suggestions *\/\r\n#suggestions {\r\n  position: absolute;\r\n  top: 100%;\r\n  left: 0;\r\n  right: 0;\r\n  max-height: 150px;\r\n  overflow-y: auto;\r\n  overflow-x: hidden;\r\n  background-color: white;\r\n  border: 1px solid #ccc;\r\n  border-top: none;\r\n  z-index: 9999;\r\n  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);\r\n  overscroll-behavior: contain;\r\n  pointer-events: auto; \/* \ud83d\udc48 important *\/\r\n}\r\n\r\n\/* Scrollbar visible *\/\r\n#suggestions::-webkit-scrollbar {\r\n  width: 6px;\r\n}\r\n#suggestions::-webkit-scrollbar-thumb {\r\n  background-color: #ccc;\r\n  border-radius: 3px;\r\n}\r\n\r\n\/* \u00c9l\u00e9ment dans la liste *\/\r\n#suggestions div {\r\n  padding: 8px;\r\n  cursor: pointer;\r\n}\r\n\r\n\/* Hover + s\u00e9lection clavier *\/\r\n#suggestions div:hover,\r\n#suggestions div.highlight {\r\n  background-color: #e0e0e0;\r\n  color: #222;\r\n  font-weight: 500;\r\n}\r\n\r\n\r\n\/* Blocs d'infos *\/\r\n.bloc {\r\n  background: white;\r\n  border: 1px solid #ddd;\r\n  border-left: 4px solid #1A5641;\r\n  border-radius: 12px;\r\n  padding: 20px;\r\n  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\r\n  margin: 20px auto;\r\n  display: none; \/* \u2705 \u00e0 ajouter ici *\/\r\n   max-width: 95vw; \/* \u2705 prend presque toute la largeur de l'\u00e9cran *\/\r\n  width: 100%;\r\n}\r\n\r\n#fiche-espece {\r\n  position: relative;\r\n  left: 50%;\r\n  transform: translateX(-50%);\r\n  width: 90vw;\r\n  max-width: min(90vw, 2000px); \/* \u2705 largeur fluide mais plafonn\u00e9e *\/\r\n  margin: 0;\r\n  padding: 0;\r\n  box-sizing: border-box;\r\n}\r\n\r\nh3 {\r\n  color: #1A5641;\r\n  border-bottom: 1px solid #eee;\r\n  padding-bottom: 5px;\r\n  margin-bottom: 15px;\r\n  text-transform: uppercase;\r\n}\r\n\r\n\r\n\/* =======================================================\r\n   \ud83d\udcca GRAPHIQUES + L\u00c9GENDES (VERSION PROPRE & RESPONSIVE)\r\n   ======================================================= *\/\r\n\r\n.charts-wrapper {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  justify-content: center;\r\n  align-items: flex-start;\r\n  gap: 30px;\r\n  margin-top: 20px;\r\n}\r\n\r\n\/* Bloc complet : 1 camembert + sa l\u00e9gende *\/\r\n.chart-block {\r\n  flex: 1 1 420px;\r\n  max-width: 520px;\r\n  width: 100%;\r\n  display: flex;\r\n  flex-direction: column;\r\n  align-items: center;\r\n}\r\n\r\n\/* Conteneur du graphique *\/\r\n.chart-container {\r\n  width: 100%;\r\n  max-width: 500px;\r\n  min-width: 0;\r\n  height: auto !important;\r\n  overflow: visible !important;\r\n}\r\n\r\n\/* =====================\r\n   \ud83c\udfaf L\u00c9GENDE CENTR\u00c9E\r\n   ===================== *\/\r\n\r\n.custom-legend {\r\n  width: 100%;\r\n  max-width: 500px;\r\n  display: flex;\r\n  flex-direction: column;\r\n  align-items: center;              \/* centre les lignes *\/\r\n  gap: 8px;\r\n  margin: 14px auto 0 auto;         \/* centre le bloc *\/\r\n  font-size: 0.95rem;\r\n  line-height: 1.4;\r\n  text-align: center;\r\n}\r\n\r\n.legend-item {\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;          \/* centre pastille + texte *\/\r\n  gap: 8px;\r\n  line-height: 1.3;\r\n  width: fit-content;               \/* \u00e9vite les lignes trop larges *\/\r\n  max-width: 100%;\r\n}\r\n\r\n.legend-color {\r\n  width: 14px;\r\n  height: 14px;\r\n  border-radius: 50%;\r\n  flex-shrink: 0;\r\n  border: 1px solid #ccc;\r\n}\r\n\r\n\/* =====================\r\n   \ud83d\udcf1 MOBILE\r\n   ===================== *\/\r\n\r\n@media (max-width: 768px) {\r\n\r\n  .charts-wrapper {\r\n    flex-direction: column !important;\r\n    align-items: stretch !important;\r\n    gap: 24px !important;\r\n  }\r\n\r\n  .chart-block {\r\n    max-width: 100% !important;\r\n    width: 100% !important;\r\n  }\r\n\r\n  .chart-container,\r\n  .custom-legend {\r\n    max-width: 100% !important;\r\n    width: 100% !important;\r\n  }\r\n\r\n  .custom-legend {\r\n    margin: 10px auto 0 auto;\r\n    padding: 0 4px;\r\n    font-size: 0.9rem;\r\n  }\r\n\r\n  .legend-item {\r\n    justify-content: center;\r\n  }\r\n}\r\n\r\n\/* Bo\u00eetes UICN *\/\r\n.uicn-boxes {\r\n  display: flex;\r\n  flex-wrap: nowrap;\r\n  overflow-x: auto;\r\n  gap: 10px;\r\n  margin-top: 20px;\r\n  padding-bottom: 5px;\r\n  justify-content: center;\r\n}\r\n\r\n.uicn-box {\r\n  padding: 10px 18px;\r\n  border-radius: 999px;\r\n  background-color: #e0e0e0;\r\n  color: white;\r\n  font-weight: bold;\r\n  text-align: center;\r\n  min-width: 60px;\r\n  text-transform: uppercase;\r\n  transform: scale(0.85);\r\n  transition: transform 0.3s ease, background-color 0.3s ease;\r\n  flex-shrink: 0;\r\n}\r\n\r\n.uicn-box.active {\r\n  transform: scale(1.1);\r\n}\r\n\r\n.uicn-box.active.uicn-EX { background-color: #000; }\r\n.uicn-box.active.uicn-EW { background-color: purple; }\r\n.uicn-box.active.uicn-CR { background-color: #e74c3c; }\r\n.uicn-box.active.uicn-EN { background-color: #e67e22; }\r\n.uicn-box.active.uicn-VU { background-color: #f1c40f; color: #000; }\r\n.uicn-box.active.uicn-NT { background-color: #a3e4a1; color: #000; }\r\n.uicn-box.active.uicn-LC { background-color: #006400; }\r\n.uicn-box.active.uicn-DD { background-color: #ccc; color: #000; }\r\n\r\n\/* Rythme, Habitat, etc. *\/\r\n.rythme-wrapper {\r\n  display: flex;\r\n  justify-content: center;\r\n  gap: 20px;\r\n  flex-wrap: wrap;\r\n  margin-top: 20px;\r\n}\r\n\r\n.rythme-box {\r\n  flex: 1 1 250px;\r\n  background-color: #ffffff;\r\n  border: 1px solid #ddd;\r\n  border-left: 4px solid #1A5641;\r\n  border-radius: 12px;\r\n  padding: 20px;\r\n  text-align: center;\r\n  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\r\n  min-width: 220px;\r\n}\r\n\r\n.rythme-box h4 {\r\n  margin-bottom: 10px;\r\n  color: #1A5641;\r\n  font-size: 1rem;\r\n  text-transform: uppercase;\r\n}\r\n\r\n.rythme-box .valeur {\r\n  font-size: 1.4rem;\r\n  font-weight: bold;\r\n  color: #222;\r\n}\r\n\r\n.rythme-liste {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  justify-content: center;\r\n  gap: 20px;\r\n  text-align: center;\r\n  margin-top: 20px;\r\n}\r\n\r\n.rythme-liste > div {\r\n  flex: 1 1 200px;\r\n  min-width: 180px;\r\n}\r\n\r\n.rythme-titre {\r\n  font-size: 0.9rem;\r\n  color: #1A5641;\r\n  font-weight: 500;\r\n  text-transform: uppercase;\r\n  margin-bottom: 5px;\r\n}\r\n\r\n.rythme-valeur {\r\n  font-size: 1.1rem;\r\n  font-weight: bold;\r\n  color: #222;\r\n}\r\n\r\n.rythme-source {\r\n  font-size: 0.75rem;\r\n  color: #666;\r\n  margin-top: 2px;\r\n  font-weight: normal;\r\n}\r\n\r\n.rythme-valeur-wrapper {\r\n  display: flex;\r\n  flex-direction: column;\r\n  align-items: center;\r\n  justify-content: center;\r\n}\r\n\r\n#suggestions:hover {\r\n  overscroll-behavior: contain;\r\n  touch-action: pan-y;\r\n}\r\n\r\n.taxonomy-tree {\r\n  margin-top: 20px;\r\n  margin-left: 20px;\r\n  display: flex;\r\n  flex-direction: column;\r\n  font-size: 15px;\r\n}\r\n\r\n.niveau {\r\n  display: flex;\r\n  align-items: center;\r\n  position: relative;\r\n  height: 20px;\r\n  margin-bottom: 0;\r\n}\r\n\r\n.branche.horizontale {\r\n  height: 2px;\r\n  background-color: #ccc;\r\n  flex-shrink: 0;\r\n  margin-right: 10px;\r\n}\r\n\r\n\/* Largeur des traits horizontaux et indentation par niveau *\/\r\n.niveau-1 .branche.horizontale { width: 30px; margin-left: 0px; }\r\n.niveau-2 .branche.horizontale { width: 30px; margin-left: 20px; }\r\n.niveau-3 .branche.horizontale { width: 30px; margin-left: 40px; }\r\n.niveau-4 .branche.horizontale { width: 30px; margin-left: 60px; }\r\n.niveau-5 .branche.horizontale { width: 30px; margin-left: 80px; }\r\n.niveau-6 .branche.horizontale { width: 30px; margin-left: 100px; }\r\n\r\n\/* Lignes verticales exactement align\u00e9es avec les horizontales *\/\r\n.branche.verticale {\r\n  width: 2px;\r\n  height: 20px;\r\n  background-color: #ccc;\r\n  margin-top: -2px;\r\n}\r\n\r\n\/* D\u00e9calage des lignes verticales pour qu\u2019elles tombent au bon endroit *\/\r\n.branche.verticale.niveau-1 { margin-left: 30px; }\r\n.branche.verticale.niveau-2 { margin-left: 50px; }\r\n.branche.verticale.niveau-3 { margin-left: 70px; }\r\n.branche.verticale.niveau-4 { margin-left: 90px; }\r\n.branche.verticale.niveau-5 { margin-left: 110px; }\r\n\r\n.taxonomy-tree .label { font-size: 15px; }\r\n\r\n.flag { font-size: 18px; margin-right: 8px; }\r\n\r\n#image-wiki-test img {\r\n  width: 100%;\r\n  max-width: 400px;\r\n  height: auto;\r\n  object-fit: cover;\r\n  border-radius: 12px;\r\n  display: block;\r\n  margin: 0 auto;\r\n}\r\n\r\n.bloc img {\r\n  max-width: 95vw;\r\n  display: block;\r\n}\r\n\r\n\/* \ud83d\udd12 Emp\u00eache d'autres images parasites dans les blocs *\/\r\n.bloc:not(#image-wiki-test) > img {\r\n  display: none !important;\r\n}\r\n\r\n.nom-fr-latin { text-align: center; margin-bottom: 10px; }\r\n.nom-fr { font-size: 1.4rem; font-weight: 600; color: #222; }\r\n.nom-latin { font-size: 1.1rem; font-style: italic; color: #555; margin-top: -5px; }\r\n\r\n\/* Titre centr\u00e9 au-dessus des deux colonnes *\/\r\n.nom-principal-global { text-align: center; margin-bottom: 30px; }\r\n.nom-principal-global .nom-fr { font-size: 1.8rem; font-weight: 700; color: #222; margin-bottom: 5px; }\r\n.nom-principal-global .nom-latin { font-size: 1.2rem; font-style: italic; color: #666; }\r\n\r\n\/* Colonnes *\/\r\n.intro-cols { display: flex; flex-wrap: wrap; align-items: center; gap: 30px; }\r\n\r\n.col-gauche {\r\n  flex: 1 1 350px;\r\n  max-width: 400px;\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n}\r\n\r\n.col-droite { flex: 2 1 500px; max-width: 700px; }\r\n\r\n\/* Titres noms *\/\r\n#nom-principal { text-align: center; margin-bottom: 30px; }\r\n\r\n#nom-principal .nom-fr {\r\n  font-size: 1.8rem;\r\n  font-weight: 700;\r\n  margin-bottom: 5px;\r\n  color: #222;\r\n}\r\n\r\n#nom-principal .nom-latin {\r\n  font-size: 1.2rem;\r\n  font-style: italic;\r\n  color: #666;\r\n}\r\n\r\n.morpho-wrapper {\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 30px;\r\n  align-items: flex-start;\r\n  margin-top: 20px;\r\n}\r\n\r\n.morpho-texte { flex: 1 1 300px; min-width: 250px; }\r\n\r\n.morpho-image {\r\n  flex: 1 1 500px;\r\n  min-width: 300px;\r\n  max-width: 700px;\r\n}\r\n\r\n.morpho-image img {\r\n  width: 100%;\r\n  height: auto;\r\n  border-radius: 12px;\r\n  box-shadow: 0 4px 12px rgba(0,0,0,0.08);\r\n  object-fit: contain;\r\n}\r\n\r\n@media print {\r\n  body { background: white !important; color: black !important; font-size: 12px; line-height: 1.4; }\r\n\r\n  #fiche-espece { max-width: 100% !important; padding: 0 !important; box-shadow: none !important; }\r\n\r\n  .intro-cols, .morpho-wrapper, .rythme-liste, .charts-wrapper {\r\n    flex-direction: column !important;\r\n    align-items: flex-start !important;\r\n    gap: 0 !important;\r\n  }\r\n\r\n  .col-gauche, .col-droite, .morpho-image, .morpho-texte, .rythme-box {\r\n    max-width: 100% !important;\r\n    width: 100% !important;\r\n    flex: none !important;\r\n  }\r\n\r\n  .chart-container { width: 100% !important; height: auto !important; }\r\n\r\n  .uicn-boxes { flex-wrap: wrap !important; justify-content: flex-start !important; }\r\n\r\n  #btn-export-pdf,\r\n  .elementor-location-footer,\r\n  .elementor-location-header { display: none !important; }\r\n}\r\n\r\n.print-mode * {\r\n  box-shadow: none !important;\r\n  background: white !important;\r\n  color: black !important;\r\n  font-size: 12px !important;\r\n  line-height: 1.4 !important;\r\n}\r\n\r\n.print-mode {\r\n  width: 100% !important;\r\n  max-width: 800px !important;\r\n  margin: 0 auto !important;\r\n  padding: 0 !important;\r\n  background: white !important;\r\n}\r\n\r\n.print-mode .intro-cols,\r\n.print-mode .charts-wrapper,\r\n.print-mode .rythme-liste,\r\n.print-mode .morpho-wrapper { display: block !important; }\r\n\r\n.print-mode .col-gauche,\r\n.print-mode .col-droite,\r\n.print-mode .morpho-image,\r\n.print-mode .morpho-texte {\r\n  width: 100% !important;\r\n  max-width: 100% !important;\r\n  display: block !important;\r\n  flex: none !important;\r\n}\r\n\r\n.print-mode .uicn-boxes { flex-wrap: wrap !important; justify-content: flex-start !important; }\r\n\r\n.print-mode canvas {\r\n  display: block !important;\r\n  margin: 20px auto !important;\r\n  max-width: 100% !important;\r\n  height: auto !important;\r\n}\r\n\r\n.print-mode img {\r\n  max-width: 100% !important;\r\n  height: auto !important;\r\n  object-fit: contain !important;\r\n}\r\n\r\n.print-mode h3 { font-size: 1.1rem !important; color: #1A5641 !important; margin-top: 30px; }\r\n\r\nbody::before {\r\n  content: \"\";\r\n  position: fixed;\r\n  top: 0;\r\n  left: 0;\r\n  width: 100vw;\r\n  height: 100vh;\r\n  background-image: url('https:\/\/fiches-especes.simonpotier.fr\/wp-content\/uploads\/2026\/02\/alan_frijns-tropical-7459826-scaled.jpg');\r\n  background-size: cover;\r\n  background-position: center;\r\n  background-repeat: no-repeat;\r\n  z-index: -1;\r\n  opacity: 0.5;\r\n}\r\n\r\n@media (max-width: 768px) {\r\n  .intro-cols,\r\n  .morpho-wrapper,\r\n  .rythme-liste,\r\n  .charts-wrapper {\r\n    flex-direction: column !important;\r\n    align-items: stretch !important;\r\n  }\r\n\r\n  .col-gauche,\r\n  .col-droite,\r\n  .morpho-image,\r\n  .morpho-texte,\r\n  .rythme-box,\r\n  .chart-container {\r\n    max-width: 100% !important;\r\n    flex: none !important;\r\n    width: 100% !important;\r\n  }\r\n\r\n  .chart-container { width: 100% !important; height: auto !important; max-width: 100% !important; }\r\n\r\n  .rythme-liste { gap: 5px !important; margin-top: 10px !important; padding: 0 !important; }\r\n  .rythme-liste > div { padding: 4px 0 !important; margin: 0 !important; min-height: unset !important; height: auto !important; flex: none !important; }\r\n\r\n  .rythme-titre { font-size: 0.75rem !important; margin-bottom: 2px !important; line-height: 1.1 !important; }\r\n  .rythme-valeur { font-size: 1rem !important; line-height: 1.2 !important; margin: 0 !important; }\r\n  .rythme-source { font-size: 0.65rem !important; margin-top: 0 !important; line-height: 1 !important; }\r\n\r\n  #search-espece input[type=\"text\"] { max-width: 90%; }\r\n\r\n  .uicn-boxes { flex-wrap: wrap !important; justify-content: center; }\r\n\r\n  .bloc { margin: 10px 10px; padding: 15px; }\r\n\r\n  .taxonomy-tree { margin-left: 5px; font-size: 14px; }\r\n\r\n  #image-wiki-test img { max-width: 100%; height: auto; }\r\n\r\n  .morpho-image { width: 100% !important; max-width: 100% !important; }\r\n  .morpho-image img { width: 100% !important; height: auto !important; object-fit: contain !important; }\r\n}\r\n\r\nhtml, body { overflow-x: hidden !important; max-width: 100% !important; }\r\n\r\n.bloc,\r\n.chart-container,\r\n.morpho-wrapper,\r\n.morpho-image,\r\n.morpho-image img,\r\n#image-wiki-test img,\r\ncanvas,\r\nimg {\r\n  max-width: 100% !important;\r\n  width: 100% !important;\r\n  box-sizing: border-box !important;\r\n  height: auto !important;\r\n  object-fit: contain !important;\r\n  overflow-x: hidden !important;\r\n}\r\n\r\n.chart-container,\r\n.morpho-image,\r\n.morpho-image img,\r\n#image-wiki-test img,\r\ncanvas,\r\nimg {\r\n  display: block !important;\r\n  width: 100% !important;\r\n  max-width: 100% !important;\r\n  height: auto !important;\r\n  object-fit: contain !important;\r\n}\r\n\r\n\/* \u2705 S'assurer que les blocs prennent la hauteur de leur contenu *\/\r\n.chart-container,\r\n.morpho-image {\r\n  height: auto !important;\r\n  min-height: auto !important;\r\n  overflow: visible !important;\r\n}\r\n\r\nhtml, body, .bloc, .charts-wrapper {\r\n  overflow-x: hidden !important;\r\n  overflow-y: visible !important;\r\n}\r\n\r\n.col-gauche { flex: 0 0 20%; max-width: 20%; }\r\n.col-milieu { flex: 0 0 30%; max-width: 30%; }\r\n.col-droite { flex: 0 0 45%; max-width: 45%; }\r\n\r\n#carte-distribution img {\r\n  width: 100%;\r\n  max-width: 100%;\r\n  height: auto;\r\n  border-radius: 12px;\r\n  box-shadow: 0 4px 12px rgba(0,0,0,0.08);\r\n}\r\n\r\n@media (max-width: 768px) {\r\n  .intro-cols { flex-direction: column !important; }\r\n  .col-gauche, .col-milieu, .col-droite {\r\n    max-width: 100% !important;\r\n    width: 100% !important;\r\n    flex: none !important;\r\n  }\r\n}\r\n\r\n#bloc-regime { overflow: visible !important; max-height: none !important; }\r\n#bloc-regime .charts-wrapper { overflow: visible !important; max-height: none !important; }\r\n#bloc-regime .chart-container { overflow: visible !important; max-height: none !important; }\r\n\r\n.custom-legend {\r\n  display: flex;\r\n  flex-direction: column;\r\n  gap: 6px;\r\n  margin-top: 10px;\r\n  font-size: 0.95rem;\r\n}\r\n\r\n.legend-item {\r\n  display: flex;\r\n  align-items: center;\r\n  line-height: 1.2;\r\n}\r\n\r\n.legend-color {\r\n  width: 14px;\r\n  height: 14px;\r\n  border-radius: 50%;\r\n  margin-right: 8px;\r\n  flex-shrink: 0;\r\n  border: 1px solid #ccc;\r\n}\r\n\r\n.uicn-bar-container {\r\n  position: relative;\r\n  width: 100%;\r\n  max-width: 1000px;\r\n  margin: 20px auto;\r\n}\r\n\r\n.uicn-bar-image {\r\n  width: 100%;\r\n  height: auto;\r\n  display: block;\r\n}\r\n\r\n.uicn-arrow {\r\n  position: absolute;\r\n  top: -5px;\r\n  width: 20px;\r\n  height: 20px;\r\n  z-index: 10;\r\n}\r\n\r\n.uicn-arrow-head {\r\n  position: absolute;\r\n  top: 0;\r\n  left: 0;\r\n  width: 0;\r\n  height: 0;\r\n  border-left: 10px solid transparent;\r\n  border-right: 10px solid transparent;\r\n  border-bottom: 15px solid black;\r\n  z-index: 2;\r\n}\r\n\r\n.uicn-arrow-bg {\r\n  position: absolute;\r\n  top: -5px;\r\n  left: -5px;\r\n  width: 20px;\r\n  height: 20px;\r\n  background: white;\r\n  border-radius: 4px;\r\n  z-index: 1;\r\n}\r\n\r\n.uicn-double-col {\r\n  display: flex;\r\n  flex-wrap: nowrap;\r\n  gap: 30px;\r\n  margin-top: 20px;\r\n  align-items: flex-start;\r\n  width: 100%;\r\n  box-sizing: border-box;\r\n}\r\n\r\n.uicn-col { box-sizing: border-box; }\r\n\r\n.uicn-gauche { flex: 0 0 75%; max-width: 75%; }\r\n.uicn-droite { flex: 0 0 25%; max-width: 25%; }\r\n\r\n.uicn-col h4 { font-size: 1.1rem; color: #1A5641; text-transform: uppercase; margin-bottom: 15px; }\r\n\r\n.uicn-droite p { margin-bottom: 15px; font-size: 1rem; }\r\n\r\n.annexes-ligne { display: flex; flex-direction: column; align-items: center; gap: 8px; }\r\n\r\n.annexes-labels,\r\n.annexes-valeurs {\r\n  display: flex;\r\n  justify-content: center;\r\n  align-items: center;\r\n  gap: 60px;\r\n  width: 100%;\r\n  text-align: center;\r\n}\r\n\r\n.annexes-labels span { font-weight: bold; text-align: center; color: #333; }\r\n.annexes-valeurs span { text-align: center; }\r\n\r\n\/* On r\u00e9affirme la couleur blanche pour les badges *\/\r\n.badge-eu,\r\n.badge-cites { color: white !important; }\r\n\r\n.badge-eu {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  width: 28px;\r\n  height: 28px;\r\n  border-radius: 50%;\r\n  font-size: 18px;\r\n  font-weight: 700;\r\n  color: white;\r\n  background-color: #ccc;\r\n  line-height: 1;\r\n  flex-shrink: 0;\r\n  flex-grow: 0;\r\n}\r\n\r\n\/* Couleurs par lettre *\/\r\n.badge-eu-a { background-color: #e74c3c; }\r\n.badge-eu-b { background-color: #f39c12; }\r\n.badge-eu-c { background-color: #4ECDC4; }\r\n.badge-eu-d { background-color: #8e44ad; }\r\n.badge-eu-na { background-color: #ccc; color: #666; }\r\n\r\n.annexes-valeurs span { flex: none; }\r\n\r\n.badge-cites {\r\n  display: inline-flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  width: 28px;\r\n  height: 28px;\r\n  border-radius: 50%;\r\n  font-size: 16px;\r\n  font-weight: 700;\r\n  color: #fff !important;\r\n  line-height: 1;\r\n  flex-shrink: 0;\r\n  flex-grow: 0;\r\n}\r\n\r\n\/* Couleurs par niveau *\/\r\n.badge-cites-i    { background-color: #c0392b; }\r\n.badge-cites-ii   { background-color: #d35400; }\r\n.badge-cites-iii  { background-color: #f1c40f; color: #000 !important; }\r\n.badge-cites-na   { background-color: #ccc; color: #666 !important; }\r\n\r\n@media (max-width: 768px) {\r\n  .uicn-double-col { flex-direction: column !important; align-items: stretch !important; gap: 20px !important; }\r\n  .uicn-col { max-width: 100% !important; width: 100% !important; flex: none !important; padding: 0 10px; box-sizing: border-box; }\r\n  .uicn-gauche, .uicn-centre, .uicn-droite { flex: none !important; max-width: 100% !important; width: 100% !important; text-align: center !important; }\r\n  .uicn-bar-container { max-width: 100% !important; margin: 0 auto !important; }\r\n  .annexes-labels, .annexes-valeurs { gap: 30px !important; }\r\n}\r\n\r\n.subfield { font-size: 0.75em; font-weight: 400; color: #4A403A; line-height: 1.4; }\r\n.subvalue { font-weight: 600; color: #000; }\r\n\r\n.morpho-texte p {\r\n  font-size: 1.1rem;\r\n  line-height: 1.3;\r\n  margin-bottom: 6px;\r\n  color: #333;\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n}\r\n\r\n.morpho-texte p strong {\r\n  font-weight: normal;\r\n  color: inherit;\r\n  min-width: 240px;\r\n  display: inline-block;\r\n}\r\n\r\n#bloc-noms p {\r\n  font-size: 1.1rem;\r\n  line-height: 1.6;\r\n  margin-bottom: 10px;\r\n  color: #333;\r\n  display: flex;\r\n  align-items: center;\r\n}\r\n\r\n#bloc-noms .flag {\r\n  font-size: 1.4rem;\r\n  margin-right: 12px;\r\n  flex-shrink: 0;\r\n}\r\n\r\n#bloc-noms h3 {\r\n  font-size: 1.2rem;\r\n  color: #1A5641;\r\n  margin-bottom: 15px;\r\n  text-transform: uppercase;\r\n}\r\n\r\n\/* =======================================================\r\n   \u2705 OVERLAY CHARGEMENT (ajout)\r\n   ======================================================= *\/\r\n#loading-overlay {\r\n  position: fixed;\r\n  inset: 0;\r\n  z-index: 999999;\r\n  background: rgba(20, 18, 16, 0.88);\r\n  backdrop-filter: blur(4px);\r\n  display: flex;\r\n  align-items: center;\r\n  justify-content: center;\r\n  padding: 20px;\r\n}\r\n#loading-card {\r\n  width: min(560px, 92vw);\r\n  background: rgba(255,255,255,0.95);\r\n  border-radius: 16px;\r\n  box-shadow: 0 10px 40px rgba(0,0,0,0.35);\r\n  padding: 22px 22px 18px 22px;\r\n  text-align: center;\r\n}\r\n#loading-title {\r\n  font-weight: 700;\r\n  font-size: 1.1rem;\r\n  margin-bottom: 10px;\r\n  color: #222;\r\n}\r\n#loading-progress-wrap {\r\n  width: 100%;\r\n  background: #eaeaea;\r\n  border-radius: 999px;\r\n  overflow: hidden;\r\n  height: 14px;\r\n  box-shadow: inset 0 1px 3px rgba(0,0,0,0.15);\r\n}\r\n#loading-progress-bar {\r\n  width: 0%;\r\n  height: 100%;\r\n  background: linear-gradient(90deg, #4ECDC4, #615241);\r\n  transition: width 0.25s ease;\r\n}\r\n#loading-percent { margin-top: 10px; font-weight: 700; color: #222; }\r\n#loading-funline { margin-top: 10px; font-size: 0.95rem; color: #444; min-height: 1.4em; }\r\n#loading-sub { margin-top: 10px; font-size: 0.85rem; color: #666; }\r\n.loading-hidden { display: none !important; }\r\n\r\n\r\n.infos-carte-distribution {\r\n  margin-top: 12px;\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  gap: 20px;\r\n  font-size: 1rem;\r\n  color: #444;\r\n  justify-content: center;\r\n}\r\n\r\n@media (max-width: 768px) {\r\n  .infos-carte-distribution {\r\n    flex-direction: column;\r\n    align-items: center;\r\n    text-align: center;\r\n    gap: 8px;\r\n  }\r\n\r\n  .infos-carte-distribution > div {\r\n    width: 100%;\r\n    text-align: center;\r\n  }\r\n}\r\n\r\n\r\n\/* ===== CARTE DISTRIBUTION ===== *\/\r\n#carte-distribution,\r\n.carte-distribution-wrap,\r\n.carte-image-wrap {\r\n  width: 100% !important;\r\n  max-width: 100% !important;\r\n  box-sizing: border-box !important;\r\n}\r\n\r\n.carte-image-wrap {\r\n  text-align: center;\r\n}\r\n\r\n.carte-image {\r\n  display: block !important;\r\n  width: 100% !important;\r\n  max-width: 100% !important;\r\n  height: auto !important;\r\n  margin: 0 auto !important;\r\n  border-radius: 12px;\r\n  box-shadow: 0 4px 12px rgba(0,0,0,0.08);\r\n}\r\n\r\n.carte-message {\r\n  color: #666;\r\n  font-style: italic;\r\n  text-align: center;\r\n  margin: 20px 0;\r\n}\r\n\r\n.infos-carte-distribution {\r\n  margin-top: 12px;\r\n  display: flex;\r\n  flex-wrap: wrap;\r\n  justify-content: center;\r\n  gap: 20px;\r\n  font-size: 1rem;\r\n  color: #444;\r\n  text-align: center;\r\n}\r\n\r\n.infos-carte-distribution > div {\r\n  text-align: center;\r\n}\r\n\r\n\/* ===== MOBILE ===== *\/\r\n@media (max-width: 768px) {\r\n  .intro-cols {\r\n    flex-direction: column !important;\r\n    gap: 20px !important;\r\n  }\r\n\r\n  .col-gauche,\r\n  .col-milieu,\r\n  .col-droite {\r\n    flex: 0 0 100% !important;\r\n    width: 100% !important;\r\n    max-width: 100% !important;\r\n  }\r\n\r\n  #carte-distribution {\r\n    width: 100% !important;\r\n    max-width: 100% !important;\r\n  }\r\n\r\n  .carte-distribution-wrap {\r\n    width: 100% !important;\r\n    max-width: 100% !important;\r\n  }\r\n\r\n  .carte-image-wrap {\r\n    width: 100% !important;\r\n    max-width: 100% !important;\r\n    margin: 0 !important;\r\n  }\r\n\r\n  .carte-image {\r\n    width: 100% !important;\r\n    max-width: 100% !important;\r\n  }\r\n\r\n  .infos-carte-distribution {\r\n    flex-direction: column !important;\r\n    align-items: center !important;\r\n    justify-content: center !important;\r\n    gap: 8px !important;\r\n    text-align: center !important;\r\n  }\r\n\r\n  .infos-carte-distribution > div {\r\n    width: 100% !important;\r\n    text-align: center !important;\r\n  }\r\n}\r\n\r\n\r\n.traits-climate-charts {\r\n  display: grid;\r\n  grid-template-columns: 1fr 1fr;\r\n  gap: 24px;\r\n  margin-top: 35px;\r\n  width: 100%;\r\n}\r\n\r\n.trait-chart-card {\r\n  background: #ffffff;\r\n  border-radius: 14px;\r\n  padding: 18px;\r\n  box-shadow: 0 4px 18px rgba(0,0,0,0.08);\r\n  min-height: 340px;\r\n}\r\n\r\n.trait-chart-card h4 {\r\n  margin: 0 0 15px;\r\n  color: #1A5641;\r\n  font-size: 16px;\r\n  font-weight: 700;\r\n  text-transform: uppercase;\r\n}\r\n\r\n.trait-chart-card canvas {\r\n  width: 100% !important;\r\n  height: 280px !important;\r\n}\r\n\r\n@media (max-width: 768px) {\r\n  .traits-climate-charts {\r\n    grid-template-columns: 1fr;\r\n  }\r\n}\r\n\r\n\r\n<\/style>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<!-- \u2705 Overlay de chargement (ajout) -->\r\n<div id=\"loading-overlay\" class=\"loading-hidden\" aria-live=\"polite\" aria-busy=\"true\">\r\n  <div id=\"loading-card\">\r\n    <div id=\"loading-title\">Pr\u00e9paration des fiches\u2026<\/div>\r\n    <div id=\"loading-progress-wrap\" role=\"progressbar\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"0\">\r\n      <div id=\"loading-progress-bar\"><\/div>\r\n    <\/div>\r\n    <div id=\"loading-percent\">0%<\/div>\r\n    <div id=\"loading-funline\">On apprivoise les donn\u00e9es\u2026<\/div>\r\n    <div id=\"loading-sub\">La recherche s\u2019active \u00e0 100%.<\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<!-- \u2705 Conteneur principal de toute la fiche -->\r\n<div id=\"fiche-espece\">\r\n\r\n  <!-- Bloc contenant image + infos -->\r\n  <div class=\"bloc\" id=\"bloc-intro-complet\">\r\n    <!-- Nom centr\u00e9 au-dessus -->\r\n    <div id=\"nom-principal\" class=\"nom-principal-global\"><\/div>\r\n\r\n    <!-- Colonnes c\u00f4te \u00e0 c\u00f4te -->\r\n    <div class=\"intro-cols\">\r\n      <div class=\"col-gauche\">\r\n        <div id=\"image-wiki-test\" style=\"overflow: hidden; display: none;\"><\/div>\r\n      <\/div>\r\n      <div class=\"col-milieu\">\r\n        <div id=\"bloc-noms\"><\/div>\r\n        <div id=\"bloc-classification\"><\/div>\r\n      <\/div>\r\n      <div class=\"col-droite\">\r\n        <div id=\"carte-distribution\"><\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div> <!-- Fin bloc intro -->\r\n\r\n  <div class=\"bloc\" id=\"bloc-uicn\"><\/div>\r\n  <div class=\"bloc\" id=\"bloc-regime\"><\/div>\r\n  <div class=\"bloc\" id=\"bloc-rythme\"><\/div>\r\n  <div class=\"bloc\" id=\"morpho-mesures\"><\/div>\r\n\r\n<\/div> <!-- Fermeture de #fiche-espece -->\r\n\r\n<script>\r\n  \/\/ Injecte le viewport si absent\r\n  if (!document.querySelector('meta[name=\"viewport\"]')) {\r\n    const meta = document.createElement('meta');\r\n    meta.name = \"viewport\";\r\n    meta.content = \"width=device-width, initial-scale=1\";\r\n    document.head.appendChild(meta);\r\n  }\r\n<\/script>\r\n\r\n<script>\r\ndocument.addEventListener('DOMContentLoaded', function () {\r\n\r\n  \/\/ =======================\r\n  \/\/ \ud83d\udd01 Traductions UICN\r\n  \/\/ =======================\r\n  function traduireCategorieUICN(valeur) {\r\n    const map = {\r\n      'EX': '\u00c9teint',\r\n      'EW': '\u00c9teint dans la nature',\r\n      'CR': 'En danger critique',\r\n      'EN': 'En danger',\r\n      'VU': 'Vuln\u00e9rable',\r\n      'NT': 'Quasi menac\u00e9e',\r\n      'LC': 'Pr\u00e9occupation mineure',\r\n      'DD': 'Donn\u00e9es insuffisantes',\r\n      'NA': 'Inconnu'\r\n    };\r\n    return map[valeur?.toUpperCase()] || 'Inconnu';\r\n  }\r\n\r\nfunction traduireTendancePopulation(valeur) {\r\n  if (!valeur) return 'Inconnue';\r\n\r\n  const clean = valeur\r\n    .toString()\r\n    .normalize(\"NFD\")\r\n    .replace(\/[\\u0300-\\u036f]\/g, \"\")\r\n    .replace(\/[\\r\\n\\t]\/g, \"\")\r\n    .trim()\r\n    .toUpperCase();\r\n\r\n  console.log(\"Nettoy\u00e9 :\", clean); \/\/ debug\r\n\r\n  const map = {\r\n    'DECREASING': 'En baisse',\r\n    'INCREASING': 'En hausse',\r\n    'STABLE': 'Stable',\r\n    'UNKNOWN': 'Inconnue',\r\n    'NA': 'Inconnue'\r\n  };\r\n\r\n  return map[clean] || 'Inconnue';\r\n}\r\n\r\n\r\n\r\n  const input = document.querySelector('#search-espece input[type=\"text\"]');\r\n  const suggestionBox = document.createElement('div');\r\n  suggestionBox.id = 'suggestions';\r\n  document.getElementById('search-espece').appendChild(suggestionBox);\r\n\r\n  const loadingInfo = document.createElement('div');\r\n  loadingInfo.id = 'chargement-especes';\r\n  loadingInfo.style.textAlign = 'center';\r\n  loadingInfo.style.marginTop = '8px';\r\n  loadingInfo.style.fontSize = '14px';\r\n  loadingInfo.style.color = '#ffffff';\r\n  loadingInfo.style.textShadow = '0 1px 3px rgba(0,0,0,0.6)';\r\n  document.getElementById('search-espece').appendChild(loadingInfo);\r\n\r\n  function removeDiacritics(str) {\r\n    return str.normalize(\"NFD\").replace(\/[\\u0300-\\u036f]\/g, \"\").toLowerCase();\r\n  }\r\n\r\n  function decodeTexte(str) {\r\n    const textarea = document.createElement('textarea');\r\n    textarea.innerHTML = str;\r\n    return textarea.value;\r\n  }\r\n\r\n  \/\/ Emp\u00eache le scroll de la page quand on scroll dans la liste\r\n  suggestionBox.addEventListener('wheel', function (e) {\r\n    if (\r\n      (e.deltaY > 0 && suggestionBox.scrollTop + suggestionBox.clientHeight < suggestionBox.scrollHeight) ||\r\n      (e.deltaY < 0 && suggestionBox.scrollTop > 0)\r\n    ) {\r\n      e.stopPropagation();\r\n    }\r\n  }, { passive: true });\r\n\r\n  const blocs = {\r\n    noms: document.getElementById('bloc-noms'),\r\n    classification: document.getElementById('bloc-classification'),\r\n    uicn: document.getElementById('bloc-uicn'),\r\n    rythme: document.getElementById('bloc-rythme'),\r\n    regime: document.getElementById('bloc-regime'),\r\n    reproduction: null,\r\n    morpho: document.getElementById('morpho-mesures'),\r\n    image: document.getElementById('image-wiki-test')\r\n  };\r\n\r\n  let fuse;\r\n  let donneesCSV = [];\r\n\r\n  \/\/ =======================================================\r\n  \/\/ \u2705 Overlay + phrases lentes (ind\u00e9pendantes du %)\r\n  \/\/ =======================================================\r\n  const overlay = document.getElementById('loading-overlay');\r\n  const bar = document.getElementById('loading-progress-bar');\r\n  const pctEl = document.getElementById('loading-percent');\r\n  const funEl = document.getElementById('loading-funline');\r\n  const progressWrap = document.getElementById('loading-progress-wrap');\r\n\r\n  const funLines = [\r\n    \"Chargement de la taille du bec\u2026 (\u00e7a picote un peu).\",\r\n    \"R\u00e9cup\u00e9ration de la couleur des plumes\u2026 nuancier valid\u00e9 par un paon.\",\r\n    \"Synchronisation des chants\u2026 volume \u00e0 11.\",\r\n    \"Indexation des esp\u00e8ces\u2026 elles se poussent dans la file.\",\r\n    \"Pr\u00e9paration des cartes de distribution\u2026 sans perdre le Nord.\",\r\n    \"On nourrit le moteur de recherche\u2026 avec des graines de donn\u00e9es.\",\r\n    \"V\u00e9rification des migrations\u2026 escales non incluses.\",\r\n    \"Derniers r\u00e9glages\u2026 on compte les plumes une par une.\"\r\n  ];\r\n\r\n  let funTimer = null;\r\n  let lastFunPick = -1;\r\n\r\n  function pickFunLine() {\r\n    if (!funEl) return;\r\n    let idx = Math.floor(Math.random() * funLines.length);\r\n    if (idx === lastFunPick) idx = (idx + 1) % funLines.length;\r\n    lastFunPick = idx;\r\n    funEl.textContent = funLines[idx];\r\n  }\r\n\r\n  function startFunRotation() {\r\n    stopFunRotation();\r\n    pickFunLine();\r\n    funTimer = setInterval(() => pickFunLine(), 2500); \/\/ \u2705 cadence lisible\r\n  }\r\n\r\n  function stopFunRotation() {\r\n    if (funTimer) { clearInterval(funTimer); funTimer = null; }\r\n  }\r\n\r\n  function setSearchEnabled(enabled) {\r\n    if (!input) return;\r\n    input.disabled = !enabled;\r\n    if (!enabled) suggestionBox.innerHTML = '';\r\n  }\r\n\r\n  function showOverlay() {\r\n    overlay.classList.remove('loading-hidden');\r\n    overlay.setAttribute('aria-busy', 'true');\r\n    setSearchEnabled(false);\r\n    startFunRotation();\r\n  }\r\n\r\n  function hideOverlay() {\r\n    overlay.classList.add('loading-hidden');\r\n    overlay.setAttribute('aria-busy', 'false');\r\n    setSearchEnabled(true);\r\n    stopFunRotation();\r\n  }\r\n\r\n  function setProgress(pct) {\r\n    const p = Math.max(0, Math.min(100, Math.round(pct)));\r\n    if (bar) bar.style.width = p + '%';\r\n    if (pctEl) pctEl.textContent = p + '%';\r\n    if (progressWrap) progressWrap.setAttribute('aria-valuenow', String(p));\r\n    if (loadingInfo) loadingInfo.textContent = p < 100 ? `Chargement : ${p}%` : '';\r\n  }\r\n\r\n  \/\/ =======================================================\r\n  \/\/ \u2705 Chargement API (ton code conserv\u00e9, avec overlay)\r\n  \/\/ =======================================================\r\n  async function loadDataFromApi() {\r\n    showOverlay();\r\n    setProgress(0);\r\n\r\n    \/\/ \u26a0\ufe0f requis : window.FICHES_API inject\u00e9 par le shortcode [fiches_rest_nonce]\r\n    if (!window.FICHES_API || !window.FICHES_API.restUrl || !window.FICHES_API.nonce) {\r\n      console.error(\"FICHES_API absent (restUrl\/nonce). Assure-toi que [fiches_rest_nonce] est pr\u00e9sent sur la page (widget Shortcode) et plac\u00e9 au-dessus du widget HTML.\");\r\n      if (funEl) funEl.textContent = \"API introuvable\u2026 impossible de charger les oiseaux.\";\r\n      return;\r\n    }\r\n\r\n    \/\/ ---- 1) Charger l'INDEX l\u00e9ger ----\r\n    const indexPerPage = 2000;\r\n    let indexPage = 1;\r\n    let indexTotal = null;\r\n    let indexLoaded = 0;\r\n    let indexAll = [];\r\n\r\n    while (true) {\r\n      const urlIndex = window.FICHES_API.restUrl + `fiches\/v1\/index?page=${indexPage}&per_page=${indexPerPage}`;\r\n\r\n      let resp;\r\n      try {\r\n        resp = await fetch(urlIndex, {\r\n          method: 'GET',\r\n          credentials: 'same-origin',\r\n          headers: {\r\n            'Accept': 'application\/json',\r\n            'X-WP-Nonce': window.FICHES_API.nonce\r\n          }\r\n        });\r\n      } catch (e) {\r\n        console.error(\"Erreur r\u00e9seau fetch INDEX:\", e);\r\n        if (funEl) funEl.textContent = \"Connexion capricieuse\u2026\";\r\n        return;\r\n      }\r\n\r\n      if (!resp.ok) {\r\n        const rawErr = await resp.text().catch(() => '');\r\n        console.error(\"API index error HTTP\", resp.status, rawErr);\r\n        if (funEl) funEl.textContent = \"Erreur serveur sur l\u2019index\u2026\";\r\n        return;\r\n      }\r\n\r\n      let json;\r\n      try {\r\n        json = await resp.json();\r\n      } catch (e) {\r\n        console.error(\"API index JSON parse error:\", e);\r\n        if (funEl) funEl.textContent = \"Index illisible\u2026\";\r\n        return;\r\n      }\r\n\r\n      const items = Array.isArray(json?.items) ? json.items : [];\r\n      if (typeof json?.total === 'number') indexTotal = json.total;\r\n\r\n      indexAll = indexAll.concat(items);\r\n      indexLoaded += items.length;\r\n\r\n      \/\/ 0 -> 30%\r\n      if (indexTotal && indexTotal > 0) {\r\n        const pctIndex = (indexLoaded \/ indexTotal) * 30;\r\n        setProgress(pctIndex);\r\n      } else {\r\n        setProgress(Math.min(30, indexPage * 5));\r\n      }\r\n\r\n      if (items.length < indexPerPage) break;\r\n      indexPage++;\r\n      if (indexPage > 2000) break;\r\n    }\r\n\r\n    \/\/ Index -> donn\u00e9es\r\n    donneesCSV = (indexAll || []).filter(ligne => (ligne.french || '').trim());\r\n\r\n    donneesCSV = donneesCSV.map(ligne => ({\r\n      ...ligne,\r\n      search_normalized: [\r\n        ligne.french,\r\n        ligne.scientific,\r\n        ligne.latin,\r\n        ligne.english2,\r\n        ligne.spanish,\r\n        ligne.german\r\n      ]\r\n        .filter(Boolean)\r\n        .map(removeDiacritics)\r\n        .join(' ')\r\n    }));\r\n\r\n    \/\/ \u2705 On ne rend PAS la recherche active ici : on attend 100%\r\n    fuse = new Fuse(donneesCSV, {\r\n      keys: ['search_normalized'],\r\n      threshold: 0.4\r\n    });\r\n\r\n    setProgress(30);\r\n\r\n    \/\/ ---- 2) Charger le DATA complet ----\r\n    const perPage = 200;\r\n    let page = 1;\r\n    let total = indexTotal;\r\n    let loaded = 0;\r\n    let allItems = [];\r\n\r\n    while (true) {\r\n      const url = window.FICHES_API.restUrl + `fiches\/v1\/data?page=${page}&per_page=${perPage}`;\r\n\r\n      let resp;\r\n      try {\r\n        resp = await fetch(url, {\r\n          method: 'GET',\r\n          credentials: 'same-origin',\r\n          headers: {\r\n            'Accept': 'application\/json',\r\n            'X-WP-Nonce': window.FICHES_API.nonce\r\n          }\r\n        });\r\n      } catch (e) {\r\n        console.error(\"Erreur r\u00e9seau fetch DATA:\", e);\r\n        if (funEl) funEl.textContent = \"Erreur r\u00e9seau\u2026\";\r\n        return;\r\n      }\r\n\r\n      if (!resp.ok) {\r\n        const rawErr = await resp.text().catch(() => '');\r\n        console.error(\"API data error HTTP\", resp.status, rawErr);\r\n        if (funEl) funEl.textContent = \"Erreur serveur sur les donn\u00e9es\u2026\";\r\n        return;\r\n      }\r\n\r\n      let json;\r\n      try {\r\n        json = await resp.json();\r\n      } catch (e) {\r\n        console.error(\"API data JSON parse error:\", e);\r\n        if (funEl) funEl.textContent = \"Donn\u00e9es illisibles\u2026\";\r\n        return;\r\n      }\r\n\r\n      const items = Array.isArray(json?.items) ? json.items : [];\r\n      if (typeof json?.total === 'number') total = json.total;\r\n\r\n      allItems = allItems.concat(items);\r\n      loaded += items.length;\r\n\r\n      \/\/ 30 -> 100\r\n      if (total && total > 0) {\r\n        const pctFull = 30 + (loaded \/ total) * 70;\r\n        setProgress(pctFull);\r\n      } else {\r\n        setProgress(Math.min(99, 30 + page));\r\n      }\r\n\r\n      if (items.length < perPage) break;\r\n      page++;\r\n      if (page > 5000) break;\r\n    }\r\n\r\n    \/\/ Upgrade dataset complet\r\n    donneesCSV = (allItems || []).filter(ligne => (ligne.french || '').trim());\r\n\r\n    donneesCSV = donneesCSV.map(ligne => ({\r\n      ...ligne,\r\n      search_normalized: [\r\n        ligne.french,\r\n        ligne.scientific,\r\n        ligne.latin,\r\n        ligne.english2,\r\n        ligne.spanish,\r\n        ligne.german\r\n      ]\r\n        .filter(Boolean)\r\n        .map(removeDiacritics)\r\n        .join(' ')\r\n    }));\r\n\r\n    fuse = new Fuse(donneesCSV, {\r\n      keys: ['search_normalized'],\r\n      threshold: 0.4\r\n    });\r\n\r\n    setProgress(100);\r\n\r\n    \/\/ \u2705 Activer recherche + masquer overlay\r\n    setTimeout(() => {\r\n      hideOverlay();\r\n      if (loadingInfo) loadingInfo.textContent = '';\r\n      chargerEspeceDepuisURL();\r\n    }, 350);\r\n  }\r\n\r\n  \/\/ Lance le chargement\r\n  loadDataFromApi();\r\n\r\n  \/\/ =======================================================\r\n  \/\/ \u2705 TON afficherEspece COMPLET (restaur\u00e9 int\u00e9gralement)\r\n  \/\/ =======================================================\r\n  function afficherEspece(espece) {\r\n    const blocIntro = document.getElementById('bloc-intro-complet');\r\n    if (blocIntro) blocIntro.style.display = 'block';\r\n\r\n    \/\/ Afficher tous les blocs disponibles\r\n    Object.values(blocs).forEach(b => {\r\n      if (b) b.style.display = 'block';\r\n    });\r\n\r\n    \/\/ \ud83c\udff7\ufe0f Bloc #nom-principal (nom FR + latin)\r\n    const nomPrincipal = document.getElementById('nom-principal');\r\n    if (nomPrincipal) {\r\n      nomPrincipal.innerHTML = `\r\n        <div class=\"nom-fr\">${espece.french || '\u2013'}<\/div>\r\n        <div class=\"nom-latin\"><em>${espece.latin || '\u2013'}<\/em><\/div>\r\n      `;\r\n    }\r\n\r\n    \/\/ \ud83c\udf0d Bloc des noms (anglais, espagnol, allemand)\r\n    blocs.noms.innerHTML = `\r\n      <h3>Noms<\/h3>\r\n      <p><span class=\"flag\">\ud83c\uddec\ud83c\udde7<\/span> ${espece.english2 || '\u2013'}<\/p>\r\n      <p><span class=\"flag\">\ud83c\uddea\ud83c\uddf8<\/span> ${espece.spanish || '\u2013'}<\/p>\r\n      <p><span class=\"flag\">\ud83c\udde9\ud83c\uddea<\/span> ${espece.german || '\u2013'}<\/p>\r\n    `;\r\n\r\n    \/\/ \ud83d\udcf7 Image Wikipedia\r\n    const nomLatin = espece.latin?.trim().replace(\/_\/g, ' ');\r\n    const imageTest = document.getElementById('image-wiki-test');\r\n\r\n    if (nomLatin) {\r\n      const wikiApiUrl = `https:\/\/en.wikipedia.org\/w\/api.php?action=query&format=json&formatversion=2&origin=*&prop=pageimages&piprop=original|thumbnail&pithumbsize=800&redirects=1&titles=${encodeURIComponent(nomLatin)}`;\r\n\r\n      fetch(wikiApiUrl)\r\n        .then(res => res.json())\r\n        .then(data => {\r\n          const page = data?.query?.pages?.[0];\r\n\r\n          if (page?.original?.source || page?.thumbnail?.source) {\r\n            const imgUrl = page.original?.source || page.thumbnail?.source;\r\n\r\n            if (imageTest) {\r\n              imageTest.style.display = 'block';\r\n              imageTest.innerHTML = `\r\n                <img decoding=\"async\" \r\n                  src=\"${imgUrl}\" \r\n                  alt=\"Image Wikip\u00e9dia\"\r\n                  style=\"width: 100%; height: auto; object-fit: cover; display: block;\"\r\n                >\r\n              `;\r\n            }\r\n          } else {\r\n            console.warn(\"Aucune image trouv\u00e9e pour :\", nomLatin);\r\n            if (imageTest) {\r\n              imageTest.style.display = 'block';\r\n              imageTest.innerHTML = `<p style=\"color:#888\">Aucune image trouv\u00e9e pour <em>${nomLatin}<\/em><\/p>`;\r\n            }\r\n          }\r\n        })\r\n        .catch(err => {\r\n          console.error(\"Erreur lors du fetch Wikipedia :\", err);\r\n          if (imageTest) {\r\n            imageTest.style.display = 'block';\r\n            imageTest.innerHTML = `<p style=\"color:red\">Erreur lors du chargement de l\u2019image.<\/p>`;\r\n          }\r\n        });\r\n    } else {\r\n      console.warn(\"Nom latin vide, recherche d\u2019image impossible.\");\r\n      if (imageTest) {\r\n        imageTest.style.display = 'block';\r\n        imageTest.innerHTML = `<p style=\"color:#888\">Nom latin manquant \u2013 pas de recherche d\u2019image possible.<\/p>`;\r\n      }\r\n    }\r\n\r\n    const ordre = espece.iocorder || 'Ordre inconnu';\r\n    const famille = espece.blfamily || espece.blfamilylatin || 'Famille inconnue';\r\n\r\nconst carteDistributionHTML = (() => {\r\n  const nomCarte = espece.latin?.trim().replace(\/\\s+\/g, '_');\r\n  const urlCarte = `https:\/\/fiches-especes.simonpotier.fr\/cartes\/${nomCarte}.jpg`;\r\n\r\n  const latitudeIndice = espece.Latitude ? parseInt(espece.Latitude) : null;\r\n  const altMin = espece.Altitudemin ? parseInt(espece.Altitudemin) : null;\r\n  const altMax = espece.Altitudemax ? parseInt(espece.Altitudemax) : null;\r\n\r\n  const latitudeLabels = {\r\n    1: \"Tropicale\",\r\n    2: \"Tropicale \u00e0 temp\u00e9r\u00e9e\",\r\n    3: \"Temp\u00e9r\u00e9e\",\r\n    4: \"Temp\u00e9r\u00e9e \u00e0 polaire\",\r\n    5: \"Tropicale \u00e0 polaire\"\r\n  };\r\n\r\n  const latDisplay = latitudeLabels[latitudeIndice] || '\u2013';\r\n  const altDisplay = (!isNaN(altMin) && !isNaN(altMax)) ? `${altMin}\u2013${altMax} m` : '\u2013';\r\n\r\n  return `\r\n    <div class=\"carte-distribution-wrap\">\r\n      <h3>Carte de distribution<\/h3>\r\n\r\n      <div class=\"carte-image-wrap\">\r\n        <img decoding=\"async\" \r\n          src=\"${urlCarte}\" \r\n          alt=\"\"\r\n          class=\"carte-image\"\r\n          onerror=\"this.style.display='none'; this.insertAdjacentHTML('afterend', '<p class=&quot;carte-message&quot;>Carte prochainement disponible<\/p>');\"\r\n        >\r\n      <\/div>\r\n\r\n      <div class=\"infos-carte-distribution\">\r\n        <div><strong>R\u00e9gion :<\/strong> ${latDisplay}<\/div>\r\n        <div><strong>Altitude moyenne :<\/strong> ${altDisplay}<\/div>\r\n      <\/div>\r\n    <\/div>\r\n  `;\r\n})();\r\n\r\n    \/\/ --- bloc classification (colonne milieu) ---\r\n    blocs.classification.innerHTML = `\r\n      <h3 style=\"margin-top: 40px;\">Classification<\/h3>\r\n      <div class=\"taxonomy-tree\">\r\n        <div class=\"niveau niveau-1\">\r\n          <div class=\"branche horizontale\"><\/div>\r\n          <div class=\"label\"><strong>R\u00e8gne<\/strong> : Animalia<\/div>\r\n        <\/div>\r\n        <div class=\"branche verticale niveau-1\"><\/div>\r\n\r\n        <div class=\"niveau niveau-2\">\r\n          <div class=\"branche horizontale\"><\/div>\r\n          <div class=\"label\"><strong>Embranchement<\/strong> : Chordata<\/div>\r\n        <\/div>\r\n        <div class=\"branche verticale niveau-2\"><\/div>\r\n\r\n        <div class=\"niveau niveau-3\">\r\n          <div class=\"branche horizontale\"><\/div>\r\n          <div class=\"label\"><strong>Sous-embranchement<\/strong> : Vertebrata<\/div>\r\n        <\/div>\r\n        <div class=\"branche verticale niveau-3\"><\/div>\r\n\r\n        <div class=\"niveau niveau-4\">\r\n          <div class=\"branche horizontale\"><\/div>\r\n          <div class=\"label\"><strong>Classe<\/strong> : Aves<\/div>\r\n        <\/div>\r\n        <div class=\"branche verticale niveau-4\"><\/div>\r\n\r\n        <div class=\"niveau niveau-5\">\r\n          <div class=\"branche horizontale\"><\/div>\r\n          <div class=\"label\"><strong>Ordre<\/strong> : ${espece.iocorder || '\u2013'}<\/div>\r\n        <\/div>\r\n        <div class=\"branche verticale niveau-5\"><\/div>\r\n\r\n        <div class=\"niveau niveau-6\">\r\n          <div class=\"branche horizontale\"><\/div>\r\n          <div class=\"label\"><strong>Famille<\/strong> : ${espece.blfamily || espece.blfamilylatin || '\u2013'}<\/div>\r\n        <\/div>\r\n      <\/div>\r\n    `;\r\n\r\n    \/\/ Carte distribution\r\n    document.getElementById('carte-distribution').innerHTML = carteDistributionHTML;\r\n    document.getElementById('carte-distribution').style.display = 'block';\r\n\r\n    const categorieUICN = traduireCategorieUICN(espece.redlistcategory);\r\n\r\n    function getPoidsSexe(espece) {\r\n      const parse = v => {\r\n        if (v === undefined || v === null) return NaN;\r\n        const s = v.toString().trim();\r\n        if (!s || s === '#N\/A') return NaN;\r\n        return parseFloat(s.replace(',', '.'));\r\n      };\r\n\r\n      const femMin  = parse(espece.FemaleMinMass);\r\n      const femMax  = parse(espece.FemaleMaxMass);\r\n      const maleMin = parse(espece.MaleMinMass);\r\n      const maleMax = parse(espece.MaleMaxMass);\r\n      const unsMin  = parse(espece.UnsexedMinMass);\r\n      const unsMax  = parse(espece.UnsexedMaxMass);\r\n\r\n      const format = (min, max) => `${min}\u2013${max} g`;\r\n\r\n      const hasFemComplete  = !isNaN(femMin)  && !isNaN(femMax);\r\n      const hasMaleComplete = !isNaN(maleMin) && !isNaN(maleMax);\r\n\r\n      if (hasFemComplete && hasMaleComplete) {\r\n        return `\u2640 ${format(femMin, femMax)}<br>\u2642 ${format(maleMin, maleMax)}`;\r\n      }\r\n\r\n      const hasUnsexedComplete = !isNaN(unsMin) && !isNaN(unsMax);\r\n      if (hasUnsexedComplete) {\r\n        return format(unsMin, unsMax);\r\n      }\r\n\r\n      const poidsBrut = parse(espece.poids);\r\n      if (isNaN(poidsBrut)) return '\u2013';\r\n\r\n      if (poidsBrut < 1000) return Math.round(poidsBrut) + ' g';\r\n      return (Math.round(poidsBrut \/ 10) \/ 100).toFixed(2) + ' kg';\r\n    }\r\n\r\n    blocs.rythme.innerHTML = `\r\n  <h3>Traits fonctionnels<\/h3>\r\n\r\n  <div class=\"rythme-liste\">\r\n    <div>\r\n      <div class=\"rythme-titre\">RYTHME CIRCADIEN<\/div>\r\n      <div class=\"rythme-valeur\">${espece.rythme_circadien || '\u2013'}<\/div>\r\n    <\/div>\r\n\r\n    <div>\r\n      <div class=\"rythme-titre\">HABITAT<\/div>\r\n      <div class=\"rythme-valeur-wrapper\">\r\n        <div class=\"rythme-valeur\">${espece.habitat || '\u2013'}<\/div>\r\n        ${\r\n          (() => {\r\n            const detail = espece.habitat_detaille?.trim();\r\n            return detail && detail !== '#N\/A'\r\n              ? `<div class=\"rythme-source\">${detail}<\/div>`\r\n              : '';\r\n          })()\r\n        }\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div>\r\n      <div class=\"rythme-titre\">MIGRATION<\/div>\r\n      <div class=\"rythme-valeur\">${espece.migration || '\u2013'}<\/div>\r\n    <\/div>\r\n\r\n    <div>\r\n      <div class=\"rythme-titre\">SOCIALIT\u00c9<\/div>\r\n      <div class=\"rythme-valeur\">\r\n        ${(() => {\r\n          const socialMap = {\r\n            Social_1: \"Esp\u00e8ce coloniale\",\r\n            Social_2: \"Esp\u00e8ce sociale\",\r\n            Social_3: \"Esp\u00e8ce vivant en couple ou groupes familiaux\",\r\n            Social_4: \"Esp\u00e8ce vivant seule ou en couple\",\r\n            Social_5: \"Esp\u00e8ce vivant seule\",\r\n            Social_6: \"Esp\u00e8ce avec syst\u00e8me de lek\"\r\n          };\r\n\r\n          const valeurs = Object.entries(socialMap)\r\n            .filter(([col]) => espece[col] === \"1\" || espece[col] === 1)\r\n            .map(([_, label]) => label);\r\n\r\n          return valeurs.length > 0 ? valeurs.join(\", \") : \"\u2013\";\r\n        })()}\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div>\r\n      <div class=\"rythme-titre\">POIDS<\/div>\r\n      <div class=\"rythme-valeur\">${getPoidsSexe(espece)}<\/div>\r\n    <\/div>\r\n\r\n    <div>\r\n      <div class=\"rythme-titre\">LONG\u00c9VIT\u00c9<\/div>\r\n      <div class=\"rythme-valeur-wrapper\">\r\n        <div class=\"rythme-valeur\">\r\n          ${(() => {\r\n            const val = parseFloat(espece.longevity?.replace(',', '.'));\r\n            return isNaN(val) ? '\u2013' : Math.ceil(val) + ' ans';\r\n          })()}\r\n        <\/div>\r\n        ${(() => {\r\n          const source = (espece.source || '').toLowerCase();\r\n          if (source === 'wild') return '<div class=\"rythme-source\">\u00c9tat naturel<\/div>';\r\n          if (source === 'captivity') return '<div class=\"rythme-source\">En captivit\u00e9<\/div>';\r\n          if (source === 'unknown') return '<div class=\"rythme-source\">Inconnu<\/div>';\r\n          if (source === 'na' || source === '#n\/a') return '';\r\n          return source ? `<div class=\"rythme-source\">${source}<\/div>` : '';\r\n        })()}\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div class=\"traits-climate-charts\">\r\n    <div class=\"trait-chart-card\">\r\n      <h4>Niche thermique<\/h4>\r\n      <canvas id=\"temperatureChart\"><\/canvas>\r\n    <\/div>\r\n\r\n    <div class=\"trait-chart-card\">\r\n      <h4>Niche d\u2019aridit\u00e9<\/h4>\r\n      <canvas id=\"aridityChart\"><\/canvas>\r\n    <\/div>\r\n  <\/div>\r\n`;\r\n\r\ncreateClimateCharts(espece);\r\n\r\n    const statutUICN = categorieUICN;\r\n\r\n    const positionsUICN = {\r\n      'Donn\u00e9es insuffisantes': 10.55,\r\n      'Pr\u00e9occupation mineure': 23.69,\r\n      'Quasi menac\u00e9e': 36.84,\r\n      'Vuln\u00e9rable': 49.99,\r\n      'En danger': 63.14,\r\n      'En danger critique': 76.29,\r\n      '\u00c9teint dans la nature': 89.43\r\n    };\r\n\r\n    const largeurCategorie = 13.14;\r\n    const positionPercent = positionsUICN[statutUICN] || 0;\r\n\r\n    function getEULabel(value) {\r\n      if (!value || value === '#N\/A') return '\u2013';\r\n      return value.trim().charAt(0).toUpperCase();\r\n    }\r\n\r\n    function getEUClass(value) {\r\n      if (!value || value === '#N\/A') return 'badge-eu-na';\r\n      const first = value.trim().charAt(0).toUpperCase();\r\n      switch (first) {\r\n        case 'A': return 'badge-eu-a';\r\n        case 'B': return 'badge-eu-b';\r\n        case 'C': return 'badge-eu-c';\r\n        case 'D': return 'badge-eu-d';\r\n        default: return 'badge-eu-na';\r\n      }\r\n    }\r\n\r\n    function getCITESLabel(value) {\r\n      if (!value || value === '#N\/A') return '\u2013';\r\n      return value.trim().toUpperCase().split(\/[^I]\/)[0] || value.trim().charAt(0);\r\n    }\r\n\r\n    function getCITESClass(value) {\r\n      if (!value || value === '#N\/A') return 'badge-cites-na';\r\n      const upper = value.trim().toUpperCase();\r\n      if (upper.startsWith('I')) return 'badge-cites-i';\r\n      if (upper.startsWith('II')) return 'badge-cites-ii';\r\n      if (upper.startsWith('III')) return 'badge-cites-iii';\r\n      return 'badge-cites-na';\r\n    }\r\n\r\n    blocs.uicn.innerHTML = `\r\n      <h3>Statut de protection<\/h3>\r\n\r\n      <div class=\"uicn-double-col\" style=\"\r\n        display: flex;\r\n        flex-wrap: nowrap;\r\n        gap: 30px;\r\n        justify-content: space-between;\r\n        align-items: flex-start;\r\n      \">\r\n\r\n        <!-- \ud83d\udd34 COLONNE GAUCHE -->\r\n        <div class=\"uicn-col uicn-gauche\" style=\"\r\n          flex: 0 0 25%;\r\n          max-width: 25%;\r\n          display: flex;\r\n          flex-direction: column;\r\n          align-items: center;\r\n          text-align: center;\r\n        \">\r\n          <h4 style=\"margin-bottom: 10px;\">Tendance des populations<\/h4>\r\n\r\n          <div style=\"\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: center;\r\n            gap: 20px;\r\n            height: 100px;\r\n          \">\r\n            ${(() => {\r\n  const tendance = (traduireTendancePopulation(espece.populationtrend) || '').toLowerCase();\r\n\r\nconst rawPop = espece.population_size;\r\nlet populationHTML = '';\r\n\r\nif (\r\n  rawPop &&\r\n  !['Unknown', '#N\/A', 'NA', 'na', 'Na', 'n\/a'].includes(rawPop.toString().trim())\r\n) {\r\n  const popClean = rawPop.toString().trim();\r\n  populationHTML = `\r\n    <div style=\"\r\n      margin-top: 8px;\r\n      font-size: 0.95rem;\r\n      color: #555;\r\n      font-weight: 500;\r\n    \">\r\n      ${popClean} individus matures\r\n    <\/div>\r\n  `;\r\n}\r\n\r\n  if (tendance === 'en baisse') {\r\n    return `\r\n      <svg width=\"50\" height=\"100\" viewBox=\"0 0 24 24\" fill=\"#d63031\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\r\n        <path d=\"M11 3h2v10h4l-5 5-5-5h4V3z\"\/>\r\n      <\/svg>\r\n      <div>\r\n        <span style=\"font-size: 1.4rem; font-weight: 500; color: #d63031;\">En baisse<\/span>\r\n        ${populationHTML}\r\n      <\/div>\r\n    `;\r\n  } else if (tendance === 'en hausse') {\r\n    return `\r\n      <svg width=\"50\" height=\"100\" viewBox=\"0 0 24 24\" fill=\"#00b894\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\r\n        <path d=\"M13 21h-2V11H7l5-5 5 5h-4v10z\"\/>\r\n      <\/svg>\r\n      <div>\r\n        <span style=\"font-size: 1.4rem; font-weight: 500; color: #00b894;\">En hausse<\/span>\r\n        ${populationHTML}\r\n      <\/div>\r\n    `;\r\n  } else if (tendance === 'stable') {\r\n    return `\r\n      <svg width=\"50\" height=\"100\" viewBox=\"0 0 24 24\" fill=\"#f1c40f\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\r\n        <rect x=\"4\" y=\"11\" width=\"16\" height=\"2\" \/>\r\n      <\/svg>\r\n      <div>\r\n        <span style=\"font-size: 1.4rem; font-weight: 500; color: #f1c40f;\">Stable<\/span>\r\n        ${populationHTML}\r\n      <\/div>\r\n    `;\r\n  } else {\r\n  return `\r\n    <div style=\"\r\n      font-size: 2.5rem;\r\n      font-weight: 700;\r\n      font-family: 'Inter', sans-serif;\r\n      color: #7f8c8d;\r\n      line-height: 1;\r\n    \">?<\/div>\r\n    <div>\r\n      <span style=\"font-size: 1.4rem; font-weight: 500; color: #7f8c8d;\">Inconnue<\/span>\r\n      ${populationHTML}\r\n    <\/div>\r\n  `;\r\n}\r\n\r\n})()}\r\n\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <!-- \ud83d\udfe1 COLONNE CENTRALE -->\r\n        <div class=\"uicn-col uicn-centre\" style=\"\r\n          flex: 1 1 50%;\r\n          max-width: 50%;\r\n          display: flex;\r\n          flex-direction: column;\r\n          align-items: center;\r\n          text-align: center;\r\n        \">\r\n          <h4 style=\"margin-bottom: 10px;\">Statut UICN<\/h4>\r\n\r\n          <div class=\"uicn-bar-container\" style=\"position: relative; width: 100%;\">\r\n            <img decoding=\"async\"\r\n              src=\"https:\/\/fiches-especes.simonpotier.fr\/wp-content\/uploads\/2025\/12\/UICN-Categories-scaled.png\"\r\n              alt=\"Barre des statuts UICN\"\r\n              class=\"uicn-bar-image\"\r\n              style=\"width: 100%; height: auto;\"\r\n            >\r\n\r\n            <div style=\"\r\n              position: absolute;\r\n              top: 0;\r\n              left: calc(${positionPercent}% - ${largeurCategorie \/ 2}%);\r\n              width: ${largeurCategorie}%;\r\n              height: 100%;\r\n              border: 3px solid black;\r\n              box-sizing: border-box;\r\n              pointer-events: none;\r\n            \"><\/div>\r\n\r\n            <div style=\"\r\n              position: absolute;\r\n              top: calc(90% - 1px);\r\n              left: calc(${positionPercent}% - 12px);\r\n              width: 0;\r\n              height: 0;\r\n              border-left: 12px solid transparent;\r\n              border-right: 12px solid transparent;\r\n              border-bottom: 18px solid black;\r\n              z-index: 2;\r\n            \"><\/div>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <!-- \ud83d\udfe2 COLONNE DROITE -->\r\n        <div class=\"uicn-col uicn-droite\" style=\"\r\n          flex: 0 0 25%;\r\n          max-width: 25%;\r\n          display: flex;\r\n          flex-direction: column;\r\n          align-items: center;\r\n          text-align: center;\r\n        \">\r\n          <h4>Annexes<\/h4>\r\n\r\n          <div class=\"annexes-ligne\">\r\n            <div class=\"annexes-labels\">\r\n              <span>EU<\/span>\r\n              <span>CITES<\/span>\r\n            <\/div>\r\n\r\n            <div class=\"annexes-valeurs\">\r\n              <span class=\"badge-eu ${getEUClass(espece.EU)}\">${getEULabel(espece.EU)}<\/span>\r\n              <span class=\"badge-cites ${getCITESClass(espece.CITES)}\">${getCITESLabel(espece.CITES)}<\/span>\r\n            <\/div>\r\n          <\/div>\r\n        <\/div>\r\n\r\n      <\/div>\r\n    `;\r\n\r\n    \/\/ \ud83d\udc23 Bloc Reproduction\r\n    const oldRepro = document.getElementById('bloc-reproduction');\r\n    if (oldRepro) oldRepro.remove();\r\n\r\n    blocs.reproduction = document.createElement('div');\r\n    blocs.reproduction.className = 'bloc';\r\n    blocs.reproduction.id = 'bloc-reproduction';\r\n\r\n    document.getElementById('morpho-mesures').before(blocs.reproduction);\r\n    blocs.reproduction.style.display = 'block';\r\n\r\n    function getSystemeAccouplement(espece) {\r\n      const mono = espece.Monogame === \"1\";\r\n      const poly = espece.Polygame === \"1\";\r\n      const coop = parseInt(espece.Coop);\r\n\r\n      let type = \"\u2013\";\r\n      if (mono && poly) type = \"Monogame et polygame\";\r\n      else if (mono) type = \"Monogame\";\r\n      else if (poly) type = \"Polygame\";\r\n\r\n      const coopMap = {\r\n        0: \"Elevage solitaire\",\r\n        1: \"Elevage coop\u00e9ratif\",\r\n        2: \"Aid\u00e9e par la famille\",\r\n        3: \"Aid\u00e9e occasionnellement\"\r\n      };\r\n      const mode = coopMap[coop] || \"\u2013\";\r\n\r\n      return `\r\n        <div class=\"subfield\">Syst\u00e8me d\u2019accouplement : <span class=\"subvalue\">${type}<\/span><\/div>\r\n        <div class=\"subfield\">M\u00e9thode d'\u00e9levage : <span class=\"subvalue\">${mode}<\/span><\/div>\r\n      `;\r\n    }\r\n\r\n    function getNid(espece) {\r\n      const typeMap = {\r\n        BU: \"Terrier\",\r\n        CP: \"Nid en coupe\",\r\n        CR: \"Fissure \/ anfractuosit\u00e9 rocheuse\",\r\n        CV: \"Cavit\u00e9 arboricole\",\r\n        DM: \"D\u00f4me\",\r\n        HC: \"Demi-coupe peu profonde\",\r\n        NO: \"Pas de nid\",\r\n        O:  \"Nid d\u2019une autre esp\u00e8ce\",\r\n        PL: \"Plateforme\",\r\n        PN: \"Nid suspendu (en sac)\",\r\n        SA: \"Nid en soucoupe\",\r\n        SC: \"Grattage \/ d\u00e9pression sommaire\",\r\n        SP: \"Nid sph\u00e9rique \/ globulaire\",\r\n        M:  \"Nid en monticule\"\r\n      };\r\n\r\n      const substratMap = {\r\n        A: \"Bambou\",\r\n        B: \"B\u00e2timent \/ construction humaine\",\r\n        C: \"Souche\",\r\n        G: \"Sol\",\r\n        K: \"Cactus\",\r\n        N: \"Nid pr\u00e9existant\",\r\n        P: \"Poteau \/ m\u00e2t\",\r\n        R: \"Rocher \/ paroi rocheuse\",\r\n        S: \"Arbuste, buisson ou liane\",\r\n        T: \"Arbre\",\r\n        W: \"Eau (flottant ou v\u00e9g\u00e9tation aquatique)\",\r\n        Z: \"Herbac\u00e9es \/ gramin\u00e9es\"\r\n      };\r\n\r\n      const decode = (raw, map) => {\r\n        if (!raw || raw === \"#N\/A\") return \"\u2013\";\r\n        return raw\r\n          .split(\",\")\r\n          .map(c => c.trim())\r\n          .map(c => map[c] || c)\r\n          .join(\", \");\r\n      };\r\n\r\n      const typeNid = decode(espece.Nest_type, typeMap);\r\n      const substrat = decode(espece.Nest_substrat, substratMap);\r\n\r\n      return `\r\n        <div class=\"subfield\">\r\n          Type de nid : <span class=\"subvalue\">${typeNid}<\/span>\r\n        <\/div>\r\n        <div class=\"subfield\">\r\n          Substrat : <span class=\"subvalue\">${substrat}<\/span>\r\n        <\/div>\r\n      `;\r\n    }\r\n\r\n    function formatRange(min, max, unit = '') {\r\n      const valMin = parseFloat(min?.toString().replace(',', '.'));\r\n      const valMax = parseFloat(max?.toString().replace(',', '.'));\r\n      if (isNaN(valMin) && isNaN(valMax)) return '\u2013';\r\n      if (!isNaN(valMin) && isNaN(valMax)) return `${valMin}${unit}`;\r\n      if (isNaN(valMin) && !isNaN(valMax)) return `${valMax}${unit}`;\r\n      return `${valMin}\u2013${valMax}${unit}`;\r\n    }\r\n\r\n    blocs.reproduction.innerHTML = `\r\n      <h3>Reproduction<\/h3>\r\n      <div class=\"rythme-liste\">\r\n        <div>\r\n          <div class=\"rythme-titre\">Strat\u00e9gie de reproduction<\/div>\r\n          <div class=\"rythme-valeur\">${getSystemeAccouplement(espece)}<\/div>\r\n        <\/div>\r\n        <div>\r\n          <div class=\"rythme-titre\">Nid<\/div>\r\n          <div class=\"rythme-valeur\">${getNid(espece)}<\/div>\r\n        <\/div>\r\n        <div>\r\n          <div class=\"rythme-titre\">Nombre d'\u0153ufs<\/div>\r\n          <div class=\"rythme-valeur\">${formatRange(espece.Clutch_min, espece.Clutch_max)}<\/div>\r\n        <\/div>\r\n        <div>\r\n          <div class=\"rythme-titre\">Incubation<\/div>\r\n          <div class=\"rythme-valeur\">${formatRange(espece.Incub_min, espece.Incub_max, ' j')}<\/div>\r\n        <\/div>\r\n        <div>\r\n          <div class=\"rythme-titre\">Envol des jeunes<\/div>\r\n          <div class=\"rythme-valeur\">${formatRange(espece.Fledg_min, espece.Fledg_max, ' j')}<\/div>\r\n        <\/div>\r\n      <\/div>\r\n    `;\r\n\r\n    blocs.morpho.innerHTML = `\r\n      <h3>Donn\u00e9es morphologiques<\/h3>\r\n      <div class=\"morpho-wrapper\">\r\n        <div class=\"morpho-texte\">\r\n          ${[\r\n            { label: \"1 - Longueur du bec (culmen)\", val: espece[\"beak_length_culmen\"] },\r\n            { label: \"2 - Longueur du bec (narines)\", val: espece[\"beak_length_nares\"] },\r\n            { label: \"3 - Largeur du bec\", val: espece[\"beak_width\"] },\r\n            { label: \"4 - \u00c9paisseur du bec\", val: espece[\"beak_depth\"] },\r\n            { label: \"5 - Longueur du tarse\", val: espece[\"tarsus_length\"] },\r\n            { label: \"6 - Longueur de l'aile\", val: espece[\"wing_length\"] },\r\n            { label: \"7 - Distance de Kipps\", val: espece[\"kipps_distance\"] },\r\n            { label: \"8 - Hand-wing index\", val: espece[\"hand_wing_index\"] },\r\n            { label: \"9 - Longueur de la queue\", val: espece[\"tail_length\"] }\r\n          ].map(d => `<p><strong>${d.label} :<\/strong> ${d.val && d.val !== \"#N\/A\" ? d.val : \"\u2013\"} mm<\/p>`).join('')}\r\n        <\/div>\r\n        <div class=\"morpho-image\">\r\n          <img decoding=\"async\" \r\n            src=\"https:\/\/fiches-especes.simonpotier.fr\/wp-content\/uploads\/2025\/11\/Morphologie-scaled.jpg\" \r\n            alt=\"Illustration morphologique de l'oiseau\"\r\n          >\r\n        <\/div>\r\n      <\/div>\r\n    `;\r\n\r\n    google.charts.load('current', { packages: ['corechart'] });\r\n    google.charts.setOnLoadCallback(() => {\r\n      blocs.regime.innerHTML = `\r\n  <h3>R\u00e9gime alimentaire & Strat\u00e9gie de fourragement<\/h3>\r\n  <div class=\"charts-wrapper\">\r\n    <div class=\"chart-block\">\r\n      <div class=\"chart-container\" id=\"chart-diet\"><\/div>\r\n      <div id=\"legend-diet\" class=\"custom-legend\"><\/div>\r\n    <\/div>\r\n    <div class=\"chart-block\">\r\n      <div class=\"chart-container\" id=\"chart-strat\"><\/div>\r\n      <div id=\"legend-strat\" class=\"custom-legend\"><\/div>\r\n    <\/div>\r\n  <\/div>`;\r\n\r\n      function drawCharts() {\r\n        const dietColorMap = {\r\n          'Invert\u00e9br\u00e9s': '#C7F464',\r\n          'Vert\u00e9br\u00e9s endothermes': '#FF6B6B',\r\n          'Vert\u00e9br\u00e9s ectothermes': '#C3B1E1',\r\n          'Poissons': '#4ECDC4',\r\n          'Vert\u00e9br\u00e9s inconnus': '#FFB6B9',\r\n          'Charognes': '#6C5B7B',\r\n          'Fruits': '#F67280',\r\n          'Nectars': '#FF9F1C',\r\n          'Graines': '#FFE66D',\r\n          'V\u00e9g\u00e9taux': '#B5EAD7'\r\n        };\r\n\r\n        const stratColorMap = {\r\n          'Sous l\u2019eau': '#4ECDC4',\r\n          'Autour surface eau': '#6C5B7B',\r\n          'Au sol': '#FF6B6B',\r\n          'Sous-bois': '#C7F464',\r\n          'Milieu de canop\u00e9e': '#FFE66D',\r\n          'Canop\u00e9e': '#B5EAD7',\r\n          'Dans les airs': '#FF9F1C'\r\n        };\r\n\r\n        function prepareData(rows) {\r\n          const filtered = rows.filter(([_, value]) => value > 0);\r\n          let hasFake = false;\r\n\r\n          if (filtered.length === 1 && filtered[0][1] === 100) {\r\n            filtered.push(['', 0.00001]);\r\n            hasFake = true;\r\n          }\r\n\r\n          return { data: filtered, hasFake };\r\n        }\r\n\r\n        const rawDiet = [\r\n          ['Invert\u00e9br\u00e9s', parseFloat(espece.diet_inv) || 0],\r\n          ['Vert\u00e9br\u00e9s endothermes', parseFloat(espece.diet_vend) || 0],\r\n          ['Vert\u00e9br\u00e9s ectothermes', parseFloat(espece.diect_vect) || 0],\r\n          ['Poissons', parseFloat(espece.diet_vfish) || 0],\r\n          ['Vert\u00e9br\u00e9s inconnus', parseFloat(espece.diet_vunk) || 0],\r\n          ['Charognes', parseFloat(espece.diet_scav) || 0],\r\n          ['Fruits', parseFloat(espece.diet_fruit) || 0],\r\n          ['Nectars', parseFloat(espece.diet_nect) || 0],\r\n          ['Graines', parseFloat(espece.diet_seed) || 0],\r\n          ['V\u00e9g\u00e9taux', parseFloat(espece.diet_planto) || 0]\r\n        ].filter(d => d[1] > 0).sort((a, b) => b[1] - a[1]);\r\n\r\n        const rawStrat = [\r\n          ['Sous l\u2019eau', parseFloat(espece.forstrat_watbelowsurf) || 0],\r\n          ['Autour surface eau', parseFloat(espece.forstrat_wataroundsurf) || 0],\r\n          ['Au sol', parseFloat(espece.forstrat_ground) || 0],\r\n          ['Sous-bois', parseFloat(espece.forstrat_understory) || 0],\r\n          ['Milieu de canop\u00e9e', parseFloat(espece.forstrat_midhigh) || 0],\r\n          ['Canop\u00e9e', parseFloat(espece.forstrat_canopy) || 0],\r\n          ['Dans les airs', parseFloat(espece.forstrat_aerial) || 0]\r\n        ].filter(d => d[1] > 0).sort((a, b) => b[1] - a[1]);\r\n\r\n        const preparedDiet = prepareData(rawDiet);\r\n        const preparedStrat = prepareData(rawStrat);\r\n\r\n        const dataDiet = google.visualization.arrayToDataTable([\r\n          ['Type', 'Pourcentage'],\r\n          ...preparedDiet.data\r\n        ]);\r\n\r\n        const dataStrat = google.visualization.arrayToDataTable([\r\n          ['Strate', 'Pourcentage'],\r\n          ...preparedStrat.data\r\n        ]);\r\n\r\n        const chartDiet = new google.visualization.PieChart(document.getElementById('chart-diet'));\r\n        const chartStrat = new google.visualization.PieChart(document.getElementById('chart-strat'));\r\n\r\n        const containerWidth = document.getElementById('chart-diet')?.offsetWidth || 300;\r\n\r\n        function getColorsFromMap(dataTable, colorMap) {\r\n          const colors = [];\r\n          for (let i = 0; i < dataTable.getNumberOfRows(); i++) {\r\n            const label = dataTable.getValue(i, 0);\r\n            colors.push(!label ? 'transparent' : (colorMap[label] || '#cccccc'));\r\n          }\r\n          return colors;\r\n        }\r\n\r\n        function makeSlices(dataTable, hasFake) {\r\n          const slices = {};\r\n          if (hasFake) {\r\n            const lastIndex = dataTable.getNumberOfRows() - 1;\r\n            slices[lastIndex] = { color: 'transparent', textStyle: { color: 'transparent' } };\r\n          }\r\n          return slices;\r\n        }\r\n\r\n        const baseOptions = {\r\n  pieHole: 0.4,\r\n  width: containerWidth,\r\n  height: Math.round(containerWidth * 0.75),\r\n  legend: 'none',\r\n  pieSliceText: 'percentage', \/\/ % dans les parts\r\n  tooltip: { text: 'value' }, \/\/ ou 'none' pour ne rien avoir au hover\r\n  chartArea: { width: '90%', height: '80%' },\r\n  pieSliceBorderColor: 'transparent',\r\n  sliceVisibilityThreshold: 0\r\n};\r\n\r\n\r\n        chartDiet.draw(dataDiet, {\r\n          ...baseOptions,\r\n          colors: getColorsFromMap(dataDiet, dietColorMap),\r\n          slices: makeSlices(dataDiet, preparedDiet.hasFake)\r\n        });\r\n\r\n        chartStrat.draw(dataStrat, {\r\n          ...baseOptions,\r\n          colors: getColorsFromMap(dataStrat, stratColorMap),\r\n          slices: makeSlices(dataStrat, preparedStrat.hasFake)\r\n        });\r\n\r\n       function generateLegend(elementId, dataTable, colorMap) {\r\n  const container = document.getElementById(elementId);\r\n  if (!container) return;\r\n\r\n  container.innerHTML = '';\r\n\r\n  for (let i = 0; i < dataTable.getNumberOfRows(); i++) {\r\n    const label = dataTable.getValue(i, 0);\r\n    const value = dataTable.getValue(i, 1);\r\n    const color = colorMap[label] || '#ccc';\r\n\r\n    if (!label || !value || isNaN(value) || value === 0) continue;\r\n\r\n    const item = document.createElement('div');\r\n    item.className = 'legend-item';\r\n    item.innerHTML = `\r\n      <span class=\"legend-color\" style=\"background:${color};\"><\/span>\r\n      <span>${label} \u2013 ${value}%<\/span>\r\n    `;\r\n    container.appendChild(item);\r\n  }\r\n}\r\n\r\n\r\n        generateLegend('legend-diet', dataDiet, dietColorMap);\r\n        generateLegend('legend-strat', dataStrat, stratColorMap);\r\n      }\r\n\r\n      drawCharts();\r\n      window.addEventListener('resize', drawCharts);\r\n    });\r\n  }\r\n\r\n  let temperatureChartInstance = null;\r\n  let aridityChartInstance = null;\r\n\r\n  function parseClimateValue(value) {\r\n    if (value === undefined || value === null) return null;\r\n\r\n    const clean = value\r\n      .toString()\r\n      .trim()\r\n      .replace(',', '.');\r\n\r\n    if (!clean || clean === '#N\/A' || clean.toLowerCase() === 'na') return null;\r\n\r\n    const number = parseFloat(clean);\r\n    return isNaN(number) ? null : number;\r\n  }\r\n\r\n  function getClimateValue(espece, month, type, minMax) {\r\n    const m1 = String(month).padStart(2, '0');\r\n    const m2 = String(month);\r\n\r\n    const possibleKeys = [\r\n      `${m1}_${type}${minMax}`,\r\n      `${m2}_${type}${minMax}`,\r\n      `${m1}${type}${minMax}`,\r\n      `${m2}${type}${minMax}`,\r\n      `${m1}_${type}_${minMax}`,\r\n      `${m2}_${type}_${minMax}`\r\n    ];\r\n\r\n    for (const key of possibleKeys) {\r\n      if (Object.prototype.hasOwnProperty.call(espece, key)) {\r\n        return parseClimateValue(espece[key]);\r\n      }\r\n    }\r\n\r\n    return null;\r\n  }\r\n\r\n  function createClimateCharts(espece) {\r\n    const tempCanvas = document.getElementById('temperatureChart');\r\n    const aridCanvas = document.getElementById('aridityChart');\r\n\r\n    if (!tempCanvas || !aridCanvas || typeof Chart === 'undefined') return;\r\n\r\n    if (temperatureChartInstance) temperatureChartInstance.destroy();\r\n    if (aridityChartInstance) aridityChartInstance.destroy();\r\n\r\n    const mois = ['Jan', 'F\u00e9v', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Ao\u00fbt', 'Sep', 'Oct', 'Nov', 'D\u00e9c'];\r\n\r\n    const tempMin = [];\r\n    const tempMax = [];\r\n    const tempMean = [];\r\n\r\n    const aridMin = [];\r\n    const aridMax = [];\r\n    const aridMean = [];\r\n\r\n    for (let i = 1; i <= 12; i++) {\r\n      const tMin = getClimateValue(espece, i, 'T', 'Min');\r\n      const tMax = getClimateValue(espece, i, 'T', 'Max');\r\n      const aMin = getClimateValue(espece, i, 'A', 'Min');\r\n      const aMax = getClimateValue(espece, i, 'A', 'Max');\r\n\r\n      tempMin.push(tMin);\r\n      tempMax.push(tMax);\r\n      tempMean.push(tMin !== null && tMax !== null ? (tMin + tMax) \/ 2 : null);\r\n\r\n      aridMin.push(aMin);\r\n      aridMax.push(aMax);\r\n      aridMean.push(aMin !== null && aMax !== null ? (aMin + aMax) \/ 2 : null);\r\n    }\r\n\r\n    temperatureChartInstance = drawRangeChart(\r\n      tempCanvas,\r\n      mois,\r\n      tempMin,\r\n      tempMax,\r\n      tempMean,\r\n      'Temp\u00e9rature moyenne',\r\n      'Temp\u00e9rature (\u00b0C)',\r\n      '#2f7d32',\r\n      'rgba(82,170,82,0.25)'\r\n    );\r\n\r\n   aridityChartInstance = drawRangeChart(\r\n  aridCanvas,\r\n  mois,\r\n  aridMin,\r\n  aridMax,\r\n  aridMean,\r\n  'Aridit\u00e9 moyenne',\r\n  'Indice d\u2019aridit\u00e9',\r\n  '#b7791f',\r\n  'rgba(211,151,45,0.25)',\r\n  true\r\n);\r\n  }\r\n\r\nfunction drawRangeChart(\r\n  canvas,\r\n  labels,\r\n  minData,\r\n  maxData,\r\n  meanData,\r\n  label,\r\n  yTitle,\r\n  darkColor,\r\n  lightColor,\r\n  autoScale = false\r\n) {\r\n  return new Chart(canvas, {\r\n    type: 'line',\r\n\r\n    data: {\r\n      labels: labels,\r\n\r\n      datasets: [\r\n        {\r\n          label: 'Maximum',\r\n          data: maxData,\r\n          borderColor: 'transparent',\r\n          backgroundColor: lightColor,\r\n          pointRadius: 0,\r\n          fill: '+1',\r\n          tension: 0.35\r\n        },\r\n\r\n        {\r\n          label: 'Minimum',\r\n          data: minData,\r\n          borderColor: 'transparent',\r\n          backgroundColor: lightColor,\r\n          pointRadius: 0,\r\n          fill: false,\r\n          tension: 0.35\r\n        }\r\n      ]\r\n    },\r\n\r\n    options: {\r\n      responsive: true,\r\n      maintainAspectRatio: false,\r\n\r\n      interaction: {\r\n        mode: 'index',\r\n        intersect: false\r\n      },\r\n\r\n      plugins: {\r\n        legend: {\r\n          display: false\r\n        },\r\n\r\n        tooltip: {\r\n          callbacks: {\r\n            label: function(context) {\r\n              if (context.raw === null) return '';\r\n              return `${context.dataset.label} : ${Number(context.raw).toFixed(2)}`;\r\n            }\r\n          }\r\n        }\r\n      },\r\n\r\n      scales: {\r\n        y: {\r\n          beginAtZero: !autoScale,\r\n          suggestedMin: autoScale ? undefined : 0,\r\n\r\n          title: {\r\n            display: true,\r\n            text: yTitle,\r\n            font: {\r\n              size: 18,\r\n              weight: '600'\r\n            }\r\n          },\r\n\r\n          ticks: {\r\n            font: {\r\n              size: 16\r\n            }\r\n          },\r\n\r\n          grid: {\r\n            color: 'rgba(0,0,0,0.08)'\r\n          }\r\n        },\r\n\r\n        x: {\r\n          ticks: {\r\n            font: {\r\n              size: 16\r\n            }\r\n          },\r\n\r\n          grid: {\r\n            color: 'rgba(0,0,0,0.05)'\r\n          }\r\n        }\r\n      }\r\n    }\r\n  });\r\n}\r\n  \r\n  \/\/ =======================================================\r\n  \/\/ \u2705 Recherche (inchang\u00e9e) + blocage par disabled input\r\n  \/\/ =======================================================\r\n  let selectedIndex = -1;\r\n  let currentSuggestions = [];\r\n\r\n  input.addEventListener('input', function () {\r\n    \/\/ si disabled, on sort\r\n    if (input.disabled) return;\r\n\r\n    const saisie = removeDiacritics(input.value.trim());\r\n    suggestionBox.innerHTML = '';\r\n    selectedIndex = -1;\r\n    currentSuggestions = [];\r\n\r\n    if (!saisie || !fuse) return;\r\n\r\n    let resultats = fuse.search(saisie);\r\n\r\n    resultats.sort((a, b) => {\r\n      const aStr = a.item.search_normalized;\r\n      const bStr = b.item.search_normalized;\r\n\r\n      const aStarts = aStr.startsWith(saisie);\r\n      const bStarts = bStr.startsWith(saisie);\r\n\r\n      if (aStarts && !bStarts) return -1;\r\n      if (!aStarts && bStarts) return 1;\r\n      return 0;\r\n    });\r\n\r\n    currentSuggestions = resultats.slice(0, 10);\r\n\r\n    currentSuggestions.forEach((result, index) => {\r\n      const nom = decodeTexte(result.item.french || '\u2013');\r\n      const nomLatin = decodeTexte(result.item.latin || '\u2013');\r\n\r\n      const div = document.createElement('div');\r\n      div.innerHTML = `<strong>${nom}<\/strong> \u2013 <em>${nomLatin}<\/em>`;\r\n      div.setAttribute('data-index', index);\r\n      div.addEventListener('click', () => {\r\n        input.value = nom;\r\n        suggestionBox.innerHTML = '';\r\n        afficherEspece(result.item);\r\n      });\r\n      suggestionBox.appendChild(div);\r\n    });\r\n  });\r\n\r\n  input.addEventListener('keydown', function (e) {\r\n    if (input.disabled) return;\r\n\r\n    const suggestionItems = suggestionBox.querySelectorAll('div');\r\n    if (e.key === 'ArrowDown') {\r\n      e.preventDefault();\r\n      if (currentSuggestions.length === 0) return;\r\n      selectedIndex = (selectedIndex + 1) % currentSuggestions.length;\r\n      updateHighlight(suggestionItems);\r\n    } else if (e.key === 'ArrowUp') {\r\n      e.preventDefault();\r\n      if (currentSuggestions.length === 0) return;\r\n      selectedIndex = (selectedIndex - 1 + currentSuggestions.length) % currentSuggestions.length;\r\n      updateHighlight(suggestionItems);\r\n    } else if (e.key === 'Enter') {\r\n      e.preventDefault();\r\n      if (selectedIndex >= 0 && currentSuggestions[selectedIndex]) {\r\n        const selectedItem = currentSuggestions[selectedIndex].item;\r\n        input.value = selectedItem.french;\r\n        suggestionBox.innerHTML = '';\r\n        afficherEspece(selectedItem);\r\n      } else {\r\n        const saisie = removeDiacritics(input.value.trim());\r\n        if (!saisie || !fuse) return;\r\n        const resultats = fuse.search(saisie);\r\n        if (resultats.length > 0) {\r\n          afficherEspece(resultats[0].item);\r\n          suggestionBox.innerHTML = '';\r\n        }\r\n      }\r\n    }\r\n  });\r\n\r\n      function chargerEspeceDepuisURL() {\r\n    const params = new URLSearchParams(window.location.search);\r\n    const especeParam = params.get('espece');\r\n    if (!especeParam || !donneesCSV || !donneesCSV.length) return;\r\n\r\n    const valeur = removeDiacritics(especeParam.trim());\r\n\r\n    const matchExact = donneesCSV.find(item =>\r\n      removeDiacritics(item.french || '') === valeur ||\r\n      removeDiacritics(item.latin || '') === valeur\r\n    );\r\n\r\n    if (matchExact) {\r\n      afficherEspece(matchExact);\r\n      return;\r\n    }\r\n\r\n    if (fuse) {\r\n      const resultats = fuse.search(valeur);\r\n      if (resultats.length > 0) {\r\n        afficherEspece(resultats[0].item);\r\n      }\r\n    }\r\n  }\r\n  \r\n  function updateHighlight(items) {\r\n    items.forEach((item, index) => {\r\n      const isActive = index === selectedIndex;\r\n      item.classList.toggle('highlight', isActive);\r\n      if (isActive) {\r\n        item.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'smooth' });\r\n      }\r\n    });\r\n  }\r\n\r\n});\r\n<\/script>\r\n\r\n\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ffc61b9 elementor-widget elementor-widget-html\" data-id=\"ffc61b9\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!-- Librairies pour l'export -->\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js\"><\/script>\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/html2canvas\/1.4.1\/html2canvas.min.js\"><\/script>\r\n\r\n<script>\r\n  document.addEventListener('DOMContentLoaded', function () {\r\n    const btnExport = document.getElementById('btn-export-pdf');\r\n\r\n    if (!btnExport) {\r\n      console.warn(\"\ud83d\udd34 Bouton #btn-export-pdf introuvable\");\r\n      return;\r\n    }\r\n\r\n    btnExport.addEventListener('click', async () => {\r\n      const elements = [\r\n        document.getElementById('bloc-noms'),\r\n        document.getElementById('bloc-classification'),\r\n        document.getElementById('bloc-rythme'),\r\n        document.getElementById('bloc-regime'),\r\n        document.getElementById('bloc-uicn'),\r\n        document.getElementById('morphologie') \/\/ \u2705 Bloc morphologie ajout\u00e9 ici\r\n      ];\r\n\r\n      const { jsPDF } = window.jspdf;\r\n      const doc = new jsPDF('p', 'mm', 'a4');\r\n      let positionY = 10;\r\n\r\n      for (const el of elements) {\r\n        if (!el) continue;\r\n\r\n        const canvas = await html2canvas(el, { scale: 2 });\r\n        const imgData = canvas.toDataURL('image\/png');\r\n\r\n        const imgWidth = 180;\r\n        const imgHeight = (canvas.height * imgWidth) \/ canvas.width;\r\n\r\n        if (positionY + imgHeight > 280) {\r\n          doc.addPage();\r\n          positionY = 10;\r\n        }\r\n\r\n        doc.addImage(imgData, 'PNG', 15, positionY, imgWidth, imgHeight);\r\n        positionY += imgHeight + 10;\r\n      }\r\n\r\n      doc.save('fiche-espece.pdf');\r\n    });\r\n  });\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b63641d e-flex e-con-boxed parallax_section_no qode_elementor_container_no e-con e-parent\" data-id=\"b63641d\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9e7cade elementor-widget elementor-widget-html\" data-id=\"9e7cade\" data-element_type=\"widget\" id=\"bloc-noms\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t \t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3bffc9e elementor-widget elementor-widget-html\" data-id=\"3bffc9e\" data-element_type=\"widget\" id=\"bloc-classification\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t \t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d6485e4 e-flex e-con-boxed parallax_section_no qode_elementor_container_no e-con e-parent\" data-id=\"d6485e4\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2e9f183 elementor-widget__width-inherit elementor-widget elementor-widget-html\" data-id=\"2e9f183\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"bloc-uicn\"><\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-78be4bb elementor-widget__width-inherit elementor-widget elementor-widget-html\" data-id=\"78be4bb\" data-element_type=\"widget\" id=\"bloc-regime\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t \t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-82eb339 elementor-widget__width-inherit elementor-widget elementor-widget-html\" data-id=\"82eb339\" data-element_type=\"widget\" id=\"bloc-rythme\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t \t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-49ceeda e-flex e-con-boxed parallax_section_no qode_elementor_container_no e-con e-parent\" data-id=\"49ceeda\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e4ee36f elementor-widget__width-inherit elementor-widget elementor-widget-html\" data-id=\"e4ee36f\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\r\n<div id=\"morphologie\">\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-cb0cc33 e-flex e-con-boxed parallax_section_no qode_elementor_container_no e-con e-parent\" data-id=\"cb0cc33\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0bcfb53 elementor-widget elementor-widget-html\" data-id=\"0bcfb53\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script>\r\n  \/\/ \u274c D\u00e9sactiver s\u00e9lection de texte\r\n  document.addEventListener('selectstart', e => e.preventDefault());\r\n\r\n  \/\/ \u274c D\u00e9sactiver glisser-d\u00e9poser\r\n  document.addEventListener('dragstart', e => e.preventDefault());\r\n\r\n  \/\/ \u274c R\u00e9action \u00e0 la touche \"Print Screen\"\r\n  document.addEventListener('keydown', function(e) {\r\n    if (e.key === 'PrintScreen') {\r\n      alert(\"La capture d\u2019\u00e9cran est d\u00e9sactiv\u00e9e sur ce site.\");\r\n      document.body.style.filter = \"blur(10px)\";\r\n      setTimeout(() => {\r\n        document.body.style.filter = \"none\";\r\n      }, 2000);\r\n    }\r\n  });\r\n  \r\n    \/\/ \u274c R\u00e9sactiver  Ctrl+P\r\n  document.addEventListener('keydown', function(e) {\r\n  if ((e.ctrlKey || e.metaKey) && e.key === 'p') {\r\n    e.preventDefault();\r\n    alert(\"L'impression est d\u00e9sactiv\u00e9e sur ce site.\");\r\n  }\r\n});\r\n\r\n<\/script>\r\n\r\n\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9f4a56e e-flex e-con-boxed parallax_section_no qode_elementor_container_no e-con e-parent\" data-id=\"9f4a56e\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7b6ccf5 elementor-widget elementor-widget-html\" data-id=\"7b6ccf5\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<?php echo do_shortcode('[fiches_rest_nonce]'); ?>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Pr\u00e9paration des fiches\u2026 0% On apprivoise les donn\u00e9es\u2026 La recherche s\u2019active \u00e0 100%.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"pmpro_default_level":"","footnotes":""},"class_list":["post-1868","page","type-page","status-publish","hentry","pmpro-has-access"],"_links":{"self":[{"href":"https:\/\/spes.anivise.fr\/index.php\/wp-json\/wp\/v2\/pages\/1868","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spes.anivise.fr\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/spes.anivise.fr\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/spes.anivise.fr\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/spes.anivise.fr\/index.php\/wp-json\/wp\/v2\/comments?post=1868"}],"version-history":[{"count":109,"href":"https:\/\/spes.anivise.fr\/index.php\/wp-json\/wp\/v2\/pages\/1868\/revisions"}],"predecessor-version":[{"id":1987,"href":"https:\/\/spes.anivise.fr\/index.php\/wp-json\/wp\/v2\/pages\/1868\/revisions\/1987"}],"wp:attachment":[{"href":"https:\/\/spes.anivise.fr\/index.php\/wp-json\/wp\/v2\/media?parent=1868"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}