{"id":218790,"date":"2025-10-06T13:12:23","date_gmt":"2025-10-06T11:12:23","guid":{"rendered":"https:\/\/yearbook-media.com\/?page_id=218790"},"modified":"2026-09-12T20:26:42","modified_gmt":"2026-09-12T18:26:42","slug":"yearbook-media-regie-publicitaire","status":"publish","type":"page","link":"https:\/\/yearbook-media.com\/en\/","title":{"rendered":"Yearbook Media Advertising Agency"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"218790\" class=\"elementor elementor-218790\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1053cf6 e-con-full e-flex e-con e-parent\" data-id=\"1053cf6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-cece097 e-con-full e-flex e-con e-child\" data-id=\"cece097\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5402a94 e-con-full e-flex e-con e-child\" data-id=\"5402a94\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-288b5b3 e-con-full e-flex e-con e-child\" data-id=\"288b5b3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-aa02ac3 BoutonMenu elementor-widget elementor-widget-image\" data-id=\"aa02ac3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Menu-bleu-1-e1781707726161-rp3esz1ke984yck29iutvgbtmzg3t5ldbo5cxld2y2.webp\" title=\"Menu-bleu.webp\" alt=\"Menu-bleu.webp\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-9cac2ec BoutonMenu elementor-hidden-tablet elementor-hidden-mobile elementor-hidden-desktop elementor-widget elementor-widget-image\" data-id=\"9cac2ec\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"#elementor-action%3Aaction%3Dpopup%3Aopen%26settings%3DeyJpZCI6IjIxNTg5IiwidG9nZ2xlIjpmYWxzZX0%3D\">\n\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Menu-bleu-1-e1781707726161-rp3esz1ke984yck29iutvgbtmzg3t5ldbo5cxld2y2.webp\" title=\"Menu-bleu.webp\" alt=\"Menu-bleu.webp\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-59d046c e-con-full elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"59d046c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-adf54fe e-con-full elementor-hidden-tablet e-flex e-con e-child\" data-id=\"adf54fe\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-bd1e72d elementor-widget-mobile__width-initial elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"bd1e72d\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"HeaderTexteGauche\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tYEARBOOK Rapport Economique en partenariat avec les&nbsp;Pr\u00e9sidences, les&nbsp;Primatures, les&nbsp;Minist\u00e8res et les&nbsp;Agences de Promotion des Investissements\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4d6567f e-con-full elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"4d6567f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-728ff34 e-con-full elementor-hidden-tablet e-flex e-con e-child\" data-id=\"728ff34\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-92083ea elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"92083ea\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tYEARBOOK Media\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-80acf94 elementor-widget__width-initial elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"80acf94\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Communiquer \u00e0 l\u2019\u00e9chelle de continents et de pays<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f1f28a0 e-con-full e-flex e-con e-child\" data-id=\"f1f28a0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-7ac5cff e-con-full e-flex e-con e-child\" data-id=\"7ac5cff\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-fffb849 e-con-full e-flex e-con e-child\" data-id=\"fffb849\" data-element_type=\"container\" data-e-type=\"container\" id=\"MobileYBMedia\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2e75705 elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"2e75705\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tYEARBOOK\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-598b4d1 elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"598b4d1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMedia\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9a48983 elementor-hidden-desktop elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"9a48983\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MobileEnteteTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCommuniquer \u00e0 l&rsquo;\u00e9chelle de continents et de pays<br>\nsur les sites YEARBOOK Rapport Economique\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-ec0d125 elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"ec0d125\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>YEARBOOK Media &#8211; R\u00e9gie publicitaire digitale<br \/>de Via Agency Media et LD Media Development<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<a class=\"elementor-element elementor-element-3718c46 e-con-full e-flex e-con e-child\" data-id=\"3718c46\" data-element_type=\"container\" data-e-type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fa353a3 SiteLangue notranslate elementor-widget elementor-widget-text-editor\" data-id=\"fa353a3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEN\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-35e8e9a e-con-full elementor-hidden-desktop e-flex e-con e-child\" data-id=\"35e8e9a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6a56a6d elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"6a56a6d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>YEARBOOK Rapport Economique est r\u00e9alis\u00e9 en partenariat avec les\u00a0Pr\u00e9sidences,<br \/>les\u00a0Primatures, les\u00a0Minist\u00e8res et les\u00a0Agences de Promotion des Investissements<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c2597a4 e-con-full e-flex e-con e-parent\" data-id=\"c2597a4\" data-element_type=\"container\" data-e-type=\"container\" id=\"AchatEspacesPub\">\n\t\t<div class=\"elementor-element elementor-element-b8a6d74 e-con-full e-flex e-con e-child\" data-id=\"b8a6d74\" data-element_type=\"container\" data-e-type=\"container\" id=\"AchatEspacesPubSubContainer\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-de3c7dc elementor-widget elementor-widget-text-editor\" data-id=\"de3c7dc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAchat d&rsquo;espaces publicitaires\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-37015014 e-con-full TobedisplayedLater elementor-hidden-tablet e-flex e-con e-parent\" data-id=\"37015014\" data-element_type=\"container\" data-e-type=\"container\" id=\"FondGris\">\n\t\t<div class=\"elementor-element elementor-element-33e23e0 elementor-hidden-tablet elementor-hidden-desktop elementor-hidden-mobile e-flex e-con-boxed e-con e-child\" data-id=\"33e23e0\" data-element_type=\"container\" data-e-type=\"container\" id=\"PresentationsFormats\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9e59ab1 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-html\" data-id=\"9e59ab1\" data-element_type=\"widget\" data-e-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=\"via-template-297292\">\r\n  \t\t<div data-elementor-type=\"page\" data-elementor-id=\"297292\" class=\"elementor elementor-297292\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ed0bd04 e-con-full e-flex e-con e-child\" data-id=\"ed0bd04\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-be6dd5b e-con-full e-flex e-con e-child\" data-id=\"be6dd5b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-161f62b elementor-widget elementor-widget-text-editor\" data-id=\"161f62b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vous pouvez cr\u00e9er vos annonces aux formats<br>Banni\u00e8re, Communiqu\u00e9, Interview, Parrainage<br>directement en ligne<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-29ea95a e-con-full e-flex e-con e-child\" data-id=\"29ea95a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d387318 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"d387318\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Cr\u00e9er une annonce en 5 \u00e9tapes<\/p>\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-0a55d53 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"0a55d53\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t1 &#8211;  Choisir le format d&rsquo;annonce \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-fa36928 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"fa36928\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tBanni\u00e8re, Communiqu\u00e9, Interview ou Parrainage\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-bec3a25 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"bec3a25\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t2 &#8211; Cr\u00e9er l&rsquo;annonce\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-9c18c24 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"9c18c24\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAjouter textes, images, logo et personnaliser l&rsquo;arri\u00e8re-plan\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-415972c elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"415972c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t3 &#8211; Visualiser l&rsquo;annonce\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-e3c9367 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"e3c9367\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVoir l&rsquo;annonce avant validation\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-af07ec5 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"af07ec5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t4 &#8211; Valider l&rsquo;annonce\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-2845c88 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"2845c88\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tG\u00e9n\u00e9ration automatique de l&rsquo;annonce pr\u00eate \u00e0 \u00eatre publi\u00e9e\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-b1d7726 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"b1d7726\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t5 &#8211; Publier l&rsquo;annonce\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-92a3c9e elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"92a3c9e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tGlisser-d\u00e9poser l&rsquo;annonce dans les espaces publicitaires de votre choix\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7a6b631 e-con-full e-flex e-con e-child\" data-id=\"7a6b631\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e3e1160 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"e3e1160\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Fonctionnalit\u00e9s de cr\u00e9ation d&rsquo;annonces<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-11541b4 e-con-full e-flex e-con e-child\" data-id=\"11541b4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-a92034f e-con-full e-flex e-con e-child\" data-id=\"a92034f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e0e0e81 elementor-widget elementor-widget-image\" data-id=\"e0e0e81\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-08-225521-rk84erlevwbdb9grvv3a0g7b06vzzghk3jfw1par4a.png\" title=\"Capture d\u2019\u00e9cran 2026-03-08 225521\" alt=\"Capture d\u2019\u00e9cran 2026-03-08 225521\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-266401d elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"266401d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tZones de texte\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c977919 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"c977919\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ajouter, d\u00e9placer et redimensionner les zones de texte. Mise en forme compl\u00e8te : police, taille, couleur, gras, italique, soulign\u00e9, alignement, interligne, texte vertical<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-0dd760e e-con-full e-flex e-con e-child\" data-id=\"0dd760e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-8677fe8 e-con-full e-flex e-con e-child\" data-id=\"8677fe8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1fcf049 elementor-widget elementor-widget-image\" data-id=\"1fcf049\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-08-230228-rk84nhjiak9510sqymso58z9evwled3wmpc2c4d9e2.png\" title=\"Capture d\u2019\u00e9cran 2026-03-08 230228\" alt=\"Capture d\u2019\u00e9cran 2026-03-08 230228\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-3c7bde3 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"3c7bde3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tZones d&rsquo;images\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7ccc784 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"7ccc784\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Importer des photos et logos. Chaque image est recadrable, redimensionnable et ajustable (zoom, luminosit\u00e9, contraste, saturation, opacit\u00e9)<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-de14fec e-con-full e-flex e-con e-child\" data-id=\"de14fec\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-2555157 e-con-full e-flex e-con e-child\" data-id=\"2555157\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-cbb49d4 elementor-widget elementor-widget-image\" data-id=\"cbb49d4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-08-230536-rk84rwe8dkalj4e071gmcmw5t05mj7mjkjl4fvtq5o.png\" title=\"Capture d\u2019\u00e9cran 2026-03-08 230536\" alt=\"Capture d\u2019\u00e9cran 2026-03-08 230536\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-13d29ed elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"13d29ed\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tZone mixte image et texte\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-40929a2 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"40929a2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Cr\u00e9er des blocs mixtes int\u00e9grant texte et visuel dans une m\u00eame zone<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f8a4eb6 e-con-full e-flex e-con e-child\" data-id=\"f8a4eb6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-505306a e-con-full e-flex e-con e-child\" data-id=\"505306a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0fa7f14 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"0fa7f14\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFond personnalisable\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-46fe78e e-con-full e-flex e-con e-child\" data-id=\"46fe78e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-51f663a elementor-widget elementor-widget-image\" data-id=\"51f663a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-13-152632-rkga4d5414rwj0q2huy9tqm5t4ytyrxvhzrw6xpvii.png\" title=\"Capture d\u2019\u00e9cran 2026-03-13 152632\" alt=\"Capture d\u2019\u00e9cran 2026-03-13 152632\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-1b72ef9 elementor-widget elementor-widget-text-editor\" data-id=\"1b72ef9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tImage\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-3789b29 elementor-widget elementor-widget-image\" data-id=\"3789b29\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-09-145334-rk9a221w0kqbzznv2xui53xprp2rn6kewc7bciaaba.png\" title=\"Capture d\u2019\u00e9cran 2026-03-09 145334\" alt=\"Capture d\u2019\u00e9cran 2026-03-09 145334\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-0f9ae91 elementor-widget elementor-widget-text-editor\" data-id=\"0f9ae91\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCouleur\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-8969546 elementor-widget elementor-widget-image\" data-id=\"8969546\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-09-145344-rk9a1xcp2ejwdxuoudtdan4esrpxkp1r7oxvy4h964.png\" title=\"Capture d\u2019\u00e9cran 2026-03-09 145344\" alt=\"Capture d\u2019\u00e9cran 2026-03-09 145344\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-c403ab6 elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"c403ab6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tluminosit\u00e9, contraste, saturation, opacit\u00e9\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-81e7669 e-con-full e-flex e-con e-child\" data-id=\"81e7669\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-c26e120 e-con-full e-flex e-con e-child\" data-id=\"c26e120\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8de4905 elementor-widget elementor-widget-image\" data-id=\"8de4905\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-13-153034-rkgaakup7pa5a7p47jnhb65v6uc6uqlzor1gesi6dw.png\" title=\"Capture d\u2019\u00e9cran 2026-03-13 153034\" alt=\"Capture d\u2019\u00e9cran 2026-03-13 153034\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-9e5cd41 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"9e5cd41\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAnnuler\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2fa2a84 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"2fa2a84\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Chaque modification est r\u00e9versible. Annuler les actions \u00e0 tout moment<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7f87166 e-con-full e-flex e-con e-child\" data-id=\"7f87166\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-917b217 e-con-full e-flex e-con e-child\" data-id=\"917b217\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b96cf24 elementor-widget elementor-widget-image\" data-id=\"b96cf24\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-08-230822-rk84xzemlymeo9jvo64ozlmk7s65cos02nl99cszvm.png\" title=\"Capture d\u2019\u00e9cran 2026-03-08 230822\" alt=\"Capture d\u2019\u00e9cran 2026-03-08 230822\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-e6ec257 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"e6ec257\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAper\u00e7u avant validation\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8709954 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"8709954\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Visualiser l&rsquo;annonce en plein \u00e9cran puis valider<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a8e8f31 e-con-full e-flex e-con e-child\" data-id=\"a8e8f31\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-7c95682 e-con-full e-flex e-con e-child\" data-id=\"7c95682\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1eb5395 elementor-widget elementor-widget-image\" data-id=\"1eb5395\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-08-230841-rk84y1aazmozbhh5d6xy4l5hejwvs2zgqww87wq7jg.png\" title=\"Capture d\u2019\u00e9cran 2026-03-08 230841\" alt=\"Capture d\u2019\u00e9cran 2026-03-08 230841\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-b750355 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"b750355\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tValider\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-35dbbcb elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"35dbbcb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>G\u00e9n\u00e9rer l&rsquo;annonce pr\u00eate \u00e0 \u00eatre d\u00e9pos\u00e9e dans les espaces publicitaires. L&rsquo;annonce reste modifiable \u00e0 tout moment<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-27fce0c elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"27fce0c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-01a56ad elementor-widget-mobile__width-inherit elementor-widget elementor-widget-html\" data-id=\"01a56ad\" data-element_type=\"widget\" data-e-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=\"via-template-297132\">\r\n  \t\t<div data-elementor-type=\"page\" data-elementor-id=\"297132\" class=\"elementor elementor-297132\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ed0bd04 e-con-full e-flex e-con e-child\" data-id=\"ed0bd04\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4669df9 e-con-full e-flex e-con e-child\" data-id=\"4669df9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-68e02ea elementor-widget elementor-widget-text-editor\" data-id=\"68e02ea\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Vous pouvez publier vos annonces banni\u00e8re<br \/>aux formats .jpg .png<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-96b3d8f e-con-full e-flex e-con e-child\" data-id=\"96b3d8f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0dc555b elementor-widget elementor-widget-text-editor\" data-id=\"0dc555b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format de banni\u00e8re \u00e0 nous transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-120de75 e-con-full e-flex e-con e-child\" data-id=\"120de75\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4a341cb e-con-full e-flex e-con e-child\" data-id=\"4a341cb\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e7d4645 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"e7d4645\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tYEARBOOK\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-2c28328 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"2c28328\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>RAPPORT ECONOMIQUE<\/p>\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-6888d24 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"6888d24\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tL&rsquo;\u00e9v\u00e8nementiel des acteurs de la croissance\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6d74c55 e-con-full e-flex e-con e-child\" data-id=\"6d74c55\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4ac50b8 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"4ac50b8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tSp\u00e9cial Afrique\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1f26cc5 e-con-full e-flex e-con e-child\" data-id=\"1f26cc5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-cdb6261 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"cdb6261\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVotre banni\u00e8re est pr\u00e9sent\u00e9e dans l&rsquo;espace publicitaire<br>que vous avez choisi\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d2d5d23 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"d2d5d23\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Formats des banni\u00e8res<\/p>\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-a269e93 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"a269e93\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>970x250px ou 300x250px (ou dimensions proportionnelles)<br \/>Banni\u00e8res fixes au format .jpg .png, taille maximale 150 Ko<br \/>Banni\u00e8res anim\u00e9s au format .gif, taille maximale 150 Ko<\/p>\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-2e9991b elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"2e9991b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-02d4bac elementor-widget-mobile__width-inherit elementor-widget elementor-widget-html\" data-id=\"02d4bac\" data-element_type=\"widget\" data-e-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=\"via-template-297312\">\r\n  \t\t<div data-elementor-type=\"page\" data-elementor-id=\"297312\" class=\"elementor elementor-297312\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ed0bd04 e-con-full e-flex e-con e-child\" data-id=\"ed0bd04\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-e8eee87 e-con-full e-flex e-con e-child\" data-id=\"e8eee87\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1549ed4 elementor-widget elementor-widget-text-editor\" data-id=\"1549ed4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Vous pouvez publier vos annonces vid\u00e9o<br \/>aux formats .mp4 .mov .webm<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-e1c2466 e-con-full e-flex e-con e-child\" data-id=\"e1c2466\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7e7f511 elementor-widget elementor-widget-text-editor\" data-id=\"7e7f511\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format de vid\u00e9os \u00e0 nous transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d0e7fd9 e-con-full e-flex e-con e-child\" data-id=\"d0e7fd9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b031ac3 elementor-widget elementor-widget-html\" data-id=\"b031ac3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"video-container\"><\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a7f8c4a e-con-full e-flex e-con e-child\" data-id=\"a7f8c4a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-56da49c elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"56da49c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Votre vid\u00e9o est pr\u00e9sent\u00e9e dans l&rsquo;espace publicitaire <br \/>que vous avez choisi<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ab3477e elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"ab3477e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFormats des vid\u00e9os\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-b6c79a4 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"b6c79a4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>16\/9, dimensions proportionnelles ou autres dimensions<br \/>Vid\u00e9os aux formats .mp4 .mov .webm<br \/>Dur\u00e9e maximale 30 sec<br \/>Taille maximale 2 Mo<\/p>\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-90c55cf elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"90c55cf\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f022454 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-html\" data-id=\"f022454\" data-element_type=\"widget\" data-e-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=\"via-template-297336\">\r\n  \t\t<div data-elementor-type=\"page\" data-elementor-id=\"297336\" class=\"elementor elementor-297336\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ed0bd04 e-con-full e-flex e-con e-child\" data-id=\"ed0bd04\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-8336887 e-con-full e-flex e-con e-child\" data-id=\"8336887\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-b433b13 e-con-full e-flex e-con e-child\" data-id=\"b433b13\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3b6a8cd elementor-widget elementor-widget-text-editor\" data-id=\"3b6a8cd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFormat pop-up\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-82dc99f elementor-widget elementor-widget-text-editor\" data-id=\"82dc99f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vous pouvez publier vos annonces de type banni\u00e8re, vid\u00e9o, communiqu\u00e9, interview et parrainage en format pop-up<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a341ad3 e-con-full e-flex e-con e-child\" data-id=\"a341ad3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e533888 elementor-widget elementor-widget-text-editor\" data-id=\"e533888\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format de pop-up \u00e0 transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ba45a8b e-con-full e-flex e-con e-child\" data-id=\"ba45a8b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-cdfe1de e-con-full e-flex e-con e-child\" data-id=\"cdfe1de\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b020c0b elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"b020c0b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tYEARBOOK\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-63aad2f elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"63aad2f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">RAPPORT ECONOMIQUE<\/p>\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-8bb89c3 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"8bb89c3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tL&rsquo;\u00e9v\u00e8nementiel des acteurs de la croissance\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-e117037 e-con-full e-flex e-con e-child\" data-id=\"e117037\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-df0bae5 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"df0bae5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tSp\u00e9cial Afrique\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a76e62a e-con-full e-flex e-con e-child\" data-id=\"a76e62a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4515350 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"4515350\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tLe pop-up reste visible dans la page et suit le scroll\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-aa7fb00 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"aa7fb00\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCaract\u00e9ristiques des pop-up\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-fe0b16b elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"fe0b16b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<ul><li>Affichage du pop-up \u00e0 l&rsquo;ouverture de la page<\/li><li>Le pop-up suit le mouvement de la barre de d\u00e9filement<\/li><li>Possibilit\u00e9 de d\u00e9placer manuellement le pop-up dans la page<\/li><li>Le pop-up ne peut \u00eatre referm\u00e9 qu&rsquo;apr\u00e8s 4 secondes en cliquant sur une croix positionn\u00e9e en haut \u00e0 droite de l&rsquo;annonce<\/li><\/ul>\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-9287998 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"9287998\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFormats des annonces\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-258368a elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"258368a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Afin de publier vos annonces au format pop-up, merci de vous reporter aux sp\u00e9cifications des formats banni\u00e8re, vid\u00e9o, communiqu\u00e9, interview, parrainage<\/p>\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-98ac640 elementor-widget__width-initial elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"98ac640\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f737274 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-html\" data-id=\"f737274\" data-element_type=\"widget\" data-e-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=\"via-template-297353\">\r\n  \t\t<div data-elementor-type=\"page\" data-elementor-id=\"297353\" class=\"elementor elementor-297353\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ed0bd04 e-con-full e-flex e-con e-child\" data-id=\"ed0bd04\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-43ee50d e-con-full e-flex e-con e-child\" data-id=\"43ee50d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4f0830c elementor-widget elementor-widget-text-editor\" data-id=\"4f0830c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vous pouvez publier vos communiqu\u00e9s<br \/>aux formats .docx .doc .pdf<\/p>\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-383b5e6 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"383b5e6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Votre communiqu\u00e9 est pr\u00e9sent\u00e9 dans l&rsquo;espace publicitaire que vous avez choisi<\/p>\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-ee93101 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"ee93101\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Un court extrait ou r\u00e9sum\u00e9 de votre communiqu\u00e9 et la 1\u00e8re photo de votre document seront imm\u00e9diatement visibles dans l&rsquo;espace publicitaire choisi. En cliquant sur l&rsquo;annonce, le communiqu\u00e9 s&rsquo;ouvre dans un pop-up d\u00e9di\u00e9.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4b50971 e-con-full e-flex e-con e-child\" data-id=\"4b50971\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a2bef85 elementor-widget elementor-widget-text-editor\" data-id=\"a2bef85\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format de communiqu\u00e9 \u00e0 nous transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9eafef6 e-con-full e-flex e-con e-child\" data-id=\"9eafef6\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-0d043a5 e-con-full e-flex e-con e-child\" data-id=\"0d043a5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b88283b elementor-widget elementor-widget-text-editor\" data-id=\"b88283b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"font-size: 16px;\">AIR<span style=\"color: #00b050;\"> AFRIKA <\/span><\/span><strong>&#8211; Air Afrika, l&rsquo;une des \u00a0principales compagnies a\u00e9riennes du continent africain, est fi\u00e8re d&rsquo;annoncer l&rsquo;ouverture de nouvelles routes a\u00e9riennes \u00e0 partir du 1er ao\u00fbt.<\/strong>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b60749e e-con-full e-flex e-con e-child\" data-id=\"b60749e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-89f708e elementor-widget elementor-widget-text-editor\" data-id=\"89f708e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAIR<span style=\"color: #00b050;\"> AFRIKA\u00a0<\/span>\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-2921e5a elementor-widget elementor-widget-image\" data-id=\"2921e5a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"448\" height=\"134\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/pexels-anugrahajaylohiya-723240-small-V2.jpg\" class=\"attachment-large size-large wp-image-175110\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/pexels-anugrahajaylohiya-723240-small-V2.jpg 448w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/pexels-anugrahajaylohiya-723240-small-V2-300x90.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/pexels-anugrahajaylohiya-723240-small-V2-18x5.jpg 18w\" sizes=\"(max-width: 448px) 100vw, 448px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-75c26ca elementor-widget elementor-widget-text-editor\" data-id=\"75c26ca\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCes nouvelles routes relieront directement Dakar, S\u00e9n\u00e9gal \u00e0 Paris, France et Johannesburg, Afrique du Sud \u00e0 Londres, Royaume-Uni. Ces vols seront op\u00e9r\u00e9s par notre flotte de Boeing 787 Dreamliner, offrant \u00e0 nos passagers une exp\u00e9rience de vol confortable et luxueuse.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2129f38 e-con-full e-flex e-con e-child\" data-id=\"2129f38\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-985830a elementor-widget elementor-widget-text-editor\" data-id=\"985830a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAIR<span style=\"color: #00b050;\"> AFRIKA\u00a0<\/span>\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-d55d99a elementor-widget elementor-widget-image\" data-id=\"d55d99a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"1024\" height=\"307\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small-1024x307.jpg\" class=\"attachment-large size-large wp-image-175113\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small-1024x307.jpg 1024w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small-300x90.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small-768x230.jpg 768w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small-18x5.jpg 18w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small.jpg 1280w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ab81d0d e-con-full e-flex e-con e-child\" data-id=\"ab81d0d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-42b4884 elementor-widget elementor-widget-image\" data-id=\"42b4884\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"448\" height=\"299\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Capture-decran-2024-06-29-110249-small.jpg\" class=\"attachment-full size-full wp-image-175114\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Capture-decran-2024-06-29-110249-small.jpg 448w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Capture-decran-2024-06-29-110249-small-300x200.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Capture-decran-2024-06-29-110249-small-18x12.jpg 18w\" sizes=\"(max-width: 448px) 100vw, 448px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-43f653a elementor-widget elementor-widget-text-editor\" data-id=\"43f653a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\u00ab\u00a0Nous sommes ravis d&rsquo;offrir ces nouvelles options de voyage \u00e0 nos clients\u00a0\u00bb, a d\u00e9clar\u00e9 le PDG d&rsquo;Air Afrika, Monsieur Peter Vivier. \u00ab\u00a0Ces nouvelles routes renforcent notre engagement \u00e0 fournir des services de qualit\u00e9 et \u00e0 connecter l&rsquo;Afrique au reste du monde\u00a0\u00bb.\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-a1f063b elementor-widget elementor-widget-text-editor\" data-id=\"a1f063b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tLa Classe Affaires d&rsquo;Air Afrika : Un Voyage de Luxe et de Confort\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-5c32af9 elementor-widget elementor-widget-text-editor\" data-id=\"5c32af9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>La classe affaires est synonyme de luxe et de confort dans le monde du voyage a\u00e9rien. Chez Air Afrika, nous nous effor\u00e7ons de d\u00e9passer ces attentes en offrant \u00e0 nos passagers de classe affaires une exp\u00e9rience de vol in\u00e9gal\u00e9e.<br \/><span style=\"color: #00b050;\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-175116 alignleft\" style=\"color: #333333;\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/9-1567360795-300x227.jpg\" alt=\"\" width=\"198\" height=\"150\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/9-1567360795-300x227.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/9-1567360795-16x12.jpg 16w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/9-1567360795.jpg 743w\" sizes=\"(max-width: 198px) 100vw, 198px\" \/><strong>Un Si\u00e8ge qui se Transforme en Lit<\/strong> <\/span>Le confort de nos passagers est notre priorit\u00e9 absolue. C&rsquo;est pourquoi nos si\u00e8ges de classe affaires peuvent \u00eatre transform\u00e9s en lits enti\u00e8rement plats, permettant \u00e0 nos passagers de se reposer et de dormir pendant le vol. Chaque si\u00e8ge est \u00e9galement \u00e9quip\u00e9 d&rsquo;un \u00e9cran personnel de grande taille, offrant une vari\u00e9t\u00e9 de divertissements \u00e0 la demande.<br \/><span style=\"color: #00b050;\"><strong>Un Service de Restauration Haut de Gamme <\/strong><\/span>La classe affaires d&rsquo;Air Afrika offre une exp\u00e9rience culinaire exceptionnelle. Nos passagers peuvent profiter d&rsquo;un menu \u00e0 la carte, pr\u00e9par\u00e9 par des chefs renomm\u00e9s, et d&rsquo;une s\u00e9lection de vins fins et de champagnes. <span style=\"color: #00b050;\"><strong>Un Acc\u00e8s aux Salons VIP <\/strong><\/span>Nos passagers de classe affaires b\u00e9n\u00e9ficient \u00e9galement d&rsquo;un acc\u00e8s \u00e0 nos salons VIP dans les a\u00e9roports du monde entier. Ces salons offrent un espace tranquille pour se d\u00e9tendre ou travailler avant le vol, avec des services tels que le Wi-Fi gratuit, des douches et une restauration de qualit\u00e9. La classe affaires d&rsquo;Air Afrika offre une exp\u00e9rience de voyage luxueuse et confortable. De l&rsquo;espace suppl\u00e9mentaire et du confort du si\u00e8ge \u00e0 la qualit\u00e9 de la nourriture et du vin, en passant par l&rsquo;acc\u00e8s aux salons VIP, nous nous effor\u00e7ons de rendre chaque vol en classe affaires aussi agr\u00e9able et relaxant que possible.<\/p>\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-6c48456 elementor-widget elementor-widget-text-editor\" data-id=\"6c48456\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tLa Classe \u00c9conomique : Un Voyage Confortable et Abordable\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-b659915 elementor-widget elementor-widget-text-editor\" data-id=\"b659915\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-175117 alignright\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Kursi-Teraman-Di-Pesawat-3-300x300.webp\" alt=\"\" width=\"241\" height=\"241\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Kursi-Teraman-Di-Pesawat-3-300x300.webp 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Kursi-Teraman-Di-Pesawat-3-150x150.webp 150w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Kursi-Teraman-Di-Pesawat-3-12x12.webp 12w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Kursi-Teraman-Di-Pesawat-3.webp 500w\" sizes=\"(max-width: 241px) 100vw, 241px\" \/>Dans\u00a0le monde du voyage a\u00e9rien, la classe \u00e9conomique est souvent consid\u00e9r\u00e9e comme l&rsquo;option la\u00a0plus abordable. Cependant, chez Air Afrika, nous croyons que le prix abordable ne devrait pas signifier un compromis sur la qualit\u00e9 du service. Notre clas<span style=\"font-size: inherit;\">se \u00e9conomique offre une exp\u00e9rience de vol confortable et agr\u00e9able, avec une attention particuli\u00e8re port\u00e9e \u00e0 chaque d\u00e9tail.<br \/><\/span><span style=\"color: #00b050;\"><strong>Un Si\u00e8ge Confortable <\/strong><\/span>Le confort commence par le si\u00e8ge. Nos si\u00e8ges de classe \u00e9conomique sont con\u00e7us pour offrir un espace suffisant pour les jambes et un soutien lombaire, garantissant ainsi un voyage confortable, m\u00eame sur les longs vols. Chaque si\u00e8ge est \u00e9quip\u00e9 d&rsquo;un \u00e9cran personnel, offrant une vari\u00e9t\u00e9 de films, de musique et de jeux pour divertir nos passagers.<br \/><span style=\"color: #00b050;\"><strong>Un Service de Restauration de Qualit\u00e9 <\/strong><\/span>Nous comprenons que la nourriture \u00e0 bord fait partie int\u00e9grante de l&rsquo;exp\u00e9rience de voyage. C&rsquo;est pourquoi nous proposons un menu vari\u00e9, pr\u00e9par\u00e9 avec des ingr\u00e9dients frais et servis avec le sourire par notre personnel de cabine d\u00e9vou\u00e9. Nos passagers peuvent \u00e9galement profiter d&rsquo;une s\u00e9lection de boissons.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-81270bd e-con-full e-flex e-con e-child\" data-id=\"81270bd\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-a834884 e-con-full e-flex e-con e-child\" data-id=\"a834884\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fc8d45b elementor-widget__width-initial elementor-widget elementor-widget-image\" data-id=\"fc8d45b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Tenues.jpeg\" title=\"Tenues\" alt=\"Tenues\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-703599c e-con-full e-flex e-con e-child\" data-id=\"703599c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b151a4 elementor-widget elementor-widget-text-editor\" data-id=\"4b151a4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tUn Personnel de Cabine Attentionn\u00e9\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-94fc2b7 elementor-widget elementor-widget-text-editor\" data-id=\"94fc2b7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tNotre personnel de cabine est form\u00e9 pour offrir un service de la plus haute qualit\u00e9. Ils sont toujours disponibles pour r\u00e9pondre aux besoins de nos passagers, qu&rsquo;il s&rsquo;agisse d&rsquo;une demande de couverture suppl\u00e9mentaire ou d&rsquo;une aide pour remplir les formulaires d&rsquo;immigration.\nChez Air Afrika, nous croyons que voyager en classe \u00e9conomique ne signifie pas renoncer au confort ou au service. Nous nous engageons \u00e0 offrir \u00e0 nos passagers une exp\u00e9rience de vol agr\u00e9able et m\u00e9morable, quel que soit le tarif qu&rsquo;ils choisissent.\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-53a81e3 e-con-full e-flex e-con e-child\" data-id=\"53a81e3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-33b818e e-con-full e-flex e-con e-child\" data-id=\"33b818e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-71ee049 elementor-widget elementor-widget-text-editor\" data-id=\"71ee049\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tNous sommes heureux de vous accueillir \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-49da7ba elementor-widget elementor-widget-text-editor\" data-id=\"49da7ba\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Les billets pour ces nouvelles routes sont maintenant disponibles \u00e0 la vente sur notre site web et via nos agents de voyage agr\u00e9\u00e9s.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-adc16d9 e-con-full e-flex e-con e-child\" data-id=\"adc16d9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5f52a3f elementor-widget__width-initial elementor-widget elementor-widget-image\" data-id=\"5f52a3f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Capture-decran-2024-06-29-110249-small.jpg\" title=\"Capture d\u2019\u00e9cran 2024-06-29 110249 small\" alt=\"Capture d\u2019\u00e9cran 2024-06-29 110249 small\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e918ef6 elementor-widget elementor-widget-text-editor\" data-id=\"e918ef6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPour plus d&rsquo;informations, veuillez contacter notre service de relations publiques \u00e0 pr@airafrique.com.\nAir Afrika est l\u2019une des principales compagnies a\u00e9riennes du continent africain, offrant des vols vers plus de 100 destinations dans le monde. Notre mission est de connecter l&rsquo;Afrique au monde et de fournir \u00e0 nos passagers une exp\u00e9rience de voyage inoubliable.\n\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-c9d62f8 elementor-widget elementor-widget-text-editor\" data-id=\"c9d62f8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"font-size: 16px;\">AIR<span style=\"color: #00b050;\"> AFRIKA<\/span><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-876ee5c e-con-full e-flex e-con e-child\" data-id=\"876ee5c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9d05944 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"9d05944\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFormats des Communiqu\u00e9s\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-9ab7f51 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"9ab7f51\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Documents comprenant des visuels et des textes<br \/>Communiqu\u00e9s aux formats .docx .doc .pdf<br \/>Taille maximale 400 Ko<\/p>\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-cc456d9 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"cc456d9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f8cb059 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-html\" data-id=\"f8cb059\" data-element_type=\"widget\" data-e-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=\"via-template-297400\">\r\n  \t\t<div data-elementor-type=\"page\" data-elementor-id=\"297400\" class=\"elementor elementor-297400\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ed0bd04 e-con-full e-flex e-con e-child\" data-id=\"ed0bd04\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-300e494 e-con-full e-flex e-con e-child\" data-id=\"300e494\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fb9b9f5 elementor-widget elementor-widget-text-editor\" data-id=\"fb9b9f5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vous pouvez publier vos interviews<br \/>aux formats .docx .doc .pdf<\/p>\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-a0316c6 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"a0316c6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Votre interview est pr\u00e9sent\u00e9e dans l&rsquo;espace publicitaire que vous avez choisi<\/p>\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-edfdeae elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"edfdeae\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Un court extrait ou r\u00e9sum\u00e9 de votre interview et la 1\u00e8re photo de votre document seront imm\u00e9diatement visibles dans l&rsquo;espace publicitaire choisi. En cliquant sur l&rsquo;annonce, l&rsquo;interview s&rsquo;ouvre dans un pop-up d\u00e9di\u00e9.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-abb5a93 e-con-full e-flex e-con e-child\" data-id=\"abb5a93\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fb66fe7 elementor-widget elementor-widget-text-editor\" data-id=\"fb66fe7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format d&rsquo;interview \u00e0 nous transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-8c47e37 e-con-full e-flex e-con e-child\" data-id=\"8c47e37\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-ae9d77c e-con-full e-flex e-con e-child\" data-id=\"ae9d77c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-cc81d37 elementor-widget elementor-widget-text-editor\" data-id=\"cc81d37\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEntretien avec Marie UATHO, Pr\u00e9sidente et Directrice g\u00e9n\u00e9rale de Union Pan Bank (UPB)\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a29c5b0 e-con-full e-flex e-con e-child\" data-id=\"a29c5b0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-d6a6040 e-con-full e-flex e-con e-child\" data-id=\"d6a6040\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7cf866b elementor-widget__width-initial elementor-widget elementor-widget-image\" data-id=\"7cf866b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/Eileen_publiee.jpg\" title=\"Eileen_publi\u00e9e\" alt=\"Eileen_publi\u00e9e\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-947f885 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"947f885\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMarie UATHO\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-915b5d0 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"915b5d0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tUPB\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f04bc25 e-con-full e-flex e-con e-child\" data-id=\"f04bc25\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f8dd370 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"f8dd370\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Entretien avec Marie UATHO, Pr\u00e9sidente et Directrice g\u00e9n\u00e9rale de Union Pan Bank (UPB). Filiale du groupe ABC services financiers, Union Pan Bank (UPB) a \u00e9t\u00e9 \u00e9lue 6 fois \u00ab Meilleure banque du continent \u00bb par le magazine EFG<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-61481aa e-con-full e-flex e-con e-child\" data-id=\"61481aa\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-656bff8 elementor-widget elementor-widget-image\" data-id=\"656bff8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/2a65f5c0-a645-4e97-a3ca-794e800695c5-qvbkx47w2hwuv264x9qe0pdw92jmo0pb841xwyjthg.jpeg\" title=\"_2a65f5c0-a645-4e97-a3ca-794e800695c5\" alt=\"_2a65f5c0-a645-4e97-a3ca-794e800695c5\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-8e9d2ef e-con-full e-flex e-con e-child\" data-id=\"8e9d2ef\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-2ef6c80 e-con-full e-flex e-con e-child\" data-id=\"2ef6c80\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7662ce6 e-transform elementor-widget elementor-widget-text-editor\" data-id=\"7662ce6\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_rotateZ_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_tablet&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_mobile&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><b><span style=\"text-align: var(--text-align); background-color: var(--base-3);\">Quelle place occupe Union Pan Bank (UPB) dans le pays ?<\/span><br \/><\/b><\/p><p>Union Pan Bank (UPB) est une institution qui conna\u00eet une croissance importante sur le march\u00e9 bancaire. Nous avons certainement une des \u00e9volutions les plus remarqu\u00e9es dans notre secteur d\u2019activit\u00e9s ces derni\u00e8res ann\u00e9es. En effet, malgr\u00e9 le fait que nous ayons connu, une crise sanitaire mondiale qui a eu un impact \u00e9galement n\u00e9gatif sur notre \u00e9conomie, nous avons fait montre de r\u00e9silience, au travers des diff\u00e9rents choix strat\u00e9giques adopt\u00e9s auparavant.\u00a0<\/p><p><!-- \/wp:paragraph --><\/p><p><!-- wp:paragraph --><\/p>\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-d4422ef elementor-widget elementor-widget-image\" data-id=\"d4422ef\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"472\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-1024x472.jpg\" class=\"attachment-large size-large wp-image-94433\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-1024x472.jpg 1024w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-300x138.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-768x354.jpg 768w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-1536x709.jpg 1536w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-2048x945.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a247728 e-con-full e-flex e-con e-child\" data-id=\"a247728\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-27691ad e-transform elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"27691ad\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_rotateZ_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_tablet&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_mobile&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"background-color: var(--base-3);\">Union Pan Bank (UPB) a \u00e0 c\u0153ur de maintenir sa philosophie du Customer First (C1st), qui pr\u00f4ne de mettre le client au premier plan de notre activit\u00e9 bancaire. Ce qui nous a d\u2019ailleurs valu pour la 6\u00e8me fois cette reconnaissance avec encore r\u00e9cemment le prix de \u00ab Meilleure banque du continent \u00bb. Je peux me permettre d\u2019affirmer que : \u00ab notre place est dans le c\u0153ur des habitants du pays \u00bb<\/span><\/p><p><!-- \/wp:paragraph --><\/p><p><!-- wp:paragraph --><\/p>\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-f4f49b6 elementor-widget elementor-widget-image\" data-id=\"f4f49b6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"473\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/b97160fadc22a6f01879003a9f2b-1570921-e1719666331172-1024x473.jpg\" class=\"attachment-large size-large wp-image-94449\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/b97160fadc22a6f01879003a9f2b-1570921-e1719666331172-1024x473.jpg 1024w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/b97160fadc22a6f01879003a9f2b-1570921-e1719666331172-300x139.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/b97160fadc22a6f01879003a9f2b-1570921-e1719666331172-768x355.jpg 768w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/b97160fadc22a6f01879003a9f2b-1570921-e1719666331172.jpg 1200w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-824cf2a e-con-full e-flex e-con e-child\" data-id=\"824cf2a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e46cc95 e-transform elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"e46cc95\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_rotateZ_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_tablet&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_mobile&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"font-weight: bold;\">Engag\u00e9e dans le d\u00e9veloppement \u00e9conomique du pays, que propose Union Pan Bank (UPB) aux chefs d\u2019entreprise ?<\/span><\/p><p>En tant qu\u2019acteur majeur de l\u2019\u00e9conomie, l\u2019engagement de notre institution au d\u00e9veloppement et \u00e0 l\u2019\u00e9mergence \u00e9conomique n\u2019est plus \u00e0 d\u00e9montrer. Naturellement, cela passe par des initiatives que nous accompagnons dans le cadre du programme MNO, de la pertinence et de la qualit\u00e9 de notre offre commerciale. En effet, nous mettons \u00e0 la disposition des acteurs \u00e9conomiques des produits de derni\u00e8re g\u00e9n\u00e9ration et un accompagnement personnalis\u00e9. Ces produits innovants offrent des facilit\u00e9s aux entreprises en termes de financement et d\u2019outils de gestion avec un fort accent sur la banque digitale. Nous mettons aussi un accent particulier sur le renforcement des capacit\u00e9s des entrepreneurs et des dirigeants d\u2019entreprises par le biais de plateformes d\u2019\u00e9changes et de partages d\u2019exp\u00e9rience.<\/p><p><!-- \/wp:paragraph --><\/p><p><!-- wp:paragraph --><\/p>\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-64c625e elementor-widget elementor-widget-image\" data-id=\"64c625e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"472\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-1024x472.jpg\" class=\"attachment-large size-large wp-image-94465\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-1024x472.jpg 1024w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-300x138.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-768x354.jpg 768w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-1536x709.jpg 1536w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-2048x945.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-556b639 e-con-full e-flex e-con e-child\" data-id=\"556b639\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-891f4b2 e-transform elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"891f4b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_rotateZ_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_tablet&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_mobile&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"background-color: var(--base-3);\">Nous sommes engag\u00e9s dans le d\u00e9veloppement des secteurs r\u00e9els de l\u2019\u00e9conomie. Nous offrons un portefeuille complet de services bancaires aux entreprises dans les secteurs de l\u2019\u00e9nergie, de la fabrication, des produits de grande consommation, des exportations et des importations, des t\u00e9l\u00e9communications, de l\u2019agriculture et du secteur public, entre autres. Notre gamme de solutions de paiement \u00e9lectronique de classe mondiale permet aux entreprises, aux \u00e9tablissements d\u2019enseignement, aux agences priv\u00e9es\/gouvernementales, de r\u00e9aliser, de recevoir et de contr\u00f4ler des paiements de mani\u00e8re transparente en temps r\u00e9el.<\/span><\/p><p><!-- \/wp:paragraph --><\/p><p><!-- wp:paragraph --><\/p>\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-c4bd532 elementor-widget elementor-widget-image\" data-id=\"c4bd532\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"462\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-1024x462.jpg\" class=\"attachment-large size-large wp-image-94402\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-1024x462.jpg 1024w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-300x135.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-768x347.jpg 768w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-1536x694.jpg 1536w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-2048x925.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-bbd06b0 e-con-full e-flex e-con e-child\" data-id=\"bbd06b0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-eb22161 e-transform elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"eb22161\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_rotateZ_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_tablet&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_mobile&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><b>A travers son programme d\u2019entrepreneuriat, quel est l\u2019impact de la Fondation ZHOD?<\/b><\/p><p>De fa\u00e7on g\u00e9n\u00e9rale, le Programme MNO est une initiative personnelle du PCA du Groupe ABC, qui est mise en \u0153uvre par la fondation ZHOD Foundation, et elle a pour ambition de contribuer au d\u00e9veloppement \u00e9conomique par le renforcement des capacit\u00e9s du secteur priv\u00e9 en g\u00e9n\u00e9ral et des entrepreneurs en particulier. Elle a aussi pour ambition de faciliter un partenariat public-priv\u00e9 plus efficace \u00e0 l\u2019\u00e9chelle du continent. Dans ce cadre, 90 millions de dollars ont \u00e9t\u00e9 mis \u00e0 la disposition des entrepreneurs. Les objectifs recherch\u00e9s \u00e9taient de financer 9 000 entrepreneurs sur 9 ans ; de g\u00e9n\u00e9rer 900 000 emplois et contribuer \u00e0 hauteur de 900 millions de dollars US dans l\u2019\u00e9conomie sur la m\u00eame p\u00e9riode.<\/p><p>Il est important de signifier, ici, que ces objectifs ont \u00e9t\u00e9 largement atteints en moins de 9 ans avec la participation des acteurs internationaux tels que la BAD, l\u2019AFD, l\u2019Union Europ\u00e9enne etc. Le MNO a financ\u00e9 depuis son lancement, des entrepreneurs qui emploient directement ou indirectement plusieurs centaines de jeunes.\u00a0<\/p><p>En 2024, nous avons travaill\u00e9 en partenariat avec le Minist\u00e8re du Commerce, afin d\u2019encourager l\u2019entrepreneuriat local dans le but de booster la production et, par la m\u00eame occasion, la croissance \u00e9conomique. Les r\u00e9sultats en ont \u00e9t\u00e9 plus que satisfaisants par le nombre \u00e9lev\u00e9 de participants par rapport aux ann\u00e9es pr\u00e9c\u00e9dentes.<\/p><p><!-- \/wp:paragraph --><\/p><p><!-- wp:paragraph --><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-cecdb14 e-con-full e-flex e-con e-child\" data-id=\"cecdb14\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-87c693b elementor-widget elementor-widget-image\" data-id=\"87c693b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/2a65f5c0-a645-4e97-a3ca-794e800695c5-qvbkx47w2hwuv264x9qe0pdw92jmo0pb841xwyjthg.jpeg\" title=\"_2a65f5c0-a645-4e97-a3ca-794e800695c5\" alt=\"_2a65f5c0-a645-4e97-a3ca-794e800695c5\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7a23dc5 e-con-full e-flex e-con e-child\" data-id=\"7a23dc5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f436d80 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"f436d80\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Formats des Interviews<\/p>\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-d694dd3 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"d694dd3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Documents comprenant des visuels et des textes<br \/>Interviews aux formats .docx .doc .pdf<br \/>Taille maximale 400 Ko<\/p>\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-0e63ea1 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"0e63ea1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6f12c71 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-html\" data-id=\"6f12c71\" data-element_type=\"widget\" data-e-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=\"via-template-297423\">\r\n  \t\t<div data-elementor-type=\"page\" data-elementor-id=\"297423\" class=\"elementor elementor-297423\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ed0bd04 e-con-full e-flex e-con e-child\" data-id=\"ed0bd04\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-aaa5360 e-con-full e-flex e-con e-child\" data-id=\"aaa5360\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-74d3906 elementor-widget elementor-widget-text-editor\" data-id=\"74d3906\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Vous pouvez publier vos parrainages<br \/>aux formats .jpg .png<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6eb11c4 e-con-full e-flex e-con e-child\" data-id=\"6eb11c4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-eea429d elementor-widget elementor-widget-text-editor\" data-id=\"eea429d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format de parrainage \u00e0 nous transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3c8f308 e-con-full e-flex e-con e-child\" data-id=\"3c8f308\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7243a4a elementor-widget elementor-widget-text-editor\" data-id=\"7243a4a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tParrainage\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-29f41e2 e-con-full e-flex e-con e-child\" data-id=\"29f41e2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-8dc6dd4 e-con-full e-flex e-con e-child\" data-id=\"8dc6dd4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a1c2c38 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"a1c2c38\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t(exemple de nom de soci\u00e9t\u00e9)\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-49c55b9 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"49c55b9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVia Agency\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-019c0c3 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"019c0c3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Communication d\u00e9di\u00e9e aux institutionnels<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ed8ff99 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"ed8ff99\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t(exemple de texte de parrainage)\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-eecee5f elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"eecee5f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVia Agency parraine<br>les sites YEARBOOK Rapport Economique\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-3cf41c7 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"3cf41c7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\ten partenariat avec les\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-b10f544 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"b10f544\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAgences de Promotion des Investissements\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7968fdf e-con-full e-flex e-con e-child\" data-id=\"7968fdf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c4005be elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"c4005be\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Votre parrainage est pr\u00e9sent\u00e9 dans l&rsquo;espace publicitaire que vous avez choisi<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e4ee1ac elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"e4ee1ac\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFormats des parrainages\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-4344983 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"4344983\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Le texte de parrainage comprend le nom de la soci\u00e9t\u00e9 et\/ou la marque et\/ou le logo <br \/>Le texte comporte un maximum 4 lignes pour un total de 120 caract\u00e8res dont l&rsquo;expression du parrainage<br \/>Le style de police, la taille de caract\u00e8res, les dimensions de logo, les ajustements des diff\u00e9rents \u00e9l\u00e9ments et l&#8217;emplacement d\u00e9finitif sont d\u00e9finis et \u00e9tablis par Via Agency<\/p>\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-35895d4 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"35895d4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n<\/div>\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-cbfa86b elementor-hidden-tablet e-flex e-con-boxed e-con e-child\" data-id=\"cbfa86b\" data-element_type=\"container\" data-e-type=\"container\" id=\"Content4ItemsContainer\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-20eb5f5c e-con-full e-flex e-con e-child\" data-id=\"20eb5f5c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7fc54e8b elementor-widget-mobile__width-inherit elementor-widget elementor-widget-html\" data-id=\"7fc54e8b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"fr\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>Pop-ups Ind\u00e9pendants<\/title>\r\n    <style>\r\n        .popup-container {\r\n            position: fixed;\r\n            width: 600px;\r\n            height: 450px;\r\n            background: #ffffff;\r\n            border: 1px solid #ccc;\r\n            padding: 10px;\r\n            box-shadow: 2px 2px 5px rgba(0,0,0,0.1);\r\n            cursor: default;\r\n            z-index: 9999;\r\n            display: none; \/* Cach\u00e9 par d\u00e9faut *\/\r\n        }\r\n        \r\n        .popup-container.active {\r\n            display: block;\r\n        }\r\n        \r\n        .popup-container.focused {\r\n            z-index: 10000; \/* Met le popup au premier plan quand il est focalis\u00e9 *\/\r\n        }\r\n        \r\n        .handle {\r\n            background: #f0f0f0;\r\n            color: #494949;\r\n            padding: 5px;\r\n            cursor: move;\r\n            font-family: 'Roboto', sans-serif;\r\n            text-align: center;\r\n            font-size: 14px;\r\n            font-weight: 600;\r\n            position: relative;\r\n        }\r\n        \r\n        .handle-icon-container {\r\n            position: absolute;\r\n            top: 5px;\r\n            right: 10px;\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: flex-end;\r\n            width: 20px;\r\n        }\r\n        \r\n        .handle-icon {\r\n            width: 10px;\r\n            height: 10px;\r\n            cursor: pointer;\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: center;\r\n            color: white;\r\n            font-size: 10px;\r\n            font-weight: bold;\r\n        }\r\n\r\n        \/* pb653 : picto reduction (trait horizontal blanc), a gauche de la croix *\/\r\n        .handle-reduce-container {\r\n            position: absolute;\r\n            top: 5px;\r\n            right: 34px;\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: center;\r\n            width: 16px;\r\n            height: 14px;\r\n            cursor: pointer;\r\n        }\r\n        \/* pb658 : mobile \u2014 remonter le picto Reduire de 2px (top 5 -> 3) *\/\r\n        @media (max-width: 1000px) {\r\n            #popup3 .handle-reduce-container { top: 3px !important; }\r\n        }\r\n        .handle-reduce-bar {\r\n            display: block;\r\n            width: 12px;\r\n            height: 2px;\r\n            background: #7f7f7f;\r\n            border-radius: 1px;\r\n        }\r\n        \/* etat reduit : header seul, contenu masque *\/\r\n        #popup3.popup-container.popup-reduced653 .popup-content { display: none !important; }\r\n        \/* pb654b : specificite .popup-container.popup-reduced653 (2 classes) pour\r\n           battre #popup3.popup-container{height:575px !important} en mobile.\r\n           Hauteur = header seul (~40px). *\/\r\n        #popup3.popup-container.popup-reduced653 {\r\n            height: 45px !important;\r\n            min-height: 45px !important;\r\n            max-height: 45px !important;\r\n            overflow: visible !important;\r\n        }\r\n        \/* pb655 (3) : en mode reduit, le picto \"reduire\" (trait) devient un CARRE,\r\n           comme le bouton Agrandir du VLP. Le trait est masque, un carre affiche. *\/\r\n        #popup3.popup-reduced653 .handle-reduce-bar {\r\n            width: 10px !important;\r\n            height: 10px !important;\r\n            background: transparent !important;\r\n            border: 2px solid #7f7f7f !important;\r\n            border-radius: 1px !important;\r\n        }\r\n        \r\n        .popup-content {\r\n            user-select: none;\r\n            width: 100%;\r\n            height: calc(100% - 40px);\r\n            padding: 10px;\r\n            overflow-y: auto;\r\n            overflow-x: hidden;\r\n            border-radius: 3px;\r\n            margin-top: 5px;\r\n        }\r\n        \r\n        \/* pb611 : redimensionnement \u2014 standard viaPop290 (yearbook-media.js) ---\r\n           4 bords + 4 coins invisibles pour la saisie, 4 equerres bleues #4a90d9\r\n           en repere visuel (pointer-events:none pour ne pas gener la saisie). *\/\r\n        .popup-rh {\r\n            position: absolute;\r\n            z-index: 10;\r\n            touch-action: none;   \/* pas de scroll pendant le redimensionnement *\/\r\n        }\r\n        .popup-rh[data-d=\"n\"]  { top: -5px; left: 14px; right: 14px; height: 10px; cursor: n-resize; }\r\n        .popup-rh[data-d=\"s\"]  { bottom: -5px; left: 14px; right: 14px; height: 10px; cursor: s-resize; }\r\n        .popup-rh[data-d=\"w\"]  { left: -5px; top: 14px; bottom: 14px; width: 10px; cursor: w-resize; }\r\n        .popup-rh[data-d=\"e\"]  { right: -5px; top: 14px; bottom: 14px; width: 10px; cursor: e-resize; }\r\n        .popup-rh[data-d=\"nw\"] { top: -5px; left: -5px; width: 16px; height: 16px; cursor: nw-resize; }\r\n        .popup-rh[data-d=\"ne\"] { top: -5px; right: -5px; width: 16px; height: 16px; cursor: ne-resize; }\r\n        .popup-rh[data-d=\"sw\"] { bottom: -5px; left: -5px; width: 16px; height: 16px; cursor: sw-resize; }\r\n        .popup-rh[data-d=\"se\"] { bottom: -5px; right: -5px; width: 16px; height: 16px; cursor: se-resize; }\r\n        .popup-rh:hover { background: rgba(43,91,166,.07); border-radius: 3px; }\r\n\r\n        .popup-sq {\r\n            position: absolute;\r\n            width: 12px;\r\n            height: 12px;\r\n            z-index: 11;\r\n            pointer-events: none;\r\n            border-color: #4a90d9;\r\n            border-style: solid;\r\n            border-width: 0;\r\n        }\r\n        \/* -1px = la bordure du conteneur. Un enfant en position:absolute se place\r\n           par rapport a la PADDING BOX (interieur de la bordure) : le padding de\r\n           10px ne decale donc rien, seule la bordure 1px separe top:0 du bord\r\n           visible. viaPop290 (sans bordure) peut rester a 0. *\/\r\n        .popup-sq.tl { top: -1px; left: -1px; border-top-width: 3px; border-left-width: 3px; border-radius: 8px 0 0 0; }\r\n        .popup-sq.tr { top: -1px; right: -1px; border-top-width: 3px; border-right-width: 3px; border-radius: 0 8px 0 0; }\r\n        .popup-sq.bl { bottom: -1px; left: -1px; border-bottom-width: 3px; border-left-width: 3px; border-radius: 0 0 0 8px; }\r\n        .popup-sq.br { bottom: -1px; right: -1px; border-bottom-width: 3px; border-right-width: 3px; border-radius: 0 0 8px 0; }\r\n\r\n        .popup-container.resizing { user-select: none; }\r\n        .popup-container.resizing .popup-content { pointer-events: none; }\r\n\r\n        \/* Positionnement initial des pop-ups *\/\r\n        #popup1 { top: 40px; left: 150px; }\r\n        #popup2 { top: 80px; left: 190px; }\r\n        #popup3 { top: 120px; left: 230px; }\r\n        #popup4 { top: 140px; left: 270px; }\r\n        \r\n        \/* Responsive pour mobile *\/\r\n        @media (max-width: 1000px) {\r\n            .popup-container,\r\n            #popup1.popup-container,\r\n            #popup2.popup-container,\r\n            #popup3.popup-container,\r\n            #popup4.popup-container {\r\n                position: fixed !important;\r\n                width: 410px !important;\r\n                height: 375px !important;\r\n                background: #ffffff;\r\n                border: 1px solid #ccc;\r\n                padding: 10px;\r\n                box-shadow: 2px 2px 5px rgba(0,0,0,0.1);\r\n                cursor: default; \r\n                z-index: 9999;\r\n            }\r\n            \r\n            .popup-container.focused {\r\n                z-index: 10000 !important; \/* Z-index plus \u00e9lev\u00e9 pour mobile *\/\r\n            }\r\n            \r\n            \/* Positionnement mobile sp\u00e9cifique pour chaque popup *\/\r\n            #popup1 { \r\n                top: 140px !important; \r\n                left: 10px !important; \r\n            }\r\n            #popup2 { \r\n                top: 100px !important; \r\n                left: 10px !important; \r\n            }\r\n            #popup3 { \r\n                top: 120px !important; \r\n                left: 10px !important; \r\n            }\r\n            #popup4 { \r\n                top: 140px !important; \r\n                left:10px !important; \r\n            }\r\n            #popup4 .e-con-inner {\r\n                margin-top: 10px;\r\n            }\r\n        }\r\n    \r\n        \/* pb625 : popup TARIFS (#popup3) plus haut de 100px -------------------\r\n           Desktop : 450 -> 700. Mobile : 375 -> 575 (la regle mobile d'origine\r\n           est en !important et cite #popup3.popup-container ; a specificite\r\n           egale c'est la DERNIERE regle qui gagne, d'ou ce bloc en fin de\r\n           feuille). Les autres popups sont inchanges. *\/\r\n        #popup3 { height: 700px; }\r\n\r\n        @media (max-width: 1000px) {\r\n            #popup3.popup-container { height: 575px !important; }\r\n        }\r\n\r\n        \/* pb684 : header du popup TARIFS (#popup3) UNIQUEMENT - fond #e5d88e et\r\n           titre #3F3F3F. Mobile + desktop. La regle .handle (fond #f0f0f0, couleur\r\n           #494949) s'applique a TOUS les popups : on la surcharge donc en la scopant\r\n           a #popup3, sans toucher aux headers de popup1\/2\/4. Bloc en fin de feuille\r\n           = cascade gagnante, comme pb625 juste au-dessus. *\/\r\n        #popup3 .handle { background: #e5d88e !important; }\r\n        #popup3 .handle .handle-title { color: #3F3F3F !important; }\r\n\r\n        \/* pb712 : picto \"Reduire\" du popup TARIFS en #2f3e6d. Le picto a DEUX etats\r\n           (pb655) : un trait plein hors mode reduit, un carre a fond transparent en\r\n           mode reduit. On colore donc le fond dans le premier cas et la bordure dans\r\n           le second.\r\n           Le :not(.popup-reduced653) est indispensable : la regle du carre pose\r\n           background:transparent !important a specificite EGALE (1 id + 2 classes) ;\r\n           sans exclusion, ma regle etant plus bas dans la feuille l'emporterait et\r\n           remplirait le carre.\r\n           Scope #popup3 : les pictos de popup1\/2\/4 gardent leur gris #7f7f7f. *\/\r\n        #popup3:not(.popup-reduced653) .handle .handle-reduce-bar {\r\n            background: #2f3e6d !important;\r\n        }\r\n        #popup3.popup-reduced653 .handle-reduce-bar {\r\n            border-color: #2f3e6d !important;\r\n        }\r\n\r\n        \/* pb710 : lien \"Reinitialiser\" du header #popup3. Meme couleur que le titre\r\n           (#3F3F3F), 11px, texte simple cliquable (pas de soulignement).\r\n           Positionne en absolu a GAUCHE du picto Reduire : celui-ci occupe\r\n           right:34px sur 16px de large (soit jusqu'a 50px), on demarre donc a 56px.\r\n           Le titre etant centre dans le header, le chevauchement reste possible en\r\n           mobile : taille et libelle seront ajustes ensuite si besoin. *\/\r\n        #popup3 .handle .handle-reset-710 {\r\n            position: absolute !important;\r\n            top: 50% !important;\r\n            \/* pb1241 : +5px vers la GAUCHE (demande user), mobile et desktop.\r\n               L'element est ancre par son bord DROIT (position absolute + right) :\r\n               augmenter 'right' l'eloigne du bord droit, donc le deplace vers la\r\n               gauche. 56 -> 61.\r\n               pb1241c : declaration SANS EFFET \u2014 une seconde 'right' plus bas dans\r\n               le meme bloc la remplace (voir pb710\/padding). Alignee sur elle. *\/\r\n            right: 58px !important;\r\n            \/* pb710 : desktop -> -7px puis +3px = -4px net. Le decalage est ajoute AU\r\n               translateY(-50%) de centrage, et non au top : le centrage vertical\r\n               reste ainsi calcule sur la hauteur reelle de l'element. *\/\r\n            transform: translateY(calc(-50% - 4px)) !important;\r\n            color: #3F3F3F !important;\r\n            font-size: 11px !important;\r\n            font-weight: 600 !important;\r\n            line-height: 1 !important;\r\n            white-space: nowrap !important;\r\n            cursor: pointer !important;\r\n            text-decoration: none !important;\r\n            z-index: 5 !important;\r\n            \/* pb710 : cible tactile agrandie. Le texte seul (11px) offrait une zone\r\n               d'environ 11px de haut, tres difficile a viser au doigt. Le padding\r\n               l'etend sans deplacer le texte : le centrage vertical passe par\r\n               translateY(-50%), insensible a la hauteur, et le retrait de 8px sur\r\n               right compense le padding-right (la boite est ancree par son bord droit). *\/\r\n            padding: 10px 8px !important;\r\n            \/* pb1241c : LE 'right' EFFECTIF EST CELUI-CI.\r\n               La meme regle declare 'right' DEUX FOIS : une premiere valeur en tete\r\n               de bloc (celle que pb1241\/pb1241b modifiaient) et celle-ci, posee plus\r\n               bas par pb710 pour compenser le padding-right. En CSS, la derniere\r\n               declaration l'emporte \u2014 mes deux corrections etaient donc sans effet,\r\n               ce que la console confirmait : 48px.\r\n               Le decalage de 10px demande s'applique ici : 48 -> 58.\r\n               La premiere declaration est ramenee a la meme valeur, pour qu'une\r\n               lecture rapide du bloc ne laisse pas croire a deux reglages\r\n               differents. *\/\r\n            right: 58px !important;\r\n            touch-action: manipulation !important;\r\n            \/* pb710 : le libelle est remplace par une icone. display:flex centre le\r\n               SVG dans la zone tactile, quelle que soit sa taille. *\/\r\n            display: flex !important;\r\n            align-items: center !important;\r\n            justify-content: center !important;\r\n        }\r\n        \/* pb710 : icone de rechargement (fleche circulaire, facon Ctrl+R), en MIROIR\r\n           sur l'axe vertical -> la fleche tourne dans l'autre sens.\r\n           Le miroir est pose sur le SVG et non sur le span : ce dernier porte deja un\r\n           transform de positionnement (translateY), et une seconde declaration\r\n           l'ecraserait au lieu de s'y ajouter.\r\n           stroke:currentColor -> l'icone herite du #3F3F3F du span. *\/\r\n        #popup3 .handle .handle-reset-710 svg {\r\n            width: 14px !important;\r\n            height: 14px !important;\r\n            display: block !important;\r\n            transform: scaleX(-1) !important;\r\n        }\r\n        \/* pb710 : lien VISIBLE aussi en mobile (le display:none precedent est leve).\r\n           Le bloc reste en place pour y poser les ajustements mobiles a venir :\r\n           taille de caractere ou libelle raccourci. *\/\r\n        @media (max-width: 1000px) {\r\n            #popup3 .handle .handle-reset-710 {\r\n                \/* pb710 : flex (et non inline) \u2014 le display:inline d'origine servait a\r\n                   lever le masquage mobile ; il annulerait desormais le centrage de\r\n                   l'icone. Le lien reste bien visible. *\/\r\n                display: flex !important;\r\n                \/* pb710 : mobile -> -10px puis +5px = -5px net ; police 10px (11 - 1) *\/\r\n                transform: translateY(calc(-50% - 5px)) !important;\r\n                font-size: 10px !important;\r\n            }\r\n            \/* pb710 : icone -1px en mobile, comme le texte qu'elle remplace *\/\r\n            #popup3 .handle .handle-reset-710 svg {\r\n                width: 13px !important;\r\n                height: 13px !important;\r\n            }\r\n        }\r\n\r\n        \/* pb729 : titre du popup Tarifs mis en forme comme le label \"Achat express\"\r\n           (#via-express-616, pb728) : lisere #3F3F3F, coins 4px, fond vert #00ff00.\r\n           Le titre est un <span> dans un header en flex : sans display:inline-block\r\n           le lisere epouserait la boite de ligne et non le texte.\r\n           Le fond etant pose sur le SPAN, il n'affecte pas le #e5d88e du header (pb684),\r\n           qui reste visible autour. La couleur #3F3F3F du titre (pb684, meme\r\n           specificite 1 id + 2 classes) est conservee telle quelle : ce bloc est plus\r\n           bas dans la feuille mais ne redeclare pas color, donc pas de conflit.\r\n           Valeurs desktop alignees sur pb728 : bordure 2px, padding 3px 8px.\r\n           Bloc en fin de feuille = cascade gagnante, comme pb684\/pb710 au-dessus. *\/\r\n        #popup3 .handle .handle-title {\r\n            display: inline-block !important;\r\n            background-color: #00ff00 !important;\r\n            border: 2px solid #3F3F3F !important;\r\n            border-radius: 4px !important;\r\n            padding: 3px 8px !important;\r\n        }\r\n\r\n        \/* pb729 : mobile -> bordure 1px et padding 2px 6px, comme pb728 (_mob616). *\/\r\n        @media (max-width: 1000px) {\r\n            #popup3 .handle .handle-title {\r\n                border-width: 1px !important;\r\n                padding: 2px 6px !important;\r\n            }\r\n        }\r\n\r\n        \/* pb729b : reduire de 8px la hauteur du bandeau jaune de #popup3.\r\n           .handle n'a PAS de height : sa hauteur = contenu + padding vertical (5px\r\n           haut + 5px bas). On retire donc 4px de chaque cote -> -8px exactement.\r\n           Le padding HORIZONTAL reste a 5px (forme longue obligatoire, un simple\r\n           \"padding: 1px\" ecraserait aussi les cotes).\r\n           Scope #popup3 : les headers de popup1\/2\/4 gardent leurs 5px.\r\n           Les 3 pictos absolus du header (croix, Reduire, Reinitialiser) sont\r\n           positionnes par rapport au .handle : leur top fixe les laisserait 4px trop\r\n           bas dans un bandeau raccourci. On les remonte donc de 4px, en conservant\r\n           les decalages deja etablis (pb658 mobile top 3, pb710 translateY -4\/-5). *\/\r\n        \/* pb729c : -2px de plus sur la hauteur du bandeau (padding vertical 1 -> 0,\r\n           soit -1px de chaque cote). Cumul depuis l'origine : 5px -> 0px = -10px.\r\n           C'est le plancher : le padding vertical ne peut pas descendre sous 0, une\r\n           reduction supplementaire devra passer par le contenu (padding du titre\r\n           pb729, ou font-size).\r\n           Pictos Reduire et Fermer : +8px vers le BAS par rapport a pb729b\r\n           (desktop 1 -> 9 ; mobile Reduire -1 -> 7, l'ecart de 2px de pb658 est\r\n           conserve). Le lien Reinitialiser (pb710) est centre en % : il suit seul. *\/\r\n        #popup3 .handle { padding: 0px 5px !important; }\r\n        #popup3 .handle-icon-container { top: 9px !important; }\r\n        \/* pb729d : picto Reduire SEUL remonte de 3px (9 -> 6 desktop, 7 -> 4 mobile).\r\n           Le picto Fermer reste a 9px : les deux ne sont plus alignes, c'est voulu. *\/\r\n        \/* pb729g : Reduire +1px vers le bas (7 -> 8 desktop, 5 -> 6 mobile). *\/\r\n        #popup3 .handle-reduce-container { top: 8px !important; }\r\n        \/* pb784 : MOBILE seul \u2014 Reduire +2px vers le BAS (6 -> 8). Desktop inchange. *\/\r\n        @media (max-width: 1000px) {\r\n            #popup3 .handle-reduce-container { top: 8px !important; }\r\n        }\r\n\r\n        \/* pb729e : lien Reinitialiser decale de 3px vers le BAS.\r\n           Il est centre par translateY(-50%) (pb710) avec un decalage additionnel\r\n           de -4px desktop \/ -5px mobile. On agit sur ce decalage, PAS sur le top :\r\n           le centrage vertical reste ainsi calcule sur la hauteur reelle de\r\n           l'element, comme le voulait pb710.  -4 + 3 = -1 ; -5 + 3 = -2.\r\n           Meme selecteur que pb710 (1 id + 2 classes) : a specificite egale, ce\r\n           bloc plus bas dans la feuille l'emporte. *\/\r\n        \/* pb729i : Reinitialiser -1px de plus vers le HAUT (-1 -> -2 desktop ;\r\n           -2 -> -3 mobile), et TRAIT en #2f3e6d, teinte du picto Reduire (pb712).\r\n           Le SVG est dessine avec stroke=\"currentColor\" : c'est donc la propriete\r\n           color qui pilote le trait, pas un attribut stroke a modifier dans le HTML.\r\n           NB : le picto Fermer est une IMAGE PNG distante, sa couleur est cuite dans\r\n           le fichier et ne peut pas etre lue ni alignee en CSS. #2f3e6d est donc\r\n           repris du seul picto colorable, Reduire. *\/\r\n        #popup3 .handle .handle-reset-710 {\r\n            transform: translateY(calc(-50% - 2px)) !important;\r\n            color: #2f3e6d !important;\r\n        }\r\n        #popup3 .handle .handle-reset-710 svg {\r\n            stroke: #2f3e6d !important;\r\n        }\r\n        \/* pb784c : MOBILE seul \u2014 Reinitialiser 3px vers le BAS depuis -3px : -3 + 3 = 0.\r\n           Le decalage additionnel s'annule : le picto est desormais au centrage pur\r\n           translateY(-50%) de pb710. Historique de ce ticket : pb784 +5, pb784b -5,\r\n           pb784c +3.\r\n           Le picto Reduire garde son +2px vers le bas (pb784), inchange ici.\r\n           Desktop (-2px) inchange. *\/\r\n        @media (max-width: 1000px) {\r\n            #popup3 .handle .handle-reset-710 {\r\n                transform: translateY(-50%) !important;\r\n            }\r\n        }\r\n\r\n    <\/style>\r\n<\/head>\r\n<body>\r\n    <!-- Pop-up 1 -->\r\n    <div id=\"popup1\" class=\"popup-container\">\r\n        <div class=\"handle\">\r\n            Audience et accompagnement\r\n            <div class=\"handle-icon-container\">\r\n                <div class=\"handle-icon\" onclick=\"closePopup('popup1')\"><img decoding=\"async\" src=\"https:\/\/via-agency.media\/wp-content\/uploads\/2024\/07\/Croix-retour-HP-fond-transparent.webp\" class=\"handle-icon\"><\/div>\r\n            <\/div>\r\n        <\/div>\r\n        <div class=\"popup-content\">\r\n            \t\t<div data-elementor-type=\"page\" data-elementor-id=\"210702\" class=\"elementor elementor-210702\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1becf802 e-con-full e-flex e-con e-child\" data-id=\"1becf802\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-a55fa3d e-con-full elementor-hidden-desktop e-flex e-con e-child\" data-id=\"a55fa3d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d727924 RedactionnelsCloseButton elementor-widget elementor-widget-image\" data-id=\"d727924\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"#\">\n\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Croix-retour-HP-fond-blanc-qvbkx47v2z3t147hgkk8f1cj4fvm32efrhdzz4ckuy.jpg\" title=\"\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-48fba79 e-con-full DeferedImageContainer e-flex e-con e-child\" data-id=\"48fba79\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-eea490b elementor-widget__width-inherit elementor-widget elementor-widget-n-accordion\" data-id=\"eea490b\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;default_state&quot;:&quot;all_collapsed&quot;,&quot;n_accordion_animation_duration&quot;:{&quot;unit&quot;:&quot;ms&quot;,&quot;size&quot;:300,&quot;sizes&quot;:[]},&quot;max_items_expended&quot;:&quot;one&quot;}\" data-widget_type=\"nested-accordion.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"e-n-accordion\" aria-label=\"Accordion. Open links with Enter or Space, close with Escape, and navigate with Arrow Keys\">\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2500\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"1\" tabindex=\"0\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2500\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Via Agency Media vous accompagne <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2500\" class=\"elementor-element elementor-element-dbbe045 e-con-full e-flex e-con e-child\" data-id=\"dbbe045\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2500\" class=\"elementor-element elementor-element-942de5d e-flex e-con-boxed e-con e-child\" data-id=\"942de5d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2500\" class=\"elementor-element elementor-element-381ab59 e-con-full e-flex e-con e-child\" data-id=\"381ab59\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-271102d elementor-widget elementor-widget-text-editor\" data-id=\"271102d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>En lien avec vos objectifs, Via Agency Media vous propose d&rsquo;associer votre communication institutionnelle ou corporate aux sites web YEARBOOK Rapport Economique. Aux homepages, aux pages et articles th\u00e9matiques et sectorielles de diff\u00e9rents pays et continents<\/p>\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-036b175 elementor-widget elementor-widget-text-editor\" data-id=\"036b175\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: justify;\">Afin de favoriser votre communication, nous mettons \u00e0 votre disposition sur la page d&rsquo;achat d&rsquo;espaces publicitaires de nos sites web, un process vous permettant de nous transmettre pour publication vos formats de visuels (vid\u00e9o ou banni\u00e8re) et des formats r\u00e9dactionnels (parrainage, communiqu\u00e9 ou interview)<\/p>\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-408f892 elementor-widget elementor-widget-text-editor\" data-id=\"408f892\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: justify;\"><span style=\"color: ##3D3D3D;\">Notre \u00e9quipe de r\u00e9dacteurs et de journalistes professionnels vous conseille et r\u00e9dige, selon vos objectifs et dans le cadre de notre charte \u00e9ditoriale, des communiqu\u00e9s, interviews et textes de parrainage. Vous pouvez nous contacter sur <\/span><a style=\"color: #225da9;\" href=\"mailto:redaction@via-agency.media\">redaction@via-agency.media<\/a><\/p>\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-ef07b69 elementor-widget elementor-widget-text-editor\" data-id=\"ef07b69\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: justify;\">Par ailleurs, notre \u00e9quipe de communicants se tient \u00e0 votre disposition pour concevoir votre communication, et notre studio graphique r\u00e9alise pour vous vos formats publicitaires (banni\u00e8re et vid\u00e9o). Vous pouvez nous contacter sur<span style=\"color: #213864;\"><a style=\"color: #225da9;\" href=\"mailto:contact@via-agency.media\"> contact@via-agency.media<\/a><\/span><\/p>\t\t\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2501\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"2\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2501\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Une audience web mondiale <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2501\" class=\"elementor-element elementor-element-837f2d6 e-con-full e-flex e-con e-child\" data-id=\"837f2d6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2501\" class=\"elementor-element elementor-element-4780488 e-flex e-con-boxed e-con e-child\" data-id=\"4780488\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2501\" class=\"elementor-element elementor-element-bd175e7 e-con-full e-flex e-con e-child\" data-id=\"bd175e7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-10d6cd6 elementor-widget-tablet__width-initial elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"10d6cd6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: justify;\"><span style=\"color: #225da9;\"><strong>L&rsquo;audience est compos\u00e9e d\u2019actifs<\/strong><\/span> \u00e0 87% et 79% des actifs correspondent aux CSP++ et CSP+<\/p>\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-fe04e86 elementor-widget-tablet__width-initial elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"fe04e86\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: justify;\"><span style=\"color: #225da9;\"><strong>Nombre de pages visit\u00e9es<\/strong><\/span> 3,1 pages sont vues en moyenne par visite et 70,7% des visiteurs consultent plusieurs pages de chacun de nos sites<\/p>\t\t\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2502\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"3\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2502\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Un lectorat de d\u00e9cideurs et CSP+ <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2502\" class=\"elementor-element elementor-element-ccace3a e-con-full e-flex e-con e-child\" data-id=\"ccace3a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2502\" class=\"elementor-element elementor-element-63faf39 e-flex e-con-boxed e-con e-child\" data-id=\"63faf39\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2502\" class=\"elementor-element elementor-element-6a1c751 e-con-full e-flex e-con e-child\" data-id=\"6a1c751\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e8645df elementor-widget-tablet__width-initial elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"e8645df\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: justify;\"><span style=\"color: #225da9;\"><strong>Un lectorat de d\u00e9cideurs<\/strong><\/span> compos\u00e9 des Pr\u00e9sidences, Primatures, Minist\u00e8res, Agences et Minist\u00e8res de la Promotion de l\u2019Investissement, de hauts responsables en Affaires Publiques, de dirigeants et responsables de Soci\u00e9t\u00e9s Priv\u00e9es Nationales et Internationales<\/p>\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-a7c908a elementor-widget-tablet__width-initial elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"a7c908a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: justify;\"><span style=\"color: #225da9;\"><strong>Une base de donn\u00e9es d\u00e9di\u00e9e et influente<\/strong><\/span>\u00a0avec plus de 3.500 d\u00e9cideurs publics et priv\u00e9s dont les partenariats, les parrainages et les annonceurs<\/p>\t\t\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t<\/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-3c67521 elementor-widget elementor-widget-html\" data-id=\"3c67521\" data-element_type=\"widget\" data-e-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\njQuery(document).ready(function($) {\r\n\r\n    \/\/ \u2705 Titres accord\u00e9on \u2014 couleur forc\u00e9e (h\u00e9ritage blanc du popup neutralis\u00e9)\r\n    if (!document.getElementById('via-kit-media-accordion-css')) {\r\n        var s = document.createElement('style');\r\n        s.id = 'via-kit-media-accordion-css';\r\n        s.textContent =\r\n            '.e-n-accordion-item-title-text { color: #225DA9 !important; font-family: Roboto, sans-serif !important; font-size: 14px !important; font-weight: 600 !important; }' +\r\n            '.e-n-accordion-item-title .e-opened, .e-n-accordion-item-title .e-closed { color: #225DA9 !important; }' +\r\n            '.e-n-accordion-item-title[aria-expanded=\"true\"] .e-n-accordion-item-title-text { color: #225DA9 !important; }';\r\n        document.head.appendChild(s);\r\n    }\r\n    \r\n    $(document).on('click', '.e-n-accordion .e-n-accordion-item-title', function(e) {\r\n        var $toggler = $(this);\r\n        var isCurrentlyClosed = $toggler.attr('aria-expanded') === 'false';\r\n        \r\n        if (isCurrentlyClosed) {\r\n            setTimeout(function() {\r\n                var container, scrollTarget;\r\n                \r\n                if (window.outerWidth > 1000) {\r\n                    container = $('#Content4Items');\r\n                    scrollTarget = $toggler.offset().top - container.offset().top + container.scrollTop();\r\n                } else {\r\n                    container = $('#ConteneurRedactionel');\r\n                    scrollTarget = $toggler.offset().top - container.offset().top + container.scrollTop() - 10;\r\n                }\r\n                \r\n                container.animate({ scrollTop: scrollTarget }, 250);\r\n            }, 400);\r\n        }\r\n    });\r\n    \r\n    \/\/ Observer qui d\u00e9tecte quand l'accord\u00e9on n'est plus visible et le referme\r\n    const accordionContainer = document.querySelector('.e-n-accordion');\r\n    \r\n    if (accordionContainer) {\r\n        const observer = new IntersectionObserver(function(entries) {\r\n            entries.forEach(function(entry) {\r\n                if (!entry.isIntersecting) {\r\n                    \/\/ Fermer tous les <details> ouverts\r\n                    accordionContainer.querySelectorAll('details.e-n-accordion-item[open]').forEach(function(detail) {\r\n                        detail.removeAttribute('open');\r\n                    });\r\n                }\r\n            });\r\n        }, { threshold: 0 });\r\n    \r\n        observer.observe(accordionContainer);\r\n    }\r\n        \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<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <!-- Pop-up 2 -->\r\n    <div id=\"popup2\" class=\"popup-container\">\r\n        <div class=\"handle\">\r\n            Kit Media & Formats des annonces\r\n            <div class=\"handle-icon-container\">\r\n                <div class=\"handle-icon\" onclick=\"closePopup('popup2')\"><img decoding=\"async\" src=\"https:\/\/via-agency.media\/wp-content\/uploads\/2024\/07\/Croix-retour-HP-fond-transparent.webp\" class=\"handle-icon\"><\/div>\r\n            <\/div>\r\n        <\/div>\r\n        <div class=\"popup-content\">\r\n            \t\t<div data-elementor-type=\"page\" data-elementor-id=\"210712\" class=\"elementor elementor-210712\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1becf802 e-con-full e-flex e-con e-child\" data-id=\"1becf802\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-a55fa3d e-con-full elementor-hidden-desktop e-flex e-con e-child\" data-id=\"a55fa3d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d727924 RedactionnelsCloseButton elementor-widget elementor-widget-image\" data-id=\"d727924\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"#\">\n\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Croix-retour-HP-fond-blanc-qvbkx47v2z3t147hgkk8f1cj4fvm32efrhdzz4ckuy.jpg\" title=\"\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-64836473 e-con-full DeferedImageContainer e-flex e-con e-child\" data-id=\"64836473\" data-element_type=\"container\" data-e-type=\"container\" id=\"AudiencewebTexteConteneur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7596b382 elementor-widget__width-inherit elementor-widget elementor-widget-n-accordion\" data-id=\"7596b382\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;default_state&quot;:&quot;all_collapsed&quot;,&quot;n_accordion_animation_duration&quot;:{&quot;unit&quot;:&quot;ms&quot;,&quot;size&quot;:300,&quot;sizes&quot;:[]},&quot;max_items_expended&quot;:&quot;one&quot;}\" data-widget_type=\"nested-accordion.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"e-n-accordion\" aria-label=\"Accordion. Open links with Enter or Space, close with Escape, and navigate with Arrow Keys\">\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1970\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"1\" tabindex=\"0\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1970\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Cr\u00e9ation d'annonces <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-26d8e40a e-con-full e-flex e-con e-child\" data-id=\"26d8e40a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-7ebb1ce e-flex e-con-boxed e-con e-child\" data-id=\"7ebb1ce\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-19923d7 e-con-full e-flex e-con e-child\" data-id=\"19923d7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f5b64ec elementor-widget elementor-widget-text-editor\" data-id=\"f5b64ec\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vous pouvez cr\u00e9er vos annonces aux formats<br>Banni\u00e8re, Communiqu\u00e9, Interview, Parrainage<br>directement en ligne<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-815e8c8 e-con-full e-flex e-con e-child\" data-id=\"815e8c8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2f0e70c elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"2f0e70c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Cr\u00e9er une annonce en 5 \u00e9tapes<\/p>\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-7a24bba elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"7a24bba\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t1 &#8211;  Choisir le format d&rsquo;annonce \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-695c613 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"695c613\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tBanni\u00e8re, Communiqu\u00e9, Interview ou Parrainage\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-66c8faa elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"66c8faa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t2 &#8211; Cr\u00e9er l&rsquo;annonce\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-5dac06b elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"5dac06b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAjouter textes, images, logo et personnaliser l&rsquo;arri\u00e8re-plan\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-3da45d6 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"3da45d6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t3 &#8211; Visualiser l&rsquo;annonce\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-b20e0b5 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"b20e0b5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVoir l&rsquo;annonce avant validation\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-2b52e07 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"2b52e07\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t4 &#8211; Valider l&rsquo;annonce\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-5e4d62a elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"5e4d62a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tG\u00e9n\u00e9ration automatique de l&rsquo;annonce pr\u00eate \u00e0 \u00eatre publi\u00e9e\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-8923384 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"8923384\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t5 &#8211; Publier l&rsquo;annonce\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-8d8ccb1 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"8d8ccb1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tGlisser-d\u00e9poser l&rsquo;annonce dans les espaces publicitaires de votre choix\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-4a41297 e-con-full e-flex e-con e-child\" data-id=\"4a41297\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-afd8126 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"afd8126\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Fonctionnalit\u00e9s de cr\u00e9ation d&rsquo;annonces<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-a44e288 e-con-full e-flex e-con e-child\" data-id=\"a44e288\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-5a201ea e-con-full e-flex e-con e-child\" data-id=\"5a201ea\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a186ebc elementor-widget elementor-widget-image\" data-id=\"a186ebc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-08-225521-rk84erlevwbdb9grvv3a0g7b06vzzghk3jfw1par4a.png\" title=\"Capture d\u2019\u00e9cran 2026-03-08 225521\" alt=\"Capture d\u2019\u00e9cran 2026-03-08 225521\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-acbf32b elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"acbf32b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tZones de texte\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-da354d9 elementor-widget__width-initial CreationAnnonceFonctionnalitesTextes elementor-widget elementor-widget-text-editor\" data-id=\"da354d9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ajouter, d\u00e9placer et redimensionner les zones de texte. Mise en forme compl\u00e8te : police, taille, couleur, gras, italique, soulign\u00e9, alignement, interligne, texte vertical<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-d503060 e-con-full e-flex e-con e-child\" data-id=\"d503060\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-f7d8fbf e-con-full e-flex e-con e-child\" data-id=\"f7d8fbf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-88e4bd1 elementor-widget elementor-widget-image\" data-id=\"88e4bd1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-08-230228-rk84nhjiak9510sqymso58z9evwled3wmpc2c4d9e2.png\" title=\"Capture d\u2019\u00e9cran 2026-03-08 230228\" alt=\"Capture d\u2019\u00e9cran 2026-03-08 230228\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-0eb6b8f elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"0eb6b8f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tZones d&rsquo;images\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9da96a4 elementor-widget__width-initial CreationAnnonceFonctionnalitesTextes elementor-widget elementor-widget-text-editor\" data-id=\"9da96a4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Importer des photos et logos. Chaque image est recadrable, redimensionnable et ajustable (zoom, luminosit\u00e9, contraste, saturation, opacit\u00e9)<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-dd0f65e e-con-full e-flex e-con e-child\" data-id=\"dd0f65e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-55db764 e-con-full e-flex e-con e-child\" data-id=\"55db764\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b349da7 elementor-widget elementor-widget-image\" data-id=\"b349da7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-08-230536-rk84rwe8dkalj4e071gmcmw5t05mj7mjkjl4fvtq5o.png\" title=\"Capture d\u2019\u00e9cran 2026-03-08 230536\" alt=\"Capture d\u2019\u00e9cran 2026-03-08 230536\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-15d2117 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"15d2117\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tZone mixte image et texte\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-eefd1d2 elementor-widget__width-initial CreationAnnonceFonctionnalitesTextes elementor-widget elementor-widget-text-editor\" data-id=\"eefd1d2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Cr\u00e9er des blocs mixtes int\u00e9grant texte et visuel dans une m\u00eame zone<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-b8ea1c3 e-con-full e-flex e-con e-child\" data-id=\"b8ea1c3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-233ac16 e-con-full e-flex e-con e-child\" data-id=\"233ac16\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ed9ebd6 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"ed9ebd6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFond personnalisable\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-760052e e-con-full CreationAnnonceFonctionnalitesTextes e-flex e-con e-child\" data-id=\"760052e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6951f43 elementor-widget elementor-widget-image\" data-id=\"6951f43\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-13-152632-rkga4d5414rwj0q2huy9tqm5t4ytyrxvhzrw6xpvii.png\" title=\"Capture d\u2019\u00e9cran 2026-03-13 152632\" alt=\"Capture d\u2019\u00e9cran 2026-03-13 152632\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-ee0249f elementor-widget elementor-widget-text-editor\" data-id=\"ee0249f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tImage\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-c2c91d7 elementor-widget elementor-widget-image\" data-id=\"c2c91d7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-09-145334-rk9a221w0kqbzznv2xui53xprp2rn6kewc7bciaaba.png\" title=\"Capture d\u2019\u00e9cran 2026-03-09 145334\" alt=\"Capture d\u2019\u00e9cran 2026-03-09 145334\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-653642e elementor-widget elementor-widget-text-editor\" data-id=\"653642e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCouleur\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-d53a862 elementor-widget elementor-widget-image\" data-id=\"d53a862\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-09-145344-rk9a1xcp2ejwdxuoudtdan4esrpxkp1r7oxvy4h964.png\" title=\"Capture d\u2019\u00e9cran 2026-03-09 145344\" alt=\"Capture d\u2019\u00e9cran 2026-03-09 145344\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-438c172 elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"438c172\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tluminosit\u00e9, contraste, saturation, opacit\u00e9\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-9c01db9 e-con-full e-flex e-con e-child\" data-id=\"9c01db9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-db0bbee e-con-full e-flex e-con e-child\" data-id=\"db0bbee\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-91162ae elementor-widget elementor-widget-image\" data-id=\"91162ae\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-13-153034-rkgaakup7pa5a7p47jnhb65v6uc6uqlzor1gesi6dw.png\" title=\"Capture d\u2019\u00e9cran 2026-03-13 153034\" alt=\"Capture d\u2019\u00e9cran 2026-03-13 153034\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-3d901b3 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"3d901b3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAnnuler\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-301a450 elementor-widget__width-initial CreationAnnonceFonctionnalitesTextes elementor-widget elementor-widget-text-editor\" data-id=\"301a450\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Chaque modification est r\u00e9versible. Annuler les actions \u00e0 tout moment<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-6cb1ed0 e-con-full e-flex e-con e-child\" data-id=\"6cb1ed0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-e438886 e-con-full e-flex e-con e-child\" data-id=\"e438886\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6de0e5e elementor-widget elementor-widget-image\" data-id=\"6de0e5e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-08-230822-rk84xzemlymeo9jvo64ozlmk7s65cos02nl99cszvm.png\" title=\"Capture d\u2019\u00e9cran 2026-03-08 230822\" alt=\"Capture d\u2019\u00e9cran 2026-03-08 230822\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-4bd3f67 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"4bd3f67\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAper\u00e7u avant validation\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4101c11 elementor-widget__width-initial CreationAnnonceFonctionnalitesTextes elementor-widget elementor-widget-text-editor\" data-id=\"4101c11\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Visualiser l&rsquo;annonce en plein \u00e9cran puis valider<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-9918edb e-con-full e-flex e-con e-child\" data-id=\"9918edb\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1970\" class=\"elementor-element elementor-element-d8423b0 e-con-full e-flex e-con e-child\" data-id=\"d8423b0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-47ee73f elementor-widget elementor-widget-image\" data-id=\"47ee73f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Capture-decran-2026-03-08-230841-rk84y1aazmozbhh5d6xy4l5hejwvs2zgqww87wq7jg.png\" title=\"Capture d\u2019\u00e9cran 2026-03-08 230841\" alt=\"Capture d\u2019\u00e9cran 2026-03-08 230841\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-8bdc38c elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"8bdc38c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tValider\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1025829 elementor-widget__width-initial CreationAnnonceFonctionnalitesTextes elementor-widget elementor-widget-text-editor\" data-id=\"1025829\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>G\u00e9n\u00e9rer l&rsquo;annonce pr\u00eate \u00e0 \u00eatre d\u00e9pos\u00e9e dans les espaces publicitaires. L&rsquo;annonce reste modifiable \u00e0 tout moment<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-36299ad elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"36299ad\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1971\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"2\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1971\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Pop-up <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1971\" class=\"elementor-element elementor-element-3236971e e-con-full e-flex e-con e-child\" data-id=\"3236971e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1971\" class=\"elementor-element elementor-element-67cedc1 e-flex e-con-boxed e-con e-child\" data-id=\"67cedc1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1971\" class=\"elementor-element elementor-element-b80a280 e-con-full e-flex e-con e-child\" data-id=\"b80a280\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9b29d3d elementor-widget elementor-widget-text-editor\" data-id=\"9b29d3d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFormat pop-up\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-9be3587 elementor-widget elementor-widget-text-editor\" data-id=\"9be3587\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vous pouvez publier vos annonces de type banni\u00e8re, vid\u00e9o, communiqu\u00e9, interview et parrainage en format pop-up<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1971\" class=\"elementor-element elementor-element-540493e e-con-full e-flex e-con e-child\" data-id=\"540493e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c18fc82 elementor-widget elementor-widget-text-editor\" data-id=\"c18fc82\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format de pop-up \u00e0 transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1971\" class=\"elementor-element elementor-element-2411b38 e-con-full e-flex e-con e-child\" data-id=\"2411b38\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1971\" class=\"elementor-element elementor-element-78a67a2 e-con-full e-flex e-con e-child\" data-id=\"78a67a2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-32d6b84 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"32d6b84\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tYEARBOOK\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-f291bc9 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"f291bc9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">RAPPORT ECONOMIQUE<\/p>\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-3f453ef elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"3f453ef\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tL&rsquo;\u00e9v\u00e8nementiel des acteurs de la croissance\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1971\" class=\"elementor-element elementor-element-6bcb26c e-con-full e-flex e-con e-child\" data-id=\"6bcb26c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-91166dc elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"91166dc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tSp\u00e9cial Afrique\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1971\" class=\"elementor-element elementor-element-b47baf2 e-con-full e-flex e-con e-child\" data-id=\"b47baf2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c74a126 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"c74a126\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tLe pop-up reste visible dans la page et suit le scroll\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-199cb01 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"199cb01\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCaract\u00e9ristiques des pop-up\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-e2b6f6d elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"e2b6f6d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<ul>\n<li>Affichage du pop-up \u00e0 l&rsquo;ouverture de la page<\/li>\n<li>Le pop-up suit le mouvement de la barre de d\u00e9filement<\/li>\n<li>Possibilit\u00e9 de d\u00e9placer manuellement le pop-up dans la page<\/li>\n<li>Le pop-up ne peut \u00eatre referm\u00e9 qu&rsquo;apr\u00e8s 4 secondes en cliquant sur une croix positionn\u00e9e en haut \u00e0 droite de l&rsquo;annonce<\/li>\n<\/ul>\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-7e304a6 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"7e304a6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFormats des annonces\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-f5f73f4 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"f5f73f4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Afin de publier vos annonces au format pop-up, merci de vous reporter aux sp\u00e9cifications des formats banni\u00e8re, vid\u00e9o, communiqu\u00e9, interview, parrainage<\/p>\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-d39fdd4 elementor-widget__width-initial elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"d39fdd4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1972\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"3\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1972\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Vid\u00e9o <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1972\" class=\"elementor-element elementor-element-f825c6c e-con-full e-flex e-con e-child\" data-id=\"f825c6c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1972\" class=\"elementor-element elementor-element-8cee4f9 e-flex e-con-boxed e-con e-child\" data-id=\"8cee4f9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1972\" class=\"elementor-element elementor-element-031917a e-con-full e-flex e-con e-child\" data-id=\"031917a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-bfd79b2 elementor-widget elementor-widget-text-editor\" data-id=\"bfd79b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vous pouvez publier vos annonces vid\u00e9o<br \/>aux formats .mp4 .mov .webm<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1972\" class=\"elementor-element elementor-element-10d8215 e-con-full e-flex e-con e-child\" data-id=\"10d8215\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2b371d0 elementor-widget elementor-widget-text-editor\" data-id=\"2b371d0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format de vid\u00e9os \u00e0 nous transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1972\" class=\"elementor-element elementor-element-28412a2 e-con-full e-flex e-con e-child\" data-id=\"28412a2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-97d44f2 elementor-widget elementor-widget-html\" data-id=\"97d44f2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"video-container\"><\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1972\" class=\"elementor-element elementor-element-0d36796 e-con-full e-flex e-con e-child\" data-id=\"0d36796\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-446b81b elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"446b81b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVotre vid\u00e9o est pr\u00e9sent\u00e9e dans l&rsquo;espace publicitaire <br>que vous avez choisi\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b6bab1c elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"b6bab1c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFormats des vid\u00e9os\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-a12709e elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"a12709e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">16\/9, dimensions proportionnelles ou autres dimensions<br \/>Vid\u00e9os aux formats .mp4 .mov .webm<br \/>Dur\u00e9e maximale 30 sec<br \/>Taille maximale 2 Mo<\/p>\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-e8d2e37 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"e8d2e37\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1973\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"4\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1973\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Banni\u00e8re <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1973\" class=\"elementor-element elementor-element-64ed26a e-con-full e-flex e-con e-child\" data-id=\"64ed26a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1973\" class=\"elementor-element elementor-element-7f7a099 e-flex e-con-boxed e-con e-child\" data-id=\"7f7a099\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1973\" class=\"elementor-element elementor-element-3d46d9f e-con-full e-flex e-con e-child\" data-id=\"3d46d9f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-70e61cf elementor-widget elementor-widget-text-editor\" data-id=\"70e61cf\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vous pouvez publier vos annonces banni\u00e8re<br \/>aux formats .jpg .png<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1973\" class=\"elementor-element elementor-element-7216347 e-con-full e-flex e-con e-child\" data-id=\"7216347\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7ac280f elementor-widget elementor-widget-text-editor\" data-id=\"7ac280f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format de banni\u00e8re \u00e0 nous transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1973\" class=\"elementor-element elementor-element-537e20b e-con-full e-flex e-con e-child\" data-id=\"537e20b\" data-element_type=\"container\" data-e-type=\"container\" id=\"FormatBanniereImage\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1973\" class=\"elementor-element elementor-element-7ca3aaa e-con-full e-flex e-con e-child\" data-id=\"7ca3aaa\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d7079df elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"d7079df\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tYEARBOOK\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-b88ba02 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"b88ba02\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">RAPPORT ECONOMIQUE<\/p>\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-c80fb34 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"c80fb34\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tL&rsquo;\u00e9v\u00e8nementiel des acteurs de la croissance\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1973\" class=\"elementor-element elementor-element-1476e0c e-con-full e-flex e-con e-child\" data-id=\"1476e0c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b357fcd elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"b357fcd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tSp\u00e9cial Afrique\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1973\" class=\"elementor-element elementor-element-9eadd07 e-con-full e-flex e-con e-child\" data-id=\"9eadd07\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b39b033 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"b39b033\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVotre banni\u00e8re est pr\u00e9sent\u00e9e dans l&rsquo;espace publicitaire<br>\nque vous avez choisi\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a0cabd1 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"a0cabd1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFormats des banni\u00e8res\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-3f33885 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"3f33885\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">970x250px ou 300x250px (ou dimensions proportionnelles)<br \/>Banni\u00e8res fixes au format .jpg .png, taille maximale 150 Ko<br \/>Banni\u00e8res anim\u00e9s au format .gif, taille maximale 150 Ko<\/p>\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-c5ad20b elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"c5ad20b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1974\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"5\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1974\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Communiqu\u00e9 <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-ed6536a e-con-full e-flex e-con e-child\" data-id=\"ed6536a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-b930562 e-flex e-con-boxed e-con e-child\" data-id=\"b930562\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-110a067 e-con-full e-flex e-con e-child\" data-id=\"110a067\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-10695fb elementor-widget elementor-widget-text-editor\" data-id=\"10695fb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vous pouvez publier vos communiqu\u00e9s<br \/>aux formats .docx .doc .pdf<\/p>\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-0aa208d elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"0aa208d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Votre communiqu\u00e9 est pr\u00e9sent\u00e9 dans l&rsquo;espace publicitaire <br \/>que vous avez choisi<\/p>\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-6c9f6ce elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"6c9f6ce\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Un court extrait ou r\u00e9sum\u00e9 de votre communiqu\u00e9 et la 1\u00e8re photo de votre document seront imm\u00e9diatement visibles dans l&rsquo;espace publicitaire choisi. En cliquant sur l&rsquo;annonce, le communiqu\u00e9 s&rsquo;ouvre dans un pop-up d\u00e9di\u00e9.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-41747c4 e-con-full e-flex e-con e-child\" data-id=\"41747c4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f82ac5a elementor-widget elementor-widget-text-editor\" data-id=\"f82ac5a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format de communiqu\u00e9 \u00e0 nous transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-1c63ae0 e-con-full e-flex e-con e-child\" data-id=\"1c63ae0\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-c86e2a6 e-con-full e-flex e-con e-child\" data-id=\"c86e2a6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d0606e0 elementor-widget elementor-widget-text-editor\" data-id=\"d0606e0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"font-size: 16px;\">AIR<span style=\"color: #00b050;\"> AFRIKA <\/span><\/span><strong>&#8211; Air Afrika, l&rsquo;une des \u00a0principales compagnies a\u00e9riennes du continent africain, est fi\u00e8re d&rsquo;annoncer l&rsquo;ouverture de nouvelles routes a\u00e9riennes \u00e0 partir du 1er ao\u00fbt.<\/strong>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-7e9282c e-con-full e-flex e-con e-child\" data-id=\"7e9282c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-544549f elementor-widget elementor-widget-text-editor\" data-id=\"544549f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAIR<span style=\"color: #00b050;\"> AFRIKA\u00a0<\/span>\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-213ade1 elementor-widget elementor-widget-image\" data-id=\"213ade1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"448\" height=\"134\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/pexels-anugrahajaylohiya-723240-small-V2.jpg\" class=\"attachment-large size-large wp-image-175110\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/pexels-anugrahajaylohiya-723240-small-V2.jpg 448w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/pexels-anugrahajaylohiya-723240-small-V2-300x90.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/pexels-anugrahajaylohiya-723240-small-V2-18x5.jpg 18w\" sizes=\"(max-width: 448px) 100vw, 448px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-98a8d1d elementor-widget elementor-widget-text-editor\" data-id=\"98a8d1d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ces nouvelles routes relieront directement Dakar, S\u00e9n\u00e9gal \u00e0 Paris, France et Johannesburg, Afrique du Sud \u00e0 Londres, Royaume-Uni. Ces vols seront op\u00e9r\u00e9s par notre flotte de Boeing 787 Dreamliner, offrant \u00e0 nos passagers une exp\u00e9rience de vol confortable et luxueuse.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-34803d1 e-con-full e-flex e-con e-child\" data-id=\"34803d1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-54f1d9f elementor-widget elementor-widget-text-editor\" data-id=\"54f1d9f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAIR<span style=\"color: #00b050;\"> AFRIKA\u00a0<\/span>\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-dc40137 elementor-widget elementor-widget-image\" data-id=\"dc40137\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"1024\" height=\"307\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small-1024x307.jpg\" class=\"attachment-large size-large wp-image-175113\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small-1024x307.jpg 1024w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small-300x90.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small-768x230.jpg 768w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small-18x5.jpg 18w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/plane-view-680993_1280-small.jpg 1280w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-4740519 e-con-full e-flex e-con e-child\" data-id=\"4740519\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-90c5001 elementor-widget elementor-widget-image\" data-id=\"90c5001\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"448\" height=\"299\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Capture-decran-2024-06-29-110249-small.jpg\" class=\"attachment-full size-full wp-image-175114\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Capture-decran-2024-06-29-110249-small.jpg 448w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Capture-decran-2024-06-29-110249-small-300x200.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Capture-decran-2024-06-29-110249-small-18x12.jpg 18w\" sizes=\"(max-width: 448px) 100vw, 448px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-353991c elementor-widget elementor-widget-text-editor\" data-id=\"353991c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\u00ab\u00a0Nous sommes ravis d&rsquo;offrir ces nouvelles options de voyage \u00e0 nos clients\u00a0\u00bb, a d\u00e9clar\u00e9 le PDG d&rsquo;Air Afrika, Monsieur Peter Vivier. \u00ab\u00a0Ces nouvelles routes renforcent notre engagement \u00e0 fournir des services de qualit\u00e9 et \u00e0 connecter l&rsquo;Afrique au reste du monde\u00a0\u00bb.\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-77e21da elementor-widget elementor-widget-text-editor\" data-id=\"77e21da\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tLa Classe Affaires d&rsquo;Air Afrika : Un Voyage de Luxe et de Confort\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-aa5f5fd elementor-widget elementor-widget-text-editor\" data-id=\"aa5f5fd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>La classe affaires est synonyme de luxe et de confort dans le monde du voyage a\u00e9rien. Chez Air Afrika, nous nous effor\u00e7ons de d\u00e9passer ces attentes en offrant \u00e0 nos passagers de classe affaires une exp\u00e9rience de vol in\u00e9gal\u00e9e.<br \/><span style=\"color: #00b050;\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-175116 alignleft\" style=\"color: #333333;\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/9-1567360795-300x227.jpg\" alt=\"\" width=\"198\" height=\"150\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/9-1567360795-300x227.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/9-1567360795-16x12.jpg 16w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/9-1567360795.jpg 743w\" sizes=\"(max-width: 198px) 100vw, 198px\" \/><strong>Un Si\u00e8ge qui se Transforme en Lit<\/strong> <\/span>Le confort de nos passagers est notre priorit\u00e9 absolue. C&rsquo;est pourquoi nos si\u00e8ges de classe affaires peuvent \u00eatre transform\u00e9s en lits enti\u00e8rement plats, permettant \u00e0 nos passagers de se reposer et de dormir pendant le vol. Chaque si\u00e8ge est \u00e9galement \u00e9quip\u00e9 d&rsquo;un \u00e9cran personnel de grande taille, offrant une vari\u00e9t\u00e9 de divertissements \u00e0 la demande.<br \/><span style=\"color: #00b050;\"><strong>Un Service de Restauration Haut de Gamme <\/strong><\/span>La classe affaires d&rsquo;Air Afrika offre une exp\u00e9rience culinaire exceptionnelle. Nos passagers peuvent profiter d&rsquo;un menu \u00e0 la carte, pr\u00e9par\u00e9 par des chefs renomm\u00e9s, et d&rsquo;une s\u00e9lection de vins fins et de champagnes. <span style=\"color: #00b050;\"><strong>Un Acc\u00e8s aux Salons VIP <\/strong><\/span>Nos passagers de classe affaires b\u00e9n\u00e9ficient \u00e9galement d&rsquo;un acc\u00e8s \u00e0 nos salons VIP dans les a\u00e9roports du monde entier. Ces salons offrent un espace tranquille pour se d\u00e9tendre ou travailler avant le vol, avec des services tels que le Wi-Fi gratuit, des douches et une restauration de qualit\u00e9. La classe affaires d&rsquo;Air Afrika offre une exp\u00e9rience de voyage luxueuse et confortable. De l&rsquo;espace suppl\u00e9mentaire et du confort du si\u00e8ge \u00e0 la qualit\u00e9 de la nourriture et du vin, en passant par l&rsquo;acc\u00e8s aux salons VIP, nous nous effor\u00e7ons de rendre chaque vol en classe affaires aussi agr\u00e9able et relaxant que possible.<\/p>\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-644f8b7 elementor-widget elementor-widget-text-editor\" data-id=\"644f8b7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tLa Classe \u00c9conomique : Un Voyage Confortable et Abordable\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-4d767b0 elementor-widget elementor-widget-text-editor\" data-id=\"4d767b0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-175117 alignright\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Kursi-Teraman-Di-Pesawat-3-300x300.webp\" alt=\"\" width=\"241\" height=\"241\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Kursi-Teraman-Di-Pesawat-3-300x300.webp 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Kursi-Teraman-Di-Pesawat-3-150x150.webp 150w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Kursi-Teraman-Di-Pesawat-3-12x12.webp 12w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Kursi-Teraman-Di-Pesawat-3.webp 500w\" sizes=\"(max-width: 241px) 100vw, 241px\" \/>Dans\u00a0le monde du voyage a\u00e9rien, la classe \u00e9conomique est souvent consid\u00e9r\u00e9e comme l&rsquo;option la\u00a0plus abordable. Cependant, chez Air Afrika, nous croyons que le prix abordable ne devrait pas signifier un compromis sur la qualit\u00e9 du service. Notre clas<span style=\"font-size: inherit;\">se \u00e9conomique offre une exp\u00e9rience de vol confortable et agr\u00e9able, avec une attention particuli\u00e8re port\u00e9e \u00e0 chaque d\u00e9tail.<br \/><\/span><span style=\"color: #00b050;\"><strong>Un Si\u00e8ge Confortable <\/strong><\/span>Le confort commence par le si\u00e8ge. Nos si\u00e8ges de classe \u00e9conomique sont con\u00e7us pour offrir un espace suffisant pour les jambes et un soutien lombaire, garantissant ainsi un voyage confortable, m\u00eame sur les longs vols. Chaque si\u00e8ge est \u00e9quip\u00e9 d&rsquo;un \u00e9cran personnel, offrant une vari\u00e9t\u00e9 de films, de musique et de jeux pour divertir nos passagers.<br \/><span style=\"color: #00b050;\"><strong>Un Service de Restauration de Qualit\u00e9 <\/strong><\/span>Nous comprenons que la nourriture \u00e0 bord fait partie int\u00e9grante de l&rsquo;exp\u00e9rience de voyage. C&rsquo;est pourquoi nous proposons un menu vari\u00e9, pr\u00e9par\u00e9 avec des ingr\u00e9dients frais et servis avec le sourire par notre personnel de cabine d\u00e9vou\u00e9. Nos passagers peuvent \u00e9galement profiter d&rsquo;une s\u00e9lection de boissons.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-172cfa7 e-con-full e-flex e-con e-child\" data-id=\"172cfa7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-821131b e-con-full e-flex e-con e-child\" data-id=\"821131b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-da56389 elementor-widget__width-initial elementor-widget elementor-widget-image\" data-id=\"da56389\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Tenues.jpeg\" title=\"Tenues\" alt=\"Tenues\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-238308f e-con-full e-flex e-con e-child\" data-id=\"238308f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-40641b7 elementor-widget elementor-widget-text-editor\" data-id=\"40641b7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tUn Personnel de Cabine Attentionn\u00e9\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-116242e elementor-widget elementor-widget-text-editor\" data-id=\"116242e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tNotre personnel de cabine est form\u00e9 pour offrir un service de la plus haute qualit\u00e9. Ils sont toujours disponibles pour r\u00e9pondre aux besoins de nos passagers, qu&rsquo;il s&rsquo;agisse d&rsquo;une demande de couverture suppl\u00e9mentaire ou d&rsquo;une aide pour remplir les formulaires d&rsquo;immigration.\nChez Air Afrika, nous croyons que voyager en classe \u00e9conomique ne signifie pas renoncer au confort ou au service. Nous nous engageons \u00e0 offrir \u00e0 nos passagers une exp\u00e9rience de vol agr\u00e9able et m\u00e9morable, quel que soit le tarif qu&rsquo;ils choisissent.\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-6bd58a7 e-con-full e-flex e-con e-child\" data-id=\"6bd58a7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-f208ab1 e-con-full e-flex e-con e-child\" data-id=\"f208ab1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fc32f0c elementor-widget elementor-widget-text-editor\" data-id=\"fc32f0c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tNous sommes heureux de vous accueillir \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-b059bf7 elementor-widget elementor-widget-text-editor\" data-id=\"b059bf7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Les billets pour ces nouvelles routes sont maintenant disponibles \u00e0 la vente sur notre site web et via nos agents de voyage agr\u00e9\u00e9s.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-c7098b1 e-con-full e-flex e-con e-child\" data-id=\"c7098b1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d931035 elementor-widget__width-initial elementor-widget elementor-widget-image\" data-id=\"d931035\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/03\/Capture-decran-2024-06-29-110249-small.jpg\" title=\"Capture d\u2019\u00e9cran 2024-06-29 110249 small\" alt=\"Capture d\u2019\u00e9cran 2024-06-29 110249 small\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9148111 elementor-widget elementor-widget-text-editor\" data-id=\"9148111\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPour plus d&rsquo;informations, veuillez contacter notre service de relations publiques \u00e0 pr@airafrique.com.\nAir Afrika est l\u2019une des principales compagnies a\u00e9riennes du continent africain, offrant des vols vers plus de 100 destinations dans le monde. Notre mission est de connecter l&rsquo;Afrique au monde et de fournir \u00e0 nos passagers une exp\u00e9rience de voyage inoubliable.\n\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-4157f81 elementor-widget elementor-widget-text-editor\" data-id=\"4157f81\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"font-size: 16px;\">AIR<span style=\"color: #00b050;\"> AFRIKA<\/span><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1974\" class=\"elementor-element elementor-element-a6b922e e-con-full e-flex e-con e-child\" data-id=\"a6b922e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-bfe6a8b elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"bfe6a8b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Formats des Communiqu\u00e9s<\/p>\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-67d206f elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"67d206f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Documents comprenant des visuels et des textes<br \/>Communiqu\u00e9s aux formats .docx .doc .pdf<br \/>Taille maximale 400 Ko<\/p>\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-9bbdd08 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"9bbdd08\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1975\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"6\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1975\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Interview <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-c51d95a e-con-full e-flex e-con e-child\" data-id=\"c51d95a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-d24ec99 e-flex e-con-boxed e-con e-child\" data-id=\"d24ec99\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-235fcc4 e-con-full e-flex e-con e-child\" data-id=\"235fcc4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9068070 elementor-widget elementor-widget-text-editor\" data-id=\"9068070\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vous pouvez publier vos interviews<br \/>aux formats .docx .doc .pdf<\/p>\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-9800c39 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"9800c39\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Votre interview est pr\u00e9sent\u00e9e dans l&rsquo;espace publicitaire <br \/>que vous avez choisi<\/p>\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-0cbb8a0 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"0cbb8a0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Merci de transmettre si possible un document structur\u00e9 en 2 parties.\u00a0<br \/>Une premi\u00e8re partie, un court extrait ou r\u00e9sum\u00e9, sera imm\u00e9diatement visible dans l&rsquo;espace publicitaire choisi. En cliquant sur cette premi\u00e8re partie, la seconde partie du document constitu\u00e9 du contenu complet de l&rsquo;interview, s&rsquo;ouvre et est visible dans une page d\u00e9di\u00e9e.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-12dae50 e-con-full e-flex e-con e-child\" data-id=\"12dae50\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5e519c8 elementor-widget elementor-widget-text-editor\" data-id=\"5e519c8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format d&rsquo;interview \u00e0 nous transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-ba5938f e-con-full e-flex e-con e-child\" data-id=\"ba5938f\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-6bc0df4 e-con-full e-flex e-con e-child\" data-id=\"6bc0df4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-51b2930 elementor-widget elementor-widget-text-editor\" data-id=\"51b2930\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEntretien avec Marie UATHO, Pr\u00e9sidente et Directrice g\u00e9n\u00e9rale de Union Pan Bank (UPB)\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-aed0992 e-con-full e-flex e-con e-child\" data-id=\"aed0992\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-d7c35e5 e-con-full e-flex e-con e-child\" data-id=\"d7c35e5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-286902a elementor-widget__width-initial elementor-widget elementor-widget-image\" data-id=\"286902a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/Eileen_publiee.jpg\" title=\"Eileen_publi\u00e9e\" alt=\"Eileen_publi\u00e9e\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-96451ad elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"96451ad\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMarie UATHO\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-adbf742 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"adbf742\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tUPB\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-f07a9f9 e-con-full e-flex e-con e-child\" data-id=\"f07a9f9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-20a592f elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"20a592f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Entretien avec Marie UATHO, Pr\u00e9sidente et Directrice g\u00e9n\u00e9rale de Union Pan Bank (UPB). Filiale du groupe ABC services financiers, Union Pan Bank (UPB) a \u00e9t\u00e9 \u00e9lue 6 fois \u00ab Meilleure banque du continent \u00bb par le magazine EFG<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-a1d6aee e-con-full e-flex e-con e-child\" data-id=\"a1d6aee\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-36edd76 elementor-widget elementor-widget-image\" data-id=\"36edd76\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/2a65f5c0-a645-4e97-a3ca-794e800695c5-qvbkx47w2hwuv264x9qe0pdw92jmo0pb841xwyjthg.jpeg\" title=\"_2a65f5c0-a645-4e97-a3ca-794e800695c5\" alt=\"_2a65f5c0-a645-4e97-a3ca-794e800695c5\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-49efafb e-con-full e-flex e-con e-child\" data-id=\"49efafb\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-3efa148 e-con-full e-flex e-con e-child\" data-id=\"3efa148\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-371d228 e-transform elementor-widget elementor-widget-text-editor\" data-id=\"371d228\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_rotateZ_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_tablet&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_mobile&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><b><span style=\"text-align: var(--text-align); background-color: var(--base-3);\">Quelle place occupe Union Pan Bank (UPB) dans le pays ?<\/span><br \/><\/b><\/p><p>Union Pan Bank (UPB) est une institution qui conna\u00eet une croissance importante sur le march\u00e9 bancaire. Nous avons certainement une des \u00e9volutions les plus remarqu\u00e9es dans notre secteur d\u2019activit\u00e9s ces derni\u00e8res ann\u00e9es. En effet, malgr\u00e9 le fait que nous ayons connu, une crise sanitaire mondiale qui a eu un impact \u00e9galement n\u00e9gatif sur notre \u00e9conomie, nous avons fait montre de r\u00e9silience, au travers des diff\u00e9rents choix strat\u00e9giques adopt\u00e9s auparavant.\u00a0<\/p><p><!-- \/wp:paragraph --><\/p><p><!-- wp:paragraph --><\/p>\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-1446183 elementor-widget elementor-widget-image\" data-id=\"1446183\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"472\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-1024x472.jpg\" class=\"attachment-large size-large wp-image-94433\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-1024x472.jpg 1024w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-300x138.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-768x354.jpg 768w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-1536x709.jpg 1536w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-pixabay-162539-scaled-e1719665490322-2048x945.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-5cbfc2d e-con-full e-flex e-con e-child\" data-id=\"5cbfc2d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-07eb074 e-transform elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"07eb074\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_rotateZ_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_tablet&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_mobile&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"background-color: var(--base-3);\">Union Pan Bank (UPB) a \u00e0 c\u0153ur de maintenir sa philosophie du Customer First (C1st), qui pr\u00f4ne de mettre le client au premier plan de notre activit\u00e9 bancaire. Ce qui nous a d\u2019ailleurs valu pour la 6\u00e8me fois cette reconnaissance avec encore r\u00e9cemment le prix de \u00ab Meilleure banque du continent \u00bb. Je peux me permettre d\u2019affirmer que : \u00ab notre place est dans le c\u0153ur des habitants du pays \u00bb<\/span><\/p><p><!-- \/wp:paragraph --><\/p><p><!-- wp:paragraph --><\/p>\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-1188569 elementor-widget elementor-widget-image\" data-id=\"1188569\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"473\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/b97160fadc22a6f01879003a9f2b-1570921-e1719666331172-1024x473.jpg\" class=\"attachment-large size-large wp-image-94449\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/b97160fadc22a6f01879003a9f2b-1570921-e1719666331172-1024x473.jpg 1024w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/b97160fadc22a6f01879003a9f2b-1570921-e1719666331172-300x139.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/b97160fadc22a6f01879003a9f2b-1570921-e1719666331172-768x355.jpg 768w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/b97160fadc22a6f01879003a9f2b-1570921-e1719666331172.jpg 1200w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-acb0037 e-con-full e-flex e-con e-child\" data-id=\"acb0037\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5a6539c e-transform elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"5a6539c\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_rotateZ_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_tablet&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_mobile&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"font-weight: bold;\">Engag\u00e9e dans le d\u00e9veloppement \u00e9conomique du pays, que propose Union Pan Bank (UPB) aux chefs d\u2019entreprise ?<\/span><\/p><p>En tant qu\u2019acteur majeur de l\u2019\u00e9conomie, l\u2019engagement de notre institution au d\u00e9veloppement et \u00e0 l\u2019\u00e9mergence \u00e9conomique n\u2019est plus \u00e0 d\u00e9montrer. Naturellement, cela passe par des initiatives que nous accompagnons dans le cadre du programme MNO, de la pertinence et de la qualit\u00e9 de notre offre commerciale. En effet, nous mettons \u00e0 la disposition des acteurs \u00e9conomiques des produits de derni\u00e8re g\u00e9n\u00e9ration et un accompagnement personnalis\u00e9. Ces produits innovants offrent des facilit\u00e9s aux entreprises en termes de financement et d\u2019outils de gestion avec un fort accent sur la banque digitale. Nous mettons aussi un accent particulier sur le renforcement des capacit\u00e9s des entrepreneurs et des dirigeants d\u2019entreprises par le biais de plateformes d\u2019\u00e9changes et de partages d\u2019exp\u00e9rience.<\/p><p><!-- \/wp:paragraph --><\/p><p><!-- wp:paragraph --><\/p>\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-ef3c7c3 elementor-widget elementor-widget-image\" data-id=\"ef3c7c3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"472\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-1024x472.jpg\" class=\"attachment-large size-large wp-image-94465\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-1024x472.jpg 1024w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-300x138.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-768x354.jpg 768w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-1536x709.jpg 1536w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-ono-kosuki-5647280-scaled-e1719668396430-2048x945.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-30db450 e-con-full e-flex e-con e-child\" data-id=\"30db450\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-cf70a82 e-transform elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"cf70a82\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_rotateZ_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_tablet&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_mobile&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"background-color: var(--base-3);\">Nous sommes engag\u00e9s dans le d\u00e9veloppement des secteurs r\u00e9els de l\u2019\u00e9conomie. Nous offrons un portefeuille complet de services bancaires aux entreprises dans les secteurs de l\u2019\u00e9nergie, de la fabrication, des produits de grande consommation, des exportations et des importations, des t\u00e9l\u00e9communications, de l\u2019agriculture et du secteur public, entre autres. Notre gamme de solutions de paiement \u00e9lectronique de classe mondiale permet aux entreprises, aux \u00e9tablissements d\u2019enseignement, aux agences priv\u00e9es\/gouvernementales, de r\u00e9aliser, de recevoir et de contr\u00f4ler des paiements de mani\u00e8re transparente en temps r\u00e9el.<\/span><\/p><p><!-- \/wp:paragraph --><\/p><p><!-- wp:paragraph --><\/p>\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-dfc2904 elementor-widget elementor-widget-image\" data-id=\"dfc2904\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"462\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-1024x462.jpg\" class=\"attachment-large size-large wp-image-94402\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-1024x462.jpg 1024w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-300x135.jpg 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-768x347.jpg 768w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-1536x694.jpg 1536w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2024\/06\/pexels-divinetechygirl-1181360-scaled-e1719667846103-2048x925.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-c4da9da e-con-full e-flex e-con e-child\" data-id=\"c4da9da\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d821a98 e-transform elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"d821a98\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_transform_rotateZ_effect&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_tablet&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;_transform_rotateZ_effect_mobile&quot;:{&quot;unit&quot;:&quot;deg&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><b>A travers son programme d\u2019entrepreneuriat, quel est l\u2019impact de la Fondation ZHOD?<\/b><\/p><p>De fa\u00e7on g\u00e9n\u00e9rale, le Programme MNO est une initiative personnelle du PCA du Groupe ABC, qui est mise en \u0153uvre par la fondation ZHOD Foundation, et elle a pour ambition de contribuer au d\u00e9veloppement \u00e9conomique par le renforcement des capacit\u00e9s du secteur priv\u00e9 en g\u00e9n\u00e9ral et des entrepreneurs en particulier. Elle a aussi pour ambition de faciliter un partenariat public-priv\u00e9 plus efficace \u00e0 l\u2019\u00e9chelle du continent. Dans ce cadre, 90 millions de dollars ont \u00e9t\u00e9 mis \u00e0 la disposition des entrepreneurs. Les objectifs recherch\u00e9s \u00e9taient de financer 9 000 entrepreneurs sur 9 ans ; de g\u00e9n\u00e9rer 900 000 emplois et contribuer \u00e0 hauteur de 900 millions de dollars US dans l\u2019\u00e9conomie sur la m\u00eame p\u00e9riode.<\/p><p>Il est important de signifier, ici, que ces objectifs ont \u00e9t\u00e9 largement atteints en moins de 9 ans avec la participation des acteurs internationaux tels que la BAD, l\u2019AFD, l\u2019Union Europ\u00e9enne etc. Le MNO a financ\u00e9 depuis son lancement, des entrepreneurs qui emploient directement ou indirectement plusieurs centaines de jeunes.\u00a0<\/p><p>En 2024, nous avons travaill\u00e9 en partenariat avec le Minist\u00e8re du Commerce, afin d\u2019encourager l\u2019entrepreneuriat local dans le but de booster la production et, par la m\u00eame occasion, la croissance \u00e9conomique. Les r\u00e9sultats en ont \u00e9t\u00e9 plus que satisfaisants par le nombre \u00e9lev\u00e9 de participants par rapport aux ann\u00e9es pr\u00e9c\u00e9dentes.<\/p><p><!-- \/wp:paragraph --><\/p><p><!-- wp:paragraph --><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-2aacd26 e-con-full e-flex e-con e-child\" data-id=\"2aacd26\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b48f308 elementor-widget elementor-widget-image\" data-id=\"b48f308\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/2a65f5c0-a645-4e97-a3ca-794e800695c5-qvbkx47w2hwuv264x9qe0pdw92jmo0pb841xwyjthg.jpeg\" title=\"_2a65f5c0-a645-4e97-a3ca-794e800695c5\" alt=\"_2a65f5c0-a645-4e97-a3ca-794e800695c5\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1975\" class=\"elementor-element elementor-element-b608960 e-con-full e-flex e-con e-child\" data-id=\"b608960\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ae3a3f5 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"ae3a3f5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Formats des Interviews<\/p>\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-472b74b elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"472b74b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Documents comprenant des visuels et des textes<br \/>Interviews aux formats .docx .doc .pdf<br \/>Taille maximale 400 Ko<\/p>\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-44e1815 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"44e1815\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1976\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"7\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1976\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Parrainage <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1976\" class=\"elementor-element elementor-element-a8e3a02 e-con-full e-flex e-con e-child\" data-id=\"a8e3a02\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1976\" class=\"elementor-element elementor-element-bfd4f86 e-flex e-con-boxed e-con e-child\" data-id=\"bfd4f86\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1976\" class=\"elementor-element elementor-element-a0a72ee e-con-full e-flex e-con e-child\" data-id=\"a0a72ee\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5cc6fc8 elementor-widget elementor-widget-text-editor\" data-id=\"5cc6fc8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Vous pouvez publier vos parrainages<br \/>aux formats .jpg .png<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1976\" class=\"elementor-element elementor-element-09effa0 e-con-full e-flex e-con e-child\" data-id=\"09effa0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-373524c elementor-widget elementor-widget-text-editor\" data-id=\"373524c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tExemple de format de parrainage \u00e0 nous transmettre\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1976\" class=\"elementor-element elementor-element-8811f96 e-con-full e-flex e-con e-child\" data-id=\"8811f96\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-169f0b5 elementor-widget elementor-widget-text-editor\" data-id=\"169f0b5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tParrainage\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1976\" class=\"elementor-element elementor-element-d4fdb29 e-con-full e-flex e-con e-child\" data-id=\"d4fdb29\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1976\" class=\"elementor-element elementor-element-a3bc98c e-con-full e-flex e-con e-child\" data-id=\"a3bc98c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-070efae elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"070efae\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t(exemple de nom de soci\u00e9t\u00e9)\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-d7b31ae elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"d7b31ae\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVia Agency\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-2f8571f elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"2f8571f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Communication d\u00e9di\u00e9e aux institutionnels<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f7ad681 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"f7ad681\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t(exemple de texte de parrainage)\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-ed73ac6 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"ed73ac6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVia Agency parraine<br>les sites YEARBOOK Rapport Economique\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-2148927 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"2148927\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\ten partenariat avec les\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-9985caa elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"9985caa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAgences de Promotion des Investissements\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1976\" class=\"elementor-element elementor-element-30b0931 e-con-full e-flex e-con e-child\" data-id=\"30b0931\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3c93112 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"3c93112\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Votre parrainage est pr\u00e9sent\u00e9 dans l&rsquo;espace publicitaire que vous avez choisi<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-631324d elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"631324d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Formats des parrainages<\/p>\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-c6a8893 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"c6a8893\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Le texte de parrainage comprend le nom de la soci\u00e9t\u00e9 et\/ou la marque et\/ou le logo <br \/>Le texte comporte un maximum 4 lignes pour un total de 120 caract\u00e8res dont l&rsquo;expression du parrainage<br \/>Le style de police, la taille de caract\u00e8res, les dimensions de logo, les ajustements des diff\u00e9rents \u00e9l\u00e9ments et l&#8217;emplacement d\u00e9finitif sont d\u00e9finis et \u00e9tablis par Via Agency<\/p>\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-48561dd elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"48561dd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Pour toutes demandes sp\u00e9cifiques<br \/>merci de nous contacter sur<br \/><span style=\"color: #3d3d3d;\"><a style=\"color: #3d3d3d;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/span><\/p>\t\t\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1977\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"8\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1977\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Modalit\u00e9s de publication  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1977\" class=\"elementor-element elementor-element-bcffd11 e-con-full e-flex e-con e-child\" data-id=\"bcffd11\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1977\" class=\"elementor-element elementor-element-ec08ff2 e-flex e-con-boxed e-con e-child\" data-id=\"ec08ff2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1977\" class=\"elementor-element elementor-element-94d1e36 e-con-full e-flex e-con e-child\" data-id=\"94d1e36\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-99fe609 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"99fe609\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: justify;\"><strong><span style=\"color: #225da9;\">Modalit\u00e9s. <\/span><\/strong>Les annonces sont publi\u00e9es si elles sont conformes aux caract\u00e9ristiques techniques d\u00e9finies dans le kit media et \u00e0 la charte \u00e9ditoriale de Via Agency<\/p>\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-778154a elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"778154a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong><span style=\"color: #225da9;\">Charte \u00e9ditoriale. <\/span><\/strong>L&rsquo;ensemble des annonces (banni\u00e8re, vid\u00e9o, communiqu\u00e9, interview et parrainage) et les \u00e9l\u00e9ments qui composent les annonces (entre autres images, vid\u00e9os,\u00a0 textes, sons, etc.) doivent respecter la l\u00e9gislation fran\u00e7aise.\u00a0<br \/>La r\u00e9daction de Via Agency se r\u00e9serve le droit de ne pas publier des annonces qui ne respectent pas le cadre l\u00e9gal et\/ou qui seraient pr\u00e9judiciables \u00e0 la soci\u00e9t\u00e9 Via Agency<\/p>\t\t\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1978\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"9\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1978\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> Kit media print <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><i aria-hidden=\"true\" class=\"fas fa-minus\"><\/i><\/span>\n\t\t\t<span class='e-closed'><i aria-hidden=\"true\" class=\"fas fa-plus\"><\/i><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1978\" class=\"elementor-element elementor-element-e4a14d5 e-con-full e-flex e-con e-child\" data-id=\"e4a14d5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1978\" class=\"elementor-element elementor-element-23532f4 e-flex e-con-boxed e-con e-child\" data-id=\"23532f4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1978\" class=\"elementor-element elementor-element-59cf39f e-con-full e-flex e-con e-child\" data-id=\"59cf39f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3421ab6 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"3421ab6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: justify;\"><strong><span style=\"color: #225da9;\">Un lectorat de d\u00e9cideurs.<\/span><\/strong> L&rsquo;audience est compos\u00e9e d&rsquo;actifs \u00e0 87%, de CSP+, d&rsquo;hommes d&rsquo;affaires et de cadres \u00e0 79%. Les Yearbooks sont publi\u00e9s en versions fran\u00e7aise et anglaise aupr\u00e8s des Pr\u00e9sidences, des Primatures, des Minist\u00e8res et des Organismes gouvernementaux. Ils b\u00e9n\u00e9ficient du r\u00e9seau de distribution des Agences et des Minist\u00e8res de la Promotion de l\u2019Investissement.<br \/>Nos publications sont distribu\u00e9es via le r\u00e9seau diplomatique, les Ambassades et les Chambres de Commerce et d\u2019Industrie, durant des \u00e9v\u00e8nements, des conf\u00e9rences, des forums d\u2019affaires, aupr\u00e8s des f\u00e9d\u00e9rations professionnelles et de nos partenaires commerciaux<\/p>\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-d1345cc elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"d1345cc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: justify;\"><strong><span style=\"color: #225da9;\">Distribution annexe. <\/span><\/strong>La distribution est assur\u00e9e dans les a\u00e9roports internationaux partenaires et par les compagnies a\u00e9riennes partenaires, dans la librairie du Commerce International, Business France et par nos partenaires m\u00e9dia pour l\u2019ensemble des Forums d\u2019Affaires et d\u2019Investissements en Afrique.<br \/>Une base de donn\u00e9es influente avec plus de 3 500 contacts permet une diffusion cibl\u00e9e notamment \u00e0 l\u2019international : pays membres\u00a0de l\u2019OCDE et de l\u2019Union Africaine<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1978\" class=\"elementor-element elementor-element-613f3f0 e-con-full e-flex e-con e-child\" data-id=\"613f3f0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9c0aac5 ZoomTitreMobile elementor-widget elementor-widget-text-editor\" data-id=\"9c0aac5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tTarifs publicitaires : nous contacter\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1978\" class=\"elementor-element elementor-element-b13cae9 e-con-full e-flex e-con e-child\" data-id=\"b13cae9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1978\" class=\"elementor-element elementor-element-6896488 e-con-full e-flex e-con e-child\" data-id=\"6896488\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7d8deb4 elementor-widget elementor-widget-image\" data-id=\"7d8deb4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"547\" height=\"484\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/01\/Kit-media-Print-3.webp\" class=\"attachment-full size-full wp-image-158173\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/01\/Kit-media-Print-3.webp 547w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/01\/Kit-media-Print-3-300x265.webp 300w\" sizes=\"(max-width: 547px) 100vw, 547px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1978\" class=\"elementor-element elementor-element-8a42bd3 e-con-full e-flex e-con e-child\" data-id=\"8a42bd3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7f31231 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"7f31231\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><a style=\"color: #225da9;\" href=\"mailto:contact@via-agency.media\">contact@via-agency.media<\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t<\/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-315240ed elementor-widget elementor-widget-html\" data-id=\"315240ed\" data-element_type=\"widget\" data-e-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\njQuery(document).ready(function($) {\r\n\r\n    \/\/ \u2705 Titres accord\u00e9on \u2014 couleur forc\u00e9e (h\u00e9ritage blanc du popup neutralis\u00e9)\r\n    if (!document.getElementById('via-kit-media-accordion-css')) {\r\n        var s = document.createElement('style');\r\n        s.id = 'via-kit-media-accordion-css';\r\n        s.textContent =\r\n            '.e-n-accordion-item-title-text { color: #225DA9 !important; font-family: Roboto, sans-serif !important; font-size: 14px !important; font-weight: 600 !important; }' +\r\n            '.e-n-accordion-item-title .e-opened, .e-n-accordion-item-title .e-closed { color: #225DA9 !important; }' +\r\n            '.e-n-accordion-item-title[aria-expanded=\"true\"] .e-n-accordion-item-title-text { color: #225DA9 !important; }';\r\n        document.head.appendChild(s);\r\n    }\r\n    \r\n    $(document).on('click', '.e-n-accordion .e-n-accordion-item-title', function(e) {\r\n        var $toggler = $(this);\r\n        var isCurrentlyClosed = $toggler.attr('aria-expanded') === 'false';\r\n        \r\n        if (isCurrentlyClosed) {\r\n            setTimeout(function() {\r\n                var container, scrollTarget;\r\n                \r\n                if (window.outerWidth > 1000) {\r\n                    container = $('#Content4Items');\r\n                    scrollTarget = $toggler.offset().top - container.offset().top + container.scrollTop();\r\n                } else {\r\n                    container = $('#ConteneurRedactionel');\r\n                    scrollTarget = $toggler.offset().top - container.offset().top + container.scrollTop() - 10;\r\n                }\r\n                \r\n                container.animate({ scrollTop: scrollTarget }, 250);\r\n            }, 400);\r\n        }\r\n    });\r\n    \r\n    \/\/ Observer qui d\u00e9tecte quand l'accord\u00e9on n'est plus visible et le referme\r\n    const accordionContainer = document.querySelector('.e-n-accordion');\r\n    \r\n    if (accordionContainer) {\r\n        const observer = new IntersectionObserver(function(entries) {\r\n            entries.forEach(function(entry) {\r\n                if (!entry.isIntersecting) {\r\n                    \/\/ Fermer tous les <details> ouverts\r\n                    accordionContainer.querySelectorAll('details.e-n-accordion-item[open]').forEach(function(detail) {\r\n                        detail.removeAttribute('open');\r\n                    });\r\n                }\r\n            });\r\n        }, { threshold: 0 });\r\n    \r\n        observer.observe(accordionContainer);\r\n    }\r\n        \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<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2ad2a8e4 e-flex e-con-boxed e-con e-parent\" data-id=\"2ad2a8e4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <!-- Pop-up 3 -->\r\n    <div id=\"popup3\" class=\"popup-container\">\r\n        <div class=\"handle\">\r\n            <span class=\"handle-title\" id=\"handle-title-popup3\">Tarifs des espaces publicitaires<\/span>\r\n            <!-- pb710 : lien Reinitialiser, a gauche du picto Reduire -->\r\n            <span class=\"handle-reset-710\" title=\"R\u00e9initialiser la saisie\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"23 4 23 10 17 10\"><\/polyline><path d=\"M20.49 15a9 9 0 1 1-2.12-9.36L23 10\"><\/path><\/svg><\/span>\r\n            <!-- pb653 : picto reduction (trait horizontal), a gauche de la croix -->\r\n            <div class=\"handle-reduce-container\" title=\"R\u00e9duire\">\r\n                <span class=\"handle-reduce-bar\"><\/span>\r\n            <\/div>\r\n            <div class=\"handle-icon-container\">\r\n                <!-- pb711 : title \"Fermer\" sur le picto, comme le \"R\u00e9duire\" du picto voisin.\r\n                     Pose sur le DIV porteur du onclick (pas sur l'IMG) : la zone\r\n                     survolee est celle du div, l'infobulle suit donc la zone cliquable. -->\r\n                <div class=\"handle-icon\" title=\"Fermer\" onclick=\"closePopup('popup3')\"><img decoding=\"async\" src=\"https:\/\/via-agency.media\/wp-content\/uploads\/2024\/07\/Croix-retour-HP-fond-transparent.webp\" class=\"handle-icon\"><\/div>\r\n            <\/div>\r\n        <\/div>\r\n        <div class=\"popup-content\">\r\n            \t\t<div data-elementor-type=\"page\" data-elementor-id=\"210721\" class=\"elementor elementor-210721\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1becf802 e-con-full e-flex e-con e-child\" data-id=\"1becf802\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-64836473 e-con-full DeferedImageContainer e-flex e-con e-child\" data-id=\"64836473\" data-element_type=\"container\" data-e-type=\"container\" id=\"AudiencewebTexteConteneur\">\n\t\t<div class=\"elementor-element elementor-element-278fe2a1 e-con-full TexteMenu3 e-flex e-con e-child\" data-id=\"278fe2a1\" data-element_type=\"container\" data-e-type=\"container\" id=\"TarifPub\">\n\t\t<div class=\"elementor-element elementor-element-4c499f80 e-con-full e-flex e-con e-child\" data-id=\"4c499f80\" data-element_type=\"container\" data-e-type=\"container\" id=\"TarifsTitre\">\n\t\t<div class=\"elementor-element elementor-element-dc42037 e-con-full e-flex e-con e-child\" data-id=\"dc42037\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c84e878 elementor-widget elementor-widget-text-editor\" data-id=\"c84e878\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Acc\u00e9der aux tarifs et r\u00e9server vos campagnes<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-83f28ef e-con-full   e-flex e-con e-child\" data-id=\"83f28ef\" data-element_type=\"container\" data-e-type=\"container\" id=\"TarifsCatalogueConteneur\">\n\t\t<div class=\"elementor-element elementor-element-efd2bb1 e-con-full e-flex e-con e-child\" data-id=\"efd2bb1\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsEtapeAnnonceurContainer\">\n\t\t<div class=\"elementor-element elementor-element-4dc484a e-con-full e-flex e-con e-child\" data-id=\"4dc484a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5dd699b e-con-full e-flex e-con e-child\" data-id=\"5dd699b\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsAnnonceurTitre\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ebe91e9 elementor-widget elementor-widget-text-editor\" data-id=\"ebe91e9\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsAnnonceurTitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tRenseigner le pays de la soci\u00e9t\u00e9 de l&rsquo;annonceur\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-126e2ed e-con-full e-flex e-con e-child\" data-id=\"126e2ed\" data-element_type=\"container\" data-e-type=\"container\" id=\"Message_Nationalite_Societe_Tarifs\">\n\t\t\t\t<div class=\"elementor-element elementor-element-465fe78   elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"465fe78\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsAnnonceurMessageTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMerci d&rsquo;indiquer le pays de l&rsquo;annonceur\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9bbf751 e-con-full e-flex e-con e-child\" data-id=\"9bbf751\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsAnnonceur\">\n\t\t<div class=\"elementor-element elementor-element-072e711 e-con-full e-flex e-con e-child\" data-id=\"072e711\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3f23a74 elementor-button-align-center elementor-widget__width-inherit elementor-widget-mobile__width-initial FormHideButton CfCSSPersonnalise elementor-widget elementor-widget-form\" data-id=\"3f23a74\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"Nationalite_Societe_Tarifs_Id\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_Nationalite_Societe_Tarifs\" aria-label=\"Formulaire_Nationalite_Societe_Tarifs\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"210721\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"3f23a74\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-Nationalite_Societe_Tarifs elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-Nationalite_Societe_Tarifs\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tNationalit\u00e9 soci\u00e9t\u00e9\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[Nationalite_Societe_Tarifs]\" id=\"form-field-Nationalite_Societe_Tarifs\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Indiquer ici le pays de l&#039;annonceur\">\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-xs\" type=\"submit\" id=\"Button_Nationalit\u00e9_Annonceur_Tarifs\">\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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5038fe6 e-con-full e-flex e-con e-child\" data-id=\"5038fe6\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsListePaysContainer\">\n\t\t<div class=\"elementor-element elementor-element-d1fd499 e-con-full e-flex e-con e-child\" data-id=\"d1fd499\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-64828de elementor-widget elementor-widget-text-editor\" data-id=\"64828de\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsListePaysTitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAssocier votre communication \u00e0 un site pays\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4408cb7 e-con-full e-flex e-con e-child\" data-id=\"4408cb7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1932f12   elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"1932f12\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsSitePaysMessageTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMerci de s\u00e9lectionner un pays\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-e2b2a88 e-con-full e-flex e-con e-child\" data-id=\"e2b2a88\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsListePays\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3973a7d e-con-full e-flex e-con e-child\" data-id=\"3973a7d\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsListeSecteursContainer\">\n\t\t<div class=\"elementor-element elementor-element-c8be341 e-con-full e-flex e-con e-child\" data-id=\"c8be341\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsListeSecteursTitreContaineur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-151b00b elementor-widget elementor-widget-text-editor\" data-id=\"151b00b\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsListeSecteursTitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #213864;\"><a style=\"color: #213864;\" href=\"#\">S\u00e9lectionner les pages secteurs, th\u00e8mes ou articles<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3c38918 e-con-full e-flex e-con e-child\" data-id=\"3c38918\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7dc4d38   elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"7dc4d38\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsListeSecteursMessageTexte2\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Merci de s\u00e9lectionner une page : homepage, th\u00e8me, secteur ou article<\/p>\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-0945904   elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"0945904\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsListeSecteursMessageTexte3\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Merci de s\u00e9lectionner un article<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-50668de e-con-full e-flex e-con e-child\" data-id=\"50668de\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsListeSecteurs\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f122474 e-con-full e-flex e-con e-child\" data-id=\"f122474\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsDatesCampagnesContainer\">\n\t\t<div class=\"elementor-element elementor-element-356a9d8 e-con-full e-flex e-con e-child\" data-id=\"356a9d8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-9d04c60 e-con-full e-flex e-con e-child\" data-id=\"9d04c60\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8ef8ec4 elementor-widget elementor-widget-text-editor\" data-id=\"8ef8ec4\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsDatesTitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tChoisir les dates et la dur\u00e9e de la campagne\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-84311a4 PopupTarifsDates elementor-widget elementor-widget-text-editor\" data-id=\"84311a4\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsDureeMinimaleTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Dur\u00e9e minimale de campagne 7 jours<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-090a343 e-con-full PopupTarifsDates e-flex e-con e-child\" data-id=\"090a343\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-427b498 e-con-full PopupTarifsDates e-flex e-con e-child\" data-id=\"427b498\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-d2f0313 e-con-full e-flex e-con e-child\" data-id=\"d2f0313\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-570b3f8   elementor-widget elementor-widget-text-editor\" data-id=\"570b3f8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tD\u00e9but\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-ea0018d elementor-button-align-center elementor-widget__width-initial FormHideButton elementor-widget elementor-widget-form\" data-id=\"ea0018d\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"TarifsDateDebutForm\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_Tarifs_D\u00e9but_Campagne\" aria-label=\"Formulaire_Tarifs_D\u00e9but_Campagne\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"210721\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"ea0018d\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-PopupTarifsDebutCampagne elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-PopupTarifsDebutCampagne\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tD\u00e9but campagne\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[PopupTarifsDebutCampagne]\" id=\"form-field-PopupTarifsDebutCampagne\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"jj\/mm\/aaaa\">\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-d88b1ac e-con-full e-flex e-con e-child\" data-id=\"d88b1ac\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1119d64   elementor-widget elementor-widget-text-editor\" data-id=\"1119d64\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFin\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-a9c16cc elementor-button-align-center elementor-widget__width-initial FormHideButton elementor-widget elementor-widget-form\" data-id=\"a9c16cc\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"TarifsDateFinForm\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_Tarifs_Fin_Campagne\" aria-label=\"Formulaire_Tarifs_Fin_Campagne\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"210721\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"a9c16cc\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-PopupTarifsFinCampagne elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-PopupTarifsFinCampagne\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tFin campagne\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[PopupTarifsFinCampagne]\" id=\"form-field-PopupTarifsFinCampagne\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"jj\/mm\/aaaa\">\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-f4c1329 e-con-full e-flex e-con e-child\" data-id=\"f4c1329\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d9dfbf0   elementor-widget elementor-widget-text-editor\" data-id=\"d9dfbf0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tNb de jours\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-85df7d5 e-con-full e-flex e-con e-child\" data-id=\"85df7d5\" data-element_type=\"container\" data-e-type=\"container\" id=\"NbJoursField\">\n\t\t<div class=\"elementor-element elementor-element-58bb340 e-con-full e-flex e-con e-child\" data-id=\"58bb340\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fe01c04 TarifsCampagneNbJours elementor-widget elementor-widget-text-editor\" data-id=\"fe01c04\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t&#8211;\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-53c6e62 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"53c6e62\" data-element_type=\"container\" data-e-type=\"container\" id=\"GrilleTarifCMsgContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b6b49bb   elementor-widget elementor-widget-text-editor\" data-id=\"b6b49bb\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"GrilleTarifCMsgTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Message d&rsquo;information sur la saisie des dates<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9d1d0f2 e-con-full e-flex e-con e-child\" data-id=\"9d1d0f2\" data-element_type=\"container\" data-e-type=\"container\" id=\"TarifsPublicitaireListe\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-e3f5004 e-con-full e-flex e-con e-child\" data-id=\"e3f5004\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f34bdb5 elementor-widget elementor-widget-text-editor\" data-id=\"f34bdb5\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsTarifsTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tChoisir un format d&rsquo;annonce et un tarif\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4637b68 e-con-full TarifsConteneur  GrilleTarifaire elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"4637b68\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3169688 elementor-widget elementor-widget-text-editor\" data-id=\"3169688\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PaysTarifsCampagne\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Pays &#8211; Tarifs de campagne<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4f4b0cf e-con-full TarifsConteneur  GrilleTarifaire elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"4f4b0cf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-d3b1b12 e-con-full e-flex e-con e-child\" data-id=\"d3b1b12\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-8ae3715 e-con-full e-flex e-con e-child\" data-id=\"8ae3715\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7fedfe3 CatalogueDevises elementor-widget elementor-widget-text-editor\" data-id=\"7fedfe3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Devises<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4092db5 e-con-full e-flex e-con e-child\" data-id=\"4092db5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-7ed9695 e-con-full e-flex e-con e-child\" data-id=\"7ed9695\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4d58f60 CatalogueDevises elementor-widget elementor-widget-text-editor\" data-id=\"4d58f60\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #213864;\"><a style=\"color: #213864;\" href=\"#\">EUR<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-abc45b4 e-con-full e-flex e-con e-child\" data-id=\"abc45b4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-36ff626 e-con-full e-flex e-con e-child\" data-id=\"36ff626\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4024c9b CatalogueDevises elementor-widget elementor-widget-text-editor\" data-id=\"4024c9b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"color: #213864;\"><a style=\"color: #213864;\" href=\"#\">USD<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c46217e e-con-full e-flex e-con e-child\" data-id=\"c46217e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-75aeeed e-con-full e-flex e-con e-child\" data-id=\"75aeeed\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-149bb74 CatalogueDevises elementor-widget elementor-widget-text-editor\" data-id=\"149bb74\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"color: #213864;\"><a style=\"color: #213864;\" href=\"#\">GBP<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-cfaf4f5 e-con-full e-flex e-con e-child\" data-id=\"cfaf4f5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5db9a30 e-con-full e-flex e-con e-child\" data-id=\"5db9a30\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f55252c CatalogueDevises elementor-widget elementor-widget-text-editor\" data-id=\"f55252c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #213864;\"><a style=\"color: #213864;\" href=\"#\">CHF<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-bbee8c2 e-con-full e-flex e-con e-child\" data-id=\"bbee8c2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5786103 e-con-full e-flex e-con e-child\" data-id=\"5786103\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b6ea54 CatalogueDevises elementor-widget elementor-widget-text-editor\" data-id=\"4b6ea54\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #213864;\"><a style=\"color: #213864;\" href=\"#\">XAF<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f2518fd e-con-full e-flex e-con e-child\" data-id=\"f2518fd\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-88c4706 e-con-full e-flex e-con e-child\" data-id=\"88c4706\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-97178bd CatalogueDevises elementor-widget elementor-widget-text-editor\" data-id=\"97178bd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #213864;\"><a style=\"color: #213864;\" href=\"#\">XOF<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-aed6576 e-con-full e-flex e-con e-child\" data-id=\"aed6576\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-30483c1 e-con-full e-flex e-con e-child\" data-id=\"30483c1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-be71b04 CatalogueDevises elementor-widget elementor-widget-text-editor\" data-id=\"be71b04\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #213864;\"><a style=\"color: #213864;\" href=\"#\">CDF<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-05180d1 e-con-full e-flex e-con e-child\" data-id=\"05180d1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5c5acbc e-con-full e-flex e-con e-child\" data-id=\"5c5acbc\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b79145d CatalogueDevises elementor-widget elementor-widget-text-editor\" data-id=\"b79145d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #213864;\"><a style=\"color: #213864;\" href=\"#\">MGA<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3cc27dd6 e-con-full TarifsFormats PopupTarifsTarifs e-flex e-con e-child\" data-id=\"3cc27dd6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-343871f2 e-con-full e-flex e-con e-child\" data-id=\"343871f2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5207ba0a e-con-full e-flex e-con e-child\" data-id=\"5207ba0a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-220c6bdf elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"220c6bdf\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Formats, tarifs &amp;<br \/>emplacements<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-63b674cb e-con-full e-flex e-con e-child\" data-id=\"63b674cb\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-6f8527e8 e-con-full e-flex e-con e-child\" data-id=\"6f8527e8\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f719979 elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"f719979\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Vid\u00e9o<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-208b45b e-con-full e-flex e-con e-child\" data-id=\"208b45b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5fcb3f9 e-con-full e-flex e-con e-child\" data-id=\"5fcb3f9\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-24a368b elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"24a368b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Banni\u00e8re<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5185ca42 e-con-full e-flex e-con e-child\" data-id=\"5185ca42\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1092bc0 e-con-full e-flex e-con e-child\" data-id=\"1092bc0\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7358e7a5 elementor-widget elementor-widget-text-editor\" data-id=\"7358e7a5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Parrainage<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-72eedd8d e-con-full e-flex e-con e-child\" data-id=\"72eedd8d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-257cce1e e-con-full e-flex e-con e-child\" data-id=\"257cce1e\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1b3a2158 elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"1b3a2158\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Communiqu\u00e9<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5b1b29a6 e-con-full e-flex e-con e-child\" data-id=\"5b1b29a6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-9c93482 e-con-full e-flex e-con e-child\" data-id=\"9c93482\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4f0bd3f elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"4f0bd3f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">Interview<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-48c7c092 e-con-full TarifsFormats e-flex e-con e-child\" data-id=\"48c7c092\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4bae00bb e-con-full e-flex e-con e-child\" data-id=\"4bae00bb\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-582d8968 e-con-full e-flex e-con e-child\" data-id=\"582d8968\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-73042f6b elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"73042f6b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPop-up &#8211; Home Page\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5346707b e-con-full e-flex e-con e-child\" data-id=\"5346707b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-16d02e3 e-con-full e-flex e-con e-child\" data-id=\"16d02e3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2f7c483f elementor-widget-mobile__width-initial Tarif7VidPoPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"2f7c483f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>950 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-27c087c4 e-con-full e-flex e-con e-child\" data-id=\"27c087c4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-140cd940 e-con-full e-flex e-con e-child\" data-id=\"140cd940\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3ae4fa42 elementor-widget-mobile__width-initial Tarif7BanPoPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"3ae4fa42\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>850 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-38255496 e-con-full e-flex e-con e-child\" data-id=\"38255496\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-36f98a49 e-con-full e-flex e-con e-child\" data-id=\"36f98a49\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-79ca758b Tarif7ParPoPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"79ca758b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>850 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1f5c49f e-con-full e-flex e-con e-child\" data-id=\"1f5c49f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-2e18b849 e-con-full e-flex e-con e-child\" data-id=\"2e18b849\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4dfe2109 elementor-widget-mobile__width-initial Tarif7ComPoPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"4dfe2109\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>950 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1d20cdb8 e-con-full e-flex e-con e-child\" data-id=\"1d20cdb8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-52ac27bc e-con-full e-flex e-con e-child\" data-id=\"52ac27bc\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3f74807a elementor-widget-mobile__width-initial Tarif7IntPoPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"3f74807a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>950 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-40640001 e-con-full TarifsFormats  e-flex e-con e-child\" data-id=\"40640001\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-edb292c e-con-full e-flex e-con e-child\" data-id=\"edb292c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-24c2344 e-con-full e-flex e-con e-child\" data-id=\"24c2344\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-54b8f06 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"54b8f06\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPop-up &#8211; Autres Pages\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2af02d35 e-con-full e-flex e-con e-child\" data-id=\"2af02d35\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-65ef91af e-con-full e-flex e-con e-child\" data-id=\"65ef91af\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-76e2a3b8 elementor-widget-mobile__width-initial Tarif7VidPoPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"76e2a3b8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>950 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5972b55e e-con-full e-flex e-con e-child\" data-id=\"5972b55e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4496733b e-con-full e-flex e-con e-child\" data-id=\"4496733b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5cff7f48 elementor-widget-mobile__width-initial Tarif7BanPoPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"5cff7f48\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>850 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-47be213d e-con-full e-flex e-con e-child\" data-id=\"47be213d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-14cbb533 e-con-full e-flex e-con e-child\" data-id=\"14cbb533\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-46585b10 Tarif7ParPoPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"46585b10\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>850 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6a7043f7 e-con-full e-flex e-con e-child\" data-id=\"6a7043f7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-7f47dba2 e-con-full e-flex e-con e-child\" data-id=\"7f47dba2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-22f78ea7 elementor-widget-mobile__width-initial Tarif7ComPoPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"22f78ea7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>950 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-131a0883 e-con-full e-flex e-con e-child\" data-id=\"131a0883\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-dea6a07 e-con-full e-flex e-con e-child\" data-id=\"dea6a07\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-151ec7f2 elementor-widget-mobile__width-initial Tarif7IntPoPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"151ec7f2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>950 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c76bbc6 e-con-full TarifsFormats e-flex e-con e-child\" data-id=\"c76bbc6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-2c3e4e6 e-con-full e-flex e-con e-child\" data-id=\"2c3e4e6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ded69d0 e-con-full e-flex e-con e-child\" data-id=\"ded69d0\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-85813e2 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"85813e2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tHome Page &#8211; Haut de page\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5fc9f962 e-con-full e-flex e-con e-child\" data-id=\"5fc9f962\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-45d2e194 e-con-full e-flex e-con e-child\" data-id=\"45d2e194\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e7f06db elementor-widget-mobile__width-initial Tarif7VidHdPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"e7f06db\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>950 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-33cd7c2 e-con-full e-flex e-con e-child\" data-id=\"33cd7c2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-3802b417 e-con-full e-flex e-con e-child\" data-id=\"3802b417\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e4b52ca elementor-widget-mobile__width-initial Tarif7BanHdPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"e4b52ca\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>850 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3930e096 e-con-full e-flex e-con e-child\" data-id=\"3930e096\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1ccf87bf e-con-full e-flex e-con e-child\" data-id=\"1ccf87bf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3de9b876 Tarif7ParHdPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"3de9b876\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>850 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-50832b95 e-con-full e-flex e-con e-child\" data-id=\"50832b95\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-77c58ecc e-con-full e-flex e-con e-child\" data-id=\"77c58ecc\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3748aaa8 elementor-widget-mobile__width-initial Tarif7ComHdPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"3748aaa8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>950 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9476177 e-con-full e-flex e-con e-child\" data-id=\"9476177\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-78b88db7 e-con-full e-flex e-con e-child\" data-id=\"78b88db7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4cdf1d30 elementor-widget-mobile__width-initial Tarif7IntHdPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"4cdf1d30\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>950 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-76b508bb e-con-full TarifsFormats e-flex e-con e-child\" data-id=\"76b508bb\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-9068445 e-con-full e-flex e-con e-child\" data-id=\"9068445\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-0b1adbf e-con-full e-flex e-con e-child\" data-id=\"0b1adbf\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6b2519f elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"6b2519f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tHome Page &#8211; Corps de page\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-70f92a3c e-con-full e-flex e-con e-child\" data-id=\"70f92a3c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-66822fa0 e-con-full e-flex e-con e-child\" data-id=\"66822fa0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1541071 elementor-widget-mobile__width-initial Tarif7VidCdPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"1541071\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>800 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-643c4a41 e-con-full e-flex e-con e-child\" data-id=\"643c4a41\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5e79a825 e-con-full e-flex e-con e-child\" data-id=\"5e79a825\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-724cc4b elementor-widget-mobile__width-initial Tarif7BanCdPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"724cc4b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>700 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-393493f3 e-con-full e-flex e-con e-child\" data-id=\"393493f3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-27e4d9fa e-con-full e-flex e-con e-child\" data-id=\"27e4d9fa\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-75c2a06e Tarif7ParCdPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"75c2a06e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>700 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b0e2953 e-con-full e-flex e-con e-child\" data-id=\"b0e2953\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-b001c59 e-con-full e-flex e-con e-child\" data-id=\"b001c59\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5c504f26 elementor-widget-mobile__width-initial Tarif7ComCdPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"5c504f26\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>800 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-18e90f38 e-con-full e-flex e-con e-child\" data-id=\"18e90f38\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-23236812 e-con-full e-flex e-con e-child\" data-id=\"23236812\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2ad5269d elementor-widget-mobile__width-initial Tarif7IntCdPHP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"2ad5269d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>800 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7bf1d361 e-con-full TarifsFormats e-flex e-con e-child\" data-id=\"7bf1d361\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4832b2b e-con-full e-flex e-con e-child\" data-id=\"4832b2b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-05136fb e-con-full e-flex e-con e-child\" data-id=\"05136fb\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-57c3932 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"57c3932\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAutres Pages &#8211; Haut de page\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-74843b7c e-con-full e-flex e-con e-child\" data-id=\"74843b7c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-7edbc750 e-con-full e-flex e-con e-child\" data-id=\"7edbc750\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3a3bb75a elementor-widget-mobile__width-initial Tarif7VidHdPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"3a3bb75a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>800 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-37aa017f e-con-full e-flex e-con e-child\" data-id=\"37aa017f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-50365db2 e-con-full e-flex e-con e-child\" data-id=\"50365db2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-504b7a5b elementor-widget-mobile__width-initial Tarif7BanHdPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"504b7a5b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>700 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-530bd0b7 e-con-full e-flex e-con e-child\" data-id=\"530bd0b7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5037bcf1 e-con-full e-flex e-con e-child\" data-id=\"5037bcf1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-249a8420 Tarif7ParHdPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"249a8420\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>700 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-30cde0b3 e-con-full e-flex e-con e-child\" data-id=\"30cde0b3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-135084a2 e-con-full e-flex e-con e-child\" data-id=\"135084a2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6ee4b01b elementor-widget-mobile__width-initial Tarif7ComHdPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"6ee4b01b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>800 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-108f8096 e-con-full e-flex e-con e-child\" data-id=\"108f8096\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-753c1fa5 e-con-full e-flex e-con e-child\" data-id=\"753c1fa5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5ef5583b elementor-widget-mobile__width-initial Tarif7IntHdPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"5ef5583b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>800 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7c643922 e-con-full TarifsFormats e-flex e-con e-child\" data-id=\"7c643922\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-76a3190 e-con-full e-flex e-con e-child\" data-id=\"76a3190\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ff1341d e-con-full e-flex e-con e-child\" data-id=\"ff1341d\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-01ec5db elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"01ec5db\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAutres Pages &#8211; Corps de page\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-500ed5e4 e-con-full e-flex e-con e-child\" data-id=\"500ed5e4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ecaf8d e-con-full e-flex e-con e-child\" data-id=\"ecaf8d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3f36c3fa elementor-widget-mobile__width-initial Tarif7VidCdPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"3f36c3fa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>800 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5722bda2 e-con-full e-flex e-con e-child\" data-id=\"5722bda2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-42fda48 e-con-full e-flex e-con e-child\" data-id=\"42fda48\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5e073f4d elementor-widget-mobile__width-initial Tarif7BanCdPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"5e073f4d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>700 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-45891232 e-con-full e-flex e-con e-child\" data-id=\"45891232\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-3b6937d3 e-con-full e-flex e-con e-child\" data-id=\"3b6937d3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-423880de Tarif7ParCdPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"423880de\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>700 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4b3cd309 e-con-full e-flex e-con e-child\" data-id=\"4b3cd309\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-31ce0ddc e-con-full e-flex e-con e-child\" data-id=\"31ce0ddc\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4cb0a76c elementor-widget-mobile__width-initial Tarif7ComCdPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"4cb0a76c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>800 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6c0930e2 e-con-full e-flex e-con e-child\" data-id=\"6c0930e2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4996732a e-con-full e-flex e-con e-child\" data-id=\"4996732a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-25c570a6 elementor-widget-mobile__width-initial Tarif7IntCdPPP PricingAmount elementor-widget elementor-widget-text-editor\" data-id=\"25c570a6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>800 \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4bc9eb4 e-con-full e-flex e-con e-child\" data-id=\"4bc9eb4\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgChoixTarifContainer\">\n\t\t<div class=\"elementor-element elementor-element-6577adb e-flex e-con-boxed e-con e-child\" data-id=\"6577adb\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-afc9f90   elementor-widget elementor-widget-text-editor\" data-id=\"afc9f90\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMerci de choisir un format et un tarif\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\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2d2cb61b TarifsConteneur GrilleTarifaire elementor-widget__width-initial elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"2d2cb61b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Haut de page : position d&rsquo;une annonce en haut de page sur l&rsquo;un des deux 1er rangs d&rsquo;espaces publicitaires<br \/>Corps de page : position d&rsquo;une annonce en corps de page \u00e0 partir du 3e rang d&rsquo;espaces publicitaires<br \/>Dur\u00e9e de campagne : minimum 7 jours, maximum 200 jours<br \/>Tarif d\u00e9gressif de 0.5% \u00e0 partir du 8e jour de campagne<br \/>Voir le d\u00e9tail des tarifs et des conditions dans les <span style=\"text-decoration: underline;\"><span style=\"color: #213864;\"><a style=\"color: #213864; text-decoration: underline;\" href=\"#\">CGV<\/a><\/span><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9792152 e-con-full elementor-hidden-desktop e-flex e-con e-child\" data-id=\"9792152\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopUpTarifsTarifsSelectContainer\">\n\t\t<div class=\"elementor-element elementor-element-92a56c0 e-con-full e-flex e-con e-child\" data-id=\"92a56c0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7139313 elementor-widget elementor-widget-text-editor\" data-id=\"7139313\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsRecapTitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tR\u00e9capitulatif et r\u00e9servation\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-66d5aad e-con-full e-flex e-con e-child\" data-id=\"66d5aad\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-459c544   elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"459c544\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsRecapMessageTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>PopupTarifsRecapMessageTexte<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4890b69 e-con-full e-flex e-con e-child\" data-id=\"4890b69\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsRecapContainer\">\n\t\t<div class=\"elementor-element elementor-element-f539eee e-con-full e-flex e-con e-child\" data-id=\"f539eee\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5fffb52 elementor-widget elementor-widget-text-editor\" data-id=\"5fffb52\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Tarif moyen \/ jour<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a1aa268 e-con-full e-flex e-con e-child\" data-id=\"a1aa268\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-bb111e9 elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"bb111e9\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopUpTarifsTJM\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\txxx \u20ac\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-448e324 e-con-full e-flex e-con e-child\" data-id=\"448e324\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-437e22a elementor-widget elementor-widget-text-editor\" data-id=\"437e22a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tTarif\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-e2e0614 e-con-full e-flex e-con e-child\" data-id=\"e2e0614\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5833674 elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"5833674\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopUpTarifsCampagneSelect\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>xxx \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6c309fa e-con-full e-flex e-con e-child\" data-id=\"6c309fa\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b50f7d8 elementor-widget elementor-widget-text-editor\" data-id=\"b50f7d8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tDur\u00e9e\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1ce4b20 e-con-full e-flex e-con e-child\" data-id=\"1ce4b20\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-adfc2ca elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"adfc2ca\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopUpTarifsDuree\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>xxx \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ce6546e e-con-full elementor-hidden-desktop e-flex e-con e-child\" data-id=\"ce6546e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-eb6d9f0 e-con-full e-flex e-con e-child\" data-id=\"eb6d9f0\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsBoutonContinuerResa\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b5c7999   elementor-widget elementor-widget-text-editor\" data-id=\"b5c7999\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsBoutonContinuerResaTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a style=\"color: #808080;\" href=\"#\">Continuer la<br>\nr\u00e9servation<\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ffe07a1 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"ffe07a1\" data-element_type=\"container\" data-e-type=\"container\" id=\"PopupTarifsBoutonContinuerResaOrdiMessageConteiner\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-100e7a5 elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"100e7a5\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PopupTarifsBoutonContinuerResaOrdiMessageTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>PopupTarifsBoutonContinuerResaOrdiMessageTexte<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d3a9361 e-con-full e-flex e-con e-child\" data-id=\"d3a9361\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a7daa0b elementor-widget elementor-widget-html\" data-id=\"a7daa0b\" data-element_type=\"widget\" data-e-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\r\n\/\/ pb740c : ECHO DE VERSION. Deux tours sans aucun log ne permettaient pas de\r\n\/\/   distinguer \"snippet non deploye \/ cache\" de \"code deploye mais branche non\r\n\/\/   atteinte\". Cette ligne sort AVANT tout le reste, sans condition ni\r\n\/\/   dependance : son absence dans la console signifie que le fichier charge\r\n\/\/   n'est pas celui-ci, et rien d'autre n'est exploitable.\r\nwindow._viaGrilleVer = 'GT-pb2408';\r\nconsole.log('%c[GRILLE ECHO] ' + window._viaGrilleVer, 'background:#2f3e6d;color:#fff;padding:2px 6px;border-radius:3px');\r\n\r\n\/\/ ========================================================================\r\n\/\/ pb1910 : LE CONTEXTE, DEMANDE UNE FOIS \u2014 ET AUCUNE SORTIE MUETTE.\r\n\/\/   Constat user : \u00ab le process classique recuperait sans probleme les donnees\r\n\/\/   site pays et secteur \u00bb. Exact, et la sonde disait pourquoi sans que je le\r\n\/\/   voie : \u00ab lignes pays cochees : 0 \/ 0 \u00bb.\r\n\/\/   pb1902 a bien leve la garde de fin de fichier, mais la MEME question est\r\n\/\/   posee TROIS FOIS DE PLUS, en tete de trois methodes, avec le meme test\r\n\/\/   d\u00e9pass\u00e9 et \u2014 plus grave \u2014 un return SANS AUCUN LOG :\r\n\/\/     rendreListePays613     (l. ~2239)  -> la liste des sites pays reste vide\r\n\/\/     rendreListeSecteurs615 (l. ~7002)  -> la liste des secteurs reste vide\r\n\/\/     lierTarifs612          (l. ~7035)  -> les tarifs ne sont pas lies\r\n\/\/   _initSafe634 les a comptees \u00ab reussies \u00bb : elles n'ont pas leve, elles ont\r\n\/\/   rendu la main. Un 6\/6 vrai et creux. C'est mot pour mot la faute que ce\r\n\/\/   projet facture depuis pb1858 : une sortie muette coute un aller-retour a\r\n\/\/   chaque fois.\r\n\/\/   On pose donc UN seul discriminant \u2014 celui de pb1902 \u2014 et les quatre points\r\n\/\/   l'interrogent. Il journalise sa sortie, une fois par appelant (signature PAR\r\n\/\/   CLE : plusieurs appelants alternent, une signature globale en masquerait).\r\n\/\/   Retour : true si nous sommes la regie \u2014 au premier plan, ou en iframe avec\r\n\/\/   mode=popup \/ layout=plein (parcours pb1642). false pour une page pays chargee\r\n\/\/   dans une iframe VLP, ou les dependances regie n'existent effectivement pas.\r\n\/\/   Revert : window._viaPb1910Off = true (retour au seul test iframe).\r\n\/\/ ========================================================================\r\n\/\/ ========================================================================\r\n\/\/ pb1918 : \u00ab POPUP PAYS ET MOBILE \u00bb, DEMANDE UNE FOIS.\r\n\/\/   Les reglages qui ne valent que la partagent donc UN discriminant, pas une\r\n\/\/   copie chacun : largeur de la liste des tarifs (pb1925) et echelle du champ\r\n\/\/   annonceur (pb1920). Le masquage du selecteur de tarif l'a quitte en pb1924,\r\n\/\/   qui vaut sur TOUS les sites pays, mobile comme desktop.\r\n\/\/   Detection du mobile identique a pb1907 et pb1914, et pour la meme raison :\r\n\/\/   maxTouchPoints d'abord, innerWidth ensuite, JAMAIS sur un innerWidth nul \u2014\r\n\/\/   l'iframe prechargee demarre a 0 et 0 < 1000 est vrai (pb1538\/pb1677).\r\n\/\/ ========================================================================\r\n\/\/ ========================================================================\r\n\/\/ pb1935 : LE GONFLEMENT DE TEXTE DE WebKit, DANS L IFRAME SEULE.\r\n\/\/   Indice user, et c est lui qui tranche : sur l iPhone 17 du collegue, L ENTETE\r\n\/\/   S AFFICHE COMME SUR LE SIEN \u2014 seul le contenu de l iframe est dilate.\r\n\/\/   L entete appartient au document PARENT (le site pays), l iframe est un\r\n\/\/   document SEPARE. Trois des quatre causes envisagees agiraient sur les deux a\r\n\/\/   la fois et sont donc ecartees d un coup :\r\n\/\/     - viewport de l appareil \/ modele d iPhone : l entete grossirait aussi ;\r\n\/\/     - reglage Display Zoom (\u00ab Texte plus grand \u00bb) : idem, il vaut pour le\r\n\/\/       document entier ;\r\n\/\/     - zoom visuel (pincement, zoom de page Safari) : idem.\r\n\/\/   Reste la seule qui soit PROPRE A CHAQUE FRAME : l algorithme d inflation de\r\n\/\/   texte de WebKit. MDN le decrit exactement ainsi \u2014 \u00ab many mobile browsers apply\r\n\/\/   a text inflation algorithm to enlarge the text [...] When an element containing\r\n\/\/   text uses 100% of the screen's width, the algorithm increases its text size,\r\n\/\/   BUT WITHOUT MODIFYING THE LAYOUT \u00bb. C est mot pour mot la capture : les blocs\r\n\/\/   restent en place, le texte grossit et passe a la ligne.\r\n\/\/   Sa valeur initiale est 'auto' sur les navigateurs mobiles qui l implementent,\r\n\/\/   et la decision se prend PAR DOCUMENT, en fonction de la largeur de ses blocs :\r\n\/\/   deux documents, deux decisions. D ou l entete intact et l iframe dilatee.\r\n\/\/   La parade est unique et connue : text-size-adjust a 100%, equivalent a 'none'.\r\n\/\/   Safari ne comprend que la forme prefixee -webkit- ; on pose les trois.\r\n\/\/   LE LOG MESURE AVANT DE POSER. Si la valeur calculee vaut deja 100% ou none,\r\n\/\/   l hypothese tombe et il ne faut pas chercher la \u2014 ce releve le dira sans\r\n\/\/   nouvel aller-retour, et c est la raison d etre de cette ligne.\r\n\/\/   PORTEE : les sites pays uniquement (mode=popup), pas la regie au premier plan.\r\n\/\/   AVERTISSEMENT ASSUME : si l inflation etait AUSSI active sur ton iPhone, tous\r\n\/\/   les calages valides a l ecran l ont ete sur du texte gonfle, et ils vont\r\n\/\/   retrecir. Le log te le dira ('auto' avant pose = elle etait active). Dans ce\r\n\/\/   cas les tailles seront a revoir UNE fois \u2014 mais sur une base enfin identique\r\n\/\/   d un appareil a l autre, ce qui est precisement le but.\r\n\/\/   Reglage a chaud : --via-tsa-1935 (100% ; 'auto' retablit le gonflement).\r\n\/\/   Revert : window._viaPb1935Off = true (feuille non injectee).\r\n\/\/ ========================================================================\r\n(function _texteAdjust1935() {\r\n    if (window._viaPb1935Off === true) { return; }\r\n    try {\r\n        var _pays1935 = false;\r\n        try {\r\n            _pays1935 = document.body\r\n                ? document.body.classList.contains('via-popup-achat') : false;\r\n            if (!_pays1935) {\r\n                _pays1935 = (new URLSearchParams(window.location.hash.substring(1)\r\n                    || window.location.search).get('mode') === 'popup');\r\n            }\r\n        } catch (_eU1935) { _pays1935 = false; }\r\n        if (!_pays1935) { return; }\r\n        if (document.getElementById('via-tsa-1935')) { return; }\r\n        \/* MESURE AVANT POSE \u2014 c est elle qui valide ou invalide l hypothese *\/\r\n        var _cs1935 = window.getComputedStyle(document.documentElement);\r\n        var _av1935 = _cs1935.webkitTextSizeAdjust || _cs1935.textSizeAdjust || '(non lu)';\r\n        var _ref1935 = document.getElementById('PopupTarifsListePaysTitreTexte')\r\n            || document.querySelector('.PopupTarifsListePaysTitreTexte');\r\n        var _fsAv1935 = _ref1935\r\n            ? parseFloat(window.getComputedStyle(_ref1935).fontSize) : 0;\r\n        var _st1935 = document.createElement('style');\r\n        _st1935.id = 'via-tsa-1935';\r\n        _st1935.textContent = 'html {'\r\n            + ' text-size-adjust: var(--via-tsa-1935, 100%) !important;'\r\n            + ' -webkit-text-size-adjust: var(--via-tsa-1935, 100%) !important;'\r\n            + ' -moz-text-size-adjust: var(--via-tsa-1935, 100%) !important; }';\r\n        document.head.appendChild(_st1935);\r\n        setTimeout(function () {\r\n            var _fsAp1935 = _ref1935\r\n                ? parseFloat(window.getComputedStyle(_ref1935).fontSize) : 0;\r\n            console.log('[pb1935] inflation de texte WebKit | AVANT pose : ' + _av1935\r\n                + ((String(_av1935).indexOf('auto') !== -1)\r\n                    ? '  <-- ELLE ETAIT ACTIVE, c est la cause'\r\n                    : '  <-- deja neutralisee, chercher ailleurs')\r\n                + ' | titre de reference ' + _fsAv1935 + 'px -> ' + _fsAp1935 + 'px'\r\n                + ' | inner=' + window.innerWidth + ' outer=' + window.outerWidth);\r\n        }, 300);\r\n    } catch (_e1935) { console.warn('[pb1935] ' + _e1935.message); }\r\n})();\r\n\r\nwindow._viaPopupPaysMobile1918 = function () {\r\n    if (typeof window._viaPopupPays1905 !== 'function') { return false; }\r\n    if (!window._viaPopupPays1905()) { return false; }\r\n    var _tp1918 = navigator.maxTouchPoints || 0;\r\n    var _iw1918 = window.innerWidth || 0;\r\n    return (_tp1918 > 0) ? true : ((_iw1918 > 0) ? (_iw1918 < 1000) : false);\r\n};\r\n\r\n\/\/ ========================================================================\r\n\/\/ pb1926 : pb1924 NE COUVRE QUE L'ETAT APRES UN CLIC.\r\n\/\/   Constat user (capture) : #PopUpTarifsTarifsSelectContainer s'affiche encore.\r\n\/\/   Et c'est logique \u2014 j'ai corrige au bon endroit, mais cet endroit ne repond\r\n\/\/   qu'a un evenement. pb1239, pb1300 et pb1924 vivent TOUS a l'interieur du\r\n\/\/   handler de clic sur un tarif (brancherSelectionTarif612) : tant qu'aucun tarif\r\n\/\/   n'a ete clique, aucune de ces trois regles n'a tourne. La capture montre\r\n\/\/   precisement cet etat \u2014 la grille affichee, aucun tarif retenu.\r\n\/\/   \u00ab pb1239 : on agit ici, dans le writer qui le revele \u00bb reste vrai pour l'etat\r\n\/\/   APRES clic ; il ne dit rien de l'etat AVANT. Il fallait les deux.\r\n\/\/   FEUILLE CSS, et elle suffit ici : les seuls inline !important poses sur ce\r\n\/\/   conteneur viennent de ce meme handler \u2014 display:none par pb1239\/pb1300\/pb1924,\r\n\/\/   display:flex par sa branche else, que pb1924 rend inatteignable sur les sites\r\n\/\/   pays. Aucun autre writer ne peut donc battre la feuille, et le recensement du\r\n\/\/   tour precedent le confirme : pb1299 et pb710 ne font que MASQUER.\r\n\/\/   AUCUNE CLASSE NOUVELLE : body.via-popup-achat existe deja et designe\r\n\/\/   exactement \u00ab la regie au service d'un site pays \u00bb. Une classe de plus serait\r\n\/\/   une strate de plus a suivre.\r\n\/\/   Injectee au chargement, sans attendre : la regle ne s'applique que si la\r\n\/\/   classe est posee, et elle l'est par yearbook-media.js quelques instants apres.\r\n\/\/   Revert : window._viaPb1926Off = true.\r\n\/\/ ========================================================================\r\n(function _feuilleSelecteur1926() {\r\n    if (window._viaPb1926Off === true) { return; }\r\n    try {\r\n        if (document.getElementById('via-masque-select-1926')) { return; }\r\n        var _st1926 = document.createElement('style');\r\n        _st1926.id = 'via-masque-select-1926';\r\n        _st1926.textContent = 'body.via-popup-achat #PopUpTarifsTarifsSelectContainer'\r\n            + ' { display: none !important; }';\r\n        document.head.appendChild(_st1926);\r\n        console.log('[pb1926] feuille inject\u00e9e : #PopUpTarifsTarifsSelectContainer'\r\n            + ' masqu\u00e9 sur les sites pays, avant tout clic comme apr\u00e8s');\r\n    } catch (_e1926) { console.warn('[pb1926] ' + _e1926.message); }\r\n})();\r\n\r\nwindow._viaContexteRegie1910 = function (_ou1910) {\r\n    var _ifr1910 = false;\r\n    try { _ifr1910 = (window.self !== window.top); } catch (_eF1910) { _ifr1910 = true; }\r\n    if (!_ifr1910) { return true; }\r\n    if (window._viaPb1910Off === true) { return false; }\r\n    var _prm1910 = '(URL illisible)';\r\n    try {\r\n        var _u1910 = new URLSearchParams(window.location.hash.substring(1)\r\n            || window.location.search);\r\n        _prm1910 = 'mode=' + (_u1910.get('mode') || '-')\r\n            + ' layout=' + (_u1910.get('layout') || '-');\r\n        if (_u1910.get('mode') === 'popup') { return true; }\r\n        if (_u1910.get('layout') === 'plein') { return true; }\r\n    } catch (_e1910) {\r\n        console.warn('[pb1910] URL illisible : ' + _e1910.message);\r\n    }\r\n    window._viaSig1910 = window._viaSig1910 || {};\r\n    if (!window._viaSig1910[_ou1910]) {\r\n        window._viaSig1910[_ou1910] = true;\r\n        console.log('[pb1910] ' + _ou1910 + ' : page pays en iframe (' + _prm1910\r\n            + ') -> sortie, enrichissements regie non applicables');\r\n    }\r\n    return false;\r\n};\r\n\r\ndocument.addEventListener('DOMContentLoaded', function() {\r\njQuery(function($) {\r\n\r\n\/**\r\n * ========================================\r\n * MODULE DE CHARGEMENT DES D\u00c9PENDANCES\r\n * ========================================\r\n *\/\r\n\r\nconst GRILLE_DEPENDENCIES = {\r\n    MAIN_JS_URL: 'https:\/\/via-agency.media\/wp-content\/plugins\/via-agency\/assets\/js\/main.js',\r\n    COUNTRIES_JS_URL: 'https:\/\/via-agency.media\/wp-content\/plugins\/via-agency\/assets\/js\/countries-config.js?v=2.0',\r\n    JQUERY_UI_URL: 'https:\/\/code.jquery.com\/ui\/1.12.1\/jquery-ui.min.js'\r\n};\r\n\r\n\/**\r\n * Charge un script externe\r\n *\/\r\nfunction loadScript(url, id) {\r\n    return new Promise((resolve, reject) => {\r\n        if (document.getElementById(id)) {\r\n            console.log(`\u2705 ${id} d\u00e9j\u00e0 charg\u00e9`);\r\n            resolve();\r\n            return;\r\n        }\r\n\r\n        console.log(`\ud83d\udd04 Chargement de ${id}...`);\r\n        \r\n        const script = document.createElement('script');\r\n        script.id = id;\r\n        script.src = url;\r\n        script.onload = () => {\r\n            console.log(`\u2705 ${id} charg\u00e9`);\r\n            resolve();\r\n        };\r\n        script.onerror = () => {\r\n            console.error(`\u274c \u00c9chec chargement ${id}`);\r\n            reject(new Error(`Impossible de charger ${id}`));\r\n        };\r\n\r\n        document.head.appendChild(script);\r\n    });\r\n}\r\n\r\n\/**\r\n * Attend qu'un objet global soit disponible\r\n *\/\r\nfunction waitForGlobal(globalName, maxAttempts = 100) {\r\n    return new Promise((resolve, reject) => {\r\n        let attempts = 0;\r\n        \r\n        const checkInterval = setInterval(() => {\r\n            attempts++;\r\n            \r\n            if (window[globalName]) {\r\n                clearInterval(checkInterval);\r\n                console.log(`\u2705 ${globalName} disponible`);\r\n                resolve();\r\n            } else if (attempts >= maxAttempts) {\r\n                clearInterval(checkInterval);\r\n                reject(new Error(`${globalName} non disponible apr\u00e8s ${maxAttempts} tentatives`));\r\n            }\r\n        }, 100);\r\n    });\r\n}\r\n\r\n\/**\r\n * Initialisation des d\u00e9pendances\r\n *\/\r\nasync function initDependencies() {\r\n    try {\r\n        console.log('\ud83c\udfa8 Initialisation des d\u00e9pendances de la grille tarifaire...');\r\n\r\n        \/\/ 1. Charger jQuery UI\r\n        await loadScript(GRILLE_DEPENDENCIES.JQUERY_UI_URL, 'jquery-ui-grille');\r\n\r\n        \/\/ 2. Charger main.js\r\n        await loadScript(GRILLE_DEPENDENCIES.MAIN_JS_URL, 'via-main-js-grille');\r\n        await waitForGlobal('VIA_App');\r\n\r\n        \/\/ 3. Charger countries-config.js\r\n        await loadScript(GRILLE_DEPENDENCIES.COUNTRIES_JS_URL, 'via-countries-config-grille');\r\n        await waitForGlobal('VIA_Countries');\r\n\r\n        \/\/ 4. Attendre les taux de change\r\n        console.log('\u23f3 Attente des taux de change...');\r\n        let tentatives = 0;\r\n        while (!window.VIA_App.tauxDeChange.EUR && tentatives < 50) {\r\n            await new Promise(resolve => setTimeout(resolve, 100));\r\n            tentatives++;\r\n        }\r\n\r\n        if (!window.VIA_App.tauxDeChange.EUR) {\r\n            \/\/ v2.9 : override checkTauxInDB sans credentials -> CORS via snippet PHP via-agency.media\r\n            window.VIA_App.checkTauxInDB = async function() {\r\n                const _r = await fetch('https:\/\/via-agency.media\/wp-admin\/admin-ajax.php', {\r\n                    method: 'POST',\r\n                    credentials: 'omit',\r\n                    headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n                    body: 'action=convRatesGet'\r\n                });\r\n                const _txt = await _r.text();\r\n                if (!_txt || _txt === 'KO') return 'KO';\r\n                const _taux = JSON.parse(_txt);\r\n                this.saveTauxToSessionStorage(_taux);\r\n                sessionStorage.setItem('TauxdeChangeActualise', 'Yes');\r\n                return 'OK';\r\n            };\r\n            try {\r\n                await window.VIA_App.initTauxDeChange();\r\n                console.log('\u2705 Taux charg\u00e9s (CORS via-agency):', window.VIA_App.tauxDeChange);\r\n            } catch (_e) {\r\n                console.warn('\u26a0\ufe0f Taux non charg\u00e9s:', _e.message);\r\n            }\r\n        } else {\r\n            sessionStorage.setItem('TauxdeChangeActualise', 'Yes');\r\n            console.log('\u2705 Taux de change disponibles');\r\n        }\r\n\r\n        console.log('\u2705 Toutes les d\u00e9pendances sont charg\u00e9es');\r\n        return true;\r\n\r\n    } catch (error) {\r\n        console.error('\u274c Erreur lors du chargement des d\u00e9pendances:', error);\r\n        \/\/alert('Erreur : Impossible de charger les ressources n\u00e9cessaires. Veuillez recharger la page.');\r\n        return false;\r\n    }\r\n}\r\n\r\n\/**\r\n * ========================================\r\n * INITIALISATION PRINCIPALE\r\n * ========================================\r\n *\/\r\n(async function() {\r\n    \/\/ Charger les d\u00e9pendances AVANT d'initialiser les modules\r\n    const dependenciesLoaded = await initDependencies();\r\n    \r\n    if (!dependenciesLoaded) {\r\n        console.error('\u274c Impossible d\\'initialiser la grille tarifaire');\r\n        return;\r\n    }\r\n\r\n    \/\/ Maintenant on peut initialiser les modules qui d\u00e9pendent de VIA_App et VIA_Countries\r\n    console.log('\ud83c\udfa8 Initialisation des modules de la grille...');\r\n\r\n    \/\/ VOTRE CODE EXISTANT COMMENCE ICI\r\n    \/\/ (CampaignDatePickers, CountryAutocomplete, GrilleTarifaire)\r\n     \r\n\/**\r\n * JS GRILLE TARIFAIRE\r\n * @version 1.0\r\n *\/\r\n\r\nclass CampaignDatePickers {\r\n    constructor(config = {}) {\r\n        this.config = {\r\n            startDateSelector: '#form-field-PopupTarifsDebutCampagne',\r\n            endDateSelector: '#form-field-PopupTarifsFinCampagne',\r\n            dateFormat: 'dd\/mm\/yy',\r\n            ...config\r\n        };\r\n\r\n        this.state = {\r\n            isInitialized: false,\r\n            startDate: null,\r\n            endDate: null\r\n        };\r\n\r\n        this.init();\r\n    }\r\n\r\n    async init() {\r\n        try {\r\n            await this.waitForJQueryUI();\r\n            \r\n            this.setupDatePickers();\r\n            this.injectDatePickerStyles();\r\n            this.state.isInitialized = true;\r\n\r\n            console.log('\u2713 Campaign Date Pickers initialis\u00e9');\r\n        } catch (error) {\r\n            console.error('\u2717 Erreur datepickers:', error);\r\n        }\r\n    }\r\n\r\n    waitForJQueryUI() {\r\n        return new Promise((resolve) => {\r\n            const checkJQueryUI = () => {\r\n                if (typeof $.fn.datepicker === 'function') {\r\n                    console.log('\u2713 jQuery UI Datepicker disponible');\r\n                    resolve();\r\n                } else {\r\n                    setTimeout(checkJQueryUI, 100);\r\n                }\r\n            };\r\n            checkJQueryUI();\r\n        });\r\n    }\r\n    \r\n    setupDatePickers() {\r\n        const $startDate = $(this.config.startDateSelector);\r\n        const $endDate = $(this.config.endDateSelector);\r\n        \r\n        if ($startDate.length === 0 || $endDate.length === 0) {\r\n            console.warn('\u26a0 Champs de date introuvables');\r\n            return;\r\n        }\r\n    \r\n        \/\/ \u2705 S'assurer que le datepicker div est dans le DOM\r\n        if ($.datepicker && $.datepicker.dpDiv && !$.contains(document.body, $.datepicker.dpDiv[0])) {\r\n            document.body.appendChild($.datepicker.dpDiv[0]);\r\n            console.log('\u2705 Datepicker rattach\u00e9 au body');\r\n        }\r\n        \r\n        \/\/ ================================================================\r\n        \/\/ pb800 : sur DESKTOP EN MODE MOBILE (fenetre etroite, aucun ecran tactile),\r\n        \/\/   les calendriers ne s'ouvraient jamais. isMobile etant calcule sur la\r\n        \/\/   LARGEUR, la DVM basculait en gestion tactile :\r\n        \/\/     - showOn passait a 'none' (plus d'ouverture au focus)\r\n        \/\/     - le focus natif etait annule par un blur() immediat\r\n        \/\/     - l'ouverture ne restait possible que par 'touchend', evenement qu'une\r\n        \/\/       souris n'emet pas.\r\n        \/\/   Aucun chemin ne subsistait donc pour ouvrir le calendrier.\r\n        \/\/   On separe les deux notions, comme partout ailleurs dans ce projet :\r\n        \/\/     isMobile      = mise en page etroite  -> styles, positionnement\r\n        \/\/     isTactile800  = appareil TACTILE      -> gestion des evenements\r\n        \/\/   Seul le second commande la bascule touchend. Un vrai telephone garde son\r\n        \/\/   comportement (userAgent OU maxTouchPoints), la DVM retrouve le focus.\r\n        \/\/   Revert : window._viaPb800Off = true.\r\n        \/\/ ================================================================\r\n        \/* ================================================================\r\n         * pb1969 : isMobile ETAIT UNE CONSTANTE FIGEE A L'INITIALISATION.\r\n         *   >>> CAS D'ECOLE DE LA REGLE 5.4 (\u00ab les deux horloges \u00bb), enoncee en\r\n         *   tete de yearbook-media.js. Y aller AVANT de rouvrir ce dossier.\r\n         *   Preuve, releve JF, deux instances du module dans la meme session :\r\n         *     [pb800] largeur=0    | isMobile=true\r\n         *     [pb800] largeur=1404 | isMobile=false\r\n         *   La premiere s'execute pendant que l'iframe est PRECHARGEE et\r\n         *   masquee : le document n'a aucun layout, innerWidth vaut 0, et\r\n         *   0 <= 1015 rend true \u2014 definitivement, sur un ecran de 1404 px.\r\n         *   Consequence mesuree : l'ecouteur \u00ab fermeture sur clic en dehors \u00bb\r\n         *   (plus bas, gard\u00e9 par isMobile) est installe sur desktop ou il n'a\r\n         *   rien a faire. Un second evenement clic de cible BODY \u2014 visible dans\r\n         *   le log \u2014 ne correspond a aucun de ses selecteurs, il ferme donc les\r\n         *   deux calendriers. D'ou \u00ab il s'ouvre puis disparait \u00bb, et d'ou le\r\n         *   _lastInput=null sur un calendrier encore affiche : _hideDatepicker\r\n         *   l'efface des son appel, le fondu dure encore 200 ms.\r\n         *   La seconde instance, elle, mesure juste \u2014 mais elle ne DEFAIT pas\r\n         *   l'ecouteur de la premiere. Corriger la mesure ne suffirait donc pas.\r\n         *   CORRECTION : la decision quitte l'instant d'INSTALLATION pour\r\n         *   l'instant de L'EVENEMENT. isMobile devient une lecture, pas une\r\n         *   constante. Un ecouteur pose par une instance qui se trompait se\r\n         *   comporte alors correctement quand meme \u2014 on n'a pas a le retrouver.\r\n         *   C'est le precedent que le projet s'est deja donne en pb1796, en\r\n         *   choisissant une media query plutot qu'un innerWidth : \u00ab un\r\n         *   innerWidth figerait la decision a l'instant ou la feuille est\r\n         *   ecrite \u00bb. Meme faute, meme remede.\r\n         *   Absence de geometrie = on ne bascule PAS en mobile. Un vrai\r\n         *   telephone est deja pris par le test userAgent, en premier.\r\n         *   isTactile800 n'est PAS touche : il porte sur l'appareil (userAgent,\r\n         *   maxTouchPoints), pas sur la mise en page. Il ne se fige pas.\r\n         *   Revert : window._viaPb1969Off = true (retour au booleen d'origine).\r\n         * ================================================================ *\/\r\n        var _estMobile1969 = function () {\r\n            if (\/iPhone|iPad|iPod|Android\/i.test(navigator.userAgent)) { return true; }\r\n            var _l1969 = window.innerWidth;\r\n            if (!_l1969) {\r\n                _l1969 = document.documentElement ? document.documentElement.clientWidth : 0;\r\n            }\r\n            if (window._viaPb1969Off === true) { return (_l1969 <= 1015); }\r\n            if (!_l1969) { return false; }   \/* aucune geometrie : on ne decide pas *\/\r\n            return (_l1969 <= 1015);\r\n        };\r\n        const isMobile = _estMobile1969();   \/* pb1969 : valeur d'instant, pour le log seul *\/\r\n        const _tactile800 = \/iPhone|iPad|iPod|Android\/i.test(navigator.userAgent)\r\n            ? true\r\n            : ((navigator.maxTouchPoints || 0) > 0 ? ('ontouchstart' in window) : false);\r\n        const isTactile800 = (window._viaPb800Off === true) ? isMobile : _tactile800;\r\n        console.log('[pb800] datepickers popup | largeur=' + window.innerWidth\r\n            + ' | isMobile=' + isMobile + ' | tactile=' + isTactile800\r\n            + ' -> ouverture par ' + (isTactile800 ? 'touchend' : 'focus')\r\n            + ' | [pb1969] la bascule mobile est desormais relue a chaque evenement');\r\n        \r\n        \/\/ \u2705 Flag pour emp\u00eacher fermeture imm\u00e9diate\r\n        let datepickerJustOpened = false;\r\n        \r\n        $startDate.attr('readonly', 'readonly');\r\n        $endDate.attr('readonly', 'readonly');\r\n            \r\n        if (isTactile800) {   \/\/ pb800 : tactile REEL, plus la simple largeur\r\n            \/\/ \u2705 Emp\u00eacher le focus natif qui cause des probl\u00e8mes\r\n            $startDate.on('focus', function(e) {\r\n                $(this).blur();\r\n            });\r\n            $endDate.on('focus', function(e) {\r\n                $(this).blur();\r\n            });\r\n            \r\n            \/\/ \u2705 Ouvrir via touchend au lieu de laisser jQuery UI g\u00e9rer\r\n            $startDate.on('touchend', function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                datepickerJustOpened = true;\r\n                $endDate.datepicker('hide');\r\n                $(this).datepicker('show');\r\n                setTimeout(() => { datepickerJustOpened = false; }, 300);\r\n            });\r\n            \r\n            $endDate.on('touchend', function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                datepickerJustOpened = true;\r\n                $startDate.datepicker('hide');\r\n                $(this).datepicker('show');\r\n                setTimeout(() => { datepickerJustOpened = false; }, 300);\r\n            });\r\n            \r\n            console.log('\ud83d\udcf1 Mode mobile : gestion tactile activ\u00e9e');\r\n        }\r\n        \r\n        const tomorrow = new Date();\r\n        tomorrow.setDate(tomorrow.getDate() + 21);   \/\/ pb651q : aligne sur la resa (J+21)\r\n        tomorrow.setHours(0, 0, 0, 0);\r\n        \r\n        $startDate.datepicker({\r\n            dateFormat: this.config.dateFormat,\r\n            minDate: tomorrow,\r\n            maxDate: '+2y',\r\n            firstDay: 1,\r\n            showButtonPanel: false,\r\n            showOn: isTactile800 ? 'none' : 'focus',   \/\/ pb800 : tactile reel uniquement\r\n            beforeShow: (input, inst) => {\r\n                setTimeout(() => {\r\n                    const rect = input.getBoundingClientRect();\r\n                    inst.dpDiv.css({\r\n                        'position': 'fixed',\r\n                        'top': (rect.bottom + 5) + 'px',\r\n                        'left': rect.left + 'px',\r\n                        'z-index': '2147483647'\r\n                    });\r\n                }, 0);\r\n            },\r\n            onSelect: (dateText, inst) => {\r\n                this.onStartDateSelect(dateText, $startDate, $endDate);\r\n            }\r\n        });\r\n        \r\n        $endDate.datepicker({\r\n            dateFormat: this.config.dateFormat,\r\n            minDate: tomorrow,\r\n            maxDate: '+2y',\r\n            firstDay: 1,\r\n            showButtonPanel: false,\r\n            showOn: isTactile800 ? 'none' : 'focus',   \/\/ pb800 : tactile reel uniquement\r\n            beforeShow: (input, inst) => {\r\n                const startDate = $startDate.datepicker('getDate');\r\n                if (startDate) {\r\n                    const minEndDate = new Date(startDate);\r\n                    minEndDate.setDate(minEndDate.getDate() + 1);\r\n                    const finalMinDate = minEndDate > tomorrow ? minEndDate : tomorrow;\r\n                    $endDate.datepicker('option', 'minDate', finalMinDate);\r\n                }\r\n                \r\n                setTimeout(() => {\r\n                    inst.dpDiv.addClass('campaign-datepicker');\r\n                    \r\n                    if (_estMobile1969()) {   \/\/ pb1969 : lu a l'ouverture, pas a l'init\r\n                        inst.dpDiv.css({\r\n                            'position': 'fixed',\r\n                            'left': '50%',\r\n                            'top': '50%',\r\n                            'transform': 'translate(-50%, -50%)',\r\n                            'margin': '0',\r\n                            'z-index': '2147483647'\r\n                        });\r\n                    }\r\n                }, 0);\r\n            },\r\n            onSelect: (dateText, inst) => {\r\n                this.onEndDateSelect(dateText, $endDate);\r\n            }\r\n        });\r\n        \r\n        \/* pb1969 : la pose n'est plus conditionnee, la FERMETURE l'est. Et elle\r\n           n'a lieu qu'une fois : deux instances du module posaient deux jeux\r\n           d'ecouteurs sur document, dont celui de l'instance qui se trompait. *\/\r\n        if (window._viaArmeFerme1969 !== true) {\r\n        window._viaArmeFerme1969 = true;\r\n        \/\/ \u2705 Fermeture sur clic en dehors (avec protection)\r\n        {\r\n            $(document).on('touchend', (e) => {\r\n                if (!_estMobile1969()) { return; }   \/\/ pb1969 : desktop -> jamais\r\n                if (datepickerJustOpened) return; \/\/ \u2705 Ne pas fermer si vient d'ouvrir\r\n\r\n                \/\/ pb606 : meme protection que sur le handler click \u2014 une cible detachee\r\n                \/\/   du DOM provient d'un re-render du calendrier, pas d'un clic exterieur.\r\n                if (!document.contains(e.target)) { return; }\r\n\r\n                if (!$(e.target).closest('.ui-datepicker, .campaign-datepicker, #form-field-PopupTarifsDebutCampagne, #form-field-PopupTarifsFinCampagne').length) {\r\n                    $startDate.datepicker('hide');\r\n                    $endDate.datepicker('hide');\r\n                }\r\n            });\r\n        }\r\n    \r\n        $startDate.on('change', (e) => {\r\n            if (!e.target.value) {\r\n                this.state.startDate = null;\r\n                $endDate.datepicker('option', 'minDate', tomorrow);\r\n                this.calculateDuration();\r\n            }\r\n        });\r\n        \r\n        $endDate.on('change', (e) => {\r\n            if (!e.target.value) {\r\n                this.state.endDate = null;\r\n                this.calculateDuration();\r\n            }\r\n        });\r\n        \r\n        \/\/ \u2705 NOUVEAU : G\u00e9rer le clic en dehors pour fermer\r\n        {\r\n            $(document).on('click', (e) => {\r\n                \/* pb1969 : C'EST CET ECOUTEUR QUI FERMAIT LE CALENDRIER DE DEBUT.\r\n                   Un second clic de cible BODY suit le clic sur le champ ; BODY ne\r\n                   correspond a aucun des selecteurs ci-dessous, donc hide(). Il\r\n                   n'aurait jamais du etre pose sur desktop. La garde est ici, a\r\n                   l'evenement, pour valoir aussi pour les ecouteurs deja poses. *\/\r\n                if (!_estMobile1969()) {\r\n                    if (window._viaSig1969 !== 'desktop') {\r\n                        window._viaSig1969 = 'desktop';\r\n                        console.log('[pb1969] fermeture sur clic exterieur NEUTRALISEE'\r\n                            + ' (largeur=' + window.innerWidth + ', contexte non mobile)');\r\n                    }\r\n                    return;\r\n                }\r\n                \/\/ pb606 : au tap sur les fleches mois (prev\/next), jQuery UI REGENERE le\r\n                \/\/   contenu du calendrier (dpDiv.empty().append(...)) AVANT que le click\r\n                \/\/   ait fini de remonter jusqu'a document. Le <span class=\"ui-icon\"> tape\r\n                \/\/   est alors DETACHE du DOM : son .closest('.ui-datepicker') ne matche\r\n                \/\/   plus rien, la garde \"clic en dehors\" se declenche a tort et ferme le\r\n                \/\/   calendrier -> le mois changeait puis le calendrier disparaissait.\r\n                \/\/   Une cible qui n'est plus dans le document vient forcement d'un\r\n                \/\/   re-render du datepicker : on ne ferme pas.\r\n                if (!document.contains(e.target)) { return; }\r\n\r\n                if (!$(e.target).closest('.ui-datepicker, .campaign-datepicker, input[type=\"text\"]').length) {\r\n                    $startDate.datepicker('hide');\r\n                    $endDate.datepicker('hide');\r\n                }\r\n            });\r\n        }\r\n        }   \/\/ pb1969 : fin de la pose unique des ecouteurs de fermeture\r\n        \r\n        console.log('\u2713 Datepickers configur\u00e9s');\r\n    }\r\n\r\n    onStartDateSelect(dateText, $startDate, $endDate) {\r\n        const startDate = $startDate.datepicker('getDate');\r\n        this.state.startDate = startDate;\r\n\r\n        const minEndDate = new Date(startDate);\r\n        minEndDate.setDate(minEndDate.getDate() + 1);\r\n\r\n        const tomorrow = new Date();\r\n        tomorrow.setDate(tomorrow.getDate() + 21);   \/\/ pb651q : aligne sur la resa (J+21)\r\n        tomorrow.setHours(0, 0, 0, 0);\r\n\r\n        const finalMinDate = minEndDate > tomorrow ? minEndDate : tomorrow;\r\n\r\n        $endDate.datepicker('option', 'minDate', finalMinDate);\r\n\r\n        const currentEndDate = $endDate.datepicker('getDate');\r\n        if (currentEndDate) {\r\n            if (currentEndDate <= startDate || currentEndDate < finalMinDate) {\r\n                $endDate.val('');\r\n                this.state.endDate = null;\r\n                this._dureeTexte844('');   \/\/ pb844\r\n                this.showDateMessage($endDate, 'Date fin effac\u00e9e (invalide)');\r\n                console.log('\u2713 Date fin effac\u00e9e');\r\n            } else {\r\n                this.state.endDate = currentEndDate;\r\n            }\r\n        }\r\n\r\n        this.flashInput($startDate);\r\n\r\n        \/\/ pb621 : enchainer sur le calendrier de FIN. Le delai laisse jQuery UI\r\n        \/\/   refermer le calendrier de debut (sinon l'ouverture est avalee) et\r\n        \/\/   laisse le beforeShow de fin recalculer sa minDate.\r\n        setTimeout(() => {\r\n            try {\r\n                $endDate.datepicker('show');\r\n                $endDate.focus();\r\n            } catch (e) {\r\n                console.warn('[pb621] ouverture calendrier fin:', e.message);\r\n            }\r\n        }, 250);\r\n\r\n        setTimeout(() => {\r\n            const updatedEndDate = $endDate.datepicker('getDate');\r\n            if (updatedEndDate) {\r\n                this.state.endDate = updatedEndDate;\r\n            }\r\n            this.calculateDuration();\r\n            \r\n            \/\/ \u2705 D\u00e9clencher le calcul de la grille\r\n            if (window.VIA_GrilleTarifaire) {\r\n                window.VIA_GrilleTarifaire.onFormulaireChange();\r\n            }\r\n        }, 50);\r\n\r\n        console.log('\u2713 Date d\u00e9but:', dateText);\r\n    }\r\n\r\n    onEndDateSelect(dateText, $endDate) {\r\n        const endDate = $endDate.datepicker('getDate');\r\n        this.state.endDate = endDate;\r\n\r\n        this.flashInput($endDate);\r\n\r\n        this.calculateDuration();\r\n        \r\n        \/\/ \u2705 D\u00e9clencher le calcul de la grille\r\n        if (window.VIA_GrilleTarifaire) {\r\n            window.VIA_GrilleTarifaire.onFormulaireChange();\r\n        }\r\n\r\n        console.log('\u2713 Date fin:', dateText);\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb844 : la duree calculee s'affiche en VERT ; vide, elle reprend sa teinte\r\n    \/\/   d'origine. Vert #56be50, celui des sous-titres .v644-sub et du marquage\r\n    \/\/   pb785 \u2014 aucune couleur nouvelle dans ce popup.\r\n    \/\/   Teinte d'origine memorisee a la premiere pose : un removeProperty rendrait\r\n    \/\/   la main aux valeurs Elementor sans garantie (lecon pb668, pb766).\r\n    \/\/   Les TROIS ecritures de .TarifsCampagneNbJours passent par ce writer unique :\r\n    \/\/   sans cela, une remise a vide oubliee laisserait un champ vert vide.\r\n    \/\/   Revert : window._viaPb844Off = true.\r\n    \/\/ ================================================================\r\n    _dureeTexte844(texte) {\r\n        const $d844 = $('.TarifsCampagneNbJours');\r\n        $d844.text(texte);\r\n        if (window._viaPb844Off === true) { return; }\r\n        $d844.each(function () {\r\n            if (!this.dataset.col844) {\r\n                this.dataset.col844 = getComputedStyle(this).color || 'inherit';\r\n            }\r\n            this.style.setProperty('color', texte ? '#56be50' : this.dataset.col844, 'important');\r\n        });\r\n        if (window._viaSigDuree844 !== texte) {\r\n            window._viaSigDuree844 = texte;\r\n            console.log('[pb844] duree -> \"' + texte + '\"' + (texte ? ' (vert)' : ' (teinte d origine)'));\r\n        }\r\n    }\r\n\r\n    calculateDuration() {\r\n        if (!this.state.startDate || !this.state.endDate) {\r\n            this._dureeTexte844('');   \/\/ pb844\r\n            return;\r\n        }\r\n\r\n        const diffTime = this.state.endDate - this.state.startDate;\r\n        const diffDays = Math.ceil(diffTime \/ (1000 * 60 * 60 * 24));\r\n\r\n        const durationText = diffDays === 1 ? '1 jour' : `${diffDays} jours`;\r\n        this._dureeTexte844(durationText);   \/\/ pb844\r\n\r\n        console.log('\u2713 Dur\u00e9e:', durationText);\r\n    }\r\n\r\n    formatDate(date) {\r\n        const day = String(date.getDate()).padStart(2, '0');\r\n        const month = String(date.getMonth() + 1).padStart(2, '0');\r\n        const year = date.getFullYear();\r\n        return `${day}\/${month}\/${year}`;\r\n    }\r\n\r\n    showDateMessage($input, message) {\r\n        const $message = $(`<div class=\"date-message\" style=\"color: #ff9800; font-size: 12px; margin-top: 5px;\">${message}<\/div>`);\r\n        $input.parent().after($message);\r\n\r\n        setTimeout(() => {\r\n            $message.fadeOut(300, () => $message.remove());\r\n        }, 3000);\r\n    }\r\n\r\n    flashInput($input) {\r\n        $input.addClass('date-selected');\r\n        setTimeout(() => {\r\n            $input.removeClass('date-selected');\r\n        }, 600);\r\n    }\r\n    \r\n    injectDatePickerStyles() {\r\n        if (document.getElementById('campaign-datepicker-styles')) {\r\n            return;\r\n        }\r\n        const styles = `\r\n            .campaign-datepicker {\r\n                z-index: 100000 !important;\r\n                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;\r\n                border: 1px solid #ddd !important;\r\n                border-radius: 8px !important;\r\n                overflow: hidden !important;\r\n            }\r\n            \/* pb730 : fond du header des calendriers (dates de debut et de fin) en\r\n               gris #808080 au lieu du bleu #007cba. Le texte reste blanc.\r\n               Le header porte aussi .ui-widget-header, dont le theme jQuery UI pose\r\n               un background ET un background-image (degrade) : sans annulation de\r\n               l'image, le degrade bleu du theme resterait visible PAR-DESSUS la\r\n               couleur unie. On neutralise donc les deux, et on double la regle sur\r\n               .ui-widget-header pour couvrir le cas ou .campaign-datepicker n'a pas\r\n               encore ete ajoutee au dpDiv (L301, ajout differe a l'ouverture). *\/\r\n            .campaign-datepicker .ui-datepicker-header,\r\n            .campaign-datepicker .ui-datepicker-header.ui-widget-header,\r\n            #ui-datepicker-div .ui-datepicker-header.ui-widget-header {\r\n                background: #808080 !important;\r\n                background-color: #808080 !important;\r\n                background-image: none !important;\r\n                border-color: #808080 !important;\r\n                color: white !important;\r\n                padding: 12px 10px !important;\r\n            }\r\n            \/* pb731 : flash du champ DATE a la selection (classe .date-selected posee\r\n               600ms par flashInput, L479). Le fond passe de #e8f5e8 a #ddeeff.\r\n               C'est bien ce flash que decrit le \"bleu gris furtif\" : il est le seul\r\n               fond temporaire applique aux champs de date. *\/\r\n            .date-selected {\r\n                background-color: #ddeeff !important;\r\n                transition: background-color 0.3s ease !important;\r\n            }\r\n            \/* \u2705 Z-index \u00e9lev\u00e9 mais PAS display: block *\/\r\n            #ui-datepicker-div {\r\n                z-index: 2147483647 !important;\r\n            }\r\n            \/* \u2705 Corriger le bug d'imbrication *\/\r\n            #ui-datepicker-div.ui-datepicker {\r\n                width: 17em;\r\n                padding: 0.2em 0.2em 0;\r\n            }\r\n            \/* pb645 : fleches de navigation mois simplifiees. On retire l'icone\r\n               jQuery UI (sprite illisible) et le fond, et on dessine un triangle\r\n               CSS blanc ; gris si le mois est indisponible (.ui-state-disabled). *\/\r\n            .ui-datepicker .ui-datepicker-prev,\r\n            .ui-datepicker .ui-datepicker-next {\r\n                background: none !important;\r\n                border: none !important;\r\n                cursor: pointer !important;\r\n                \/* pb715 : ALIGNEMENT sur le texte du mois. Le top:12px fixe ne suivait\r\n                   pas la hauteur reelle du header (padding 12px + titre) ; on centre\r\n                   donc sur le header, qui ne contient que le titre. *\/\r\n                top: 50% !important;\r\n                transform: translateY(-50%) !important;\r\n                \/* pb715 : boite agrandie (1.5em -> 2em) pour contenir le triangle +80% *\/\r\n                width: 2em !important;\r\n                height: 2em !important;\r\n            }\r\n            .ui-datepicker .ui-datepicker-prev span,\r\n            .ui-datepicker .ui-datepicker-next span {\r\n                background-image: none !important;\r\n                display: block !important;\r\n                width: 0 !important;\r\n                height: 0 !important;\r\n                margin: 0 !important;\r\n                left: 50% !important;\r\n                top: 50% !important;\r\n                overflow: visible !important;\r\n                \/* pb645b : masquer le libelle \"Prev\"\/\"Next\" (texte jQuery UI) *\/\r\n                font-size: 0 !important;\r\n                line-height: 0 !important;\r\n                color: transparent !important;\r\n                text-indent: -9999px !important;\r\n            }\r\n            \/* triangle gauche (prev) : pointe vers la gauche *\/\r\n            .ui-datepicker .ui-datepicker-prev span {\r\n                \/* pb715 : +80% (6 -> 10.8 ; 8 -> 14.4) *\/\r\n                border-top: 10.8px solid transparent !important;\r\n                border-bottom: 10.8px solid transparent !important;\r\n                border-right: 14.4px solid #ffffff !important;\r\n                transform: translate(-50%, -50%) !important;\r\n            }\r\n            \/* triangle droit (next) : pointe vers la droite *\/\r\n            .ui-datepicker .ui-datepicker-next span {\r\n                \/* pb715 : +80% (6 -> 10.8 ; 8 -> 14.4) *\/\r\n                border-top: 10.8px solid transparent !important;\r\n                border-bottom: 10.8px solid transparent !important;\r\n                border-left: 14.4px solid #ffffff !important;\r\n                transform: translate(-50%, -50%) !important;\r\n            }\r\n            \/* mois indisponible -> triangle gris + curseur par defaut *\/\r\n            .ui-datepicker .ui-datepicker-prev.ui-state-disabled span {\r\n                border-right-color: #9bbdd0 !important;\r\n            }\r\n            .ui-datepicker .ui-datepicker-next.ui-state-disabled span {\r\n                border-left-color: #9bbdd0 !important;\r\n            }\r\n            \/* pb645c : NE PAS toucher .ui-state-disabled en general (jQuery UI\r\n               grise les DATES indisponibles via l'opacite). On limite le\r\n               curseur\/opacite aux seules FLECHES desactivees. *\/\r\n            .ui-datepicker .ui-datepicker-prev.ui-state-disabled,\r\n            .ui-datepicker .ui-datepicker-next.ui-state-disabled {\r\n                cursor: default !important;\r\n                opacity: 1 !important;\r\n            }\r\n            \/* pas de hover-highlight jQuery UI (bord\/fond) sur les fleches *\/\r\n            .ui-datepicker .ui-datepicker-prev-hover,\r\n            .ui-datepicker .ui-datepicker-next-hover {\r\n                background: none !important;\r\n                border: none !important;\r\n                \/* pb715 : meme centrage que l'etat normal, sinon la fleche sautait\r\n                   de quelques pixels au survol (jQuery UI ajoute cette classe). *\/\r\n                top: 50% !important;\r\n                transform: translateY(-50%) !important;\r\n            }\r\n        `;\r\n    \r\n        const styleElement = document.createElement('style');\r\n        styleElement.id = 'campaign-datepicker-styles';\r\n        styleElement.textContent = styles;\r\n        document.head.appendChild(styleElement);\r\n    }\r\n\r\n    destroy() {\r\n        const $startDate = $(this.config.startDateSelector);\r\n        const $endDate = $(this.config.endDateSelector);\r\n\r\n        if ($startDate.length > 0 && $startDate.data('datepicker')) {\r\n            $startDate.datepicker('destroy');\r\n            $startDate.off('change');\r\n        }\r\n\r\n        if ($endDate.length > 0 && $endDate.data('datepicker')) {\r\n            $endDate.datepicker('destroy');\r\n            $endDate.off('change');\r\n        }\r\n\r\n        $('#campaign-datepicker-styles').remove();\r\n    }\r\n}\r\n\r\n\/**\r\n * Country Autocomplete Module (Version 2.0 - CONFIG CENTRALIS\u00c9E)\r\n *\/\r\n\r\nclass CountryAutocomplete {\r\n    constructor(config = {}) {\r\n        this.config = {\r\n            inputSelector: 'input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]',\r\n            columnSelector: '.TarifsColonneDroite',\r\n            messageSelector: '#Message_Nationalite_Societe_Tarifs',\r\n            \/\/ pb787 : la liste s'ouvre des la 1re lettre (etait 2).\r\n            minLength: 1,\r\n            maxResults: 10,\r\n            autoSelectDelay: 800,\r\n            searchDelay: 200,\r\n            jqueryUIUrl: 'https:\/\/code.jquery.com\/ui\/1.12.1\/jquery-ui.min.js',\r\n            ...config\r\n        };\r\n\r\n        this.state = {\r\n            isInitialized: false,\r\n            validSelection: false,\r\n            autoSelectTimeout: null\r\n        };\r\n\r\n        this.init();\r\n    }\r\n\r\n    async init() {\r\n        try {\r\n            if (typeof window.VIA_Countries === 'undefined') {\r\n                console.error('\u274c Config pays non charg\u00e9e, retry...');\r\n                \r\n                setTimeout(() => {\r\n                    if (typeof window.VIA_Countries !== 'undefined') {\r\n                        this.init();\r\n                    }\r\n                }, 1000);\r\n                return;\r\n            }\r\n\r\n            await this.loadJQueryUI();\r\n            this.setupAutocomplete();\r\n            this.injectStyles();\r\n            this.state.isInitialized = true;\r\n\r\n            console.log('\u2713 Country Autocomplete initialis\u00e9');\r\n        } catch (error) {\r\n            console.error('\u2717 Erreur autocomplete:', error);\r\n        }\r\n    }\r\n\r\n    loadJQueryUI() {\r\n        return new Promise((resolve, reject) => {\r\n            if (typeof $.fn.autocomplete === 'function') {\r\n                console.log('\u2713 jQuery UI d\u00e9j\u00e0 charg\u00e9');\r\n                resolve();\r\n                return;\r\n            }\r\n\r\n            const script = document.createElement('script');\r\n            script.src = this.config.jqueryUIUrl;\r\n            script.onload = () => {\r\n                console.log('\u2713 jQuery UI charg\u00e9');\r\n                resolve();\r\n            };\r\n            script.onerror = () => {\r\n                reject(new Error('\u00c9chec chargement jQuery UI'));\r\n            };\r\n\r\n            document.head.appendChild(script);\r\n        });\r\n    }\r\n\r\n    setupAutocomplete() {\r\n        const $input = $(this.config.inputSelector);\r\n\r\n        if ($input.length === 0) {\r\n            console.warn('\u26a0 Champ pays introuvable');\r\n            return;\r\n        }\r\n\r\n        $(this.config.columnSelector).hide();\r\n\r\n        $input.autocomplete({\r\n            source: (request, response) => this.filterCountries(request, response),\r\n            minLength: this.config.minLength,\r\n            delay: this.config.searchDelay,\r\n            appendTo: 'body',\r\n            select: (event, ui) => this.onSelect(event, ui, $input),\r\n            \/* pb2242 : on garde le seul acquis de pb2221 \u2014 viser l'instance qui a\r\n               ouvert plutot que la premiere de la collection, ce qui compte des\r\n               qu'il existe plusieurs copies du champ. Un repli sur la collection\r\n               couvre l'appel sans evenement. onSelect n'est pas touche : il ecrit\r\n               la valeur sur toutes les copies, ce qui les tient synchronisees. *\/\r\n            open: (event) => this.onOpen(event ? $(event.target) : $input),\r\n            close: () => this.onClose($input)\r\n        });\r\n\r\n        this.attachInputEvents($input);\r\n\r\n        console.log('\u2713 Autocomplete configur\u00e9');\r\n    }\r\n\r\n    filterCountries(request, response) {\r\n        const term = request.term.trim();\r\n        \r\n        if (term.length < this.config.minLength) {\r\n            response([]);\r\n            return;\r\n        }\r\n    \r\n        \/\/ \u2705 v2.0 : Utiliser searchCountries si disponible\r\n        \/\/ pb787b : la liste n'apparaissait toujours qu'a la 2e lettre alors que\r\n        \/\/   minLength vaut bien 1 et que personne ne le surcharge (new\r\n        \/\/   CountryAutocomplete() est appele sans argument). Le blocage est en AVAL :\r\n        \/\/   VIA_Countries.searchCountries applique son propre minimum et renvoie une\r\n        \/\/   liste vide a une seule lettre.\r\n        \/\/   Je ne modifie pas cette fonction \u2014 elle est partagee avec le process\r\n        \/\/   d'achat. Repli local : si elle ne rend rien alors que la saisie n'est pas\r\n        \/\/   vide, on filtre COUNTRIES_DATA nous-memes, avec le meme critere que la\r\n        \/\/   branche de secours ci-dessous (deja presente et eprouvee).\r\n        \/\/   Le repli ne se declenche QUE sur un resultat vide : une recherche qui\r\n        \/\/   aboutit garde le comportement d'origine, classement compris.\r\n        \/\/   Revert : window._viaPb787Off = true (desactive aussi le tri pb787).\r\n        let results;\r\n        const _filtreLocal787 = () => {\r\n            const _tl787 = term.toLowerCase();\r\n            return (window.VIA_Countries.COUNTRIES_DATA || []).filter(\r\n                (country) => String(country.label || '').toLowerCase().includes(_tl787)\r\n            );\r\n        };\r\n        if (typeof window.VIA_Countries.searchCountries === 'function') {\r\n            results = window.VIA_Countries.searchCountries(term) || [];\r\n            if (results.length === 0 ? (window._viaPb787Off !== true) : false) {\r\n                results = _filtreLocal787();\r\n                console.log('[pb787b] searchCountries vide pour \"' + term\r\n                    + '\" -> repli filtre local : ' + results.length + ' pays');\r\n            }\r\n        } else {\r\n            results = _filtreLocal787();\r\n        }\r\n\r\n        \/\/ pb787 : les pays COMMENCANT par la saisie d'abord, les autres ensuite.\r\n        \/\/   Le tri est fait ICI et non dans searchCountries : cette fonction est\r\n        \/\/   partagee avec le process d'achat, et je ne change pas son comportement\r\n        \/\/   pour un besoin propre au popup.\r\n        \/\/   Comparaison sans accents ni casse : taper \"e\" doit remonter \"Egypte\"\r\n        \/\/   comme \"Etats-Unis\" ecrits avec ou sans accent dans les donnees.\r\n        \/\/   Tri STABLE dans chaque groupe (l'ordre d'origine, alphabetique, est\r\n        \/\/   conserve) : Array.prototype.sort l'est depuis ES2019.\r\n        \/\/   La decoupe a maxResults intervient APRES le tri \u2014 sinon les prefixes\r\n        \/\/   classes au-dela du 10e rang seraient perdus avant d'etre remontes.\r\n        \/\/   Revert : window._viaPb787Off = true.\r\n        if (window._viaPb787Off !== true) {\r\n            const _norm787 = (s) => {\r\n                const _t = String(s || '');\r\n                return _t.normalize ? _t.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase()\r\n                                    : _t.toLowerCase();\r\n            };\r\n            const _q787 = _norm787(term);\r\n            const _prefixes787 = [];\r\n            const _autres787 = [];\r\n            results.forEach((_c787) => {\r\n                if (_norm787(_c787.label).indexOf(_q787) === 0) { _prefixes787.push(_c787); }\r\n                else { _autres787.push(_c787); }\r\n            });\r\n            results = _prefixes787.concat(_autres787);\r\n            console.log('[pb787] \"' + term + '\" -> ' + _prefixes787.length + ' par prefixe + '\r\n                + _autres787.length + ' autres | affiches=' + Math.min(results.length, this.config.maxResults));\r\n        }\r\n\r\n        \/* pb2236 : dire ce qui est REELLEMENT rendu a jQuery UI. Si ce compte est\r\n           nul, la liste n'apparait pas parce qu'elle est vide \u2014 et le placement\r\n           n'y est pour rien. *\/\r\n        const _rendus2236 = results.slice(0, this.config.maxResults);\r\n        console.log('[pb2236] filtre \"' + term + '\" -> ' + _rendus2236.length\r\n            + ' pays rendus a jQuery UI');\r\n        response(_rendus2236);\r\n    }\r\n\r\n    onSelect(event, ui, $input) {\r\n        $input.val(ui.item.label);\r\n        this.state.validSelection = true;\r\n        this._fond788($input, false);   \/\/ pb788 : pays choisi -> fond retire\r\n\r\n        this.updateTariffData(ui.item);\r\n        this.showTariffColumn();\r\n        this.flashSelection($input);\r\n        \r\n        \/\/ \u2705 D\u00e9clencher le calcul de la grille\r\n        if (window.VIA_GrilleTarifaire) {\r\n            window.VIA_GrilleTarifaire.onFormulaireChange();\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb2242 : L'APPAREILLAGE DE PLACEMENT EST RETIRE.\r\n    \/\/   Test JF, decisif : avec window._viaAutoNatif2236 = true \u2014 c'est-a-dire\r\n    \/\/   sans deplacement vers <body>, sans position:fixed, sans centrage, sans\r\n    \/\/   rejeux et sans veille \u2014 \u00ab cela fonctionne normalement \u00bb.\r\n    \/\/   jQuery UI positionne donc le menu correctement tout seul, par son propre\r\n    \/\/   ul.position({ my:'left top', at:'left bottom', of: input }), rejoue a\r\n    \/\/   chaque frappe. Tout ce que j'avais construit par-dessus ne corrigeait pas\r\n    \/\/   un defaut : il en creait un, en figeant a un instant donne une geometrie\r\n    \/\/   que jQuery UI, lui, recalcule en permanence.\r\n    \/\/   Sept marqueurs sont donc RETIRES, pas desarmes \u2014 pb2219 (pose centree),\r\n    \/\/   pb2221 (instance ouvrante), pb2224 (garde), pb2228 (rejeux), pb2234\r\n    \/\/   (veille), pb2236 (interrupteur), pb2239 (ResizeObserver). Les desarmer\r\n    \/\/   aurait laisse deux cents lignes de code mort et un knob de plus ; le\r\n    \/\/   carnet dit de simplifier, pas d'empiler.\r\n    \/\/   Ce qui reste ici est le comportement d'avant pb2219, moins le\r\n    \/\/   deplacement vers <body> : la branche que JF vient de valider.\r\n    \/\/   Reste a surveiller : pb655 contraignait la largeur du menu a celle du\r\n    \/\/   champ \u00ab sinon jQuery UI le laisse deborder a droite sur mobile \u00bb. Cette\r\n    \/\/   contrainte part avec le reste. Si le debordement mobile reapparait, il\r\n    \/\/   se corrigera par UNE ligne de largeur \u2014 pas par le retour de tout ceci.\r\n    \/\/ ================================================================\r\n    onOpen($input) {\r\n        try {\r\n            const menu = $input.autocomplete('widget');\r\n            \/* ============================================================\r\n             * pb2244 : UNE SEULE PROPRIETE \u2014 LE z-index.\r\n             *   Constat JF : la liste s'affiche SOUS le popup\r\n             *   #via-col-ColonneGauche. Le menu est deja dans <body>, par\r\n             *   l'option native appendTo de jQuery UI : il n'est donc pas\r\n             *   rogne, il est simplement DERRIERE. Les popups de colonne\r\n             *   montent au-dela de 10 000 000 (leur z-index est lu, pas fixe,\r\n             *   par _vlpMaxZ663), quand jQuery UI laisse son menu a la valeur\r\n             *   de .ui-front, deux ordres de grandeur plus bas.\r\n             *   C'est exactement le cas que j'avais annonce en retirant\r\n             *   l'appareillage en pb2242 : \u00ab si le probleme reapparait, il se\r\n             *   corrigera par UNE ligne \u2014 pas par le retour de tout ceci \u00bb.\r\n             *   On ne touche donc NI la position, NI la largeur, NI le haut :\r\n             *   jQuery UI garde entierement la main sur la geometrie, qui est\r\n             *   ce que JF a valide. On empile seulement le menu au-dessus.\r\n             *   La valeur reste sous 2147483647, reserve au ghost de drag.\r\n             *   Knob : window._viaPb2244Z = <n>.\r\n             * ============================================================ *\/\r\n            if (menu.length) {\r\n                const _z2244 = (typeof window._viaPb2244Z === 'number')\r\n                    ? window._viaPb2244Z : 2147483000;\r\n                menu[0].style.setProperty('z-index', String(_z2244), 'important');\r\n                if (window._viaSig2244 !== _z2244) {\r\n                    window._viaSig2244 = _z2244;\r\n                    console.log('[pb2244] menu autocomplete empile a z-index=' + _z2244\r\n                        + ' | parent=' + (menu[0].parentNode\r\n                            ? String(menu[0].parentNode.nodeName).toLowerCase() : '(aucun)')\r\n                        + ' (position laissee a jQuery UI)');\r\n                }\r\n            }\r\n            const items = menu.find('li');\r\n            if (items.length === 1) {\r\n                this.handleSingleResult($input, items);\r\n            }\r\n        } catch (_e2242) {\r\n            console.warn('[pb2242] onOpen : ' + _e2242.message);\r\n        }\r\n    }\r\n\r\n\r\n    onClose($input) {\r\n        this.clearAutoSelectTimeout();\r\n    }\r\n\r\n    handleSingleResult($input, items) {\r\n        items.first().addClass('ui-state-active');\r\n        const currentTerm = $input.val();\r\n\r\n        this.clearAutoSelectTimeout();\r\n\r\n        this.state.autoSelectTimeout = setTimeout(() => {\r\n            if ($input.val() === currentTerm && $input.autocomplete('widget').is(':visible')) {\r\n                const item = items.first().data('ui-autocomplete-item');\r\n                \r\n                if (item) {\r\n                    $input.autocomplete('close');\r\n                    $input.val(item.label);\r\n                    this.state.validSelection = true;\r\n\r\n                    this.updateTariffData(item);\r\n                    this.showTariffColumn();\r\n                    this.flashSelection($input);\r\n                    \r\n                    \/\/ \u2705 D\u00e9clencher le calcul de la grille\r\n                    if (window.VIA_GrilleTarifaire) {\r\n                        window.VIA_GrilleTarifaire.onFormulaireChange();\r\n                    }\r\n                }\r\n            }\r\n        }, this.config.autoSelectDelay);\r\n    }\r\n\r\n    attachInputEvents($input) {\r\n        $input.on('keydown', (e) => {\r\n            this.clearAutoSelectTimeout();\r\n\r\n            if (this.state.validSelection) {\r\n                if (e.key === 'Backspace' || e.key === 'Delete') {\r\n                    $input.val('');\r\n                    this.state.validSelection = false;\r\n                    return;\r\n                }\r\n\r\n                if (e.key.length === 1 && \/[a-zA-Z]\/.test(e.key)) {\r\n                    $input.val('');\r\n                    this.state.validSelection = false;\r\n                }\r\n            }\r\n        });\r\n\r\n        $input.on('input', () => {\r\n            this._fond788($input, true);   \/\/ pb788 : maintenu pendant la frappe\r\n            this.clearAutoSelectTimeout();\r\n            if (this.state.validSelection) {\r\n                this.state.validSelection = false;\r\n            }\r\n        });\r\n\r\n        $input.on('focus', () => {\r\n            $input.select();\r\n            this._fond788($input, true);   \/\/ pb788\r\n        });\r\n\r\n        \/\/ pb788 : le fond suit la SAISIE. Pose au focus, maintenu a chaque frappe,\r\n        \/\/   retire des qu'un pays est selectionne (onSelect) ou que le champ perd le\r\n        \/\/   focus \u2014 la saisie est alors terminee dans les deux cas.\r\n        $input.on('blur', () => { this._fond788($input, false); });\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb788 : fond #ddeeff du champ \"pays de l'annonceur\" pendant la saisie.\r\n    \/\/   Meme bleu que l'aplat des devises (pb613) et le surlignage de la liste\r\n    \/\/   d'autocompletion (pb731) : une seule teinte pour \"element actif\".\r\n    \/\/   La couleur d'origine est memorisee a la premiere pose et restauree telle\r\n    \/\/   quelle. Pas de removeProperty : il rendrait la main aux valeurs Elementor\r\n    \/\/   sans garantie (lecon pb668).\r\n    \/\/   Ecrit en inline !important pour passer devant Elementor, comme partout\r\n    \/\/   ailleurs dans ce popup.\r\n    \/\/   Revert : window._viaPb788Off = true.\r\n    \/\/ ================================================================\r\n    _fond788($input, actif) {\r\n        if (window._viaPb788Off === true) { return; }\r\n        try {\r\n            const _el788 = $input ? $input[0] : null;\r\n            if (!_el788) { return; }\r\n            if (!_el788.dataset.bg788) {\r\n                _el788.dataset.bg788 = getComputedStyle(_el788).backgroundColor || 'transparent';\r\n            }\r\n            _el788.style.setProperty('background-color',\r\n                actif ? '#ddeeff' : _el788.dataset.bg788, 'important');\r\n            if (window._viaSigFond788 !== actif) {\r\n                window._viaSigFond788 = actif;\r\n                console.log('[pb788] fond champ annonceur -> ' + (actif ? '#ddeeff (saisie)' : 'origine'));\r\n            }\r\n        } catch (_e788) { console.warn('[pb788]', _e788.message); }\r\n    }\r\n\r\n    updateTariffData(item) {\r\n        sessionStorage.setItem('PaysAnnonceurTarifsSelection', 'Yes');\r\n        sessionStorage.setItem('SelectedCountry', JSON.stringify({\r\n            label: item.label,\r\n            code: item.code,\r\n            group: item.group,\r\n            ZoneTVA: item.ZoneTVA,\r\n            timestamp: new Date().toISOString()\r\n        }));\r\n\r\n        console.log('\u2713 Pays s\u00e9lectionn\u00e9:', item.label);\r\n    }\r\n\r\n    showTariffColumn() {\r\n        $(this.config.columnSelector).fadeIn(300);\r\n        $(this.config.messageSelector).fadeOut(200);\r\n    }\r\n\r\n    flashSelection($input) {\r\n        $input.addClass('auto-selected');\r\n        setTimeout(() => {\r\n            $input.removeClass('auto-selected');\r\n        }, 1000);\r\n    }\r\n\r\n    clearAutoSelectTimeout() {\r\n        if (this.state.autoSelectTimeout) {\r\n            clearTimeout(this.state.autoSelectTimeout);\r\n            this.state.autoSelectTimeout = null;\r\n        }\r\n    }\r\n\r\n    injectStyles() {\r\n        if (document.getElementById('country-autocomplete-styles')) {\r\n            return;\r\n        }\r\n\r\n        const styles = `\r\n            \/* pb689 : le flash VERT du champ annonceur est supprime (demande user).\r\n               La regle .auto-selected posait un fond #e8f5e8 pendant 1s a la\r\n               selection d'un pays (cf flashSelection, appelee depuis 2 endroits).\r\n               On neutralise le RENDU en retirant la declaration, plutot que de\r\n               toucher a flashSelection : la classe continue d'etre posee\/retiree,\r\n               donc rien d'autre n'est perturbe et le revert tient en une ligne.\r\n               NB : .date-selected (datepickers) garde SON fond vert, non concerne. *\/\r\n            .auto-selected {\r\n                background-color: transparent !important;\r\n            }\r\n            .ui-autocomplete {\r\n                z-index: 9999 !important;\r\n                max-height: 300px;\r\n                overflow-y: auto;\r\n                background: white;\r\n                border: 1px solid #ccc;\r\n                border-radius: 4px;\r\n                box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\r\n            }\r\n            .ui-menu .ui-menu-item {\r\n                padding: 10px 14px;\r\n                cursor: pointer;\r\n            }\r\n            \/* pb731 : surlignage de l'item PAYS dans la liste d'autocompletion.\r\n               Le bleu vif est remplace par #ddeeff. Fond desormais TRES clair : le\r\n               texte blanc deviendrait illisible, il repasse donc en #3F3F3F (teinte\r\n               de texte du popup, cf pb684\/pb685).\r\n               .ui-state-active est aussi pose en JS par handleSingleResult (L799) sur\r\n               le resultat unique : cette regle couvre les deux cas, survol et\r\n               preselection automatique.\r\n               background-image:none : le theme jQuery UI ajoute un degrade sur\r\n               .ui-state-active, qui resterait visible par-dessus l'aplat. *\/\r\n            \/* pb731b : le bleu #007fff ne vient pas d'ici mais du THEME jQuery UI\r\n               (.ui-state-active : background #007fff, border #003eff). pb731 ciblait\r\n               .ui-menu-item.ui-state-active, or depuis jQuery UI 1.12 la classe est\r\n               posee sur le <div class=\"ui-menu-item-wrapper\"> INTERNE, pas sur le\r\n               <li> : le selecteur ne matchait donc rien au survol.\r\n               On couvre ici les DEUX structures (ancienne et nouvelle) et les trois\r\n               etats du theme (active, hover, focus), scopes a la liste\r\n               d'autocompletion pour ne rien casser ailleurs.\r\n               border-color + background-image sont neutralises aussi : le theme pose\r\n               une bordure bleue et un degrade qui resteraient visibles. *\/\r\n            .ui-autocomplete .ui-menu-item.ui-state-active,\r\n            .ui-autocomplete .ui-menu-item.ui-state-hover,\r\n            .ui-autocomplete .ui-menu-item.ui-state-focus,\r\n            .ui-autocomplete .ui-menu-item-wrapper.ui-state-active,\r\n            .ui-autocomplete .ui-menu-item-wrapper.ui-state-hover,\r\n            .ui-autocomplete .ui-menu-item-wrapper.ui-state-focus,\r\n            .ui-autocomplete .ui-menu-item .ui-state-active,\r\n            .ui-autocomplete .ui-menu-item:hover,\r\n            .ui-autocomplete .ui-menu-item-wrapper:hover,\r\n            .ui-menu .ui-menu-item.ui-state-active,\r\n            .ui-menu .ui-menu-item-wrapper.ui-state-active {\r\n                background: #ddeeff !important;\r\n                background-color: #ddeeff !important;\r\n                background-image: none !important;\r\n                border: 1px solid #ddeeff !important;\r\n                border-color: #ddeeff !important;\r\n                color: #3F3F3F !important;\r\n                margin: 0 !important;\r\n            }\r\n            .PricingAmount {\r\n                display: flex !important;\r\n                align-items: center !important;\r\n                justify-content: center !important;\r\n                text-align: center !important;\r\n                margin-top: 5px !important;\r\n            }\r\n            \/* ============================================================\r\n               pb2197 : LA GRILLE EST MASQUEE PAR DEFAUT, EN FEUILLE.\r\n               Proposition JF, adoptee : plutot que de masquer\/devoiler au coup\r\n               par coup en inline (pb2183, pb2189, pb2194, pb2196 \u2014 quatre\r\n               tentatives, un clignotement toujours la), la grille NAIT\r\n               invisible et ne se montre que lorsqu on le dit explicitement.\r\n               visibility et non display : la grille garde sa place, donc aucun\r\n               saut de mise en page, et elle reste MESURABLE (lecon pb1392).\r\n               La classe .via-grille-prete est posee une seule fois, quand les\r\n               tarifs sont poses, convertis et stables ; elle est retiree a\r\n               chaque masquage. Un writer qui forcerait display:block ne peut\r\n               plus reveler un etat intermediaire : sans la classe, rien ne se\r\n               voit.\r\n               Revert : window._viaPb2197Off = true (voir le JS : la classe est\r\n               alors posee immediatement). *\/\r\n            html body .GrilleTarifaire {\r\n                visibility: hidden !important;\r\n            }\r\n            html body .GrilleTarifaire.via-grille-prete {\r\n                visibility: visible !important;\r\n            }\r\n            \/* ============================================================\r\n               pb2178 : MONTANTS +2px VERS LE BAS EN MOBILE (demande JF).\r\n               La feuille pose 5px pour tous ; le mobile passe a 7px.\r\n               EN FEUILLE et non dans le writer pb1240\/pb2151 : celui-ci\r\n               SORT en mobile (outerWidth < 1000) sauf sur les sites pays\r\n               (pb1959) \u2014 y poser la valeur laisserait la regie mobile de\r\n               cote. La feuille, elle, couvre les deux contextes.\r\n               Aucun risque de conflit avec le desktop : pb2151 y ecrit un\r\n               inline 12px !important, qui bat toute regle de feuille.\r\n               Seuil 1000px, celui de tout le projet. La media query mesure\r\n               le viewport du DOCUMENT : dans le popup des sites pays, celui\r\n               de l iframe \u2014 desktop y vaut ~1404, mobile bien moins.\r\n               ============================================================ *\/\r\n            @media (max-width: 1000px) {\r\n                .PricingAmount {\r\n                    margin-top: 7px !important;\r\n                }\r\n            }\r\n            \/* pb2151 : aucun soulignage sur les montants, quelle qu'en soit\r\n               l'origine. pb612 est corrige a la source, mais le theme souligne\r\n               aussi les <a> par defaut : une feuille !important bat un inline\r\n               SANS important, donc cette regle couvre les deux cas. *\/\r\n            .PricingAmount,\r\n            .PricingAmount a,\r\n            .PricingAmount a.via-tarif-lien-612 {\r\n                text-decoration: none !important;\r\n            }\r\n        `;\r\n\r\n        const styleElement = document.createElement('style');\r\n        styleElement.id = 'country-autocomplete-styles';\r\n        styleElement.textContent = styles;\r\n        document.head.appendChild(styleElement);\r\n\r\n        \/\/ ================================================================\r\n        \/\/ pb731c : la capture montre que les items du dropdown n'ont NI le\r\n        \/\/   padding 10px 14px, NI les coins arrondis, NI l'ombre definis\r\n        \/\/   ci-dessus -> ce n'est pas la couleur qui echoue, c'est toute la\r\n        \/\/   feuille qui est hors jeu sur cette liste. Plutot que de surenchierir\r\n        \/\/   en specificite (deux tentatives infructueuses : pb731, pb731b), on\r\n        \/\/   change de MODE d'ecriture : inline + important, qui bat toute regle\r\n        \/\/   de feuille quels que soient l'ordre et la specificite (lecon pb668).\r\n        \/\/   Liaison unique gardee par un flag ; delegation sur document car le\r\n        \/\/   menu est deplace dans body a l'ouverture (L778).\r\n        \/\/   Revert : window._viaPb731Off = true.\r\n        \/\/ ================================================================\r\n        if (!window._viaPb731cBound) {\r\n            window._viaPb731cBound = true;\r\n            const _BG731 = '#ddeeff';\r\n            const _FG731 = '#3F3F3F';\r\n            const _peindre731 = function (_el, _on) {\r\n                if (!_el) { return; }\r\n                if (_on) {\r\n                    _el.style.setProperty('background', _BG731, 'important');\r\n                    _el.style.setProperty('background-color', _BG731, 'important');\r\n                    _el.style.setProperty('background-image', 'none', 'important');\r\n                    _el.style.setProperty('border-color', _BG731, 'important');\r\n                    _el.style.setProperty('color', _FG731, 'important');\r\n                } else {\r\n                    _el.style.removeProperty('background');\r\n                    _el.style.removeProperty('background-color');\r\n                    _el.style.removeProperty('background-image');\r\n                    _el.style.removeProperty('border-color');\r\n                    _el.style.removeProperty('color');\r\n                }\r\n            };\r\n            \/\/  Peint le <li> ET son wrapper interne : depuis jQuery UI 1.12 le fond\r\n            \/\/  du theme est porte par .ui-menu-item-wrapper, pas par le <li>.\r\n            const _peindreItem731 = function (_li, _on) {\r\n                if (window._viaPb731Off === true) { return; }\r\n                _peindre731(_li, _on);\r\n                if (_li.querySelector) {\r\n                    _peindre731(_li.querySelector('.ui-menu-item-wrapper'), _on);\r\n                    _peindre731(_li.querySelector('a'), _on);\r\n                }\r\n            };\r\n            const _SEL731 = '.ui-autocomplete .ui-menu-item, .ui-menu .ui-menu-item';\r\n            $(document).on('mouseenter', _SEL731, function () { _peindreItem731(this, true); });\r\n            $(document).on('mouseleave', _SEL731, function () { _peindreItem731(this, false); });\r\n            \/\/  Navigation clavier + preselection auto (handleSingleResult, L799) :\r\n            \/\/  jQuery UI pose .ui-state-active sans passer par la souris.\r\n            \/\/  pb731d : le DOM montre des ids ui-id-3 \/ ui-id-14.. -> PLUSIEURS widgets\r\n            \/\/    autocomplete coexistent dans la page. Un document.querySelector\r\n            \/\/    renvoyait le PREMIER menu du document, pas celui qui est ouvert :\r\n            \/\/    on peignait potentiellement une liste invisible. On retient donc le\r\n            \/\/    menu reellement affiche (offsetParent non nul = ni display:none ni\r\n            \/\/    ancetre masque).\r\n            const _menuVisible731 = function () {\r\n                const _tous731 = document.querySelectorAll('.ui-autocomplete, .ui-menu');\r\n                for (let _m731 = 0; _m731 < _tous731.length; _m731++) {\r\n                    if (_tous731[_m731].offsetParent !== null) { return _tous731[_m731]; }\r\n                }\r\n                return null;\r\n            };\r\n            $(document).on('menufocus autocompletefocus', function (_e731, _ui731) {\r\n                if (window._viaPb731Off === true) { return; }\r\n                const _menu731 = _menuVisible731();\r\n                if (!_menu731) { return; }\r\n                const _lis731 = _menu731.querySelectorAll('.ui-menu-item');\r\n                for (let _k731 = 0; _k731 < _lis731.length; _k731++) {\r\n                    _peindreItem731(_lis731[_k731], false);\r\n                }\r\n                const _act731 = (_ui731 && _ui731.item && _ui731.item[0]) ? _ui731.item[0]\r\n                    : _menu731.querySelector('.ui-state-active, .ui-state-focus');\r\n                if (_act731) {\r\n                    _peindreItem731(_act731.closest ? (_act731.closest('.ui-menu-item') || _act731) : _act731, true);\r\n                }\r\n            });\r\n            console.log('[pb731c] surlignage inline branche | feuille #country-autocomplete-styles presente='\r\n                + (document.getElementById('country-autocomplete-styles') ? 'oui' : 'NON'));\r\n        }\r\n    }\r\n\r\n    destroy() {\r\n        const $input = $(this.config.inputSelector);\r\n        if ($input.length > 0 && $input.data('ui-autocomplete')) {\r\n            $input.autocomplete('destroy');\r\n            $input.off('keydown input focus');\r\n        }\r\n        this.clearAutoSelectTimeout();\r\n        $('#country-autocomplete-styles').remove();\r\n    }\r\n}\r\n\r\n\/**\r\n * \u2728 Module Grille Tarifaire\r\n *\/\r\n\r\nconst TARIF_MAPPING = {\r\n    'Tarif7VidPoPHP': { format: 'Vid\u00e9o', position: 'Pop-up Homepage' },\r\n    'Tarif7BanPoPHP': { format: 'Banni\u00e8re', position: 'Pop-up Homepage' },\r\n    'Tarif7ParPoPHP': { format: 'Parrainage', position: 'Pop-up Homepage' },\r\n    'Tarif7ComPoPHP': { format: 'Communiqu\u00e9', position: 'Pop-up Homepage' },\r\n    'Tarif7IntPoPHP': { format: 'Interview', position: 'Pop-up Homepage' },\r\n    'Tarif7VidPoPPP': { format: 'Vid\u00e9o', position: 'Pop-up Autres P.' },\r\n    'Tarif7BanPoPPP': { format: 'Banni\u00e8re', position: 'Pop-up Autres P.' },\r\n    'Tarif7ParPoPPP': { format: 'Parrainage', position: 'Pop-up Autres P.' },\r\n    'Tarif7ComPoPPP': { format: 'Communiqu\u00e9', position: 'Pop-up Autres P.' },\r\n    'Tarif7IntPoPPP': { format: 'Interview', position: 'Pop-up Autres P.' },\r\n    'Tarif7VidHdPHP': { format: 'Vid\u00e9o', position: 'hdp Home P.' },\r\n    'Tarif7BanHdPHP': { format: 'Banni\u00e8re', position: 'hdp Home P.' },\r\n    'Tarif7ParHdPHP': { format: 'Parrainage', position: 'hdp Home P.' },\r\n    'Tarif7ComHdPHP': { format: 'Communiqu\u00e9', position: 'hdp Home P.' },\r\n    'Tarif7IntHdPHP': { format: 'Interview', position: 'hdp Home P.' },\r\n    'Tarif7VidHdPPP': { format: 'Vid\u00e9o', position: 'hdp Autres P.' },\r\n    'Tarif7BanHdPPP': { format: 'Banni\u00e8re', position: 'hdp Autres P.' },\r\n    'Tarif7ParHdPPP': { format: 'Parrainage', position: 'hdp Autres P.' },\r\n    'Tarif7ComHdPPP': { format: 'Communiqu\u00e9', position: 'hdp Autres P.' },\r\n    'Tarif7IntHdPPP': { format: 'Interview', position: 'hdp Autres P.' },\r\n    'Tarif7VidCdPHP': { format: 'Vid\u00e9o', position: 'cdp Home P.' },\r\n    'Tarif7BanCdPHP': { format: 'Banni\u00e8re', position: 'cdp Home P.' },\r\n    'Tarif7ParCdPHP': { format: 'Parrainage', position: 'cdp Home P.' },\r\n    'Tarif7ComCdPHP': { format: 'Communiqu\u00e9', position: 'cdp Home P.' },\r\n    'Tarif7IntCdPHP': { format: 'Interview', position: 'cdp Home P.' },\r\n    'Tarif7VidCdPPP': { format: 'Vid\u00e9o', position: 'cdp Autres P.' },\r\n    'Tarif7BanCdPPP': { format: 'Banni\u00e8re', position: 'cdp Autres P.' },\r\n    'Tarif7ParCdPPP': { format: 'Parrainage', position: 'cdp Autres P.' },\r\n    'Tarif7ComCdPPP': { format: 'Communiqu\u00e9', position: 'cdp Autres P.' },\r\n    'Tarif7IntCdPPP': { format: 'Interview', position: 'cdp Autres P.' }\r\n};\r\n\r\nclass GrilleTarifaire {\r\n    constructor() {\r\n        this.state = {\r\n            isCalculating: false,\r\n            tarifsCalcules: {},\r\n            paysSelectionne: null,\r\n            dureeJours: 0,\r\n            deviseAffichage: 'EUR'\r\n        };\r\n\r\n        this.init();\r\n    }\r\n\r\n    init() {\r\n        console.log('\ud83c\udfa8 Grille Tarifaire initialis\u00e9e');\r\n        \/\/ pb704 : masquage a l'init RETIRE (demande user).\r\n        \/\/   Etait : $('#TarifsPublicitaireListe').hide();\r\n        \/\/   Les 5 autres masquages conditionnels (dates\/pays incomplets, duree hors\r\n        \/\/   bornes, aucun site pays, pendant le calcul) restent en place : l'etat de\r\n        \/\/   depart est desormais celui du template Elementor, non force par le JS.\r\n        \r\n        \/\/ \u2705 AJOUTER listener devises\r\n        this.setupDeviseListener();\r\n        this.brancherReinitialiser710();   \/\/ pb710\r\n    }\r\n\r\n    \/\/ pb2115 : retour de la duree au VERT de pb844 (#56be50) des que la duree\r\n    \/\/   redevient valide. Appelee par la branche \"duree valide\" de pb2113.\r\n    _dureeVerte2115() {\r\n        if (window._viaPb2115Off === true) { return; }\r\n        $('.TarifsCampagneNbJours').each(function () {\r\n            this.style.setProperty('color', '#56be50', 'important');\r\n        });\r\n        if (window._viaSig2115 !== 'vert') {\r\n            window._viaSig2115 = 'vert';\r\n            console.log('[pb2115] duree revenue au VERT (duree valide)');\r\n        }\r\n    }\r\n\r\n    \/\/ pb2114d : methode DEPLACEE ici (classe GrilleTarifaire). Elle etait nee\r\n    \/\/   dans CampaignDatePickers alors que ses trois appelants (pb2113, pb604f,\r\n    \/\/   pb609) sont ici : chaque pose levait un TypeError non capte apres la\r\n    \/\/   couleur \u2014 ni police ni flex poses, et la suite du bloc appelant sautee.\r\n    \/\/ ================================================================\r\n    \/\/ pb2114 : STYLE DU MESSAGE DATES (#GrilleTarifCMsgTexte), applique a\r\n    \/\/   CHAQUE pose du message (pb2113, pb604f min, pb609 max) :\r\n    \/\/   - desktop (outerWidth >= 1000) : taille de police +2px. La base est\r\n    \/\/     memorisee dans data-via-fs2114 a la premiere pose (offset additif =>\r\n    \/\/     base gelee, jamais de derive cumulative).\r\n    \/\/   - mobile (outerWidth < 1000) : le conteneur passe sous la rangee des\r\n    \/\/     dates comme en desktop \u2014 flex-basis 100% + flex-wrap:wrap sur le\r\n    \/\/     parent .PopupTarifsDates (sinon le flex row mobile le garde a cote).\r\n    \/\/   outerWidth est le discriminant du projet (innerWidth vaut 0 en iframe\r\n    \/\/   mobile). Revert : window._viaPb2114Off = true.\r\n    \/\/ ================================================================\r\n    _stylerMsgDates2114() {\r\n        if (window._viaPb2114Off === true) { return; }\r\n        \/\/ pb2115 : tant que le message dates est affiche (duree invalide), la\r\n        \/\/   duree \".TarifsCampagneNbJours\" passe en ROUGE (#fb5e2a, le corail du\r\n        \/\/   process) par-dessus le vert de pb844. Le retour au vert est fait par\r\n        \/\/   la branche \"duree valide\" de pb2113 (_dureeVerte2115). L'ordre est\r\n        \/\/   sur : pb844 (vert) ecrit au changement de date, AVANT l'evaluation\r\n        \/\/   qui appelle ce styler. Revert : window._viaPb2115Off = true.\r\n        if (window._viaPb2115Off !== true) {\r\n            $('.TarifsCampagneNbJours').each(function () {\r\n                this.style.setProperty('color', '#fb5e2a', 'important');\r\n            });\r\n            if (window._viaSig2115 !== 'rouge') {\r\n                window._viaSig2115 = 'rouge';\r\n                console.log('[pb2115] duree affichee en ROUGE (message dates actif)');\r\n            }\r\n        }\r\n        const _t14 = document.getElementById('GrilleTarifCMsgTexte');\r\n        if (!_t14) { console.log('[pb2114] #GrilleTarifCMsgTexte introuvable'); return; }\r\n        const _desk14 = window.outerWidth >= 1000;\r\n        if (_desk14) {\r\n            const _cibles14 = [_t14].concat(Array.from(_t14.querySelectorAll('p, span, div')));\r\n            _cibles14.forEach(function (_el) {\r\n                if (!_el.dataset.viaFs2114) {\r\n                    const _fs = parseFloat(getComputedStyle(_el).fontSize);\r\n                    _el.dataset.viaFs2114 = isNaN(_fs) ? '14' : String(_fs);\r\n                }\r\n                _el.style.setProperty('font-size', (parseFloat(_el.dataset.viaFs2114) + 2) + 'px', 'important');   \/\/ pb2114e : +4 ramene a +2 (base gelee)\r\n            });\r\n            \/\/ pb2114e : texte decale de 5px vers le bas (base margin-top gelee\r\n            \/\/   dans data-via-mt2114, offset additif \u2014 pas de derive).\r\n            if (!_t14.dataset.viaMt2114) {\r\n                const _mt14 = parseFloat(getComputedStyle(_t14).marginTop);\r\n                _t14.dataset.viaMt2114 = isNaN(_mt14) ? '0' : String(_mt14);\r\n            }\r\n            _t14.style.setProperty('margin-top', (parseFloat(_t14.dataset.viaMt2114) + 5) + 'px', 'important');\r\n            if (window._viaSig2114 !== 'desk-e') {\r\n                window._viaSig2114 = 'desk-e';\r\n                console.log('[pb2114e] desktop : police +2px (base ' + _t14.dataset.viaFs2114\r\n                    + 'px) | texte descendu de 5px (mt base ' + _t14.dataset.viaMt2114 + 'px)');\r\n            }\r\n        } else {\r\n            \/\/ pb2114b : sur MOBILE SITE PAYS uniquement (body.via-popup-achat, pose\r\n            \/\/   seulement dans l'iframe #ViaPopupProcessAchat des sites pays \u2014\r\n            \/\/   discriminant exact du projet ; la regie mobile n'est pas touchee),\r\n            \/\/   police du message +1px, meme base gelee data-via-fs2114.\r\n            \/\/ pb2114c : branche parlante (regle 5.2 \u2014 \"aucun effet\" etait\r\n            \/\/   indiscernable entre discriminant absent et ecriture battue).\r\n            \/\/   Toute ligne est relayee au top (vlp-diag-log) pour lecture mobile.\r\n            const _dire14c = function (_m) {\r\n                console.log(_m);\r\n                if (window !== window.top) {\r\n                    try { window.parent.postMessage({ type: 'vlp-diag-log', source: 'iframe', msg: _m, url: window.location.search }, '*'); } catch (_e) {}\r\n                }\r\n            };\r\n            const _pays14c = document.body ? document.body.classList.contains('via-popup-achat') : false;\r\n            if (_pays14c) {\r\n                const _cibM14 = [_t14].concat(Array.from(_t14.querySelectorAll('p, span, div')));\r\n                _cibM14.forEach(function (_el) {\r\n                    if (!_el.dataset.viaFs2114) {\r\n                        const _fsM = parseFloat(getComputedStyle(_el).fontSize);\r\n                        _el.dataset.viaFs2114 = isNaN(_fsM) ? '14' : String(_fsM);\r\n                    }\r\n                    _el.style.setProperty('font-size', (parseFloat(_el.dataset.viaFs2114) + 1) + 'px', 'important');\r\n                });\r\n                const _eff14c = getComputedStyle(_t14).fontSize;\r\n                _dire14c('[pb2114c] mobile site pays : +1px ecrit (base ' + _t14.dataset.viaFs2114\r\n                    + 'px) | effectif apres ecriture=' + _eff14c\r\n                    + ' | cibles=' + _cibM14.length);\r\n            } else {\r\n                _dire14c('[pb2114c] mobile SANS via-popup-achat -> pas de +1px | body.className=\"'\r\n                    + (document.body ? String(document.body.className).slice(0, 120) : 'BODY ABSENT')\r\n                    + '\" | html.className=\"' + String(document.documentElement.className).slice(0, 120) + '\"');\r\n            }\r\n            const _c14 = document.getElementById('GrilleTarifCMsgContainer');\r\n            if (_c14) {\r\n                _c14.style.setProperty('flex', '0 0 100%', 'important');\r\n                _c14.style.setProperty('width', '100%', 'important');\r\n                const _par14 = _c14.closest('.PopupTarifsDates');\r\n                if (_par14) { _par14.style.setProperty('flex-wrap', 'wrap', 'important'); }\r\n                if (window._viaSig2114 !== 'mob') {\r\n                    window._viaSig2114 = 'mob';\r\n                    console.log('[pb2114] mobile : message passe sous la rangee des dates (basis 100%'\r\n                        + (_par14 ? ' + wrap parent' : ' | parent .PopupTarifsDates INTROUVABLE') + ')');\r\n                }\r\n            } else {\r\n                console.log('[pb2114] #GrilleTarifCMsgContainer introuvable');\r\n            }\r\n        }\r\n    }\r\n\r\n    onFormulaireChange() {\r\n        this._diag652();   \/\/ pb652 DIAG (a retirer)\r\n        \/\/ pb648 : une modification = nouvelle configuration a valider -> le bouton\r\n        \/\/   Continuer pourra repasser en rouge (on efface le flag \"deja clique\").\r\n        \/\/ pb656 : MAIS pas pendant le verrou post-clic Continuer (les rejeux\/synchros\r\n        \/\/   rappellent onFormulaireChange juste apres le clic et re-rougissaient le\r\n        \/\/   bouton). On ne reinitialise que hors de cette fenetre.\r\n        if (!window._resaVerrou656 && !window._sync651EnCours) {\r\n            window._resaClique644f = false;\r\n        }\r\n        const paysLabel = $('input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]').val();\r\n        const dateDebut = $('#form-field-PopupTarifsDebutCampagne').val();\r\n        const dateFin = $('#form-field-PopupTarifsFinCampagne').val();\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb1900 : LA DUREE NE DEPEND QUE DES DATES.\r\n        \/\/   Depuis pb1899 l'annonceur est saisi APRES les dates. Or la garde\r\n        \/\/   ci-dessous \u2014 \u00ab !paysLabel || !dateDebut || !dateFin \u00bb \u2014 remettait la\r\n        \/\/   duree a ZERO des que le pays de l'ANNONCEUR manquait, et datesOk vaut\r\n        \/\/   \u00ab state.dureeJours > 0 \u00bb (etapesCompletees631). Consequence : l'etape\r\n        \/\/   Dates ne se completait jamais, le sequenceur restait bloque dessus,\r\n        \/\/   l'etape Annonceur n'etait donc jamais ouverte, et le pays ne pouvait\r\n        \/\/   plus etre saisi. Impasse fermee \u2014 que l'ancien ordre masquait\r\n        \/\/   entierement, l'annonceur etant deja renseigne quand les dates\r\n        \/\/   arrivaient.\r\n        \/\/   calculerDuree() ne prend que les deux dates : la duree EST une\r\n        \/\/   fonction des seules dates. Les gardes qui suivent ne gouvernent plus\r\n        \/\/   que l'AFFICHAGE DE LA GRILLE, qui depend bien, lui, du pays de\r\n        \/\/   l'annonceur (cf _signatureGrille1359 : pays annonceur, duree, devise).\r\n        \/\/   Les bornes min\/max sont appliquees ICI aussi : hors bornes la duree\r\n        \/\/   reste a 0 et l'etape Dates reste incomplete \u2014 comportement inchange,\r\n        \/\/   seul le MOMENT du calcul a bouge. Les blocs pb604f\/pb609 plus bas\r\n        \/\/   gardent leur role : afficher le pourquoi dans #GrilleTarifCMsgTexte.\r\n        \/\/   Ecriture conditionnee au CHANGEMENT de valeur : _setDuree735 ecrit\r\n        \/\/   dans le DOM et loggue a chaque appel, or onFormulaireChange passe tres\r\n        \/\/   souvent \u2014 sans cette garde le log deviendrait illisible.\r\n        \/\/   Revert : window._viaPb1900Off = true (duree posee en fin de chaine,\r\n        \/\/   comportement d'avant \u2014 a n'utiliser qu'avec l'ancien ordre d'etapes).\r\n        \/\/ ====================================================================\r\n        if (window._viaPb1900Off !== true) {\r\n            var _duree1900 = 0;\r\n            if (dateDebut ? !!dateFin : false) {\r\n                var _d1900 = this.calculerDuree(dateDebut, dateFin);\r\n                var _min1900 = (typeof window.VIA_DureeMinGrille === 'number')\r\n                    ? window.VIA_DureeMinGrille\r\n                    : (window._viaParams610 ? window._viaParams610.min : 7);\r\n                var _max1900 = (typeof window.VIA_DureeMaxGrille === 'number')\r\n                    ? window.VIA_DureeMaxGrille\r\n                    : (window._viaParams610 ? window._viaParams610.max : 200);\r\n                var _ok1900 = (_d1900 >= 1);\r\n                if (_ok1900 ? (_min1900 > 0) : false) {\r\n                    if (_d1900 < _min1900) { _ok1900 = false; }\r\n                }\r\n                if (_ok1900 ? (_max1900 > 0) : false) {\r\n                    if (_d1900 > _max1900) { _ok1900 = false; }\r\n                }\r\n                _duree1900 = _ok1900 ? _d1900 : 0;\r\n            }\r\n            if (this.state.dureeJours !== _duree1900) {\r\n                this._setDuree735(_duree1900);\r\n                console.log('[pb1900] dur\u00e9e pos\u00e9e depuis les seules dates : ' + _duree1900\r\n                    + ' jour(s) | dates=' + (dateDebut || '-') + '>' + (dateFin || '-')\r\n                    + ' | annonceur=' + (paysLabel || '(vide, sans effet)'));\r\n            }\r\n        }\r\n\r\n        \/* ====================================================================\r\n         * pb1938 : LE CONTROLE DE DISPONIBILITE REMONTE AVANT LA GARDE ANNONCEUR.\r\n         *   Constat user : \u00ab dans le site pays le controle doit se faire EN PLUS a\r\n         *   la selection des dates \u00bb. pb1937 etait pose juste avant\r\n         *   calculerEtAfficherGrille \u2014 donc APRES la garde\r\n         *   \u00ab !paysLabel || !dateDebut || !dateFin \u00bb.\r\n         *   Or depuis pb1899 les dates PRECEDENT l'annonceur. Quand l'utilisateur\r\n         *   finit ses dates, paysLabel est encore vide : onFormulaireChange sortait\r\n         *   la, et le controle ne se declenchait qu'une etape plus tard, une fois le\r\n         *   pays de l'annonceur saisi. D'ou le decalage.\r\n         *   C'est mot pour mot le raisonnement de pb1900, quinze lignes plus haut :\r\n         *   la DUREE ne depend que des dates, elle ne pouvait pas rester derriere une\r\n         *   garde qui exige l'annonceur. La DISPONIBILITE non plus \u2014 elle ne depend\r\n         *   que de l'emplacement et des deux dates, et l'API ne recoit rien d'autre.\r\n         *   On la remonte donc au meme endroit, pour la meme raison. Les gardes qui\r\n         *   suivent ne gouvernent plus que l'AFFICHAGE DE LA GRILLE, qui depend bien,\r\n         *   lui, du pays de l'annonceur.\r\n         *   DECLENCHEUR : les deux dates renseignees. Rien d'autre. La fonction\r\n         *   exposee rend { available: true } sur emplacement vide, donc la regie \u2014\r\n         *   ou l'espace se choisit ensuite dans le VLP \u2014 n'est pas touchee : c'est\r\n         *   Formulaire.txt qui verifie a ce moment-la, comme avant.\r\n         *   ASYNCHRONE, donc SIGNATURE : la reponse arrive apres que\r\n         *   onFormulaireChange a rendu la main, et cette fonction passe tres souvent.\r\n         *   Sans signature, une reponse en retard sur d'anciennes dates masquerait une\r\n         *   grille valide. Meme precaution que _signatureGrille1359.\r\n         *   EMPLACEMENT lu sur l'ITEM et nulle part ailleurs \u2014 regle pb1311, \u00ab en\r\n         *   express, seul l'item fait foi \u00bb.\r\n         *   BLOQUER, ICI, C'EST MASQUER LA GRILLE : depuis pb1906 le clic sur un tarif\r\n         *   est le seul moyen d'avancer. afficherIndisponibilite (pb1936) se charge du\r\n         *   message et du reste du blocage.\r\n         *   Revert : window._viaPb1937Off = true (aucun controle dans l'express).\r\n         * ==================================================================== *\/\r\n        if (window._viaPb1937Off !== true) {\r\n            try {\r\n                if (dateDebut ? !!dateFin : false) {\r\n                    var _st1937 = window.VIA_Panier ? (window.VIA_Panier.state || null) : null;\r\n                    var _it1937 = _st1937\r\n                        ? (_st1937.items || []).filter(function (_i) {\r\n                            return _i.id === _st1937.itemActif; })[0]\r\n                        : null;\r\n                    var _emp1937 = _it1937\r\n                        ? (_it1937.emplacementPageWeb\r\n                            || (_it1937.donneesIframe\r\n                                ? _it1937.donneesIframe.Commande_Emplacement_Page_Web : '')\r\n                            || '')\r\n                        : '';\r\n                    var _sv1937 = (_it1937 ? _it1937.id : '(aucun item)')\r\n                        + '|' + _emp1937 + '|' + dateDebut + '|' + dateFin;\r\n                    if (!_emp1937) {\r\n                        \/* pb1937b : signature PAR VALEUR \u2014 un drapeau unique se taisait\r\n                           des le second passage et la ligne sortait du tampon de logs. *\/\r\n                        if (window._viaSigVide1937 !== _sv1937) {\r\n                            window._viaSigVide1937 = _sv1937;\r\n                            console.log('[pb1938] contr\u00f4le NON d\u00e9clench\u00e9 : aucun emplacement'\r\n                                + ' sur l item actif | item='\r\n                                + (_it1937 ? _it1937.id : 'AUCUN')\r\n                                + ' | dates=' + dateDebut + '>' + dateFin\r\n                                + '  (normal sur la r\u00e9gie : Formulaire.txt v\u00e9rifie au choix'\r\n                                + ' de l espace dans le VLP)');\r\n                        }\r\n                    } else if (typeof window._viaVerifierDispo1936 !== 'function') {\r\n                        console.warn('[pb1938] _viaVerifierDispo1936 absente'\r\n                            + ' (Formulaire.txt en FORM-pb1936 ?) -> aucun contr\u00f4le');\r\n                    } else if (window._viaSig1937 !== _sv1937) {\r\n                        window._viaSig1937 = _sv1937;\r\n                        var _self1937 = this;\r\n                        console.log('[pb1938] contr\u00f4le lanc\u00e9 d\u00e8s les dates | ' + _sv1937\r\n                            + ' | annonceur=' + (paysLabel || '(vide, sans effet)'));\r\n                        window._viaVerifierDispo1936(_emp1937, dateDebut, dateFin)\r\n                            .then(function (_d1937) {\r\n                                if (window._viaSig1937 !== _sv1937) {\r\n                                    console.log('[pb1938] r\u00e9ponse p\u00e9rim\u00e9e ignor\u00e9e (' + _sv1937 + ')');\r\n                                    return;\r\n                                }\r\n                                if (_d1937 ? (_d1937.available === false) : false) {\r\n                                    console.log('[pb1938] espace INDISPONIBLE | ' + _sv1937\r\n                                        + ' | prochaine date : '\r\n                                        + (_d1937.next_available || '(non fournie)')\r\n                                        + ' -> grille masqu\u00e9e, progression bloqu\u00e9e');\r\n                                    _self1937._afficherGrilleTarifaire703(false);\r\n                                    if (typeof window._viaAfficherIndispo1936 === 'function') {\r\n                                        window._viaAfficherIndispo1936(_d1937.next_available);\r\n                                    }\r\n                                    \/* pb1941 : l etape Dates redevient incomplete ->\r\n                                       le sequenceur la rouvre et s y arrete. *\/\r\n                                    if (window._viaIndispo1941 !== true) {\r\n                                        window._viaIndispo1941 = true;\r\n                                        console.log('[pb1941] verrou pos\u00e9 : \u00e9tape Dates'\r\n                                            + ' rendue incompl\u00e8te, le s\u00e9quenceur la garde ouverte');\r\n                                    }\r\n                                    try { _self1937.majEtapes631(); }\r\n                                    catch (_eM1941) { console.warn('[pb1941] ' + _eM1941.message); }\r\n                                    return;\r\n                                }\r\n                                console.log('[pb1938] espace disponible | ' + _sv1937);\r\n                                if (typeof window._viaMasquerIndispo1936 === 'function') {\r\n                                    window._viaMasquerIndispo1936();\r\n                                }\r\n                                \/* pb1941 : verrou leve -> l etape Dates peut se completer\r\n                                   et le sequenceur passe a la suivante. *\/\r\n                                if (window._viaIndispo1941 === true) {\r\n                                    window._viaIndispo1941 = false;\r\n                                    console.log('[pb1941] verrou lev\u00e9 : \u00e9tape Dates de nouveau'\r\n                                        + ' compl\u00e9table');\r\n                                    try { _self1937.majEtapes631(); }\r\n                                    catch (_eM1941b) { console.warn('[pb1941] ' + _eM1941b.message); }\r\n                                }\r\n                            })\r\n                            .catch(function (_e1937) {\r\n                                console.warn('[pb1938] v\u00e9rification en \u00e9chec : '\r\n                                    + _e1937.message + ' \u2014 on suppose disponible');\r\n                            });\r\n                    }\r\n                } else if (window._viaIndispo1941 === true) {\r\n                    \/* pb1941 : plus de dates completes -> le verrou n a plus d objet.\r\n                       Sans cette levee, effacer une date figerait l etape a jamais. *\/\r\n                    window._viaIndispo1941 = false;\r\n                    console.log('[pb1941] dates incompl\u00e8tes -> verrou lev\u00e9');\r\n                }\r\n            } catch (_eG1937) { console.warn('[pb1938] ' + _eG1937.message); }\r\n        }\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb1901 : CE MESSAGE N'A PLUS D'OBJET (demande user).\r\n        \/\/   pb619 disait \u00ab les dates sont saisies mais pas le pays de\r\n        \/\/   l'annonceur \u00bb. Reproche fonde tant que l'annonceur etait l'etape 1 :\r\n        \/\/   l'utilisateur avait saute une etape. Depuis pb1899 l'annonceur vient\r\n        \/\/   APRES les dates \u2014 le message s'afficherait SYSTEMATIQUEMENT, a\r\n        \/\/   l'instant meme ou l'utilisateur finit les dates, pour lui reprocher\r\n        \/\/   une etape qu'on ne lui a pas encore proposee.\r\n        \/\/   Exactement le cas de pb1348 sur PopupTarifsListeSecteursMessageTexte\r\n        \/\/   apres pb1346, et traite pareil : on MASQUE au lieu d'evaluer. Le texte\r\n        \/\/   Elementor peut etre supprime, plus rien ne l'affiche.\r\n        \/\/   L'information n'est pas perdue : le titre de l'etape Annonceur passe\r\n        \/\/   en rouge (pb1186) et _prerequisTarifs707 le dit au recapitulatif.\r\n        \/\/   Revert : window._viaPb1901Off = true (ancienne evaluation).\r\n        \/\/ ====================================================================\r\n        const paysManquant = (window._viaPb1901Off === true)\r\n            ? ((!paysLabel) && (!!dateDebut) && (!!dateFin))\r\n            : false;\r\n        this.messageAnnonceur619(paysManquant);\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb2113 : DUREE MINIMALE EVALUEE DES QUE LES DEUX DATES SONT SAISIES.\r\n        \/\/   Constat user : en express, duree < 7 jours ne montrait aucun message\r\n        \/\/   dans l'etape dates. Cause : le controle pb604f est situe APRES la\r\n        \/\/   garde \"!paysLabel -> return\" ci-dessous ; or depuis pb1899 l'annonceur\r\n        \/\/   vient APRES les dates \u2014 au moment ou l'utilisateur finit ses dates,\r\n        \/\/   paysLabel est vide et la fonction sort avant le controle (meme famille\r\n        \/\/   que pb1901). Ici on evalue la duree a partir des SEULES dates, avant\r\n        \/\/   la garde : message \"duree minimale\" affiche en rouge (#fb5e2a, le\r\n        \/\/   corail du process) en bas de l'etape (GrilleTarifCMsgContainer), et\r\n        \/\/   grille masquee. Le controle pb604f d'origine reste en place plus loin\r\n        \/\/   (il re-evalue a l'identique quand le pays est connu).\r\n        \/\/   Revert : window._viaPb2113Off = true.\r\n        \/\/ ====================================================================\r\n        if (window._viaPb2113Off !== true) {\r\n            const dureeMin2113 = (typeof window.VIA_DureeMinGrille === 'number') ? window.VIA_DureeMinGrille\r\n                : (window._viaParams610 ? window._viaParams610.min : 7);\r\n            const $msgC2113 = $('#GrilleTarifCMsgContainer');\r\n            const $msgT2113 = $('#GrilleTarifCMsgTexte');\r\n            let dureeSeule2113 = 0;\r\n            if (dateDebut ? dateFin : false) { dureeSeule2113 = this.calculerDuree(dateDebut, dateFin); }\r\n            const sousMin2113 = (dureeSeule2113 >= 1) ? ((dureeMin2113 > 0) ? (dureeSeule2113 < dureeMin2113) : false) : false;\r\n            if (window._viaSigMin2113 !== String(sousMin2113) + '\/' + dureeSeule2113) {\r\n                window._viaSigMin2113 = String(sousMin2113) + '\/' + dureeSeule2113;\r\n                console.log('[pb2113] duree seule=' + dureeSeule2113 + 'j | min=' + dureeMin2113\r\n                    + ' -> ' + (sousMin2113 ? 'MESSAGE duree minimale' : 'pas de message (ce controle)'));\r\n            }\r\n            if (sousMin2113) {\r\n                const lang2113 = sessionStorage.getItem('SiteLangue') === 'EN' ? 'EN' : 'FR';\r\n                const msg2113 = (lang2113 === 'EN')\r\n                    ? `Please select a campaign with a minimum duration of ${dureeMin2113} days`\r\n                    : `Merci de s\u00e9lectionner une campagne d'une dur\u00e9e minimale de ${dureeMin2113} jours`;\r\n                $msgT2113.text(msg2113);\r\n                $msgT2113.find('*').addBack().each(function () {\r\n                    this.style.setProperty('color', '#fb5e2a', 'important');\r\n                });\r\n                $msgC2113.css('display', 'block').show();\r\n                this._stylerMsgDates2114();   \/\/ pb2114\r\n                this._afficherGrilleTarifaire703(false);   \/\/ pb705\/pb703\r\n            } else if (dureeSeule2113 >= 1) {\r\n                \/\/ duree valide pour CE controle : on retire notre message ; les\r\n                \/\/ controles pb604f\/pb609 plus bas re-afficheront le leur au besoin.\r\n                $msgC2113.hide();\r\n                this._dureeVerte2115();   \/\/ pb2115 : la duree reprend le vert pb844\r\n            }\r\n        }\r\n\r\n        if (!paysLabel || !dateDebut || !dateFin) {\r\n            \/\/ pb705 : regle transferee de #TarifsPublicitaireListe vers .GrilleTarifaire.\r\n            this._afficherGrilleTarifaire703(false);   \/\/ pb705 (dates ou pays annonceur manquants)\r\n            \/\/ pb1900 : la remise a ZERO de la duree est RETIREE d'ici. C'etait le\r\n            \/\/   verrou : elle effacait une duree parfaitement valide au seul motif\r\n            \/\/   que le pays de l'annonceur manquait. La duree est posee plus haut,\r\n            \/\/   a partir des seules dates. Conservee sous revert.\r\n            if (window._viaPb1900Off === true) {\r\n                this._setDuree735(0);   \/\/ pb735 (etait : this.state.dureeJours = 0)\r\n            }\r\n            this.majEtapes631();   \/\/ pb631\r\n            window._viaReplie633 = false;   \/\/ pb633 : re-armer pour le prochain affichage\r\n            return;\r\n        }\r\n\r\n        const pays = window.VIA_Countries.getCountryByLabel(paysLabel);\r\n        if (!pays) {\r\n            return;\r\n        }\r\n\r\n        const duree = this.calculerDuree(dateDebut, dateFin);\r\n        if (duree < 1) {\r\n            return;\r\n        }\r\n\r\n        \/\/ pb604f : duree minimale de campagne (7 jours). Sous le seuil, on affiche\r\n        \/\/   le message dans GrilleTarifCMsgContainer (masque par defaut par Elementor)\r\n        \/\/   et on n'affiche pas la grille. Au-dessus, on masque le message.\r\n        const dureeMin = (typeof window.VIA_DureeMinGrille === 'number') ? window.VIA_DureeMinGrille\r\n            : (window._viaParams610 ? window._viaParams610.min : 7);\r\n        const $msgContainer = $('#GrilleTarifCMsgContainer');\r\n        const $msgTexte = $('#GrilleTarifCMsgTexte');\r\n        if (dureeMin > 0 && duree < dureeMin) {\r\n            const lang = sessionStorage.getItem('SiteLangue') === 'EN' ? 'EN' : 'FR';\r\n            const message = (lang === 'EN')\r\n                ? `Please select a campaign with a minimum duration of ${dureeMin} days`\r\n                : `Merci de s\u00e9lectionner une campagne d'une dur\u00e9e minimale de ${dureeMin} jours`;\r\n            $msgTexte.text(message);\r\n            $msgContainer.css('display', 'block').show();\r\n            this._stylerMsgDates2114();   \/\/ pb2114\r\n            \/\/ pb705 : masquage transfere sur .GrilleTarifaire (ligne suivante) \u2014 duree < min\r\n            this._afficherGrilleTarifaire703(false);   \/\/ pb703\r\n            return;\r\n        }\r\n        \/\/ pb609 : duree MAXIMALE de campagne (defaut 200 jours).\r\n        \/\/   Knob : window.VIA_DureeMaxGrille (0 = desactive).\r\n        const dureeMax = (typeof window.VIA_DureeMaxGrille === 'number') ? window.VIA_DureeMaxGrille\r\n            : (window._viaParams610 ? window._viaParams610.max : 200);\r\n        if (dureeMax > 0 && duree > dureeMax) {\r\n            const langX = sessionStorage.getItem('SiteLangue') === 'EN' ? 'EN' : 'FR';\r\n            const messageX = (langX === 'EN')\r\n                ? `Please select a campaign with a maximum duration of ${dureeMax} days`\r\n                : `Merci de s\u00e9lectionner une campagne d'une dur\u00e9e maximale de ${dureeMax} jours`;\r\n            $msgTexte.text(messageX);\r\n            $msgContainer.css('display', 'block').show();\r\n            this._stylerMsgDates2114();   \/\/ pb2114\r\n            \/\/ pb705 : masquage transfere sur .GrilleTarifaire (ligne suivante) \u2014 duree > max\r\n            this._afficherGrilleTarifaire703(false);   \/\/ pb703\r\n            return;\r\n        }\r\n        $msgContainer.hide();\r\n\r\n        \/\/ pb620 : aucun SITE PAYS choisi dans la liste du haut -> message\r\n        \/\/   PopupTarifsSitePaysMessageTexte (masque par Elementor) et pas de\r\n        \/\/   grille. A ne pas confondre avec le pays de l'ANNONCEUR (pb619).\r\n        if (!this.sitePaysSelectionne620()) {\r\n            this.messageSitePays620(true);\r\n            \/\/ pb705 : masquage transfere sur .GrilleTarifaire (ligne suivante) \u2014 aucun site pays\r\n            this._afficherGrilleTarifaire703(false);   \/\/ pb703\r\n            return;\r\n        }\r\n        this.messageSitePays620(false);\r\n\r\n        this.state.paysSelectionne = pays;\r\n        this._setDuree735(duree);   \/\/ pb735 (etait : this.state.dureeJours = duree)\r\n        this.majEtapes631();   \/\/ pb631\r\n        \/\/ pb1036 : fermeture retiree \u2014 le sequenceur ferme cette etape des que sa\r\n        \/\/   completion bascule, et ouvre la suivante dans le meme mouvement.\r\n        if (window._viaPb1036Off === true) { this.fermerSmooth647('dates'); }\r\n        \/\/ pb706 : l'affichage pb703 pose ICI est RETIRE. Il precedait\r\n        \/\/   calculerEtAfficherGrille (ligne ci-dessous), qui masque aussitot la\r\n        \/\/   grille pendant le calcul : l'element clignotait. L'affichage a lieu\r\n        \/\/   desormais APRES le calcul reussi, comme le faisait #TarifsPublicitaireListe.\r\n        \/\/   Etait : this._afficherGrilleTarifaire703(true);\r\n\r\n        console.log('\u2705 Calcul grille:', pays.label, duree, 'jours');\r\n\r\n        this.calculerEtAfficherGrille();\r\n        this.syncVersResa651();   \/\/ pb651 B : live vers l'item actif (si existant)\r\n    }\r\n\r\n    calculerDuree(dateDebut, dateFin) {\r\n        try {\r\n            const [d1, m1, y1] = dateDebut.split('\/');\r\n            const [d2, m2, y2] = dateFin.split('\/');\r\n            \r\n            const debut = new Date(y1, m1 - 1, d1);\r\n            const fin = new Date(y2, m2 - 1, d2);\r\n            \r\n            const diffDays = Math.ceil((fin - debut) \/ (1000 * 60 * 60 * 24));\r\n            \r\n            return diffDays;\r\n        } catch (error) {\r\n            return 0;\r\n        }\r\n    }\r\n\r\n    \/\/ pb646 : spinner rotatif + \"Loading in progress\" pendant les chargements\r\n    \/\/   (grille tarifaire, liste articles). Modele local au popup Express checking.\r\n    static _spinnerCss646Static() {\r\n        if (document.getElementById('via-spinner646-css')) { return; }\r\n        const st = document.createElement('style');\r\n        st.id = 'via-spinner646-css';\r\n        st.textContent =\r\n            '@keyframes via-spin646{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}' +\r\n            '.via-attente646{display:flex;flex-direction:column;align-items:center;justify-content:center;' +\r\n            'gap:10px;padding:24px 12px;width:100%;color:#4B689B;font-size:13px;font-weight:600;text-align:center;}' +\r\n            '.via-attente646 .via-spin646{width:28px;height:28px;border:3px solid #d9e2f0;' +\r\n            'border-top-color:#4B689B;border-radius:50%;animation:via-spin646 .8s linear infinite;}';\r\n        document.head.appendChild(st);\r\n    }\r\n    _spinnerCss646() {\r\n        if (document.getElementById('via-spinner646-css')) { return; }\r\n        const st = document.createElement('style');\r\n        st.id = 'via-spinner646-css';\r\n        st.textContent =\r\n            '@keyframes via-spin646{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}' +\r\n            '.via-attente646{display:flex;flex-direction:column;align-items:center;justify-content:center;' +\r\n            'gap:10px;padding:24px 12px;width:100%;color:#4B689B;font-size:13px;font-weight:600;text-align:center;}' +\r\n            '.via-attente646 .via-spin646{width:28px;height:28px;border:3px solid #d9e2f0;' +\r\n            'border-top-color:#4B689B;border-radius:50%;animation:via-spin646 .8s linear infinite;}';\r\n        document.head.appendChild(st);\r\n    }\r\n    afficherAttente646(sel) {\r\n        this._spinnerCss646();\r\n        const $c = $(sel).first();\r\n        if ($c.length === 0) { return; }\r\n        if ($c.find('.via-attente646').length) { return; }   \/\/ deja affiche\r\n        const txt = (sessionStorage.getItem('SiteLangue') === 'FR')\r\n            ? 'Chargement en cours' : 'Loading in progress';\r\n        $c.append('<div class=\"via-attente646\"><div class=\"via-spin646\"><\/div><div>' + txt + '<\/div><\/div>');\r\n        console.log('[pb646] attente ->', sel);\r\n    }\r\n    masquerAttente646(sel) {\r\n        $(sel).find('.via-attente646').remove();\r\n    }\r\n    \/\/ pb646 : exposer pour yearbook-media.js (liste articles rendue la-bas)\r\n    static htmlAttente646() {\r\n        const txt = (sessionStorage.getItem('SiteLangue') === 'FR')\r\n            ? 'Chargement en cours' : 'Loading in progress';\r\n        return '<div class=\"via-attente646\"><div class=\"via-spin646\"><\/div><div>' + txt + '<\/div><\/div>';\r\n    }\r\n\r\n    async calculerEtAfficherGrille() {\r\n        if (this.state.isCalculating) return;\r\n\r\n        \/\/ ================================================================\r\n        \/\/ pb1360 : NE PAS RECALCULER CE QUI N'A PAS CHANGE.\r\n        \/\/   Constat user : de la homepage vers une page secteur, le VLP suit bien\r\n        \/\/   (pb1358) mais .v707-msg affiche \u00ab Les tarifs n ont pas pu \u00eatre obtenus \u00bb\r\n        \/\/   et la grille reste masquee. Le log s'arrete net :\r\n        \/\/     \u2705 Calcul grille: France 20 jours\r\n        \/\/     [pb709] grilleCalculee709 = false\r\n        \/\/     [pb703] .GrilleTarifaire x3 -> masquee\r\n        \/\/     [pb646] attente -> .TarifsConteneur      <- et plus rien\r\n        \/\/   Le premier calcul, lui, etait alle au bout. Le second part, masque la\r\n        \/\/   grille, pose le spinner \u2014 et n'aboutit pas : entre-temps le VLP est\r\n        \/\/   ferme puis rouvert (_fermerVlp744, fillEspacesPub, Promise.catch) et\r\n        \/\/   l'appel echoue. L'utilisateur perd sa grille pour un calcul qui n'avait\r\n        \/\/   pas lieu d'etre : le SECTEUR n'entre pas dans le tarif (pb1359).\r\n        \/\/   Changer de page ne perime pas la grille \u2014 elle demande seulement a etre\r\n        \/\/   RE-FILTREE (pb1347).\r\n        \/\/   Meme signature que pb1359 : pays annonceur, duree, devise. Identique et\r\n        \/\/   grille encore garnie -> on reaffiche et on refiltre, sans appel reseau,\r\n        \/\/   donc sans fenetre d'echec. Sinon, calcul normal.\r\n        \/\/   La garde \u00ab garnie \u00bb evite de reafficher une grille videe entre-temps :\r\n        \/\/   on ne reaffiche que ce qui existe encore.\r\n        \/\/   Revert : window._viaPb1360Off = true.\r\n        \/\/ ================================================================\r\n        if (window._viaPb1360Off !== true) {\r\n            try {\r\n                const _mem1360 = window._viaSigneGrille1359 || '';\r\n                const _garnie1360 = document.querySelectorAll('.PricingAmount').length > 0;\r\n                if ((_mem1360 ? (_mem1360 === this._signatureGrille1359()) : false)\r\n                    ? _garnie1360 : false) {\r\n                    console.log('[pb1360] grille d\u00e9j\u00e0 calcul\u00e9e pour ' + _mem1360\r\n                        + ' -> r\u00e9affichage et re-filtrage, sans nouvel appel');\r\n                    this.masquerAttente646('.TarifsConteneur');\r\n                    this._messageTarifs707('');\r\n                    this._afficherGrilleTarifaire703(true);\r\n                    try { this._filtrerLignes1347(); }\r\n                    catch (_e1360b) { console.warn('[pb1360] filtrage : ' + _e1360b.message); }\r\n                    return;\r\n                }\r\n            } catch (_e1360) {\r\n                console.warn('[pb1360] r\u00e9affichage impossible : ' + _e1360.message);\r\n            }\r\n        }\r\n\r\n        this.state.isCalculating = true;\r\n        \r\n        \/\/ ================================================================\r\n        \/\/ pb2154 : LE CONTENU NE DISPARAIT PLUS PENDANT UN RECALCUL.\r\n        \/\/   Constat JF (log au changement de devise CHF -> XAF) :\r\n        \/\/     [pb709] grilleCalculee709 = false -> [pb703] .GrilleTarifaire x3\r\n        \/\/     -> masquee ... puis [pb709] true -> AFFICHEE\r\n        \/\/   Entre les deux, l'etape \u00ab format et tarifs \u00bb est vide : c'est ce\r\n        \/\/   masquage-ci (pb705) qui la vide, pendant l'appel reseau de\r\n        \/\/   conversion.\r\n        \/\/   REMEDE : quand la grille est DEJA GARNIE (des .PricingAmount sont\r\n        \/\/   presents), on la LAISSE VISIBLE et on superpose seulement le\r\n        \/\/   voile d'attente pb646. L'ancienne grille reste lisible jusqu'a ce\r\n        \/\/   que la nouvelle la remplace \u2014 un remplacement, plus un vide suivi\r\n        \/\/   d'un retour. C'est le meme raisonnement que pb1360 juste au-dessus\r\n        \/\/   (\u00ab ne pas defaire ce qui est encore bon \u00bb) et le meme test de\r\n        \/\/   garniture, deja eprouve.\r\n        \/\/   PREMIER CALCUL INCHANGE : sans .PricingAmount il n'y a rien a\r\n        \/\/   preserver, on masque comme avant \u2014 sinon on afficherait un cadre\r\n        \/\/   vide au lieu du spinner seul.\r\n        \/\/   L'affichage final (_afficherGrilleTarifaire703(true), l.2083) et\r\n        \/\/   le voile d'attente ne changent pas : rien a synchroniser en plus.\r\n        \/\/   Revert : window._viaPb2154Off = true (masquage systematique).\r\n        \/\/ ================================================================\r\n        var _garnie2154 = (window._viaPb2154Off === true)\r\n            ? false\r\n            : (document.querySelectorAll('.PricingAmount').length > 0);\r\n        if (_garnie2154) {\r\n            \/\/ pb2156 : PAS DE SPINNER quand la grille reste affichee (demande JF,\r\n            \/\/   capture : anneau + \u00ab Chargement en cours \u00bb au-dessus d'une grille\r\n            \/\/   parfaitement lisible). Le voile pb646 servait a occuper le vide\r\n            \/\/   laisse par le masquage ; pb2154 ayant supprime ce vide, il n'a\r\n            \/\/   plus d'objet \u2014 il annonce une attente que l'utilisateur ne subit\r\n            \/\/   plus. Il reste pose au PREMIER calcul, ou l'ecran est bien vide.\r\n            \/\/   masquerAttente646 continue d'etre appele plus loin : sans attente\r\n            \/\/   posee, il ne fait rien.\r\n            console.log('[pb2154] recalcul : grille garnie -> laissee VISIBLE'\r\n                + ' | [pb2156] sans spinner');\r\n        } else {\r\n            \/\/ \u2705 MASQUER la grille pendant calcul\r\n            \/\/ pb705 : la regle porte desormais sur .GrilleTarifaire, plus sur\r\n            \/\/   #TarifsPublicitaireListe. Etait : $('#TarifsPublicitaireListe').hide();\r\n            this._afficherGrilleTarifaire703(false);   \/\/ pb705 (pendant le calcul)\r\n            this.afficherAttente646('.TarifsConteneur');   \/\/ pb646\r\n        }\r\n        try {\r\n            \/\/ v2.9 : proxy via yearbook-media.com\/admin-ajax.php pour eviter CORS\r\n            const _proxyParams = new URLSearchParams({\r\n                action: 'via_calculer_grille_proxy',\r\n                pays_cible: this.state.paysSelectionne.code,\r\n                duree: this.state.dureeJours\r\n            });\r\n            \/\/ ================================================================\r\n            \/\/ pb1038 : FIABILISER l'appel tarifs (constat user : \"Calcul des tarifs\r\n            \/\/   en cours...\" bloque indefiniment, non reproductible).\r\n            \/\/   Ce message n'est pas un etat d'attente : c'est le texte par defaut\r\n            \/\/   affiche des que _viaGrilleCalculee709 n'est pas true. Il apparait\r\n            \/\/   donc a l'identique dans TOUS les cas d'echec \u2014 et le code n'en\r\n            \/\/   traitait AUCUN :\r\n            \/\/     - pas de verification de response.ok (une 500 ou une page HTML\r\n            \/\/       d'erreur passait a response.json(), qui levait) ;\r\n            \/\/     - aucun timeout : une requete sans reponse laissait l'interface\r\n            \/\/       en attente indefinie (cas plausible en 5G instable, cf capture) ;\r\n            \/\/     - le catch se contentait d'un console.error, sans rien afficher ;\r\n            \/\/     - if (data.success) { if (data.tarifs) { ... } } n'avait AUCUN\r\n            \/\/       else : succes partiel ou charge vide = silence total.\r\n            \/\/   Corrections : timeout de 12s (AbortController), controle de\r\n            \/\/   response.ok, et 2 nouvelles tentatives avec backoff sur erreur\r\n            \/\/   reseau\/JSON \u2014 c'est ce qui fiabilise reellement sur mobile, ou la\r\n            \/\/   perte d'une requete est le cas courant.\r\n            \/\/   Le message d'echec est ecrit par pb707, la ou pb709 ecrivait le\r\n            \/\/   message d'attente : l'utilisateur sait enfin que ca a echoue, et\r\n            \/\/   quoi faire.\r\n            \/\/   Revert : window._viaPb1038Off = true (comportement d'origine).\r\n            \/\/ ================================================================\r\n            let data = null;\r\n            if (window._viaPb1038Off === true) {\r\n                const response = await fetch('https:\/\/yearbook-media.com\/wp-admin\/admin-ajax.php', {\r\n                    method: 'POST',\r\n                    credentials: 'omit',\r\n                    headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n                    body: _proxyParams.toString()\r\n                });\r\n                data = await response.json();\r\n            } else {\r\n                const _essais1038 = 3;\r\n                let _err1038 = null;\r\n                for (let _i1038 = 1; _i1038 <= _essais1038; _i1038++) {\r\n                    let _ctrl1038 = null;\r\n                    let _tmo1038 = null;\r\n                    try {\r\n                        _ctrl1038 = (typeof AbortController === 'function') ? new AbortController() : null;\r\n                        if (_ctrl1038) { _tmo1038 = setTimeout(() => { _ctrl1038.abort(); }, 12000); }\r\n                        const _opt1038 = {\r\n                            method: 'POST',\r\n                            credentials: 'omit',\r\n                            headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n                            body: _proxyParams.toString()\r\n                        };\r\n                        if (_ctrl1038) { _opt1038.signal = _ctrl1038.signal; }\r\n                        const _rep1038 = await fetch('https:\/\/yearbook-media.com\/wp-admin\/admin-ajax.php', _opt1038);\r\n                        if (_tmo1038) { clearTimeout(_tmo1038); _tmo1038 = null; }\r\n                        if (!_rep1038.ok) { throw new Error('HTTP ' + _rep1038.status); }\r\n                        data = await _rep1038.json();\r\n                        _err1038 = null;\r\n                        if (_i1038 > 1) { console.log('[pb1038] tarifs obtenus \u00e0 l essai ' + _i1038); }\r\n                        break;\r\n                    } catch (_e1038) {\r\n                        if (_tmo1038) { clearTimeout(_tmo1038); }\r\n                        _err1038 = _e1038;\r\n                        console.warn('[pb1038] essai ' + _i1038 + '\/' + _essais1038 + ' \u00e9chou\u00e9 : ' + _e1038.message);\r\n                        if (_i1038 < _essais1038) {\r\n                            await new Promise(_r => setTimeout(_r, 600 * _i1038));   \/\/ backoff\r\n                        }\r\n                    }\r\n                }\r\n                if (_err1038) { throw _err1038; }\r\n            }\r\n            \/\/ pb1038 : charge inexploitable -> on le DIT, au lieu de laisser le\r\n            \/\/   message d'attente a l'ecran indefiniment.\r\n            if (window._viaPb1038Off !== true) {\r\n                const _okData1038 = data ? (data.success ? !!data.tarifs : false) : false;\r\n                if (!_okData1038) {\r\n                    console.warn('[pb1038] r\u00e9ponse sans tarifs exploitables', data);\r\n                    this.masquerAttente646('.TarifsConteneur');\r\n                    this._messageTarifs707(\r\n                        (sessionStorage.getItem('SiteLangue') === 'EN')\r\n                            ? 'Rates could not be retrieved. Please change the dates or try again.'\r\n                            : 'Les tarifs n ont pas pu \u00eatre obtenus. Merci de modifier les dates ou de r\u00e9essayer.');\r\n                }\r\n            }\r\n            if (data.success) {\r\n            if (data.tarifs) {\r\n                \/\/ \u2705 METTRE \u00c0 JOUR le titre\r\n                const texteJours = this.state.dureeJours === 1 ? '1 jour' : `${this.state.dureeJours} jours`;\r\n                \/\/ ================================================================\r\n                \/\/ pb2218 : REVERT de pb2155 + pb2158 (demande JF) \u2014 retour au titre\r\n                \/\/   d'UNE SEULE LIGNE. Tout le bloc a deux lignes est supprime, et\r\n                \/\/   avec lui la recherche d'URL de site de pb2158 : elle ne servait\r\n                \/\/   qu'a alimenter le segment \u00ab site \u00bb de la ligne 1, qui n'existe\r\n                \/\/   plus. Rien d'autre ne la lisait.\r\n                \/\/   La forme retenue est celle de l'AUTRE ecrivain du meme titre,\r\n                \/\/   Entete.txt (~l.7079) : \u00ab <pays> - Tarifs publicitaires d'une\r\n                \/\/   campagne de <N jours> \u00bb, avec sa variante anglaise. Les deux\r\n                \/\/   ecrivains disent de nouveau exactement la meme chose \u2014 c'est ce\r\n                \/\/   que pb2155 avait rompu.\r\n                \/\/   Plus de .html() : le titre n'a plus de balise, donc .text(), qui\r\n                \/\/   echappe de lui-meme. Les fonctions d'echappement de pb2155\r\n                \/\/   disparaissent avec lui.\r\n                \/\/ ================================================================\r\n                $('#PaysTarifsCampagne').text(\r\n                    (sessionStorage.getItem('SiteLangue') === 'EN')\r\n                        ? `${this.state.paysSelectionne.label} - Advertising rates for a ${texteJours} campaign`\r\n                        : `${this.state.paysSelectionne.label} - Tarifs publicitaires d'une campagne de ${texteJours}`\r\n                );\r\n                \r\n                \/\/ Stocker et afficher les tarifs\r\n                data.tarifs.forEach(tarif => {\r\n                    const classe = this.getClasseFromParams(tarif.format, tarif.position);\r\n                    this.state.tarifsCalcules[classe] = tarif.tarif_ht;\r\n                    \r\n                    const $element = $(`.${classe}`);\r\n                    if ($element.length) {\r\n                        $element.text(this.formaterSansDevise613(tarif.tarif_ht));\r\n                    }\r\n                });\r\n                \r\n                \/\/ ================================================================\r\n                \/\/ pb2157 : LA GRILLE S'AFFICHE DEJA CONVERTIE.\r\n                \/\/   Constats JF, une seule cause : la boucle ci-dessus ecrit\r\n                \/\/   formaterSansDevise613(tarif.tarif_ht), c'est-a-dire le montant\r\n                \/\/   EUR BRUT renvoye par le serveur. D'ou :\r\n                \/\/     - \u00ab de faux tarifs qui se mettent ensuite a jour \u00bb au premier\r\n                \/\/       affichage (des EUR affiches sous un autre libelle) ;\r\n                \/\/     - \u00ab les tarifs reviennent en euros \u00bb apres un changement de\r\n                \/\/       devise (log : \u00ab Grille convertie en GBP \u00bb puis recalcul qui\r\n                \/\/       repose les EUR).\r\n                \/\/   On convertit donc ICI, AVANT l'affichage : la grille n'est\r\n                \/\/   revelee qu'une fois juste. convertirEtAfficherGrille repose\r\n                \/\/   aussi les liens pb612 et la devise active pb613 \u2014 les appels\r\n                \/\/   qui suivent restent en place, ils sont idempotents (lierTarifs612\r\n                \/\/   sort si le lien existe deja).\r\n                \/\/   Rien a faire si l'affichage est en EUR : la boucle a deja pose\r\n                \/\/   les bonnes valeurs.\r\n                \/\/   Revert : window._viaPb2157Off = true.\r\n                \/\/ ================================================================\r\n                if (window._viaPb2157Off === true ? false\r\n                    : (this.state.deviseAffichage ? this.state.deviseAffichage !== 'EUR' : false)) {\r\n                    try {\r\n                        \/\/ pb2159 : MONTANTS SEULS. Constat JF : trois rangees\r\n                        \/\/   s'affichaient au lieu d'une. Cause \u2014 mon appel pb2157\r\n                        \/\/   declenchait aussi lierTarifs612, qui enveloppe chaque\r\n                        \/\/   cellule dans un <a> AVANT le filtrage pb1347\/pb1396,\r\n                        \/\/   dont l'ordre est explicitement critique (pb1396 :\r\n                        \/\/   \u00ab filtrer fige la famille de chaque rangee \u00bb). Habiller\r\n                        \/\/   avant de filtrer brouillait la lecture des rangees.\r\n                        \/\/   On ne convertit donc QUE les montants ici ; les liens et\r\n                        \/\/   le marquage de devise restent a leur place, apres\r\n                        \/\/   _afficherGrilleTarifaire703(true), inchanges.\r\n                        this.convertirEtAfficherGrille(true);\r\n                        console.log('[pb2157] grille convertie en ' + this.state.deviseAffichage\r\n                            + ' AVANT affichage | [pb2159] montants seuls, filtrage non perturbe');\r\n                    } catch (_e2157) { console.warn('[pb2157] conversion : ' + _e2157.message); }\r\n                }\r\n                this.masquerAttente646('.TarifsConteneur');   \/\/ pb646\r\n                \/\/ pb706 : affichage transfere de #TarifsPublicitaireListe vers .GrilleTarifaire.\r\n                \/\/   Etait : $('#TarifsPublicitaireListe').fadeIn(300, () => this.scrollVersBasGrille());\r\n                this._afficherGrilleTarifaire703(true, true, () => this.scrollVersBasGrille());\r\n                this.lierTarifs612();\r\n                this.marquerDeviseActive613();\r\n                this.agrandirTarifs613();\r\n                this.afficherTitreSecteurs618();\r\n                this.replierEtapesAmont633();\r\n                \/\/ pb651o : un tarif etait deja selectionne -> le re-selectionner pour\r\n                \/\/   rafraichir #PopUpTarifsCampagneSelect avec le nouveau montant.\r\n                const _selO = this.state.tarifSelectionne;\r\n                if (_selO ? (this.state.tarifsCalcules ? this.state.tarifsCalcules[_selO] != null : false) : false) {\r\n                    window._sync651AClic = true;   \/\/ anti-boucle pendant la re-selection\r\n                    this._selectionnerTarif651(_selO);\r\n                    setTimeout(() => { window._sync651AClic = false; }, 500);\r\n                }\r\n            }}\r\n            \r\n        } catch (error) {\r\n            console.error('\u274c Erreur:', error);\r\n            \/\/ pb1038 : l'echec etait AVALE \u2014 la grille restait masquee et le\r\n            \/\/   message \"Calcul des tarifs en cours...\" s'affichait pour toujours.\r\n            \/\/   On informe desormais l'utilisateur et on lui donne une action.\r\n            if (window._viaPb1038Off !== true) {\r\n                try {\r\n                    const _ab1038 = (error ? error.name === 'AbortError' : false);\r\n                    const _en1038 = (sessionStorage.getItem('SiteLangue') === 'EN');\r\n                    this._messageTarifs707(_ab1038\r\n                        ? (_en1038 ? 'Rates request timed out. Please try again.'\r\n                                   : 'Le calcul des tarifs a expir\u00e9. Merci de r\u00e9essayer.')\r\n                        : (_en1038 ? 'Rates could not be retrieved. Please try again.'\r\n                                   : 'Les tarifs n ont pas pu \u00eatre obtenus. Merci de r\u00e9essayer.'));\r\n                    console.warn('[pb1038] \u00e9chec d\u00e9finitif du calcul des tarifs : '\r\n                        + (error ? error.message : '(inconnu)'));\r\n                } catch (_eM1038) {}\r\n            }\r\n        } finally {\r\n            this.state.isCalculating = false;\r\n            this.masquerAttente646('.TarifsConteneur');   \/\/ pb646 : securite\r\n        }\r\n    }\r\n\r\n    getClasseFromParams(format, position) {\r\n        const mapping = {\r\n            'Vid\u00e9o': 'Vid', 'Video': 'Vid',\r\n            'Banni\u00e8re': 'Ban', 'Banniere': 'Ban',\r\n            'Parrainage': 'Par',\r\n            'Communiqu\u00e9': 'Com', 'Communique': 'Com',\r\n            'Interview': 'Int'\r\n        };\r\n        const posCodes = {\r\n            'Pop-up Homepage': 'PoPHP', 'Pop-up Autres P.': 'PoPPP',\r\n            'hdp Home P.': 'HdPHP', 'hdp Autres P.': 'HdPPP',\r\n            'cdp Home P.': 'CdPHP', 'cdp Autres P.': 'CdPPP'\r\n        };\r\n        \r\n        return `Tarif7${mapping[format]}${posCodes[position]}`;\r\n    }\r\n\r\n    async calculerUnTarif(classe, params) {\r\n        try {\r\n            const resultat = await window.VIA_App.calculerTarifAPI(\r\n                params.format,\r\n                params.position,\r\n                this.state.dureeJours,\r\n                this.state.paysSelectionne.code\r\n            );\r\n    \r\n            if (resultat.success) {\r\n                this.state.tarifsCalcules[classe] = resultat.tarif_ht;\r\n                \r\n                \/\/ \u2705 AFFICHER IMM\u00c9DIATEMENT (au lieu d'attendre tout)\r\n                const $element = $(`.${classe}`);\r\n                if ($element.length) {\r\n                    $element.text(this.formaterSansDevise613(resultat.tarif_ht));\r\n                    this.lierTarifs612();   \/\/ pb612\r\n                    this.marquerDeviseActive613();\r\n                    this.agrandirTarifs613();\r\n                    this.afficherTitreSecteurs618();\r\n                    this.replierEtapesAmont633();\r\n                    \/\/ pb614 : scroll une fois la salve d'affichage terminee (debounce)\r\n                    clearTimeout(this._scrollTimer614);\r\n                    this._scrollTimer614 = setTimeout(() => this.scrollVersBasGrille(), 200);\r\n                }\r\n            }\r\n        } catch (error) {\r\n            this.state.tarifsCalcules[classe] = null;\r\n        }\r\n    }\r\n\r\n    \/\/ pb607 : scroll automatique vers le bas quand la grille s'affiche.\r\n    \/\/   Cherche le premier ancetre REELLEMENT scrollable (overflow-y auto|scroll et\r\n    \/\/   contenu plus haut que la zone visible) : selon le contexte la grille vit dans\r\n    \/\/   .via-popup-content, dans une iframe, ou directement dans la page.\r\n    \/\/   Repli : scrollIntoView sur le bas de la grille.\r\n    \/\/ pb612b : SELECTION D'UN TARIF dans la grille.\r\n    \/\/   Au clic sur un tarif (liens poses par lierTarifs612) :\r\n    \/\/     1. afficher #PopUpTarifsTarifsSelectContainer (masque par Elementor)\r\n    \/\/     2. tarif moyen \/ jour de campagne -> #PopUpTarifsTJM\r\n    \/\/     3. tarif selectionne -> #PopUpTarifsCampagneSelect\r\n    \/\/   Delegation document (posee une fois) : survit aux reecritures des cases.\r\n    \/\/ pb613b : montant au format FR SANS le suffixe devise (la grille n'affiche\r\n    \/\/   plus EUR\/USD\/... a cote des montants ; la devise active est signalee par\r\n    \/\/   sa couleur dans .CatalogueDevises).\r\n    formaterSansDevise613(montant, decimales = 0) {\r\n        const s = montant.toFixed(decimales).replace('.', ',');\r\n        const parts = s.split(',');\r\n        parts[0] = parts[0].replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, ' ');\r\n        return parts.join(',');\r\n    }\r\n\r\n    \/\/ pb613b : devise ACTIVE en #225DA9, les autres en #213864 (leur couleur\r\n    \/\/   nominale). Les DEUX couleurs sont posees explicitement : removeProperty\r\n    \/\/   ne restaurait pas le #213864 (pose en inline par ailleurs) et laissait\r\n    \/\/   les devises en blanc.\r\n    \/\/ ================================================================\r\n    \/\/ pb785 : marquage VERT du tarif selectionne, de son FORMAT (en-tete de\r\n    \/\/   colonne) et de son EMPLACEMENT (libelle de ligne, ex. \"Home P. Cdp\").\r\n    \/\/   L'aplat bleu #ddeeff est conserve : le vert s'y ajoute.\r\n    \/\/   La grille n'est pas un <table> \u2014 impossible de remonter d'une cellule a\r\n    \/\/   son en-tete par la structure. Mais la CLASSE du tarif porte deja tout :\r\n    \/\/     Tarif7 + format(3) + position(3 : PoP\/HdP\/CdP) + famille(HP\/PP)\r\n    \/\/   On reconstruit donc les deux libelles et on les retrouve par leur TEXTE,\r\n    \/\/   exactement comme ils sont ecrits dans la legende de la grille.\r\n    \/\/   COULEUR D'ORIGINE memorisee en dataset a la premiere passe : sans elle, la\r\n    \/\/   deselection ne saurait pas quoi restaurer et un removeProperty rendrait la\r\n    \/\/   main aux valeurs Elementor (lecon pb668).\r\n    \/\/   Revert : window._viaPb785Off = true.\r\n    \/\/ ================================================================\r\n    _libelleLigne785(classe) {\r\n        if (!classe ? true : classe.length < 12) { return null; }\r\n        const _pos785 = classe.slice(-5, -2);            \/\/ PoP | HdP | CdP\r\n        const _fam785 = classe.slice(-2);                \/\/ HP  | PP\r\n        const _famTxt785 = (_fam785 === 'HP') ? 'Home P.' : 'Autres P.';\r\n        if (_pos785 === 'PoP') { return 'Pop-up ' + _famTxt785; }\r\n        if (_pos785 === 'HdP') { return _famTxt785 + ' Hdp'; }\r\n        if (_pos785 === 'CdP') { return _famTxt785 + ' Cdp'; }\r\n        return null;\r\n    }\r\n\r\n    \/\/   normalisation : accents, casse, espaces multiples\r\n    _norm785(s) {\r\n        return String(s || '').normalize ? String(s || '').normalize('NFD')\r\n            .replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase().replace(\/\\s+\/g, ' ').trim()\r\n            : String(s || '').toLowerCase().trim();\r\n    }\r\n\r\n    \/\/   applique le vert (ou restaure) sur un element, en memorisant sa teinte d'origine\r\n    \/\/   pb785b : le 3e argument demande +200 de graisse. Il ne concerne QUE le tarif\r\n    \/\/   et la devise ; le format et l'emplacement gardent leur graisse d'origine.\r\n    \/\/   La graisse de base est mesuree UNE fois et memorisee, comme la couleur :\r\n    \/\/   sans cela chaque passe ajouterait 200 de plus (motif pb722b, pb738).\r\n    \/\/   Plafond 900 : au-dela, la valeur est invalide en CSS.\r\n    _teinte785(el, vert, gras) {\r\n        if (!el) { return; }\r\n        if (!el.dataset.col785) {\r\n            el.dataset.col785 = getComputedStyle(el).color || 'inherit';\r\n        }\r\n        el.style.setProperty('color', vert ? '#56be50' : el.dataset.col785, 'important');\r\n        if (!gras) { return; }\r\n        if (!el.dataset.fw785) {\r\n            const _fw785 = parseInt(getComputedStyle(el).fontWeight, 10);\r\n            el.dataset.fw785 = String((_fw785 > 0) ? _fw785 : 400);\r\n        }\r\n        const _base785 = parseInt(el.dataset.fw785, 10);\r\n        const _cible785 = vert ? Math.min(_base785 + 200, 900) : _base785;\r\n        el.style.setProperty('font-weight', String(_cible785), 'important');\r\n        \/\/ pb785c : +1,5px de taille sur le TARIF selectionne seulement (le 3e argument\r\n        \/\/   'gras' n'est vrai que pour lui). Base mesuree une fois et memorisee, comme\r\n        \/\/   la couleur et la graisse \u2014 sinon chaque passe ajouterait 1,5px de plus.\r\n        \/\/   ATTENTION : pb617g fixe deja la taille des tarifs par inline. La base lue\r\n        \/\/   ici est donc celle de pb617g, pas la taille du theme : c'est bien elle\r\n        \/\/   qu'il faut restaurer a la deselection.\r\n        if (!el.dataset.fs785) {\r\n            const _fs785c = parseFloat(getComputedStyle(el).fontSize);\r\n            if (_fs785c > 0) { el.dataset.fs785 = String(_fs785c); }\r\n        }\r\n        \/\/ pb785d : agrandissement DESKTOP UNIQUEMENT. Meme seuil que partout ailleurs\r\n        \/\/   dans ce projet (innerWidth < 1000 = mobile \/ DVM). En mobile on restaure\r\n        \/\/   la base au lieu de ne rien faire : sinon un agrandissement pose en desktop\r\n        \/\/   survivrait a une rotation ou a un redimensionnement de fenetre.\r\n        if (el.dataset.fs785) {\r\n            const _bs785c = parseFloat(el.dataset.fs785);\r\n            const _desk785d = (window.innerWidth >= 1000);\r\n            const _agrandi785d = _desk785d ? vert : false;\r\n            el.style.setProperty('font-size',\r\n                (_agrandi785d ? (_bs785c + 1.5) : _bs785c) + 'px', 'important');\r\n        }\r\n    }\r\n\r\n    _marquerVert785(classe, $case) {\r\n        if (window._viaPb785Off === true) { return; }\r\n        try {\r\n            const _m785 = (typeof TARIF_MAPPING !== 'undefined') ? TARIF_MAPPING[classe] : null;\r\n            const _fmt785 = _m785 ? _m785.format : null;\r\n            const _lig785 = this._libelleLigne785(classe);\r\n            \/\/ 1) la cellule du tarif (le lien herite de color:inherit)\r\n            $('.PricingAmount').each((i, el) => { this._teinte785(el, false, true); });\r\n            if ($case.length) { this._teinte785($case[0], true, true); }   \/\/ pb785b : +200\r\n            \/\/ 2) en-tete de colonne (format) + libelle de ligne (emplacement)\r\n            const _cibles785 = [this._norm785(_fmt785), this._norm785(_lig785)]\r\n                .filter((x) => !!x);\r\n            let _trouves785 = 0;\r\n            $('.GrilleTarifaire, .TarifsFormats').find('*').each((i, el) => {\r\n                if (el.children.length > 0) { return; }        \/\/ feuilles seulement\r\n                if ($(el).closest('.PricingAmount').length) { return; }   \/\/ pas les tarifs\r\n                const _t785 = this._norm785(el.textContent);\r\n                if (!_t785) { return; }\r\n                if (_cibles785.indexOf(_t785) !== -1) {\r\n                    this._teinte785(el, true, false); _trouves785++;   \/\/ pb785b : couleur seule\r\n                } else if (el.dataset.col785) {\r\n                    this._teinte785(el, false, false);   \/\/ ancien marquage a retirer\r\n                }\r\n            });\r\n            console.log('[pb785] vert | tarif=' + classe + ' | format=\"' + _fmt785\r\n                + '\" | ligne=\"' + _lig785 + '\" | libelles marques=' + _trouves785);\r\n        } catch (_e785) { console.warn('[pb785]', _e785.message); }\r\n    }\r\n\r\n    marquerDeviseActive613() {\r\n        const active = this.state.deviseAffichage;\r\n        $('.CatalogueDevises a').each(function() {\r\n            const estActive = ($(this).text().trim() === active);\r\n            \/\/ pb785 : texte de la devise active en VERT, l'aplat bleu est conserve.\r\n            \/\/   Vert #56be50 : celui des sous-titres .v644-sub, deja en place dans ce\r\n            \/\/   popup \u2014 pas de nouvelle teinte introduite.\r\n            const _vert785 = (window._viaPb785Off === true) ? '#225DA9' : '#56be50';\r\n            this.style.setProperty('color', estActive ? _vert785 : '#213864', 'important');\r\n            \/\/ pb785b : +200 de graisse sur la devise active. Base memorisee une fois.\r\n            if (window._viaPb785Off !== true) {\r\n                if (!this.dataset.fw785) {\r\n                    const _fwD785 = parseInt(getComputedStyle(this).fontWeight, 10);\r\n                    this.dataset.fw785 = String((_fwD785 > 0) ? _fwD785 : 400);\r\n                }\r\n                const _bD785 = parseInt(this.dataset.fw785, 10);\r\n                this.style.setProperty('font-weight',\r\n                    String(estActive ? Math.min(_bD785 + 200, 900) : _bD785), 'important');\r\n            }\r\n            \/\/ pb2152 : PLUS DE FOND SOUS LA DEVISE ACTIVE (demande JF).\r\n            \/\/   L'aplat #ddeeff etait pose ici et nulle part ailleurs \u2014 ce writer\r\n            \/\/   est l'ecrivain unique, on corrige donc a la source plutot que de\r\n            \/\/   le recouvrir.\r\n            \/\/   'transparent' est ECRIT EXPLICITEMENT pour tous, actifs comme\r\n            \/\/   inactifs : jamais de removeProperty (lecon des couleurs \u2014 retirer\r\n            \/\/   la propriete rendrait la main a un ecrivain anterieur, et l'aplat\r\n            \/\/   pose lors d'un passage precedent survivrait au changement de\r\n            \/\/   devise).\r\n            \/\/   padding et border-radius CONSERVES : ils fixent la geometrie du\r\n            \/\/   lien ; les retirer ferait bouger les devises au changement de\r\n            \/\/   selection. La devise active reste distinguee par le vert #56be50\r\n            \/\/   et la graisse +200 (pb785\/pb785b), inchanges.\r\n            \/\/   Revert : window._viaPb2152Off = true (aplat #ddeeff retabli).\r\n            var _fond2152 = (window._viaPb2152Off === true)\r\n                ? (estActive ? '#ddeeff' : 'transparent')\r\n                : 'transparent';\r\n            this.style.setProperty('background-color', _fond2152, 'important');\r\n            this.style.setProperty('padding', '2px 6px', 'important');\r\n            this.style.setProperty('border-radius', '4px', 'important');\r\n        });\r\n    }\r\n\r\n    \/\/ pb617g : +2px sur la taille de police des tarifs de la grille (etait +1px\r\n    \/\/   en pb613b). La taille de BASE est mesuree a chaque chargement de page\r\n    \/\/   (l'inline pose par JS ne survit pas au rechargement), puis fixee une\r\n    \/\/   seule fois par element (flag) pour ne pas s'incrementer a chaque recalcul.\r\n    agrandirTarifs613() {\r\n        $('.PricingAmount').each(function() {\r\n            if (this.dataset.fsBoost613) { return; }\r\n            this.dataset.fsBoost613 = '1';\r\n            const fs = parseFloat(getComputedStyle(this).fontSize);\r\n            if (fs > 0) {\r\n                this.style.setProperty('font-size', (fs + 2) + 'px', 'important');\r\n            }\r\n        });\r\n    }\r\n\r\n    brancherSelectionTarif612() {\r\n        if (window._viaSelTarif612Bound) { return; }\r\n        window._viaSelTarif612Bound = true;\r\n\r\n        $(document).on('click', 'a.via-tarif-lien-612', (e) => {\r\n            e.preventDefault();\r\n\r\n            \/\/ retrouver la classe Tarif7* de la case cliquee (sur le lien, un\r\n            \/\/ parent ou un descendant selon la structure Elementor)\r\n            const $lien = $(e.currentTarget);\r\n            let classe = null;\r\n            const chercher = ($el) => {\r\n                const m = ($el.attr('class') || '').match(\/Tarif7\\w+\/);\r\n                return m ? m[0] : null;\r\n            };\r\n            classe = chercher($lien);\r\n            if (!classe) {\r\n                const $porteur = $lien.closest('[class*=\"Tarif7\"]');\r\n                if ($porteur.length) { classe = chercher($porteur); }\r\n            }\r\n            if (!classe) {\r\n                const $enfant = $lien.find('[class*=\"Tarif7\"]').first();\r\n                if ($enfant.length) { classe = chercher($enfant); }\r\n            }\r\n            if (!classe) { console.warn('[pb612b] classe Tarif7* introuvable'); return; }\r\n\r\n            const tarifEUR = this.state.tarifsCalcules[classe];\r\n            const duree = this.state.dureeJours;\r\n            if (tarifEUR === null || tarifEUR === undefined || !duree) {\r\n                console.warn('[pb612b] tarif ou duree indisponible', classe, tarifEUR, duree);\r\n                return;\r\n            }\r\n\r\n            this.state.tarifSelectionne = classe;   \/\/ pb622 \/ pb628\r\n            try { this._majMsgChoixTarif2202(); } catch (_e2202c) {}   \/\/ pb2202 : masquer des le clic\r\n            \/\/ pb651r : si le clic vient de la synchro A (pas d'un vrai clic user),\r\n            \/\/   ne pas invalider la resa (bouton rouge \/ etape a refaire). La synchro\r\n            \/\/   A tourne sous _sync651EnCours (clic differe) ou _sync651AClic.\r\n            if (!window._sync651AClic && !window._sync651EnCours) {\r\n                window._resaClique644f = false;   \/\/ pb648 : nouveau tarif -> bouton re-actif\r\n                \/\/ pb1348 : pb631 remettait ici l'etape secteur a refaire \u2014 \u00ab nouveau\r\n                \/\/   tarif -> etape 5 a refaire \u00bb. Vrai dans l'ANCIEN ordre, ou le tarif\r\n                \/\/   precedait le secteur. Depuis pb1346 c'est l'inverse : le tarif est\r\n                \/\/   choisi APRES, et il ne peut plus invalider un secteur deja retenu \u2014\r\n                \/\/   pb1347 garantit meme qu'il appartient a la bonne famille.\r\n                \/\/   Laisser cette ligne effacait le secteur juste apres l'avoir choisi\r\n                \/\/   (c'etait deja le symptome de pb1338, ici il deviendrait systematique).\r\n                \/\/   Revert : window._viaPb1348Off = true.\r\n                if (window._viaPb1348Off === true) {\r\n                    window._viaEtape5Ok631 = false;\r\n                }\r\n            }\r\n            this.syncVersResa651();   \/\/ pb651 B : live vers l'item actif\r\n\r\n            const devise = this.state.deviseAffichage;\r\n            const montant = window.VIA_App.convertirDevise(tarifEUR, 'EUR', devise);\r\n            const tjm = montant \/ duree;\r\n            this._tarifMontant644 = montant;   \/\/ pb644 : pour le sous-titre\r\n            this._tarifDevise644 = devise;\r\n\r\n            $('#PopUpTarifsCampagneSelect').text(window.VIA_App.formaterMontant(montant, devise, 0));\r\n            $('#PopUpTarifsTJM').text(window.VIA_App.formaterMontant(tjm, devise, 0));\r\n            console.log('[pb651 DIAG] PopUpTarifsCampagneSelect ->', $('#PopUpTarifsCampagneSelect').length, 'el | texte affiche=', $('#PopUpTarifsCampagneSelect').first().text(), '| resa .CampagneTarifClass=', $('.CampagneTarifClass').first().text());\r\n\r\n            \/\/ pb2171 : PLUS DE FOND SOUS LE TARIF SELECTIONNE (demande JF).\r\n            \/\/   L aplat #ddeeff etait pose ici, et ici seulement : c est\r\n            \/\/   l ecrivain unique, on corrige a la source plutot que de le\r\n            \/\/   recouvrir. Meme geste que pb2152 pour la devise active.\r\n            \/\/   Le blanc reste ECRIT explicitement sur toutes les cases, y\r\n            \/\/   compris la selectionnee : jamais de removeProperty (retirer la\r\n            \/\/   propriete rendrait la main a un ecrivain anterieur, et l aplat\r\n            \/\/   d une selection precedente survivrait au changement de tarif).\r\n            \/\/   Le tarif choisi reste distingue par le vert #56be50 et la\r\n            \/\/   graisse +200 de pb785, inchanges.\r\n            \/\/   Revert : window._viaPb2171Off = true (aplat retabli).\r\n            $('.PricingAmount').each(function() {\r\n                this.style.setProperty('background-color', '#ffffff', 'important');\r\n            });\r\n            const $case = $(`.${classe}`);\r\n            if ($case.length) {\r\n                if (window._viaPb2171Off === true) {\r\n                    $case[0].style.setProperty('background-color', '#ddeeff', 'important');\r\n                } else {\r\n                    $case[0].style.setProperty('background-color', '#ffffff', 'important');\r\n                }\r\n            }\r\n            this._marquerVert785(classe, $case);   \/\/ pb785\r\n\r\n            \/\/ conteneur masque par Elementor -> display force en important\r\n            \/\/ pb1239 : #PopUpTarifsTarifsSelectContainer MASQUE sur desktop\r\n            \/\/   (demande user). Il reste affiche sur mobile, ou il sert toujours.\r\n            \/\/   On agit ici, dans le writer qui le revele : le masquer ailleurs\r\n            \/\/   serait defait au prochain passage de pb612b.\r\n            \/\/   Revert : window._viaPb1239Off = true.\r\n            const $cont = $('#PopUpTarifsTarifsSelectContainer');\r\n            if ($cont.length) {\r\n                \/\/ ========================================================\r\n                \/\/ pb1300 : masquer AUSSI quand le catalogue a quitte le popup.\r\n                \/\/   Constat user : pb1299 loggue \u00ab masqu\u00e9 \u00bb et le conteneur\r\n                \/\/   reste visible \u2014 son style inline vaut display:flex\r\n                \/\/   !important. C'est CETTE ligne qui le repose, et un inline\r\n                \/\/   !important ne se laisse pas battre par un autre inline pose\r\n                \/\/   plus tot : meme situation qu'en pb1268.\r\n                \/\/   pb1239 a eu la bonne intuition \u2014 \u00ab on agit ici, dans le\r\n                \/\/   writer qui le revele : le masquer ailleurs serait defait au\r\n                \/\/   prochain passage \u00bb. Il ne couvrait que le desktop ; on ajoute\r\n                \/\/   le cas ou le catalogue vit hors du popup Tarifs, ou ce\r\n                \/\/   conteneur n'a plus d'objet quelle que soit la taille d'ecran.\r\n                \/\/   Revert : window._viaPb1300Off = true.\r\n                \/\/ ========================================================\r\n                \/\/ pb1302 : suspendu pendant une NOUVELLE reservation \u2014 le bouton\r\n                \/\/   \u00ab Continuer \u00bb vit dans ce conteneur, il doit rester\r\n                \/\/   atteignable tant que la resa n'est pas relancee.\r\n                \/\/ ============================================================\r\n                \/\/ pb1918 : LE POPUP PAYS EST LE MEME CAS QUE L'ACHAT EXPRESS.\r\n                \/\/   Demande user : #PopUpTarifsTarifsSelectContainer n'a plus\r\n                \/\/   d'objet sur mobile dans le popup des sites pays \u2014 comme sur\r\n                \/\/   desktop, cliquer un tarif dans la grille mene directement a\r\n                \/\/   l'etape \u00ab Vos reservations \u00bb.\r\n                \/\/   pb1300 traite deja exactement ce cas, mais sur le drapeau de\r\n                \/\/   l'achat express regie (_viaCatalogueDeplace1264). Le popup pays\r\n                \/\/   porte le sien (pb1905, reponse user Q7) : on l'ajoute ici, a la\r\n                \/\/   source, plutot que de masquer le conteneur ailleurs. pb1239 le\r\n                \/\/   disait deja : \u00ab on agit ici, dans le writer qui le revele ; le\r\n                \/\/   masquer ailleurs serait defait au prochain passage \u00bb \u2014 et un\r\n                \/\/   inline !important pose plus tard ne battrait pas celui-ci.\r\n                \/\/ ============================================================\r\n                \/\/ pb1924 : SUR LES SITES PAYS, JAMAIS AFFICHE (demande user).\r\n                \/\/   pb1918 avait deux limites, que cette demande leve toutes deux :\r\n                \/\/   1. son critere etait _viaPopupPays1905 \u2014 mode=popup ET\r\n                \/\/      layout=plein, donc le seul parcours pb1642. \u00ab Les sites pays \u00bb\r\n                \/\/      couvre aussi l'ancien popup #via-process-iframe, qui n'a que\r\n                \/\/      mode=popup. Le discriminant exact de \u00ab je suis la regie au\r\n                \/\/      service d'un site pays \u00bb est body.via-popup-achat, posee par le\r\n                \/\/      bloc mode=popup de yearbook-media.js et documentee comme telle.\r\n                \/\/      Repli sur l'URL si body n'est pas encore la.\r\n                \/\/   2. la suspension pb1302 passait AVANT lui : pendant une nouvelle\r\n                \/\/      reservation express, le conteneur revenait. \u00ab Jamais \u00bb ne\r\n                \/\/      souffre pas d'exception : le cas sites pays passe donc en\r\n                \/\/      premier et l'emporte sur pb1302. Le bouton \u00ab Continuer \u00bb qui y\r\n                \/\/      vit n'a de toute facon plus d'objet ici \u2014 c'est pb1906 qui l'a\r\n                \/\/      etabli, le clic sur un tarif suffit.\r\n                \/\/   pb1924 REMPLACE le terme de pb1918 au lieu de s'ajouter a lui :\r\n                \/\/   il le contient entierement. Les deux reverts restent honores, l'un\r\n                \/\/   ou l'autre suffit a retablir l'ancien comportement.\r\n                \/\/   Ce bloc reste le SEUL endroit a corriger : le recensement montre\r\n                \/\/   que tous les autres points touchant ce conteneur le MASQUENT\r\n                \/\/   (pb1299, pb710) ; il n'existe qu'un revelateur, la branche else\r\n                \/\/   trois lignes plus bas.\r\n                \/\/   Revert : window._viaPb1924Off = true (ou _viaPb1918Off).\r\n                \/\/ ============================================================\r\n                var _pays1924 = false;\r\n                if (window._viaPb1924Off === true ? false : (window._viaPb1918Off !== true)) {\r\n                    try {\r\n                        _pays1924 = document.body\r\n                            ? document.body.classList.contains('via-popup-achat') : false;\r\n                        if (!_pays1924) {\r\n                            _pays1924 = (new URLSearchParams(window.location.hash.substring(1)\r\n                                || window.location.search).get('mode') === 'popup');\r\n                        }\r\n                    } catch (_e1924) { _pays1924 = false; }\r\n                }\r\n                var _hors1300 = (window._viaPb1300Off === true)\r\n                    ? false\r\n                    : (_pays1924\r\n                        ? true\r\n                        : ((window._viaNouvelleResaExpress1302 === true)\r\n                            ? false\r\n                            : (window._viaCatalogueDeplace1264 === true)));\r\n                if (window._viaSig1924 !== _pays1924) {\r\n                    window._viaSig1924 = _pays1924;\r\n                    console.log('[pb1924] site pays = ' + _pays1924\r\n                        + ' -> #PopUpTarifsTarifsSelectContainer '\r\n                        + (_pays1924 ? 'JAMAIS affich\u00e9 (pb1302 sans effet ici)'\r\n                                     : 'selon les r\u00e8gles pb1239\/pb1300'));\r\n                }\r\n                var _deskMasq1239 = _hors1300\r\n                    ? true\r\n                    : ((window._viaPb1239Off !== true)\r\n                        ? (window.outerWidth >= 1000) : false);\r\n                if (_hors1300) {\r\n                    if (window._viaSig1300 !== 'masque') {\r\n                        window._viaSig1300 = 'masque';\r\n                        console.log('[pb1300] s\u00e9lecteur de tarif masqu\u00e9'\r\n                            + ' (catalogue hors du popup Tarifs)');\r\n                    }\r\n                }\r\n                if (_deskMasq1239) {\r\n                    $cont[0].style.setProperty('display', 'none', 'important');\r\n                } else {\r\n                    $cont[0].style.setProperty('display', 'flex', 'important');\r\n                    $cont.show();\r\n                }\r\n            } else {\r\n                console.warn('[pb612b] #PopUpTarifsTarifsSelectContainer introuvable');\r\n            }\r\n\r\n            console.log('[pb612b] selection', classe, '->', montant, devise, '| TJM', tjm.toFixed(2), '(' + duree + ' j)');\r\n            \/\/ pb651m : pousser le tarif frais vers la resa (item actif), sans passer\r\n            \/\/   par syncVersResa651 (bloque par verrou anti-boucle). En EUR pour l'item.\r\n            try {\r\n                const _p651m = window.VIA_Panier;\r\n                const _ia651m = (_p651m && _p651m.state) ? _p651m.state.itemActif : null;\r\n                if (_ia651m ? typeof _p651m.mettreAJourItem === 'function' : false) {\r\n                    window._sync651AClic = true;   \/\/ couvre le hook pb651d pendant le push\r\n                    _p651m.mettreAJourItem(_ia651m, { tarifHT: tarifEUR, statut: 'valide' });\r\n                    \/\/ pb651p : #Tariftobedisplayed (tarif affiche dans l'Etape 1 resa)\r\n                    try {\r\n                        $('#Tariftobedisplayed').html(window.VIA_App.formaterMontant(montant, devise, 0)).css('color', '#4B689B');\r\n                    } catch (eTTBD651) {}\r\n                    console.log('[pb651m] tarif pousse vers resa:', tarifEUR, 'EUR (item', _ia651m + ')');\r\n                    setTimeout(() => { window._sync651AClic = false; }, 500);\r\n                }\r\n            } catch (e651m) { console.warn('[pb651m]', e651m.message); }\r\n            this.majEtapes631();   \/\/ pb631\r\n            this.evaluerMessage630();   \/\/ pb630b : le tarif vient de changer\r\n            \/\/ pb1036 : idem \u2014 fermeture deleguee au sequenceur.\r\n            if (window._viaPb1036Off === true) { this.fermerSmooth647('tarifs'); }\r\n            \/\/ pb749 : memorise + horodate + POUSSE en direct vers le process.\r\n            this._noter749('format', classe);\r\n            \/\/ pb635c : un tarif Home Page (suffixe HP) n'a pas de secteur dans le\r\n            \/\/   popup -> le bandeau attend \"Homepage\". On le memorise ici ; un\r\n            \/\/   tarif Autres P. (PP) laisse le secteur au choix de l'utilisateur.\r\n            if (classe.endsWith('HP')) {\r\n                this._sync635.secteur = 'Homepage';\r\n            } else if (this._sync635.secteur === 'Homepage') {\r\n                this._sync635.secteur = null;   \/\/ bascule HP -> PP : oublier Homepage\r\n            }\r\n\r\n            \/\/ ====================================================================\r\n            \/\/ pb1058 : COHERENCE entre la PAGE choisie et l'EMPLACEMENT du tarif.\r\n            \/\/   Regles demandees :\r\n            \/\/     (2) page = Homepage + tarif \"Autres Pages\" (PP) -> la page ne\r\n            \/\/         convient plus : on l'efface et on invite a en choisir une autre ;\r\n            \/\/     (3) page = Autres Pages + tarif \"Home Page\" (HP) -> la homepage du\r\n            \/\/         pays est la SEULE page possible : on la selectionne d'office et\r\n            \/\/         le tarif se recalcule.\r\n            \/\/   L'asymetrie est voulue et vient du metier : une homepage est unique\r\n            \/\/   par pays, donc deductible ; \"Autres Pages\" en compte plusieurs, donc\r\n            \/\/   seul l'utilisateur peut trancher.\r\n            \/\/   pb635c, juste au-dessus, connaissait deja la bascule HP <-> PP mais se\r\n            \/\/   contentait de memoriser\/oublier 'Homepage' : rien n'invalidait la page\r\n            \/\/   reellement selectionnee ni ne la rouvrait.\r\n            \/\/   Le type de page vient de sessionStorage.SelectedPageType, ecrit par\r\n            \/\/   tous les chemins de selection (HPType \/ PTType \/ ArtType) \u2014 source\r\n            \/\/   unique, plutot qu'un etat parallele qui pourrait diverger.\r\n            \/\/   Revert : window._viaPb1058Off = true.\r\n            \/\/ ====================================================================\r\n            if (window._viaPb1058Off !== true) {\r\n                try {\r\n                    var _typePage1058 = '';\r\n                    try { _typePage1058 = sessionStorage.getItem('SelectedPageType') || ''; } catch (_eS) {}\r\n                    var _estHP1058 = classe.endsWith('HP');\r\n                    var _pageEstHome1058 = (_typePage1058 === 'HPType');\r\n\r\n                    \/\/ ========================================================\r\n                    \/\/ pb1364 : NE PAS INVALIDER SUR UN SEUL TEMOIN.\r\n                    \/\/   Constat user : apres homepage -> page secteur, le choix d'un\r\n                    \/\/   tarif \u00ab Autres Pages \u00bb invalide la page. Le log montre que\r\n                    \/\/   les deux temoins se contredisent :\r\n                    \/\/     LinkSecteurPage : ...\/Agro-industries   (page secteur)\r\n                    \/\/     SelectedPageType : HPType               (homepage)\r\n                    \/\/     item.secteurDisplayed : Agro-industries (page secteur)\r\n                    \/\/   Deux sources sur trois disent \u00ab page secteur \u00bb. pb1058 ne\r\n                    \/\/   lisait que la troisieme et invalidait un choix valide.\r\n                    \/\/   La regle (2) reste juste \u2014 un tarif PP sur une homepage est\r\n                    \/\/   bien incoherent \u2014 mais elle ne doit se declencher que si\r\n                    \/\/   l'URL confirme le type. Une invalidation efface le travail\r\n                    \/\/   de l'utilisateur : elle exige deux temoins concordants, pas\r\n                    \/\/   un seul, surtout quand on sait qu'il peut etre perime.\r\n                    \/\/   L'URL est comparee a HPPays, l'adresse de la homepage du\r\n                    \/\/   pays \u2014 la seule donnee que le VLP a reellement suivie.\r\n                    \/\/   Si l'URL est absente ou HPPays inconnu, on garde le\r\n                    \/\/   comportement d'avant : on ne desactive pas une regle faute\r\n                    \/\/   de pouvoir la verifier.\r\n                    \/\/   NOTE : la desynchronisation elle-meme reste a corriger a sa\r\n                    \/\/   source \u2014 un writer met LinkSecteurPage a jour sans toucher\r\n                    \/\/   SelectedPageType. Ceci empeche seulement qu'elle detruise\r\n                    \/\/   une selection.\r\n                    \/\/   Revert : window._viaPb1364Off = true.\r\n                    \/\/ ========================================================\r\n                    var _urlConfirme1364 = true;\r\n                    if (window._viaPb1364Off !== true) {\r\n                        try {\r\n                            var _n1364 = function (_u) {\r\n                                return String(_u || '').split('?')[0].split('#')[0]\r\n                                    .replace(\/\\\/+$\/, '').toLowerCase();\r\n                            };\r\n                            var _lien1364 = _n1364(sessionStorage.getItem('LinkSecteurPage'));\r\n                            var _hp1364 = _n1364(sessionStorage.getItem('HPPays'));\r\n                            if (_lien1364 ? !!_hp1364 : false) {\r\n                                _urlConfirme1364 = (_lien1364 === _hp1364);\r\n                                if (!_urlConfirme1364) {\r\n                                    console.log('[pb1364] SelectedPageType dit Homepage mais'\r\n                                        + ' l\\'URL est ' + _lien1364 + ' (homepage = ' + _hp1364\r\n                                        + ') -> page NON invalid\u00e9e');\r\n                                }\r\n                            }\r\n                        } catch (_e1364) {\r\n                            console.warn('[pb1364] comparaison d\\'URL impossible : ' + _e1364.message);\r\n                        }\r\n                    }\r\n                    if ((!_estHP1058 ? _pageEstHome1058 : false) ? _urlConfirme1364 : false) {\r\n                        \/\/ (2) Homepage choisie mais tarif Autres Pages -> page invalidee\r\n                        console.log('[pb1058] tarif \"Autres Pages\" mais page = Homepage'\r\n                            + ' -> page invalid\u00e9e, choisir une autre page');\r\n                        this._invaliderPage1058('Merci de s\u00e9lectionner une autre page');\r\n                    } else if (_estHP1058 ? (_typePage1058 ? !_pageEstHome1058 : false) : false) {\r\n                        \/\/ (3) page Autres Pages mais tarif Home Page -> homepage imposee\r\n                        console.log('[pb1058] tarif \"Home Page\" mais page = ' + _typePage1058\r\n                            + ' -> s\u00e9lection automatique de la Homepage du pays');\r\n                        this._selectionnerHomepage1058();\r\n                    }\r\n                } catch (_e1058) { console.warn('[pb1058]', _e1058.message); }\r\n            }\r\n\r\n            \/\/ pb615 : la liste des secteurs ne concerne que les positions\r\n            \/\/   \"Autres P.\" (suffixe PP des classes Tarif7*, vs HP = Home Page) :\r\n            \/\/   une position Home Page n'a pas de secteur.\r\n            \/\/ ================================================================\r\n            \/\/ pb1054 : NE PAS ROUVRIR l'etape Secteurs apres le Continuer.\r\n            \/\/   Constat user (regie, achat express) : apres \"Continuer la\r\n            \/\/   reservation\", changer le pays de l'annonceur ROUVRE l'etape\r\n            \/\/   secteur, qui devrait rester fermee.\r\n            \/\/   Enchainement : changer le pays relance le calcul de la grille,\r\n            \/\/   celui-ci re-selectionne le tarif courant (pb651o), et cette\r\n            \/\/   re-selection rejoue le present bloc \u2014 dont l'affichage de la liste\r\n            \/\/   des secteurs. Ce bloc est ecrit pour un CHOIX de tarif par\r\n            \/\/   l'utilisateur, qui doit alors preciser son secteur ; il ne\r\n            \/\/   distingue pas ce cas d'un simple rafraichissement.\r\n            \/\/   Une fois le Continuer fait, le secteur est arrete : la resa est\r\n            \/\/   transmise au process, ou l'utilisateur poursuit. Le drapeau\r\n            \/\/   _resaClique644f porte deja cet etat (pb737 s'en sert pour le\r\n            \/\/   recap) \u2014 on le reutilise plutot que d'en inventer un second.\r\n            \/\/   Le titre reste pilote comme avant : seule la REOUVERTURE de la\r\n            \/\/   liste est supprimee, la coherence du libelle est preservee.\r\n            \/\/   Revert : window._viaPb1054Off = true.\r\n            \/\/ ================================================================\r\n            var _transmise1054 = false;\r\n            if (window._viaPb1054Off !== true) {\r\n                \/\/ pb1056 : critere DURABLE (cf commentaire au point de pose).\r\n                \/\/   _resaClique644f, utilise en 1re version, est remis a false par\r\n                \/\/   onFormulaireChange et par pb648 : il ne survit pas a un changement\r\n                \/\/   de pays, precisement le cas a couvrir.\r\n                _transmise1054 = (window._viaContinuerFait1056 === true);\r\n            }\r\n            if (classe.endsWith('PP')) {\r\n                this._titreSecteursTexte708(true);    \/\/ pb708 : tarif Autres P. -> titre visible\r\n                if (_transmise1054) {\r\n                    console.log('[pb1054] r\u00e9sa d\u00e9j\u00e0 transmise -> liste des secteurs NON rouverte');\r\n                } else {\r\n                    this.rendreListeSecteurs615();\r\n                }\r\n            } else {\r\n                \/\/ ================================================================\r\n                \/\/ pb1351 : UN TARIF HOME PAGE NE MASQUE PLUS L'ETAPE SECTEUR.\r\n                \/\/   Constat user (HTML) : #PopupTarifsListeSecteursContainer porte\r\n                \/\/   \u00ab display: none !important \u00bb alors que le sous-titre vert dit\r\n                \/\/   deja \u00ab Homepage \u00bb \u2014 l'etape est faite, mais invisible.\r\n                \/\/   pb708 masquait cette etape des qu'un tarif Home P. etait choisi :\r\n                \/\/   \u00ab Home Page -> pas de secteur \u00bb. C'etait vrai dans l'ANCIEN ordre,\r\n                \/\/   ou le tarif precedait le secteur et le rendait sans objet.\r\n                \/\/   Depuis pb1346 le secteur vient EN PREMIER, et pb1345 a fait de\r\n                \/\/   Homepage un choix de cette etape : la masquer revient a effacer\r\n                \/\/   le choix que l'utilisateur vient de faire, et a lui interdire\r\n                \/\/   d'en changer.\r\n                \/\/   Le titre reste pilote comme avant (libelle coherent) ; seule la\r\n                \/\/   disparition du conteneur est supprimee. La LISTE, elle, reste\r\n                \/\/   repliee : le choix est fait, il n'y a rien a y reselectionner.\r\n                \/\/   Revert : window._viaPb1351Off = true.\r\n                \/\/ ================================================================\r\n                if (window._viaPb1351Off === true) {\r\n                    this._titreSecteursTexte708(false);\r\n                } else {\r\n                    this._titreSecteursTexte708(true);\r\n                }\r\n                this.masquerListeSecteurs615();\r\n            }\r\n        });\r\n    }\r\n\r\n    \/\/ pb613 : grille des pays (rendu viaPop290) dans le conteneur\r\n    \/\/   PopupTarifsListePays \u2014 SITE REGIE UNIQUEMENT (l'API viaRenderPays613\r\n    \/\/   vit dans yearbook-media.js, document parent regie ; dans l'iframe des\r\n    \/\/   sites pays elle n'existe pas et on ne fait rien).\r\n    \/\/   Action au clic : a definir (surlignage + log pour l'instant).\r\n    rendreListePays613() {\r\n        \/\/ pb1910 : discriminant partage, et sortie journalisee (etait un return muet).\r\n        if (!window._viaContexteRegie1910('rendreListePays613')) { return; }\r\n        if (typeof window.viaRenderPays613 !== 'function') {\r\n            console.warn('[pb613] viaRenderPays613 absente (yearbook-media.js pas a jour ?)');\r\n            return;\r\n        }\r\n        const $host = $('#PopupTarifsListePays, .PopupTarifsListePays').first();\r\n        if ($host.length === 0) {\r\n            console.warn('[pb613] conteneur PopupTarifsListePays introuvable');\r\n            return;\r\n        }\r\n        \/\/ pb620 : au choix d'un site pays, masquer le message et relancer le\r\n        \/\/   calcul (la grille etait bloquee tant qu'aucun site n'etait choisi)\r\n        window.viaRenderPays613($host[0], (paysRow) => {\r\n            this.messageSitePays620(false);\r\n            this.onFormulaireChange();\r\n            this.majEtapes631();   \/\/ pb631\r\n            if (paysRow) { this._noter749('pays', paysRow); }   \/\/ pb635b + pb749 (poussee directe)\r\n            \/\/ pb702 : un site pays vient d'etre choisi -> replier l'etape, comme le\r\n            \/\/   font deja dates (pb647), tarifs et secteurs. C'est ce callback, et lui\r\n            \/\/   seul, qui signale la selection : les .v290-row sont rendues par\r\n            \/\/   viaRenderPays613 (yearbook-media.js), il n'y a pas de handler local.\r\n            \/\/   Appel EN DERNIER : fermerSmooth647 anime puis appelle setSection632,\r\n            \/\/   qui relance majEtapes631 -> le sous-titre vert pb644 est calcule sur\r\n            \/\/   l'etat deja a jour (_sync635.pays pose juste au-dessus).\r\n            \/\/   La garde one-shot _autoFerme647 est re-armee si l'utilisateur rouvre\r\n            \/\/   l'etape a la main : un changement de pays la refermera donc aussi.\r\n            this.fermerSmooth647('pays');\r\n        });\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb631 : COULEUR DES TITRES selon l'avancement du process.\r\n    \/\/   Le titre ACTIF est la PREMIERE etape non completee -> unicite garantie\r\n    \/\/   et gestion du remplissage dans le desordre. Tout complete -> aucun actif.\r\n    \/\/   Etat recalcule a chaque evenement, jamais deduit d'un enchainement.\r\n    \/\/ ================================================================\r\n    etapes631() {\r\n        return [\r\n            \/\/ ================================================================\r\n            \/\/ pb1899 : ANNONCEUR APRES LES DATES (demande user, maquette).\r\n            \/\/   Troisieme interversion apres pb1346 et pb1366. L'ordre est\r\n            \/\/   desormais : site pays, secteur, dates, annonceur, tarif,\r\n            \/\/   recapitulatif.\r\n            \/\/   HUIT emplacements suivent cet ordre par INDEX, tous repris dans\r\n            \/\/   ce meme pb :\r\n            \/\/     CINQ listes \u2014 celle-ci, config632(), le tableau rendu par\r\n            \/\/       etapesCompletees631(), _clesOrdre1236 et _msgs737 ;\r\n            \/\/     TROIS lectures positionnelles \u2014 CHAMPS686, _prerequisTarifs707\r\n            \/\/       et la revelation pb1351.\r\n            \/\/   Tout le reste du fichier lit par CLE (config632, _CONT1236,\r\n            \/\/   majSousTitres644, _sequenceur1036, initAccordeons632, pb1238) et\r\n            \/\/   suit donc sans modification. Rien hors de ce fichier ne reference\r\n            \/\/   ces titres : verifie sur yearbook-media.js, Panier_manage.txt,\r\n            \/\/   Entete.txt et le widget HTML_Redactionels.\r\n            \/\/   L'ordre VISUEL vient du template Elementor, repris par l'utilisateur ;\r\n            \/\/   aucune position DOM n'est connue du JS.\r\n            \/\/   PAS DE REVERT : c'est une donnee, pas un comportement. Garder les\r\n            \/\/   deux ordres en parallele demanderait de doubler les huit\r\n            \/\/   emplacements \u2014 c'est precisement pour en avoir manque un que\r\n            \/\/   pb1366 a du corriger _msgs737 apres coup.\r\n            \/\/   CONSEQUENCE TRAITEE AILLEURS : les dates precedent desormais\r\n            \/\/   l'annonceur, d'ou pb1900 (la duree ne depend que des dates) et\r\n            \/\/   pb1901 (le message pb619 n'a plus d'objet).\r\n            \/\/ ================================================================\r\n            \/\/ ================================================================\r\n            \/\/ pb2408 : ANNONCEUR EN ETAPE 1 (demande JF, 12\/09\/2026).\r\n            \/\/   Quatrieme interversion apres pb1346, pb1366 et pb1899. Ordre :\r\n            \/\/     annonceur, site pays, secteur, dates, formats et tarifs, recap.\r\n            \/\/   Les HUIT emplacements positionnels de pb1899 sont repris dans ce\r\n            \/\/   meme pb, plus un neuvieme arrive depuis : _E2047 (pb2047), qui\r\n            \/\/   masquait l'annonceur \u00ab a venir \u00bb par son index 3 \u2014 un premier\r\n            \/\/   pas n'est jamais a venir, l'entree est retiree.\r\n            \/\/   Temoins : '[pb631] etapes' (1er chiffre = annonceur),\r\n            \/\/   '[pb709] prerequis' (libelle de l'ordre), '[pb737] ... index='.\r\n            \/\/   PAS DE REVERT, comme pb1899 : c'est une donnee, doubler neuf\r\n            \/\/   emplacements est exactement ce qui a fait manquer _msgs737 a pb1346.\r\n            \/\/   pb1900 et pb1901 restent valides : la duree ne depend toujours que\r\n            \/\/   des dates, et le sequenceur (premiere etape non faite) signale\r\n            \/\/   deja un annonceur manquant.\r\n            \/\/ ================================================================\r\n            'PopupTarifsAnnonceurTitreTexte',\r\n            'PopupTarifsListePaysTitreTexte',\r\n            'PopupTarifsListeSecteursTitreTexte',\r\n            'PopupTarifsDatesTitreTexte',\r\n            'PopupTarifsTarifsTexte',\r\n            'PopupTarifsRecapTitreTexte'   \/\/ pb736\r\n        ];\r\n    }\r\n\r\n    etapesCompletees631() {\r\n        \/\/ 1. pays de l'annonceur saisi ET reconnu\r\n        const paysLabel = $('input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]').val();\r\n        const annonceurOk = paysLabel\r\n            ? (window.VIA_Countries ? !!window.VIA_Countries.getCountryByLabel(paysLabel) : true)\r\n            : false;\r\n\r\n        \/\/ 2. site pays choisi dans la liste\r\n        const sitePaysOk = this.sitePaysSelectionne620();\r\n\r\n        \/\/ 3. dates valides (la duree est posee dans state quand tout est bon)\r\n        \/* ====================================================================\r\n         * pb1941 : DES DATES INDISPONIBLES NE SONT PAS DES DATES VALIDES.\r\n         *   Demande user : sur les sites pays, en cas d indisponibilite, l etape\r\n         *   Dates doit RESTER active et ouverte.\r\n         *   Je ne la force pas ouverte : ce serait un second decideur face au\r\n         *   sequenceur, et pb1862\/pb1864 ont montre qu aucun delai ne fait\r\n         *   converger deux decideurs en desaccord. On corrige la ou la question se\r\n         *   pose vraiment \u2014 la COMPLETION de l etape.\r\n         *   Une periode deja prise n est pas une saisie valide : tant que le\r\n         *   verrou est pose, l etape n est pas faite, et _sequenceur1036 la garde\r\n         *   ouverte de lui-meme, sans qu on lui dise rien. Le recapitulatif est\r\n         *   bloque par la meme occasion, puisque recapOk depend de datesOk.\r\n         *   Le verrou est pose et leve par le seul controle qui sait \u2014 pb1938 \u2014\r\n         *   et il ne peut concerner que les sites pays : sans emplacement, le\r\n         *   controle ne part pas et le verrou reste faux.\r\n         *   Revert : window._viaPb1941Off = true.\r\n         * ==================================================================== *\/\r\n        \/* pb1942 : LE VERROU EST POUR LES SITES PAYS, ET POUR EUX SEULS.\r\n             Constat user : sur la regie, la carte de reservation affichait \u00ab Merci de\r\n             choisir les dates de campagne pour un tarif \u00bb alors que les dates etaient\r\n             saisies. C est mon verrou qui parlait : il rendait datesOk faux, et le\r\n             libelle de la carte en tirait la conclusion litterale \u2014 dates manquantes.\r\n             La demande etait \u00ab sur les sites pays, conserver l etape Dates ouverte \u00bb.\r\n             Sur la regie, l espace se choisit dans le VLP et Formulaire.txt bloque deja\r\n             la progression a sa maniere (pb1602) : un second verrou y est de trop, et il\r\n             ment sur la raison.\r\n             Discriminant : body.via-popup-achat, celui de \u00ab la regie au service d un\r\n             site pays \u00bb \u2014 le meme que pb1924 et pb1926. *\/\r\n        var _indispo1941 = false;\r\n        if (window._viaPb1941Off !== true) {\r\n            if (window._viaIndispo1941 === true) {\r\n                _indispo1941 = document.body\r\n                    ? document.body.classList.contains('via-popup-achat') : false;\r\n            }\r\n        }\r\n        const datesOk = _indispo1941 ? false : (this.state.dureeJours > 0);\r\n\r\n        \/\/ 4. un tarif clique dans la grille\r\n        const tarifOk = (typeof this.state.tarifSelectionne === 'string');\r\n\r\n        \/\/ 5. \"Secteur\" ou un titre d'article selectionne. Un tarif Home P. n'a pas\r\n        \/\/    de secteur : l'etape est alors consideree comme sans objet (completee).\r\n        const homePage = tarifOk ? !this.state.tarifSelectionne.endsWith('PP') : false;\r\n        \/\/ pb771 : le secteur peut avoir ete choisi DANS LE PROCESS et repercute par la\r\n        \/\/   synchro (sens A). _viaEtape5Ok631 n'est pose que par un clic dans le POPUP :\r\n        \/\/   l'etape passait donc en rouge alors qu'il n'y avait rien a faire, le secteur\r\n        \/\/   etant deja selectionne cote process.\r\n        \/\/   La resa active fait foi : un secteur (ou un article) renseigne sur l'item\r\n        \/\/   complete l'etape, quelle que soit la main qui l'a choisi.\r\n        \/\/   Revert : window._viaPb771Off = true.\r\n        let _secteurResa771 = false;\r\n        if (window._viaPb771Off !== true) {\r\n            try {\r\n                const _s771 = window.VIA_Panier ? (window.VIA_Panier.state || null) : null;\r\n                const _it771 = _s771 ? (_s771.items || []).find(i => i.id === _s771.itemActif) : null;\r\n                if (_it771) {\r\n                    const _sec771 = _it771.selectedPageSecteurDisplayed || _it771.selectedPageSecteur || '';\r\n                    _secteurResa771 = _sec771 ? (_sec771 !== 'Homepage') : false;\r\n                    if (!_secteurResa771 ? !!_it771.articleTitre : false) { _secteurResa771 = true; }\r\n                }\r\n            } catch (_e771) {}\r\n        }\r\n        let secteurOk = homePage ? true : (window._viaEtape5Ok631 === true ? true : _secteurResa771);\r\n        \/\/ ================================================================\r\n        \/\/ pb1338 : UN NOUVEAU TARIF NE DOIT PAS EFFACER UN SECTEUR DEJA CHOISI.\r\n        \/\/   Constat user (achat express) : secteur choisi EN PREMIER, puis\r\n        \/\/   annonceur, site, dates et tarif \u2014 et l'etape secteur reste rouge,\r\n        \/\/   \u00ab Merci de selectionner un theme, secteur ou article \u00bb, liste\r\n        \/\/   redeployee. Le log :\r\n        \/\/     [pb631]  etapes 111100 -> actif: PopupTarifsListeSecteursTitreTexte\r\n        \/\/     [pb737]  recap bloque | etape manquante index=4 | faits=111100\r\n        \/\/   alors que le secteur est bien connu partout ailleurs :\r\n        \/\/     SelectedPageSecteur: Culture\r\n        \/\/     [pb84] DisplayPageWeb redirect | pays=Congo | secteur=Culture\r\n        \/\/   Cause : au clic sur un tarif, _viaEtape5Ok631 est remis a false\r\n        \/\/   (l. ~1849, \u00ab nouveau tarif -> etape 5 a refaire \u00bb). Le repli pb771 sur\r\n        \/\/   la resa active ne rattrape pas : a cet instant l'item n'existe pas\r\n        \/\/   encore (il est cree plus tard dans le log). Les deux signaux tombent\r\n        \/\/   donc en meme temps, et le choix de l'utilisateur disparait.\r\n        \/\/   La remise a zero de l. ~1849 garde son sens \u2014 changer de famille de\r\n        \/\/   tarif peut rendre le secteur sans objet \u2014 mais elle ne doit pas\r\n        \/\/   OUBLIER un secteur toujours connu. secteurRenseigne1337 porte\r\n        \/\/   justement cette memoire (_sync635, pose au clic secteur et\r\n        \/\/   independant du tarif), avec le repli sur la resa.\r\n        \/\/   Purement ADDITIF : on n'ajoute qu'un cas positif, aucune situation\r\n        \/\/   deja valide ne change. La branche Home P. reste prioritaire.\r\n        \/\/   Revert : window._viaPb1338Off = true.\r\n        \/\/ ================================================================\r\n        if (secteurOk ? false : (homePage ? false : (window._viaPb1338Off !== true))) {\r\n            if (this.secteurRenseigne1337()) {\r\n                secteurOk = true;\r\n                if (window._viaSig1338 !== true) {\r\n                    window._viaSig1338 = true;\r\n                    console.log('[pb1338] secteur oubli\u00e9 par le changement de tarif'\r\n                        + ' mais toujours connu -> \u00e9tape 5 conserv\u00e9e');\r\n                }\r\n            }\r\n        }\r\n\r\n        \/\/ pb736 : 6. RECAPITULATIF. Cette etape n'a aucune saisie propre : elle\r\n        \/\/   est completee des que les cinq precedentes le sont. Consequence\r\n        \/\/   voulue du mecanisme pb631 (l'actif est la PREMIERE non completee) :\r\n        \/\/   le titre Recap devient rouge quand tout le reste est fait, et rien\r\n        \/\/   avant. Il n'est donc jamais actif prematurement.\r\n        const recapOk = annonceurOk ? (sitePaysOk ? (datesOk ? (tarifOk ? secteurOk : false) : false) : false) : false;\r\n        \/\/ pb1899 : annonceurOk passe APRES datesOk. Cet ordre EST celui\r\n        \/\/   d'etapes631() et de config632() ; tout le fichier lit ce tableau par\r\n        \/\/   index. recapOk est une conjonction : il ne depend pas de l'ordre.\r\n        \/\/ pb2408 : annonceurOk repasse en tete \u2014 meme ordre que etapes631().\r\n        return [annonceurOk, sitePaysOk, secteurOk, datesOk, tarifOk, recapOk];\r\n    }\r\n\r\n    \/* ========================================================================\r\n     * pb2047 : LES ETAPES \u00ab A VENIR \u00bb NE S'AFFICHENT PLUS \u2014 ACHAT EXPRESS.\r\n     *   Demande JF, SITES PAYS UNIQUEMENT. Meme regle que pb2046 cote process,\r\n     *   mais l'autre modele : ce fichier tient sa PROPRE table d'etapes\r\n     *   (etapes631 \/ config632, six entrees depuis pb1899), son propre calcul\r\n     *   de completion (etapesCompletees631) et, depuis pb1186, les MEMES trois\r\n     *   etats \u2014 #fb5e2a actif, #7f7f7f faite, #525252 a venir. Aucune des deux\r\n     *   tables ne connait l'autre : deux ecrivains, un par modele, et surtout\r\n     *   pas un tronc commun qui ecraserait les cas particuliers (la lecon du\r\n     *   chantier _viaPageChoisie, toujours ouvert).\r\n     *   PORTEE : annonceur, tarifs, recap \u2014 index 3, 4 et 5. Les DATES (index 2)\r\n     *   [pb2408 : annonceur retire, devenu etape 1 ; tarifs 4 et recap 5 inchanges.]\r\n     *   sont exclues sur reponse JF, ainsi que site pays et secteurs.\r\n     *   ARMEMENT (reponse JF) : seulement une fois l'espace EFFECTIVEMENT\r\n     *   reserve, soit le critere de pb1126 \u2014 estReserveEffective ou\r\n     *   statut 'complete' \u2014 et seulement sur les sites pays, discriminant\r\n     *   body.via-popup-achat. Un verrou a sens unique en memoire : la\r\n     *   finalisation deselectionne l'item, et sans verrou tout se remasquerait\r\n     *   au moment ou l'utilisateur en a le plus besoin.\r\n     *   LE RECAP NE DEVIENT JAMAIS ACTIF : recapOk est la conjonction des cinq\r\n     *   autres, donc des qu'il pourrait etre actif il est deja fait. Il passe\r\n     *   de masque a affiche en #7f7f7f, sans etape rouge \u2014 accepte par JF.\r\n     *   Le commentaire de pb736 dit l'inverse ; il est perime.\r\n     *   Le CHEVRON est un ::before de .via632-titre, porte par le titre\r\n     *   lui-meme : masquer le titre le masque avec, rien a viser en plus.\r\n     *   FEUILLE CSS + CLASSE SUR <body> : motif pb1183 \/ pb1917 \/ pb1926.\r\n     *   Revert : window._viaPb2047Off = true.\r\n     * ======================================================================== *\/\r\n    _arme2047() {\r\n        if (window._viaArme2047 === true) { return true; }\r\n        var _pays2047 = document.body\r\n            ? document.body.classList.contains('via-popup-achat') : false;\r\n        if (!_pays2047) { return false; }\r\n        var _res2047 = false;\r\n        try {\r\n            var _pm2047 = window.VIA_Panier;\r\n            var _s2047 = _pm2047 ? (_pm2047.state || null) : null;\r\n            var _it2047 = _s2047\r\n                ? (_s2047.items || []).find(function (_i) { return _i.id === _s2047.itemActif; })\r\n                : null;\r\n            if (_it2047) {\r\n                _res2047 = (_it2047.estReserveEffective === true)\r\n                    ? true : (_it2047.statut === 'complete');\r\n            }\r\n        } catch (_e2047a) { _res2047 = false; }\r\n        if (_res2047) {\r\n            window._viaArme2047 = true;\r\n            console.log('[pb2047] espace effectivement r\u00e9serv\u00e9 -> masquage arm\u00e9 (verrou pos\u00e9)');\r\n        }\r\n        return _res2047;\r\n    }\r\n\r\n    _masqueAvenir2047(faits, actif) {\r\n        if (window._viaPb2047Off === true) { return; }\r\n        try {\r\n            \/\/ pb2408 : l'entree 'annonceur' (index 3) est RETIREE \u2014 l'annonceur est\r\n            \/\/   l'etape 1, active des l'ouverture, elle n'est jamais \u00ab a venir \u00bb.\r\n            \/\/   tarifs et recap gardent leurs index 4 et 5, inchanges par pb2408.\r\n            var _E2047 = [\r\n                { cle: 'tarifs',    i: 4, cls: 'via-m2047-tar',\r\n                  sel: ['#PopupTarifsTarifsTexte', '.PopupTarifsTarifsTexte',\r\n                        '.TarifsConteneur'] },\r\n                { cle: 'recap',     i: 5, cls: 'via-m2047-rec',\r\n                  sel: ['#PopupTarifsRecapTitreTexte', '.PopupTarifsRecapTitreTexte',\r\n                        '#PopupTarifsRecapContainer', '.PopupTarifsRecapContainer'] }\r\n            ];\r\n            \/* ================================================================\r\n             * pb2048 : LE \u00ab VOS RESERVATIONS \u00bb RESTE EN PLACE PARCE QU IL N EST\r\n             *   PAS CELUI QUE JE MASQUAIS.\r\n             *   Constat JF (capture) : le titre reste affiche alors que\r\n             *   pb2047 journalise \u00ab recap=MASQUEE \u00bb. Les deux sont exacts : le\r\n             *   noeud rendu appartient a l AUTRE modele.\r\n             *   DEUX SIGNAUX CONCORDANTS, aucun n est une deduction :\r\n             *   1. le CHEVRON s affiche. Il est un ::before de .via632-titre,\r\n             *      porte par le titre express LUI-MEME (initAccordeons632) : si\r\n             *      ce titre etait masque, aucun chevron ne pourrait etre trace.\r\n             *   2. sa COULEUR est le bleu, pas le #525252 \u00ab a venir \u00bb. pb1203b\r\n             *      l ecrit : le titre du recapitulatif garde le bleu impose par\r\n             *      le watchdog pb294, \u00ab la seule etape qui ne suit pas la regle\r\n             *      des trois etats \u00bb. C est la signature du recap du PROCESS.\r\n             *   Sur un site pays, pb1917 masque les cinq etapes AMONT du process\r\n             *   mais laisse #ColonneDroite intacte \u2014 les etapes de commande y\r\n             *   restent celles du process. Le recapitulatif visible est donc\r\n             *   #EtapeRecapitulatif, que pb2046 exclut deliberement (pb1213b :\r\n             *   \u00ab c est depuis lui qu on clique sur Finaliser \u00bb) et que pb2047\r\n             *   ne connait pas.\r\n             *   POURQUOI ICI ET PAS DANS pb2046 : son critere \u00ab faite ou active \u00bb\r\n             *   ne peut pas le reveler. faits.recapitulatif vaut FinaliserStep\r\n             *   === 'Yes', et le log de JF montre la cible passant directement de\r\n             *   processAnnonceur a references \u2014 'recapitulatif' n est JAMAIS la\r\n             *   cible. Le masquer sur ce critere l aurait rendu inatteignable,\r\n             *   et le bouton Finaliser avec lui : exactement le piege pb1213b.\r\n             *   Sur un site pays, l amont du recapitulatif n est pas le process,\r\n             *   c est l ACHAT EXPRESS. Il devient donc atteignable quand les cinq\r\n             *   etapes express sont faites \u2014 c est-a-dire faits[5], recapOk, la\r\n             *   conjonction meme. Il suit donc l index 5, comme le recap express :\r\n             *   les deux apparaissent au meme instant, celui ou \u00ab Continuer la\r\n             *   reservation \u00bb devient disponible.\r\n             *   L armement de pb2047 le borne aux sites pays : sur la regie le\r\n             *   predicat est faux, les classes sont retirees, rien ne change.\r\n             *   Revert : window._viaPb2048Off = true (cette entree seule).\r\n             * ================================================================ *\/\r\n            if (window._viaPb2048Off !== true) {\r\n                _E2047.push({ cle: 'recapProcess', i: 5, cls: 'via-m2047-recp',\r\n                    sel: ['#EtapeRecapitulatif', '#RecapitulatifVosCommandesContainer',\r\n                          '.RecapitulatifVosCommandestitre',\r\n                          '#RecapitulatifVosCommandestitreTexte',\r\n                          '#RecapitulatifVosCommandestitreContainer',\r\n                          '#RecapitulatifVosCommandesIconeUp',\r\n                          '#RecapitulatifVosCommandesIconeDown'] });\r\n            }\r\n            if (!document.getElementById('via-masque-avenir-2047')) {\r\n                var _regles2047 = [];\r\n                _E2047.forEach(function (_e) {\r\n                    _e.sel.forEach(function (_s) {\r\n                        _regles2047.push('body.' + _e.cls + ' ' + _s);\r\n                    });\r\n                });\r\n                var _st2047 = document.createElement('style');\r\n                _st2047.id = 'via-masque-avenir-2047';\r\n                _st2047.textContent = _regles2047.join(',\\n') + ' { display: none !important; }';\r\n                document.head.appendChild(_st2047);\r\n                console.log('[pb2047] feuille de masquage inject\u00e9e (' + _regles2047.length\r\n                    + ' s\u00e9lecteurs)');\r\n            }\r\n            if (!document.body) { return; }\r\n            var _ok2047 = this._arme2047();\r\n            if (!_ok2047) {\r\n                \/* pb2034 : la sortie n'est pas muette \u2014 elle nomme ses discriminants,\r\n                   sinon \u00ab rien ne se passe \u00bb coute un aller-retour pour rien. *\/\r\n                _E2047.forEach(function (_e) { document.body.classList.remove(_e.cls); });\r\n                if (window._viaSig2047 !== 'nonarme') {\r\n                    window._viaSig2047 = 'nonarme';\r\n                    console.log('[pb2047] non arm\u00e9 -> aucune \u00e9tape masqu\u00e9e'\r\n                        + ' | via-popup-achat=' + (document.body\r\n                            ? document.body.classList.contains('via-popup-achat') : false)\r\n                        + ' | espace r\u00e9serv\u00e9=false');\r\n                }\r\n                return;\r\n            }\r\n            if (!window._viaAcquis2047) { window._viaAcquis2047 = {}; }\r\n            var _etat2047 = [];\r\n            for (var _k2047 = 0; _k2047 < _E2047.length; _k2047++) {\r\n                var _e2047 = _E2047[_k2047];\r\n                var _fait2047 = faits ? !!faits[_e2047.i] : false;\r\n                var _act2047 = (actif === _e2047.i);\r\n                var _acq2047 = (window._viaAcquis2047[_e2047.cle] === true);\r\n                var _vu2047 = _fait2047 ? true : (_act2047 ? true : _acq2047);\r\n                if (_vu2047) { window._viaAcquis2047[_e2047.cle] = true; }\r\n                document.body.classList[_vu2047 ? 'remove' : 'add'](_e2047.cls);\r\n                _etat2047.push(_e2047.cle + '='\r\n                    + (_vu2047\r\n                        ? (_fait2047 ? 'affich\u00e9e\/faite'\r\n                                     : (_act2047 ? 'affich\u00e9e\/active' : 'affich\u00e9e\/acquise'))\r\n                        : 'MASQU\u00c9E'));\r\n            }\r\n            var _sg2047 = _etat2047.join(' | ');\r\n            if (window._viaSig2047 !== _sg2047) {\r\n                window._viaSig2047 = _sg2047;\r\n                console.log('[pb2047] arm\u00e9 | actif=' + ((actif === -1) ? 'aucun' : actif)\r\n                    + ' | ' + _sg2047);\r\n            }\r\n        } catch (_e2047b) { console.warn('[pb2047] ' + _e2047b.message); }\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb2202 : #MsgChoixTarifContainer \u2014 VISIBLE TANT QU AUCUN TARIF N EST\r\n    \/\/   CHOISI, MASQUE SINON (demande JF, achat express, etape format et\r\n    \/\/   tarif).\r\n    \/\/   L element est nouveau (aucune occurrence dans le corpus) ; son\r\n    \/\/   absence est journalisee une fois, jamais subie.\r\n    \/\/   Un seul ecrivain, appele depuis majEtapes631 \u2014 qui repasse a chaque\r\n    \/\/   changement d etat, dont la selection et les trois desselections du\r\n    \/\/   tarif (l.3951, 5554, 7512) \u2014 et depuis _selectionnerTarif651 pour\r\n    \/\/   le retour immediat au clic, sans attendre la passe suivante.\r\n    \/\/   Temoin : state.tarifSelectionne, le meme que lit tarifOk (l.3220).\r\n    \/\/   display inline !important : Elementor peut porter une classe\r\n    \/\/   elementor-hidden-* sur ce conteneur, qu on leve aussi.\r\n    \/\/   Revert : window._viaPb2202Off = true (element laisse tel quel).\r\n    \/\/ ================================================================\r\n    _majMsgChoixTarif2202() {\r\n        try {\r\n            if (window._viaPb2202Off === true) { return; }\r\n            var _els = document.querySelectorAll('[id=\"MsgChoixTarifContainer\"]');\r\n            if (_els.length === 0) {\r\n                if (window._viaSig2202 !== 'absent') {\r\n                    window._viaSig2202 = 'absent';\r\n                    console.warn('[pb2202] #MsgChoixTarifContainer introuvable');\r\n                }\r\n                return;\r\n            }\r\n            var _choisi = (typeof this.state.tarifSelectionne === 'string');\r\n            for (var _i = 0; _i < _els.length; _i++) {\r\n                _els[_i].classList.remove('elementor-hidden-desktop',\r\n                    'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                _els[_i].style.setProperty('display', _choisi ? 'none' : 'block', 'important');\r\n            }\r\n            var _etat = _choisi ? 'masque (tarif ' + this.state.tarifSelectionne + ')' : 'AFFICHE (aucun tarif)';\r\n            if (window._viaSig2202 !== _etat) {\r\n                window._viaSig2202 = _etat;\r\n                console.log('[pb2202] MsgChoixTarifContainer -> ' + _etat + ' | x' + _els.length);\r\n            }\r\n        } catch (_e2202) { console.warn('[pb2202] ' + _e2202.message); }\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb2203 : le lien CGV du texte sous la grille ouvre les mentions\r\n    \/\/   legales du PARENT (#fp-popup-via-footer-mentions-281).\r\n    \/\/   Le popup est construit par le handler .UrlMentionsLegales de\r\n    \/\/   Entete_VLP ; ici on se contente de le DEMANDER par postMessage \u2014\r\n    \/\/   l iframe est cross-origin, aucun clic ne traverse.\r\n    \/\/   Delegation sur document : le texte est reconstruit a chaque\r\n    \/\/   affichage de la grille, un binding direct ne survivrait pas.\r\n    \/\/   pb2241 : le commentaire d origine annoncait viser \u00ab .TarifsConditions,\r\n    \/\/   #TarifsConditions \u00bb. Ce selecteur n existe NULLE PART \u2014 ni dans le DOM\r\n    \/\/   fourni par JF, ni ailleurs dans le corpus. pb2203 ne le testait pas, ce\r\n    \/\/   qui rendait l invention sans consequence ; pb2240 en a fait une condition\r\n    \/\/   reelle et a tout bloque. La vraie ancre est #TarifsPublicitaireListe.\r\n    \/\/   Pose une seule fois. Revert : window._viaPb2203Off = true.\r\n    \/\/ ================================================================\r\n    _armerLienCGV2203() {\r\n        if (window._viaLienCGV2203) { return; }\r\n        window._viaLienCGV2203 = true;\r\n        try {\r\n            document.addEventListener('click', function (_ev) {\r\n                try {\r\n                    if (window._viaPb2203Off === true) { return; }\r\n                    var _a = _ev.target ? (_ev.target.closest ? _ev.target.closest('a') : null) : null;\r\n                    if (!_a) { return; }\r\n                    if ((_a.textContent || '').trim().toUpperCase() !== 'CGV') { return; }\r\n                    \/* ============================================================\r\n                     * pb2240 : LE CLIC OUVRE LE POPUP CGV LOCAL, PAS LES MENTIONS\r\n                     *          DU PARENT.\r\n                     *   Point 6 du cahier des charges : la delegation est RESTREINTE\r\n                     *   au bloc des conditions de la grille. pb2203 disait viser ce\r\n                     *   bloc dans son commentaire mais ne le verifiait pas dans son\r\n                     *   code : elle attrapait tout <a> dont le texte vaut \u00ab CGV \u00bb,\r\n                     *   y compris le \u00ab Mentions legales & CGV \u00bb du footer. Le\r\n                     *   commentaire et le code disent desormais la meme chose.\r\n                     *   Point 1 : la cible est locale \u2014 grille et yearbook-media.js\r\n                     *   partagent le meme document \u2014 donc appel direct, sans\r\n                     *   postMessage. Le repli sur l ancien message est conserve : si\r\n                     *   yearbook-media.js n est pas encore en pb2240, le lien continue\r\n                     *   d ouvrir les mentions au lieu de ne rien faire.\r\n                     * ============================================================ *\/\r\n                    \/* pb2241 : ANCRE MESUREE, PAS SUPPOSEE.\r\n                       Le HTML de JF montre le lien CGV dans\r\n                         #TarifsPublicitaireListe > \u2026 > .TarifsConteneur.GrilleTarifaire\r\n                       et le selecteur que pb2240 employait \u2014 .TarifsConditions \u2014\r\n                       n existe dans aucun des deux. On retient l id du bloc tarifs,\r\n                       qui est un identifiant stable et deja utilise seize fois dans\r\n                       ce fichier ; le lien \u00ab Mentions legales & CGV \u00bb du footer est\r\n                       en dehors, donc epargne, ce qui etait tout l objet du point 6.\r\n                       En cas de refus, la chaine d ancetres est journalisee : si la\r\n                       structure change, elle se nommera d elle-meme au lieu de me\r\n                       faire redemander le HTML. *\/\r\n                    \/* on teste les ancres UNE PAR UNE plutot qu en liste : le log peut\r\n                       alors nommer CELLE qui a repondu, au lieu d afficher la premiere\r\n                       classe du noeud \u2014 qui serait une classe elementor-, precisement\r\n                       celle sur laquelle le carnet interdit de s appuyer. *\/\r\n                    var _ancres2241 = ['#TarifsPublicitaireListe', '.TarifsConteneur', '.GrilleTarifaire'];\r\n                    var _sel2241 = _ancres2241.join(', ');\r\n                    var _bloc2240 = null, _quelle2241 = '';\r\n                    for (var _j2241 = 0; _j2241 < _ancres2241.length; _j2241++) {\r\n                        if (_bloc2240) { break; }\r\n                        if (!_a.closest) { break; }\r\n                        _bloc2240 = _a.closest(_ancres2241[_j2241]);\r\n                        if (_bloc2240) { _quelle2241 = _ancres2241[_j2241]; }\r\n                    }\r\n                    if (!_bloc2240) {\r\n                        var _chaine2241 = [];\r\n                        var _n2241 = _a;\r\n                        for (var _k2241 = 0; _k2241 < 6; _k2241++) {\r\n                            if (!_n2241) { break; }\r\n                            if (_n2241.nodeType !== 1) { break; }\r\n                            _chaine2241.push((_n2241.tagName || '?')\r\n                                + (_n2241.id ? ('#' + _n2241.id) : '')\r\n                                + (_n2241.className\r\n                                    ? ('.' + String(_n2241.className).trim().split(\/\\s+\/).join('.'))\r\n                                    : ''));\r\n                            _n2241 = _n2241.parentElement;\r\n                        }\r\n                        console.log('[pb2241] clic CGV hors du bloc tarifs -> lien natif'\r\n                            + ' | cherche : ' + _sel2241\r\n                            + ' | ancetres : ' + _chaine2241.join(' < '));\r\n                        return;\r\n                    }\r\n                    _ev.preventDefault();\r\n                    _ev.stopPropagation();\r\n                    if (typeof window._viaOuvrirCGV2240 === 'function') {\r\n                        window._viaOuvrirCGV2240();\r\n                        console.log('[pb2241] clic CGV, ancre ' + _quelle2241\r\n                            + ' -> popup CGV local');\r\n                    } else {\r\n                        window.parent.postMessage({ type: 'viaOuvrirCGV2203' }, '*');\r\n                        console.warn('[pb2240] _viaOuvrirCGV2240 absent (yearbook-media.js pas en pb2240)'\r\n                            + ' -> repli pb2203 : mentions du parent');\r\n                    }\r\n                } catch (_ec) { console.warn('[pb2203] ' + _ec.message); }\r\n            }, true);\r\n            console.log('[pb2203] lien CGV arme (delegation document)');\r\n        } catch (_e2203) { console.warn('[pb2203] ' + _e2203.message); }\r\n    }\r\n\r\n    majEtapes631() {\r\n        try { this._armerLienCGV2203(); } catch (_e2203b) {}       \/\/ pb2203\r\n        try { this._majMsgChoixTarif2202(); } catch (_e2202b) {}   \/\/ pb2202\r\n        try { this._feuilleExpress1922(); } catch (_e1922b) {}      \/\/ pb1922\r\n        try { this._feuilleMobilePays1925(); } catch (_e1925b) {}   \/\/ pb1925\r\n        try { this._echelleAnnonceur1920(); } catch (_e1920b) {}    \/\/ pb1920\r\n        try { this._taillePhrases1237(); } catch (_e1237b) {}   \/\/ pb1237\r\n        try { this._tailleItems1240(); } catch (_e1240b) {}     \/\/ pb1240\r\n        \/\/ pb1240c : VEILLE. Constat user : en revenant sur la grille tarifaire, les\r\n        \/\/   montants retrouvent leur taille d'origine.\r\n        \/\/   Cause : la grille est RECONSTRUITE a chaque affichage \u2014 les nouveaux\r\n        \/\/   .PricingAmount n'ont ni l'attribut de base ni la taille posee, et\r\n        \/\/   majEtapes631 n'est pas rejoue a ce moment-la.\r\n        \/\/   Une veille legere rattrape les elements neufs. Elle ne fait rien sur\r\n        \/\/   ceux deja traites : le seuil de 0.1px les ecarte.\r\n        if (!window._viaVeille1240) {\r\n            window._viaVeille1240 = true;\r\n            var _self1240c = this;\r\n            setInterval(function () {\r\n                try { _self1240c._tailleItems1240(); } catch (_e) {}\r\n            }, 600);\r\n        }\r\n        const ids = this.etapes631();\r\n        const faits = this.etapesCompletees631();\r\n        \/\/ ================================================================\r\n        \/\/ pb1351 : L'ETAPE SECTEUR DOIT ETRE ATTEIGNABLE SANS TARIF PREALABLE.\r\n        \/\/   Le conteneur #PopupTarifsListeSecteursContainer est masque par\r\n        \/\/   defaut cote Elementor, et n'etait revele qu'a UN endroit : le choix\r\n        \/\/   d'un tarif \u00ab Autres P. \u00bb (~l.2037). C'etait coherent tant que le\r\n        \/\/   tarif precedait le secteur. Depuis pb1346 l'ordre est inverse \u2014 le\r\n        \/\/   secteur est l'etape 4, le tarif la 5 \u2014 et plus rien ne revelait\r\n        \/\/   l'etape : elle restait invisible jusqu'a un tarif qu'on ne pouvait\r\n        \/\/   plus choisir avant elle.\r\n        \/\/   On la revele donc des que les TROIS premieres sont faites\r\n        \/\/   (annonceur, site pays, dates), et on rend la liste dans la foulee,\r\n        \/\/   sinon l'etape serait visible mais vide.\r\n        \/\/   Ce bloc ne fait que REVELER : le masquage reste a pb710\r\n        \/\/   (reinitialisation). Test sur le display courant -> une seule pose,\r\n        \/\/   bien que majEtapes631 soit appelee a chaque evenement.\r\n        \/\/   Revert : window._viaPb1351Off = true.\r\n        \/\/ ================================================================\r\n        if (window._viaPb1351Off !== true) {\r\n            try {\r\n                \/\/ pb1899 : l'etape secteur est passee 2e. Une seule etape la\r\n                \/\/   precede desormais \u2014 le SITE PAYS, index 0. La regle est\r\n                \/\/   inchangee depuis pb1351 : reveler des que tout ce qui precede\r\n                \/\/   est fait. Garder faits[1] l'aurait revelee une fois deja\r\n                \/\/   faite, puisque l'index 1 EST le secteur.\r\n                \/\/   Le conteneur reste masque par defaut cote Elementor (reponse\r\n                \/\/   user) : ce bloc garde donc tout son objet.\r\n                \/\/ pb2408 : le secteur est 3e ; le precedent l'ANNONCEUR (0) et\r\n                \/\/   le SITE PAYS (1). Regle inchangee : tout ce qui precede est fait.\r\n                var _pret1351 = (faits[0] === true) ? (faits[1] === true) : false;\r\n                if (_pret1351) {\r\n                    var $c1351 = this._elt618('PopupTarifsListeSecteursContainer');\r\n                    if ($c1351.length ? ($c1351[0].style.display === 'none') : false) {\r\n                        this._titreSecteursTexte708(true);\r\n                        this.rendreListeSecteurs615();\r\n                        console.log('[pb1351] \u00e9tape secteur r\u00e9v\u00e9l\u00e9e (annonceur + site pays faits, pb2408)');\r\n                    }\r\n                }\r\n            } catch (_e1351) {\r\n                console.warn('[pb1351] r\u00e9v\u00e9lation impossible : ' + _e1351.message);\r\n            }\r\n        }\r\n        const actif = faits.indexOf(false);   \/\/ -1 si tout est complete -> aucun actif\r\n        \/\/ pb682 : gris des titres NON actifs ajuste #999999 -> #808080. Les chevrons\r\n        \/\/   suivent automatiquement : leur ::before (pb632) est trace en currentColor,\r\n        \/\/   donc il herite de la couleur posee ici sur le titre.\r\n        \/\/ ====================================================================\r\n        \/\/ pb1186 : MEMES TROIS ETATS QUE LE PROCESS D'ACHAT (demande user).\r\n        \/\/   Jusqu'ici deux couleurs seulement : actif en rouge, tout le reste en\r\n        \/\/   gris #808080 \u2014 sans distinguer une etape DEJA FAITE d'une etape a\r\n        \/\/   venir. Le process, lui, les separe depuis pb1177b.\r\n        \/\/   Les deux interfaces montrent le meme parcours : elles doivent le\r\n        \/\/   representer pareil.\r\n        \/\/     active    -> #fb5e2a, taille standard\r\n        \/\/     completee -> #7f7f7f, -1px\r\n        \/\/     a venir   -> #525252, -0.5px\r\n        \/\/   Les tailles sont posees ici meme, sur la base memorisee dans\r\n        \/\/   data-viafs1186 : l'operation repart toujours de cette base, donc elle\r\n        \/\/   ne cumule pas, quel que soit le nombre de passages (lecon pb913).\r\n        \/\/   L'attribut plutot qu'une propriete JS : il survit a cloneNode.\r\n        \/\/   Revert : window._viaPb1186Off = true (deux couleurs, tailles libres).\r\n        \/\/ ====================================================================\r\n        const GRIS = '#808080';\r\n        const ACTIF = '#fb5e2a';   \/\/ pb631 : titre actif en rouge (pb643+)\r\n        const FAIT1186 = '#7f7f7f';\r\n        const AVENIR1186 = '#525252';\r\n        \/\/ pb686 : champs de saisie rattaches a chaque etape (index dans etapes631()).\r\n        \/\/   pb1899 : les dates passent de l'index 3 a l'index 2, l'annonceur de\r\n        \/\/   l'index 0 a l'index 3 \u2014 ils echangent leurs places. Sans cette\r\n        \/\/   permutation, la mise en forme des champs de dates aurait suivi l'etape\r\n        \/\/   SITE PAYS et celle du champ annonceur l'etape DATES : deux etapes sans\r\n        \/\/   champ texte pour la premiere, donc un decalage silencieux.\r\n        \/\/   Les etapes 0, 1 et 4 (liste pays, secteurs, tarifs) n'ont pas de champ.\r\n        \/\/   pb2408 : annonceur a l'index 0, dates a l'index 3 (pays 1, secteurs 2,\r\n        \/\/   tarifs 4 sans champ).\r\n        const CHAMPS686 = {\r\n            0: 'input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]',\r\n            3: '#form-field-PopupTarifsDebutCampagne, #form-field-PopupTarifsFinCampagne'\r\n        };\r\n        ids.forEach((id, i) => {\r\n            const $el = $('#' + id + ', .' + id).first();\r\n            if ($el.length === 0) { return; }\r\n            let couleur = (i === actif) ? ACTIF : GRIS;\r\n            \/\/ ================================================================\r\n            \/\/ pb1236 : +10px de marge haute et basse sur la SECTION de l'etape\r\n            \/\/   active (demande user, aligne sur pb1234 cote process).\r\n            \/\/   Les selecteurs de section existent deja dans ce fichier \u2014\r\n            \/\/   sections632() les declare pour le pliage\/depliage. On les reutilise\r\n            \/\/   plutot que d'en tenir une seconde liste.\r\n            \/\/   Base memorisee dans data-viamg1236 a la premiere rencontre, puis\r\n            \/\/   toujours relue depuis elle : le delta ne se cumule jamais.\r\n            \/\/   Revert : window._viaPb1236Off = true.\r\n            \/\/ ================================================================\r\n            \/\/ ================================================================\r\n            \/\/ pb1238 : #PopupTarifsDureeMinimaleTexte en ROUGE quand l'etape DATES\r\n            \/\/   est active (demande user).\r\n            \/\/   Meme principe que pb1223 cote process : ce texte accompagne son\r\n            \/\/   titre, les deux changent d'etat ensemble.\r\n            \/\/   Couleur posee EN INLINE sur l'element et ses descendants \u2014 une\r\n            \/\/   feuille se ferait battre par les regles Elementor.\r\n            \/\/   L'etape Dates est la 3e de etapes631 ; on la reconnait par sa cle\r\n            \/\/   dans sections632, pas par son rang, pour ne pas dependre de l'ordre.\r\n            \/\/   Revert : window._viaPb1238Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1238Off !== true) {\r\n                try {\r\n                    var _dm1238 = document.getElementById('PopupTarifsDureeMinimaleTexte')\r\n                        || document.querySelector('.PopupTarifsDureeMinimaleTexte');\r\n                    if (_dm1238) {\r\n                        var _estDates1238 = (id === 'PopupTarifsDatesTitreTexte');\r\n                        var _actifDates1238 = _estDates1238 ? (i === actif) : false;\r\n                        if (_estDates1238) {\r\n                            $(_dm1238).find('*').addBack().each(function () {\r\n                                if (_actifDates1238) {\r\n                                    this.style.setProperty('color', '#fb5e2a', 'important');\r\n                                } else {\r\n                                    this.style.removeProperty('color');\r\n                                }\r\n                            });\r\n                        }\r\n                    }\r\n                } catch (_e1238) {}\r\n            }\r\n\r\n            if (window._viaPb1236Off !== true) {\r\n                try {\r\n                    \/\/ ============================================================\r\n                    \/\/ pb1236c : LES BONS CONTENEURS, donnes par l'utilisateur.\r\n                    \/\/   Mes deux tentatives visaient les selecteurs de sections632\r\n                    \/\/   (#PopupTarifsAnnonceur, .PopupTarifsDates...) \u2014 ceux du\r\n                    \/\/   pliage\/depliage, pas les conteneurs d'etape. La marge etait\r\n                    \/\/   donc posee sur des elements qui ne portent pas l'espacement.\r\n                    \/\/   Les conteneurs reels sont ceux-ci. Le recapitulatif n'en a pas\r\n                    \/\/   dans la liste fournie : il garde ses marges.\r\n                    \/\/   Base memorisee dans data-viamg1236, relue a chaque passage :\r\n                    \/\/   aucun cumul.\r\n                    \/\/   Revert : window._viaPb1236Off = true.\r\n                    \/\/ ============================================================\r\n                    var _CONT1236 = [\r\n                        { cle: 'annonceur', sel: '#PopupTarifsEtapeAnnonceurContainer' },\r\n                        { cle: 'pays',      sel: '#PopupTarifsListePaysContainer' },\r\n                        { cle: 'dates',     sel: '#PopupTarifsDatesCampagnesContainer' },\r\n                        { cle: 'tarifs',    sel: '#TarifsPublicitaireListe' },\r\n                        { cle: 'secteurs',  sel: '#PopupTarifsListeSecteursContainer' }\r\n                    ];\r\n                    \/\/ pb1347 : QUATRIEME liste indexee par l'ordre des etapes \u2014 elle est\r\n                    \/\/   lue par _clesOrdre1236[actif], ou 'actif' est un index dans\r\n                    \/\/   etapes631(). Sans cette permutation, pb1236 aurait pose ses\r\n                    \/\/   marges sur le conteneur voisin.\r\n                    \/\/   (_CONT1236 juste au-dessus est indexe par CLE : il ne bouge\r\n                    \/\/   pas. Le forEach de pb846 ne depend pas de l'ordre non plus :\r\n                    \/\/   il replie tout, sans index.)\r\n                    \/\/ pb1899 : 'annonceur' passe de l'index 0 a l'index 3.\r\n                    \/\/ pb2408 : 'annonceur' revient a l'index 0.\r\n                    var _clesOrdre1236 = ['annonceur', 'pays', 'secteurs', 'dates', 'tarifs', 'recap'];\r\n                    var _cleAct1236 = (actif >= 0) ? _clesOrdre1236[actif] : null;\r\n                    _CONT1236.forEach(function (_c1236) {\r\n                        var _el1236 = document.querySelector(_c1236.sel);\r\n                        if (!_el1236) { return; }\r\n                        var _bt = _el1236.getAttribute('data-viamgt1236');\r\n                        var _bb = _el1236.getAttribute('data-viamgb1236');\r\n                        if (_bt === null) {\r\n                            var _cs = window.getComputedStyle(_el1236);\r\n                            _bt = String(parseFloat(_cs.marginTop) || 0);\r\n                            _bb = String(parseFloat(_cs.marginBottom) || 0);\r\n                            _el1236.setAttribute('data-viamgt1236', _bt);\r\n                            _el1236.setAttribute('data-viamgb1236', _bb);\r\n                        }\r\n                        var _d1236 = (_c1236.cle === _cleAct1236) ? 10 : 0;\r\n                        _el1236.style.setProperty('margin-top',\r\n                            (parseFloat(_bt) + _d1236) + 'px', 'important');\r\n                        _el1236.style.setProperty('margin-bottom',\r\n                            (parseFloat(_bb) + _d1236) + 'px', 'important');\r\n                    });\r\n                } catch (_e1236) {}\r\n            }\r\n            let _delta1186 = null;\r\n            if (window._viaPb1186Off !== true) {\r\n                \/\/ pb1235 : l'etape ACTIVE gagne 1px (demande user, aligne sur pb1233\r\n                \/\/   cote process). Les deux autres etats sont inchanges.\r\n                if (i === actif) { couleur = ACTIF; _delta1186 = 1; }\r\n                else if (faits[i]) { couleur = FAIT1186; _delta1186 = -1; }\r\n                else { couleur = AVENIR1186; _delta1186 = -0.5; }\r\n                \/\/ ============================================================\r\n                \/\/ pb1186b : ECRIRE LA TAILLE SUR LA RACINE SEULEMENT.\r\n                \/\/   Constat user (HTML) : les bases memorisees divergent \u2014\r\n                \/\/   14 sur le titre, 13.5 sur son conteneur, 13 puis 12.5 sur le\r\n                \/\/   span et le lien. Chaque niveau a ete mesure APRES l'ecriture\r\n                \/\/   du niveau au-dessus : sa base est deja la valeur reduite, et\r\n                \/\/   le delta s'y ajoute une seconde fois. La cascade se decale a\r\n                \/\/   chaque cran.\r\n                \/\/   C'est la lecon pb913b, que j'ai reproduite : mesurer et ecrire\r\n                \/\/   element par element fait heriter au descendant la reduction\r\n                \/\/   deja appliquee a son parent.\r\n                \/\/   Correction : on n'ecrit QUE sur la racine du titre. Les\r\n                \/\/   descendants heritent naturellement de sa taille \u2014 c'est le\r\n                \/\/   comportement CSS normal, aucune ecriture n'est necessaire.\r\n                \/\/   Les attributs et tailles poses a tort sur les descendants sont\r\n                \/\/   retires, pour que l'heritage reprenne.\r\n                \/\/ ============================================================\r\n                $el.find('*').each(function () {\r\n                    if (this.hasAttribute('data-viafs1186')) {\r\n                        this.removeAttribute('data-viafs1186');\r\n                        this.style.removeProperty('font-size');\r\n                    }\r\n                });\r\n                var _elRac = $el[0];\r\n                var _b1186 = _elRac.getAttribute('data-viafs1186');\r\n                if (_b1186 === null) {\r\n                    var _fs1186 = parseFloat(window.getComputedStyle(_elRac).fontSize);\r\n                    if (_fs1186 > 0) {\r\n                        _elRac.setAttribute('data-viafs1186', _fs1186);\r\n                        _b1186 = String(_fs1186);\r\n                    }\r\n                }\r\n                var _base1186 = parseFloat(_b1186);\r\n                if (_base1186 > 0) {\r\n                    \/\/ ========================================================\r\n                    \/\/ pb1922 : LE +1 PX DE pb1566, TRANSPOSE A L'ACHAT EXPRESS.\r\n                    \/\/   Demande user : reprendre pour le catalogue des sites pays\r\n                    \/\/   l'agrandissement deja obtenu sur le process classique.\r\n                    \/\/   pb1566 le fait cote process, dans pb913 :\r\n                    \/\/     _cible913 = base x 0.85 - _moins1170 + _plus1566\r\n                    \/\/   avec _plus1566 = 1 quand mode=popup. Son commentaire dit\r\n                    \/\/   pourquoi le delta est ADDITIF et pose APRES la regle commune :\r\n                    \/\/   \u00ab on ajoute 1 px A TOUS LES STATUTS, ce qui decale l'echelle\r\n                    \/\/   sans toucher aux ECARTS entre statuts \u00bb.\r\n                    \/\/   Ici la regle commune est celle de pb1186 : base + _delta1186,\r\n                    \/\/   avec _delta1186 = +1 (active, pb1235) \/ -1 (completee) \/\r\n                    \/\/   -0.5 (a venir). On ajoute donc _plus1922 au meme endroit \u2014 au\r\n                    \/\/   bout, jamais sur la base : agir sur la base contaminerait la\r\n                    \/\/   regie, dont les bases sont les memes.\r\n                    \/\/   Les trois ecarts sont conserves a l'identique : 2 px entre\r\n                    \/\/   active et completee, 0.5 px entre completee et a venir.\r\n                    \/\/   Mobile ET desktop, comme pb1566 : pb1179 avait retire la sortie\r\n                    \/\/   mobile de pb913 pour cette raison meme.\r\n                    \/\/   Les CHEVRONS suivent, mais par une autre voie \u2014 ils ne sont pas\r\n                    \/\/   pilotes par la font-size ici : pb632 les trace en ::before avec\r\n                    \/\/   des dimensions en dur. C'est _feuilleExpress1922 qui s'en charge.\r\n                    \/\/   Reglable a chaud : window._viaPb1922Delta = 2 (ou 0 pour annuler).\r\n                    \/\/   Revert : window._viaPb1922Off = true.\r\n                    \/\/ ========================================================\r\n                    var _plus1922 = 0;\r\n                    if (window._viaPb1922Off !== true) {\r\n                        if ((typeof window._viaPopupPays1905 === 'function')\r\n                            ? window._viaPopupPays1905() : false) {\r\n                            \/* pb1922b : defaut porte de 1 a 2 px (demande user). *\/\r\n                            _plus1922 = (typeof window._viaPb1922Delta === 'number')\r\n                                ? window._viaPb1922Delta : 2;\r\n                            \/* ================================================\r\n                             * pb1922c : DESKTOP -0.5 PX, ET LES TITRES SEULS.\r\n                             *   Demande user. Jusqu'ici titres et chevrons partageaient\r\n                             *   un knob unique \u2014 \u00ab ils grandissent ensemble, par\r\n                             *   construction \u00bb. C'etait vrai tant que le reglage etait\r\n                             *   le meme partout ; ca ne l'est plus, et deux besoins\r\n                             *   distincts ne doivent pas rester derriere une seule\r\n                             *   valeur.\r\n                             *   On retranche donc ICI, sur les titres et sur le seul\r\n                             *   desktop. Le retrait est un TERME A PART, pas un second\r\n                             *   defaut du delta : il se lit dans le log, il s'annule en\r\n                             *   le mettant a 0, et le mobile n'a rien a savoir de lui.\r\n                             *   Les CHEVRONS ne sont pas touches : _feuilleExpress1922\r\n                             *   continue de lire _viaPb1922Delta brut, donc 9 px de cote\r\n                             *   et 3 px de trait, mobile comme desktop.\r\n                             *   Les ecarts entre statuts restent intacts \u2014 c'est la\r\n                             *   propriete du terme additif, celle qui a fait choisir\r\n                             *   cette forme des pb1566.\r\n                             *   Detection : _viaPopupPaysMobile1918, deja le\r\n                             *   discriminant mobile de ce fichier.\r\n                             *   Knob : window._viaRetraitDesk1922 (0.5, 0 pour annuler).\r\n                             *   Revert : window._viaPb1922cOff = true.\r\n                             * ================================================ *\/\r\n                            if (window._viaPb1922cOff !== true) {\r\n                                var _mob1922 = (typeof window._viaPopupPaysMobile1918 === 'function')\r\n                                    ? window._viaPopupPaysMobile1918() : false;\r\n                                if (!_mob1922) {\r\n                                    _plus1922 = _plus1922\r\n                                        - ((typeof window._viaRetraitDesk1922 === 'number')\r\n                                            ? window._viaRetraitDesk1922 : 0.5);\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                    var _cible1186 = Math.round((_base1186 + _delta1186 + _plus1922) * 100) \/ 100;\r\n                    if (window._viaSig1922 !== _plus1922) {\r\n                        window._viaSig1922 = _plus1922;\r\n                        console.log('[pb1922c] delta taille des titres = +' + _plus1922 + 'px'\r\n                            + ' (' + ((typeof window._viaPopupPaysMobile1918 === 'function')\r\n                                ? (window._viaPopupPaysMobile1918() ? 'mobile' : 'desktop') : '?')\r\n                            + ') | base=' + _base1186 + ' x etat ' + _delta1186\r\n                            + ' -> ' + _cible1186 + 'px'\r\n                            + ' | chevrons inchang\u00e9s (delta brut)');\r\n                    }\r\n                    if (Math.abs(parseFloat(window.getComputedStyle(_elRac).fontSize) - _cible1186) > 0.1) {\r\n                        _elRac.style.setProperty('font-size', _cible1186 + 'px', 'important');\r\n                    }\r\n                }\r\n            }\r\n            \/\/ pb686 : le placeholder des champs de CETTE etape suit la couleur du titre.\r\n            \/\/   Variable CSS lue par la regle ::placeholder (feuille en fin de fichier) :\r\n            \/\/   ::placeholder ne peut pas etre atteint par un style inline.\r\n            if (CHAMPS686[i]) {\r\n                $(CHAMPS686[i]).each(function() {\r\n                    this.style.setProperty('--via686-ph', couleur);\r\n                });\r\n            }\r\n            \/\/ le texte visible est dans des enfants span\/a qui portent leur PROPRE\r\n            \/\/ color inline (#213864) : colorer le conteneur ne suffit pas, il faut\r\n            \/\/ forcer le conteneur ET tous ses descendants.\r\n            $el[0].style.setProperty('color', couleur, 'important');\r\n            $el.find('*').each(function() {\r\n                this.style.setProperty('color', couleur, 'important');\r\n            });\r\n        });\r\n        \/\/ pb644f : le bouton \"Continuer la reservation\" est la DERNIERE etape.\r\n        \/\/   Son texte passe en rouge quand les 5 etapes sont completees (actif===-1\r\n        \/\/   => plus rien a renseigner => il ne reste qu'a cliquer), et revient au\r\n        \/\/   bleu initial une fois clique (flag _resaClique644f).\r\n        this.majBoutonEtape644f(actif === -1);\r\n\r\n        console.log('[pb631] etapes', faits.map(f => f ? 1 : 0).join(''), '-> actif:',\r\n            (actif === -1) ? 'aucun' : ids[actif]);\r\n        this._sequenceur1036(faits, actif);   \/\/ pb1036\r\n        this.majSousTitres644(faits);   \/\/ pb644\r\n        \/\/ ================================================================\r\n        \/\/ pb1404 : HOOK POUR REJOUER CETTE PASSE DE L'EXTERIEUR.\r\n        \/\/   Constat user : en achat express les cinq phrases vertes restent\r\n        \/\/   visibles. pb1401 empeche leur POSE quand la page web est affichee,\r\n        \/\/   mais elles ont ete posees AVANT \u2014 l'utilisateur remplit les etapes,\r\n        \/\/   puis la page web s'ouvre. Rien ne retirait celles qui existaient deja.\r\n        \/\/   majSousTitres644 commence par retirer chaque sous-titre avant de\r\n        \/\/   decider s'il le recree : la rejouer suffit donc a les faire\r\n        \/\/   disparaitre, sans code de nettoyage separe qui pourrait diverger.\r\n        \/\/   Le hook est pose ici, sur l'instance vivante et avec ses arguments\r\n        \/\/   d'origine, plutot que d'exposer la methode nue \u2014 elle a besoin de son\r\n        \/\/   \u00ab this \u00bb et de faits[].\r\n        \/\/   Consomme par pb1403 (yearbook-media.js) au changement d'etat.\r\n        \/\/   Revert : window._viaPb1404Off = true.\r\n        \/\/ ================================================================\r\n        if (window._viaPb1404Off !== true) {\r\n            var _self1404 = this;\r\n            window._viaRejouerSousTitres1404 = function () {\r\n                try {\r\n                    _self1404.majSousTitres644(_self1404.etapesCompletees631());\r\n                } catch (_e1404) {\r\n                    console.warn('[pb1404] rejeu impossible : ' + _e1404.message);\r\n                }\r\n            };\r\n            \/\/ pb1413 : hook d'ouverture du recapitulatif (achat express).\r\n            \/\/   Pose ici pour la meme raison que pb1404 : setSection632 est une\r\n            \/\/   methode d'instance, elle a besoin de son \u00ab this \u00bb.\r\n            window._viaOuvrirRecapExpress1413 = function () {\r\n                try {\r\n                    _self1404.setSection632('recap', true);\r\n                    console.log('[pb1413] r\u00e9capitulatif ouvert (achat express)');\r\n                } catch (_e1413) {\r\n                    console.warn('[pb1413] ouverture impossible : ' + _e1413.message);\r\n                }\r\n            };\r\n        }\r\n        this.majRecap737();   \/\/ pb737\r\n        this._msgOrdi850();   \/\/ pb851 : etat calcule, independant de _resaClique644f\r\n        this.majLibelleResa738();   \/\/ pb738b\r\n        \/* pb2047 : en DERNIER, comme pb1169 pose la couleur en dernier \u2014 les\r\n           writers d'ouverture (_sequenceur1036) ont deja passe. Memes `faits`\r\n           et meme `actif` que la couleur : un seul calcul, deux consequences. *\/\r\n        try { this._masqueAvenir2047(faits, actif); } catch (_e2047c) {}\r\n    }\r\n\r\n    \/\/ ========================================================================\r\n    \/\/ pb1036 : SEQUENCEUR UNIQUE d'ouverture des etapes (demande user).\r\n    \/\/   Regle, en une phrase : l'etape OUVERTE est la premiere NON COMPLETEE ;\r\n    \/\/   toutes les autres sont fermees. C'est exactement ce que majEtapes631\r\n    \/\/   calcule deja pour la couleur (actif = faits.indexOf(false)) \u2014 on\r\n    \/\/   reutilise ce meme verdict pour la visibilite, au lieu de le recalculer\r\n    \/\/   ailleurs sous une autre forme.\r\n    \/\/\r\n    \/\/   CE QUE CELA REMPLACE. Six mecanismes se disputaient la decision, chacun\r\n    \/\/   ajoute pour rattraper un cas du precedent : pb647 (fermeture auto a la\r\n    \/\/   completion, avec son garde _autoFerme647 \"pour ne pas lutter si\r\n    \/\/   l'utilisateur rouvre\"), pb633 (repli des etapes amont), pb703, pb707,\r\n    \/\/   pb740\/pb740b \u2014 ce dernier avouant en commentaire avoir cherche\r\n    \/\/   l'appelant reel a la pile d'appel. Des gardes anti-conflit n'etaient\r\n    \/\/   necessaires QUE parce que plusieurs autorites ecrivaient la meme chose.\r\n    \/\/   Une seule autorite supprime le besoin de gardes.\r\n    \/\/\r\n    \/\/   OPTION (B) retenue : le clic manuel gagne. Rouvrir une etape completee\r\n    \/\/   pour corriger une saisie est un besoin reel ; le sequenceur ne la\r\n    \/\/   referme donc pas tant que la COMPLETION n'a pas change. Des qu'elle\r\n    \/\/   change (l'utilisateur a corrige, ou complete autre chose), la main\r\n    \/\/   revient au sequenceur. C'etait l'intention de _autoFerme647, exprimee\r\n    \/\/   ici une seule fois au lieu d'etre eparpillee.\r\n    \/\/\r\n    \/\/   La signature des completions sert de detecteur de changement : tant\r\n    \/\/   qu'elle est identique, on ne touche a rien \u2014 ce qui rend l'appel\r\n    \/\/   idempotent et sans cout, alors que majEtapes631 est rejoue souvent.\r\n    \/\/\r\n    \/\/   Revert : window._viaPb1036Off = true (les anciens mecanismes restent en\r\n    \/\/   place et reprennent la main).\r\n    \/\/ ========================================================================\r\n    \/\/ ========================================================================\r\n    \/\/ pb1269 : LA SIGNATURE SUIT LES VALEURS, PLUS SEULEMENT LES COMPLETIONS.\r\n    \/\/   Constat user : en achat express, modifier une etape met bien la resa a\r\n    \/\/   jour, mais l'etape reste ouverte. Le log le dit mot pour mot :\r\n    \/\/     [pb1036] completions 111111 -> \u00e9tape ouverte : dates [choix manuel]\r\n    \/\/   Explication : l'option B de pb1036 laisse une etape ouverte au clic\r\n    \/\/   manuel \u00ab tant que la COMPLETION n'a pas change \u00bb. Or quand tout est deja\r\n    \/\/   complete, corriger une date fait passer la signature de 111111 a 111111 :\r\n    \/\/   elle ne change pas, le drapeau manuel n'est jamais efface, et l'etape\r\n    \/\/   reste ouverte indefiniment.\r\n    \/\/   L'intention de pb1036 etait \u00ab des que l'utilisateur a corrige quelque\r\n    \/\/   chose, le sequenceur reprend la main \u00bb. Le bitmap des completions ne sait\r\n    \/\/   pas dire cela : il ne voit que le passage de vide a rempli. On lui adjoint\r\n    \/\/   donc les VALEURS.\r\n    \/\/   Seules les valeurs VALIDEES entrent dans la signature \u2014 un pays non\r\n    \/\/   reconnu, des dates sans duree exploitable n'y figurent pas. Sans cela, la\r\n    \/\/   frappe dans le champ annonceur ferait bouger la signature a chaque lettre\r\n    \/\/   et refermerait l'etape sous les doigts de l'utilisateur.\r\n    \/\/   Memes sources que etapesCompletees631 : une seule definition de ce qui\r\n    \/\/   constitue une etape, pour le compte comme pour le contenu.\r\n    \/\/   Revert : window._viaPb1269Off = true (signature des completions seule).\r\n    \/\/ ========================================================================\r\n    \/\/ pb1307 : la signature des valeurs est exposee \u2014 _pretPageWeb1148, dans\r\n    \/\/   yearbook-media.js, en a besoin pour savoir si la selection courante a\r\n    \/\/   deja ete validee par un \u00ab Continuer \u00bb. Une seule definition de ce qui\r\n    \/\/   constitue une selection, partagee par les deux fichiers.\r\n    _valeurs1269() {\r\n        try {\r\n            const _p1269 = $('input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]').val() || '';\r\n            const _pOk1269 = _p1269\r\n                ? (window.VIA_Countries\r\n                    ? (window.VIA_Countries.getCountryByLabel(_p1269) ? _p1269 : '')\r\n                    : _p1269)\r\n                : '';\r\n            const _site1269 = sessionStorage.getItem('ContinentPaysTitre') || '';\r\n            const _dates1269 = (this.state.dureeJours > 0)\r\n                ? (($('#form-field-PopupTarifsDebutCampagne').val() || '') + '>'\r\n                    + ($('#form-field-PopupTarifsFinCampagne').val() || ''))\r\n                : '';\r\n            const _tarif1269 = (typeof this.state.tarifSelectionne === 'string')\r\n                ? this.state.tarifSelectionne : '';\r\n            let _sec1269 = '';\r\n            const _s1269 = window.VIA_Panier ? (window.VIA_Panier.state || null) : null;\r\n            const _it1269 = _s1269\r\n                ? (_s1269.items || []).find(i => i.id === _s1269.itemActif) : null;\r\n            if (_it1269) {\r\n                _sec1269 = (_it1269.selectedPageSecteurDisplayed\r\n                    || _it1269.selectedPageSecteur || '')\r\n                    + '\/' + (_it1269.articleTitre || '');\r\n            }\r\n            return [_pOk1269, _site1269, _dates1269, _tarif1269, _sec1269].join('|');\r\n        } catch (_e1269) { return ''; }\r\n    }\r\n\r\n    \/\/ ========================================================================\r\n    \/\/ pb1285 : NOUVELLE RESERVATION EN ACHAT EXPRESS.\r\n    \/\/   Demande user : le bouton \u00ab Ajouter une reservation \u00bb doit fonctionner\r\n    \/\/   aussi quand le catalogue tarifaire a pris la place du process (pb1264).\r\n    \/\/   Or tout ce qui a ete construit pour le classique \u2014 purge des cles\r\n    \/\/   (pb1271), vidage des dates (pb961\/pb1281) \u2014 agit sur le PROCESS. L'etat\r\n    \/\/   du catalogue, lui, vit dans cette classe : tarif retenu, duree, drapeau\r\n    \/\/   de choix manuel. Rien ne le reinitialisait.\r\n    \/\/   Regles retenues (reponses user) :\r\n    \/\/     - l'annonceur est CONSERVE, comme en classique (pb669) ;\r\n    \/\/     - pays, secteur, format, tarif et dates repartent a zero ;\r\n    \/\/     - le sequenceur n'ouvre que la PREMIERE etape non renseignee : une fois\r\n    \/\/       le reste vide et l'annonceur garde, c'est le site pays. On ne force\r\n    \/\/       donc aucune ouverture \u2014 il suffit de rendre la main au sequenceur en\r\n    \/\/       effacant le choix manuel et la signature, et il conclut tout seul.\r\n    \/\/   Les cles sessionStorage ne sont pas touchees ici : pb1271 les purge deja\r\n    \/\/   au meme instant, et deux writers pour la meme chose est precisement ce\r\n    \/\/   que ce projet s'efforce d'eviter.\r\n    \/\/   Revert : window._viaPb1285Off = true.\r\n    \/\/ ========================================================================\r\n    resetCatalogue1285() {\r\n        if (window._viaPb1285Off === true) { return; }\r\n        try {\r\n            \/\/ --- etat interne du catalogue\r\n            this.state.tarifSelectionne = null;\r\n            this.state.dureeJours = null;\r\n            if (typeof this.state.dernierResultatCalcul !== 'undefined') {\r\n                this.state.dernierResultatCalcul = null;\r\n            }\r\n            \/\/ --- champs de dates DU POPUP (ceux du process sont vides par pb961)\r\n            ['#form-field-PopupTarifsDebutCampagne',\r\n             '#form-field-PopupTarifsFinCampagne',\r\n             '#form-field-PopupTarifsNbJours'].forEach(function (_s1285) {\r\n                var _el1285 = document.querySelector(_s1285);\r\n                if (!_el1285) { return; }\r\n                if (typeof _el1285.value === 'string') { _el1285.value = ''; }\r\n            });\r\n            \/\/ --- liser\u00e9s de selection : pays, secteur, format\r\n            \/\/ ============================================================\r\n            \/\/ pb1287 : NE PAS EFFACER LE LISERE DES CARTES.\r\n            \/\/   Constat user (HTML) : la nouvelle resa perd son liser\u00e9 vert, et\r\n            \/\/   sa carte porte border-style:none + box-shadow:none \u2014 la\r\n            \/\/   signature d'un .css('border','none') jQuery, alors que\r\n            \/\/   data-via-item-actif vaut bien true.\r\n            \/\/   C'est MON reset : la carte du panier porte la classe\r\n            \/\/   .SiteContinentPaysTitre, que je visais sans la borner. Elle\r\n            \/\/   designe les vignettes de la liste des sites \u2014 pas une carte.\r\n            \/\/   Le projet borne d'ailleurs deja ce selecteur ailleurs :\r\n            \/\/   $('#ListeSitesConteneurScroll .SiteContinentPaysTitre'). On\r\n            \/\/   reprend cette portee, et on exclut les cartes par surete.\r\n            \/\/ ============================================================\r\n            $('#ListeSitesConteneurScroll .SiteContinentPaysTitre,'\r\n                + ' .HPContinentPays, .HPType, .PTType,'\r\n                + ' .CartoucheArticles, .FormatClassique, .FormatPopup, .CreationFormat')\r\n                .not('.CampagneTemplateClass')\r\n                .css({ 'border': 'none', 'box-shadow': 'none' });\r\n            \/\/ --- rendre la main au sequenceur : plus de choix manuel, signature\r\n            \/\/   effacee pour qu'il recalcule des la passe suivante.\r\n            window._viaManuel1036 = null;\r\n            window._viaSig1036 = null;\r\n            \/\/ ============================================================\r\n            \/\/ pb1286 : EFFACER AUSSI CE QUI EST AFFICHE, ET REDESSINER.\r\n            \/\/   Constat user : pb1285 s'execute (le log le montre) mais les\r\n            \/\/   etapes du catalogue affichent toujours Cameroun, les dates et le\r\n            \/\/   tarif de la reservation precedente.\r\n            \/\/   J'avais vide l'ETAT sans toucher a ce que l'ecran montre. Or ces\r\n            \/\/   valeurs vertes ne sont pas relues a chaque passe : elles ont ete\r\n            \/\/   ecrites une fois, au choix de l'utilisateur, et rien ne les\r\n            \/\/   efface.\r\n            \/\/   Critere : la couleur. Dans tout ce projet, une valeur retenue\r\n            \/\/   s'affiche en #56BE50 \u2014 c'est la convention, pas une supposition.\r\n            \/\/   On vide donc les textes verts DU CATALOGUE, et seulement eux :\r\n            \/\/   la recherche est bornee a #TarifsCatalogueConteneur, le process\r\n            \/\/   n'est pas concerne.\r\n            \/\/   Puis on redemande au catalogue de se redessiner : c'est lui qui\r\n            \/\/   sait ouvrir la premiere etape non renseignee.\r\n            \/\/ ============================================================\r\n            \/\/ ============================================================\r\n            \/\/ pb1288 : DESELECTIONNER LE SITE PAYS DANS SA PROPRE LISTE.\r\n            \/\/   Constat user : le site pays reste sur Cameroun, et le sequenceur\r\n            \/\/   ouvre les Dates \u2014 donc ce n'est pas un residu d'affichage : l'etat\r\n            \/\/   dit que le site EST choisi.\r\n            \/\/   sitePaysSelectionne620 ne lit ni sessionStorage ni l'item : il\r\n            \/\/   compte les lignes .v290-row.v290-on dans #PopupTarifsListePays.\r\n            \/\/   C'est la CLASSE de selection qui fait foi ; purger des cles ne\r\n            \/\/   pouvait rien y changer.\r\n            \/\/   On retire donc la marque la ou elle est posee. Meme raisonnement\r\n            \/\/   pour les listes secteurs et formats du catalogue, qui suivent la\r\n            \/\/   meme convention v290.\r\n            \/\/ ============================================================\r\n            var _on1288 = document.querySelectorAll('#PopupTarifsListePays .v290-row.v290-on,'\r\n                + ' .PopupTarifsListePays .v290-row.v290-on,'\r\n                + ' #PopupTarifsListeSecteurs .v290-row.v290-on,'\r\n                + ' #TarifsCatalogueConteneur .v290-row.v290-on');\r\n            for (var _o1288 = 0; _o1288 < _on1288.length; _o1288++) {\r\n                _on1288[_o1288].classList.remove('v290-on');\r\n            }\r\n            if (_on1288.length) {\r\n                console.log('[pb1288] ' + _on1288.length + ' s\u00e9lection(s) v290 retir\u00e9e(s)');\r\n            }\r\n            var _cat1286 = document.getElementById('TarifsCatalogueConteneur');\r\n            if (_cat1286) {\r\n                var _txt1286 = _cat1286.querySelectorAll('p, span, div');\r\n                var _n1286 = 0;\r\n                for (var _i1286 = 0; _i1286 < _txt1286.length; _i1286++) {\r\n                    var _e1286 = _txt1286[_i1286];\r\n                    if (_e1286.children.length) { continue; }   \/\/ que les feuilles\r\n                    \/\/ ====================================================\r\n                    \/\/ pb1292 : NE JAMAIS VIDER UN TEXTE DE LA GRILLE.\r\n                    \/\/   Constat user : l'en-tete du format precedemment choisi a\r\n                    \/\/   disparu \u2014 la colonne \u00ab Banniere \u00bb est vide.\r\n                    \/\/   C'est pb1286 : il efface les textes verts, or pb785 met\r\n                    \/\/   justement en vert l'en-tete de format, le libelle de\r\n                    \/\/   ligne, la devise et le tarif. Effacer un libelle de la\r\n                    \/\/   grille le detruit definitivement.\r\n                    \/\/   Ces elements portent tous data-col785 : pb1291 sait deja\r\n                    \/\/   leur rendre leur couleur. Ils sont donc exclus ici \u2014 le\r\n                    \/\/   demarquage suffit, l'effacement serait une perte.\r\n                    \/\/ ====================================================\r\n                    if (_e1286.dataset ? _e1286.dataset.col785 : false) { continue; }\r\n                    if (_e1286.closest ? _e1286.closest('.GrilleTarifaire, .TarifsFormats, .PricingAmount') : false) { continue; }\r\n                    var _c1286 = window.getComputedStyle(_e1286).color;\r\n                    if (_c1286 !== 'rgb(86, 190, 80)') { continue; }\r\n                    if (!((_e1286.textContent || '').trim())) { continue; }\r\n                    _e1286.textContent = '';\r\n                    _n1286++;\r\n                }\r\n                if (_n1286) { console.log('[pb1286] ' + _n1286 + ' valeur(s) affich\u00e9e(s) effac\u00e9e(s)'); }\r\n            }\r\n            \/\/ ============================================================\r\n            \/\/ pb1291 : DEMARQUER LA GRILLE TARIFAIRE.\r\n            \/\/   Constat user : la grille garde le tarif, le format, la ligne et\r\n            \/\/   la devise de la reservation precedente en vert.\r\n            \/\/   Ce marquage est celui de pb785, et il memorise lui-meme ce qu'il\r\n            \/\/   remplace : data-col785 (couleur), data-fw785 (graisse),\r\n            \/\/   data-fs785 (taille). On ne devine donc aucune valeur \u2014 on rend a\r\n            \/\/   chaque element ce qu'il avait, exactement comme _teinte785 le\r\n            \/\/   fait pour une deselection normale.\r\n            \/\/   Effacer le texte, comme pb1286 le fait pour les valeurs vertes\r\n            \/\/   des etapes, serait ici une faute : les prix doivent rester\r\n            \/\/   lisibles, c'est leur MISE EN AVANT qui doit partir.\r\n            \/\/ ============================================================\r\n            var _mq1291 = document.querySelectorAll('[data-col785]');\r\n            for (var _q1291 = 0; _q1291 < _mq1291.length; _q1291++) {\r\n                var _el1291 = _mq1291[_q1291];\r\n                var _st1291 = _el1291.style;\r\n                _st1291.setProperty('color', _el1291.dataset.col785 || 'inherit', 'important');\r\n                if (_el1291.dataset.fw785) {\r\n                    _st1291.setProperty('font-weight', _el1291.dataset.fw785, 'important');\r\n                }\r\n                if (_el1291.dataset.fs785) {\r\n                    _st1291.setProperty('font-size', _el1291.dataset.fs785 + 'px', 'important');\r\n                }\r\n                \/\/ pb1292 : le tarif retenu garde aussi un FOND (demande user).\r\n                \/\/   Il n'est pas pose par pb785, qui ne touche qu'a la couleur,\r\n                \/\/   la graisse et la taille \u2014 donc rien ne l'a memorise. On\r\n                \/\/   retire l'inline et on rend la main a la feuille, plutot que\r\n                \/\/   d'inventer une couleur de fond qui ne serait juste nulle part.\r\n                _st1291.removeProperty('background');\r\n                _st1291.removeProperty('background-color');\r\n            }\r\n            var _pa1292 = document.querySelectorAll('.PricingAmount');\r\n            for (var _r1292 = 0; _r1292 < _pa1292.length; _r1292++) {\r\n                _pa1292[_r1292].style.removeProperty('background');\r\n                _pa1292[_r1292].style.removeProperty('background-color');\r\n            }\r\n            if (_mq1291.length) {\r\n                console.log('[pb1291] grille d\u00e9marqu\u00e9e : ' + _mq1291.length\r\n                    + ' \u00e9l\u00e9ment(s) rendus \u00e0 leur \u00e9tat d\\'origine');\r\n            }\r\n            \/\/ ============================================================\r\n            \/\/ pb1318 : NEUTRALISER LA MARGE NEGATIVE DES RANGEES DE LA GRILLE.\r\n            \/\/   Constat user, mesure a l'appui : les rangees .TarifsFormats\r\n            \/\/   different d'une seule propriete \u2014\r\n            \/\/     48c7c092 (Home Page)    margin-block-start = 0px\r\n            \/\/     40640001 (Autres Pages) margin-block-start = -15px\r\n            \/\/   La seconde remonte donc de 15px sur celle du dessus. Venant apres\r\n            \/\/   dans le DOM, avec un fond opaque et position:relative, elle PEINT\r\n            \/\/   par-dessus et recouvre le bas des libelles sur deux lignes. Ce\r\n            \/\/   n'est pas une troncature, c'est un chevauchement \u2014 seules les\r\n            \/\/   SECONDES lignes disparaissent, jamais les premieres.\r\n            \/\/   Cette valeur vient du template Elementor, pas de nous : elle est\r\n            \/\/   introuvable dans les trois fichiers du projet. Elle ne se voit que\r\n            \/\/   lorsque les rangees sont au plus juste (height 40 pour min-height\r\n            \/\/   35), ce qui arrive quand la grille est reconstruite hors de son\r\n            \/\/   popup d'origine.\r\n            \/\/   Meme condition que pb1268 et pb1300 \u2014 le catalogue a quitte le\r\n            \/\/   popup Tarifs \u2014 et meme mecanisme que pb1273 : rendre a un element\r\n            \/\/   une valeur adaptee au contexte ou il se trouve reellement.\r\n            \/\/   Revert : window._viaPb1318Off = true.\r\n            \/\/ ============================================================\r\n            if (window._viaPb1318Off !== true) {\r\n                if (window._viaCatalogueDeplace1264 === true) {\r\n                    var _rg1318 = document.querySelectorAll('.TarifsFormats');\r\n                    var _n1318 = 0;\r\n                    \/\/ pb1318c : -5 -> -8px, valeur retenue par l'utilisateur apres\r\n                    \/\/   essai direct sur .TarifsFormats. Entre le chevauchement des\r\n                    \/\/   -15px d'origine et l'espace laisse par 0, c'est le point\r\n                    \/\/   d'equilibre.\r\n                    var _cible1318 = (typeof window._viaMargeRangee1318 === 'number')\r\n                        ? window._viaMargeRangee1318 : -8;\r\n                    for (var _r1318 = 0; _r1318 < _rg1318.length; _r1318++) {\r\n                        var _e1318 = _rg1318[_r1318];\r\n                        \/\/ ============================================================\r\n                        \/\/ pb1388 : PAS DE MARGE NEGATIVE SUR UNE RANGEE DEVENUE PLUS\r\n                        \/\/   HAUTE. Constat user : chevauchement dans la grille mobile,\r\n                        \/\/   uniquement quand une page secteur ou article est choisie \u2014\r\n                        \/\/   jamais avec une homepage.\r\n                        \/\/   L'explication est dans le HTML fourni : les rangees\r\n                        \/\/   fautives portent data-via1386. C'est pb1386 qui les a\r\n                        \/\/   passees sur deux lignes, et le template mobile n'emploie le\r\n                        \/\/   tiret cadratin QUE pour les libelles \u00ab Autres Pages \u00bb : les\r\n                        \/\/   libelles Home Page n'ont jamais ete touches, d'ou l'ecart\r\n                        \/\/   entre les deux cas.\r\n                        \/\/   pb1318 pose -8px, une valeur mesuree sur des libelles d'UNE\r\n                        \/\/   ligne. Sur deux lignes, ce resserrement fait remonter la\r\n                        \/\/   rangee sous l'en-tete. Les deux correctifs sont justes\r\n                        \/\/   separement et se contredisent ensemble.\r\n                        \/\/   La rangee reformatee garde donc sa marge naturelle : elle\r\n                        \/\/   n'a plus de hauteur a rattraper, c'est le retour a la ligne\r\n                        \/\/   qui l'occupe. Les autres rangees sont inchangees.\r\n                        \/\/   Revert : window._viaPb1388Off = true.\r\n                        \/\/ ============================================================\r\n                        if (window._viaPb1388Off !== true) {\r\n                            if (_e1318.querySelector('[data-via1386]')) {\r\n                                if (_e1318.getAttribute('data-via1388') !== '1') {\r\n                                    _e1318.setAttribute('data-via1388', '1');\r\n                                    _e1318.style.removeProperty('margin-top');\r\n                                    console.log('[pb1388] rang\u00e9e sur deux lignes ->'\r\n                                        + ' marge n\u00e9gative pb1318 non appliqu\u00e9e');\r\n                                }\r\n                                continue;\r\n                            }\r\n                        }\r\n                        var _mt1318 = parseFloat(window.getComputedStyle(_e1318).marginTop) || 0;\r\n                        if (_mt1318 >= 0) { continue; }\r\n                        \/\/ pb1318b : PAS 0, MAIS -5px (demande user).\r\n                        \/\/   Constat : a 0, les rangees se detachent et la grille\r\n                        \/\/   s'aere trop. Les -15px d'origine servaient bien a\r\n                        \/\/   resserrer les rangees ; ils allaient simplement trop\r\n                        \/\/   loin dans ce contexte, ou les rangees sont au plus\r\n                        \/\/   juste. On garde le resserrement, on supprime le\r\n                        \/\/   chevauchement \u2014 la valeur mesuree sur le rendu correct.\r\n                        \/\/   Knob : window._viaMargeRangee1318 (-5).\r\n                        if (_mt1318 === _cible1318) { continue; }\r\n                        _e1318.style.setProperty('margin-top', _cible1318 + 'px', 'important');\r\n                        _n1318++;\r\n                    }\r\n                    if (_n1318) {\r\n                        if (window._viaSig1318 !== _n1318) {\r\n                            window._viaSig1318 = _n1318;\r\n                            console.log('[pb1318] ' + _n1318 + ' rang\u00e9e(s) de grille :'\r\n                                + ' marge haute ramen\u00e9e \u00e0 ' + _cible1318 + 'px'\r\n                                + ' (chevauchement supprim\u00e9, resserrement conserv\u00e9)');\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            \/\/ ====================================================================\r\n            \/\/ pb1382 : VIDER L'ETAT SEMANTIQUE DU SECTEUR, PAS SEULEMENT SON\r\n            \/\/   MARQUAGE. Constat user : apres \u00ab Ajouter une r\u00e9servation \u00bb, l'etape\r\n            \/\/   secteur affiche toujours \u00ab Agro-industries \u00bb en vert alors que la\r\n            \/\/   nouvelle resa reclame \u00ab un pays, un secteur et un format \u00bb.\r\n            \/\/   resetCatalogue1285 retire bien les classes .v290-on (~l.2752) \u2014 mais\r\n            \/\/   c'est l'etat VISUEL. Le sous-titre .v644-sub, lui, vient de\r\n            \/\/   nomSecteur1339, qui lit _sync635.secteur, puis l'item actif, puis\r\n            \/\/   sessionStorage. Aucune des trois sources n'etait videe, et le libelle\r\n            \/\/   survivait a la reinitialisation.\r\n            \/\/   C'est la lecon pb734\/pb1337-1340, prise par l'autre bout : on avait\r\n            \/\/   appris a LIRE l'etat semantique plutot que le marquage ; il faut\r\n            \/\/   aussi l'EFFACER quand on efface le marquage.\r\n            \/\/   On ne touche qu'aux champs de page : l'annonceur est conserve, comme\r\n            \/\/   l'annonce le message de cette fonction. Les ITEMS existants ne sont\r\n            \/\/   pas modifies non plus \u2014 les reservations deja prises gardent leur\r\n            \/\/   secteur, seule la saisie en cours est remise a zero.\r\n            \/\/   Revert : window._viaPb1382Off = true.\r\n            \/\/ ====================================================================\r\n            if (window._viaPb1382Off !== true) {\r\n                try {\r\n                    var _sy1382 = this._sync635 || {};\r\n                    var _av1382 = _sy1382.secteur || _sy1382.articleTitre || '';\r\n                    this._sync635 = _sy1382;\r\n                    _sy1382.secteur = null;\r\n                    _sy1382.articleTitre = null;\r\n                    _sy1382.articleUrl = null;\r\n                    window._viaEtape5Ok631 = false;\r\n                    ['SelectedPageSecteur', 'SelectedPageSecteurDisplayed',\r\n                     'SelectedPageType', 'Commande_Article', 'commandePage']\r\n                        .forEach(function (_k1382) {\r\n                            try { sessionStorage.removeItem(_k1382); }\r\n                            catch (_eK1382) {\r\n                                console.warn('[pb1382] ' + _k1382 + ' : ' + _eK1382.message);\r\n                            }\r\n                        });\r\n                    if (_av1382) {\r\n                        console.log('[pb1382] \u00e9tape secteur r\u00e9initialis\u00e9e (\u00e9tait \u00ab '\r\n                            + _av1382 + ' \u00bb) \u2014 nouvelle r\u00e9servation');\r\n                    }\r\n                } catch (_e1382) {\r\n                    console.warn('[pb1382] r\u00e9initialisation du secteur : ' + _e1382.message);\r\n                }\r\n            }\r\n            if (typeof this.majEtapes631 === 'function') { this.majEtapes631(); }\r\n            console.log('[pb1285] catalogue r\u00e9initialis\u00e9 (annonceur conserv\u00e9,'\r\n                + ' pays\/secteur\/format\/tarif\/dates vid\u00e9s)');\r\n        } catch (_e1285) { console.warn('[pb1285]', _e1285.message); }\r\n    }\r\n\r\n    _sequenceur1036(faits, actif) {\r\n        if (window._viaPb1036Off === true) { return; }\r\n\r\n        try {\r\n            const sig = faits.map(f => f ? 1 : 0).join('');\r\n            \/\/ pb1269 : le detecteur de changement ecoute aussi les valeurs.\r\n            \/\/   'sig' reste le bitmap et sert au log : il se lit d'un coup d'oeil.\r\n            const _sigVal1269 = (window._viaPb1269Off === true)\r\n                ? ''\r\n                : this._valeurs1269();\r\n            const _sigTot1269 = sig + '|' + _sigVal1269;\r\n            const change = (window._viaSig1036 !== _sigTot1269);\r\n            if (change) {\r\n                window._viaSig1036 = _sigTot1269;\r\n                window._viaManuel1036 = null;   \/\/ la completion a bouge -> le sequenceur reprend la main\r\n                \/\/ ================================================================\r\n                \/\/ pb1064b : RESTAURER le libelle \"Continuer la reservation\".\r\n                \/\/   Constat user : le recap rouvert a la main affiche \"Merci de\r\n                \/\/   choisir un espace publicitaire\" \u2014 le libelle pose par pb688\r\n                \/\/   apres le premier Continuer. Il reste en place indefiniment,\r\n                \/\/   alors que la selection vient d'etre modifiee : l'utilisateur\r\n                \/\/   doit pouvoir transmettre la NOUVELLE selection.\r\n                \/\/   pb688 memorise le libelle d'origine dans dataset.txtInit688\r\n                \/\/   \"pour pouvoir le restaurer si besoin\" \u2014 c'est ce besoin.\r\n                \/\/   Conditionne au changement de completion, donc au moment ou la\r\n                \/\/   selection a reellement bouge : un simple rejeu ne restaure rien.\r\n                \/\/   Revert : window._viaPb1064Off = true.\r\n                \/\/ ================================================================\r\n                if (window._viaPb1064Off !== true) {\r\n                    try {\r\n                        var $b1064 = $('#PopupTarifsBoutonContinuerResaTexte, .PopupTarifsBoutonContinuerResaTexte').first();\r\n                        var _e1064 = $b1064.length ? $b1064[0] : null;\r\n                        var _init1064 = _e1064 ? _e1064.dataset.txtInit688 : '';\r\n                        if (_init1064 ? (_e1064.dataset.txt688 !== _init1064) : false) {\r\n                            _e1064.innerHTML = _init1064;\r\n                            delete _e1064.dataset.txt688;\r\n                            \/\/ ================================================\r\n                            \/\/ pb1315 : NE PAS INVALIDER SUR NOS PROPRES SYNCHROS.\r\n                            \/\/   Constat user (log) : apres le Continuer, les\r\n                            \/\/   completions passent a 1111100000 \u2014 dix positions,\r\n                            \/\/   donc pb1312 a retire les etapes page web, donc le\r\n                            \/\/   critere est encore \u00ab en attente \u00bb. La cible tombe\r\n                            \/\/   sur le recapitulatif : c'est ce que tu vois.\r\n                            \/\/   Cause : rejouerSync635 s'execute juste apres le\r\n                            \/\/   Continuer et rappelle onFormulaireChange, donc\r\n                            \/\/   pb1064b, qui rabaisse le drapeau \u2014 alors que\r\n                            \/\/   l'utilisateur n'a rien touche. Meme piege que la\r\n                            \/\/   signature de pb1307 : nos propres synchros font\r\n                            \/\/   bouger le temoin.\r\n                            \/\/   Ce projet a deja un discriminant pour cela :\r\n                            \/\/   _resaVerrou656, pose 3 s au Continuer precisement\r\n                            \/\/   parce que \u00ab les synchros post-clic rappellent\r\n                            \/\/   onFormulaireChange \u00bb. On s'en sert.\r\n                            \/\/   Revert : window._viaPb1315Off = true.\r\n                            \/\/ ================================================\r\n                            if (window._viaPb1315Off === true\r\n                                ? true\r\n                                : (window._resaVerrou656 !== true)) {\r\n                                window._viaExpressValide1313 = false;\r\n                            } else if (window._viaSig1315 !== 'ignore') {\r\n                                window._viaSig1315 = 'ignore';\r\n                                console.log('[pb1315] synchro post-Continuer -> s\u00e9lection'\r\n                                    + ' toujours consid\u00e9r\u00e9e comme valid\u00e9e');\r\n                            }\r\n                            console.log('[pb1064b] s\u00e9lection modifi\u00e9e -> libell\u00e9 bouton restaur\u00e9 : \"'\r\n                                + _init1064 + '\"');\r\n                        }\r\n                    } catch (_eB1064) { console.warn('[pb1064b]', _eB1064.message); }\r\n                }\r\n            }\r\n            \/\/ etape a ouvrir : celle choisie manuellement, sinon la premiere non completee.\r\n            \/\/   actif === -1 : tout est complete, plus rien a ouvrir.\r\n            let cible = window._viaManuel1036 || null;\r\n            if (!cible) { cible = (actif === -1) ? null : this.config632()[actif].cle; }\r\n            \/\/ ================================================================\r\n            \/\/ pb1036b : MOBILE \u2014 garder le RECAP ouvert quand tout est complete.\r\n            \/\/   Quand actif === -1 (plus rien a renseigner), la regle generale\r\n            \/\/   ferme TOUTES les etapes. Sur desktop c'est sans consequence : le\r\n            \/\/   bouton \"Continuer la reservation\" reste visible hors du recap.\r\n            \/\/   Sur mobile il est DANS le recap replie -> l'utilisateur arrive au\r\n            \/\/   bout de sa saisie sans plus rien a cliquer, ce qui bloque le\r\n            \/\/   parcours a sa derniere etape.\r\n            \/\/   On ouvre donc le recap plutot que de ne rien ouvrir : c'est un\r\n            \/\/   cas particulier de la meme regle \u2014 la derniere etape reste\r\n            \/\/   l'etape courante tant que l'action finale n'est pas faite.\r\n            \/\/   Un repli MANUEL du recap reste possible : _viaManuel1036 est\r\n            \/\/   evalue avant et l'emporte (option B, inchangee).\r\n            \/\/   Desktop non concerne, conformement a la demande.\r\n            \/\/   Revert : window._viaPb1036bOff = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1036bOff !== true) {\r\n                if (actif === -1) {\r\n                    if (!window._viaManuel1036) {\r\n                        if (window.outerWidth < 1000) { cible = 'recap'; }\r\n                    }\r\n                }\r\n            }\r\n            \/\/ ================================================================\r\n            \/\/ pb1064 : NE PAS SE FIER A SA PROPRE DECISION PRECEDENTE.\r\n            \/\/   Constat user (mobile) : apres le Continuer, si l'on modifie un\r\n            \/\/   element et que la selection redevient complete, le RECAP reste\r\n            \/\/   FERME \u2014 alors que pb1036b doit l'ouvrir.\r\n            \/\/   Cause : ce court-circuit. La signature reste '111111' avant et\r\n            \/\/   apres la modification, et la cible reste 'recap' : le sequenceur\r\n            \/\/   conclut \"rien de nouveau\" et sort. Or entre-temps pb740d a FERME\r\n            \/\/   le recap au Continuer. Le sequenceur croyait sa decision encore\r\n            \/\/   appliquee, alors que le DOM avait change sous lui.\r\n            \/\/   Meme famille que pb1025 : un mecanisme qui relit son propre etat\r\n            \/\/   memorise au lieu de l'etat reel.\r\n            \/\/   On retire donc ce raccourci. Le cout est nul : la boucle qui suit\r\n            \/\/   compare deja section par section l'etat REEL (etat[c.cle]) a l'etat\r\n            \/\/   voulu, et ne touche que ce qui differe. Elle est donc idempotente\r\n            \/\/   par construction \u2014 le court-circuit n'apportait qu'un faux gain.\r\n            \/\/   Revert : window._viaPb1064Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1064Off === true) {\r\n                if (!change) {\r\n                    if (window._viaCible1036 === cible) { return; }\r\n                }\r\n            }\r\n            \/\/ pb1251b : demande explicite d'ouverture des Secteurs (pb1058).\r\n            \/\/   Consommee une seule fois : l'utilisateur reste libre de replier\r\n            \/\/   l'etape ensuite, la demande ne se represente pas.\r\n            if (window._viaForceSecteurs1251 === true) {\r\n                window._viaForceSecteurs1251 = false;\r\n                window._viaManuel1036 = null;\r\n                cible = 'secteurs';\r\n            }\r\n            window._viaCible1036 = cible;\r\n            const etat = window._via632 || {};\r\n            this.config632().forEach(c => {\r\n                const doitEtreOuvert = (c.cle === cible);\r\n                const estOuvert = (etat[c.cle] !== false);\r\n                if (estOuvert === doitEtreOuvert) {\r\n                    return;\r\n                }   \/\/ deja dans le bon etat\r\n                if (doitEtreOuvert) {\r\n                    \/\/ ========================================================\r\n                    \/\/ pb2172 : PENDANT UNE RESYNCHRONISATION, ON NE ROUVRE RIEN.\r\n                    \/\/   Constat JF : au choix d'un TARIF, les etapes secteurs et\r\n                    \/\/   dates (deja faites) se rouvrent.\r\n                    \/\/   Le releve des completions donne la mecanique : la chaine\r\n                    \/\/   syncDepuisResa651 -> _selectionnerSitePays651 ->\r\n                    \/\/   onFormulaireChange -> majEtapes631 REJOUE la sequence\r\n                    \/\/   depuis le debut \u2014 010000, 110000, 111000, 111100, 111111.\r\n                    \/\/   A chaque etat INTERMEDIAIRE, le sequenceur fait son\r\n                    \/\/   travail et ouvre la premiere etape non encore completee\r\n                    \/\/   (\u00ab dates[false]=OUVRE \u00bb, puis annonceur, puis tarifs).\r\n                    \/\/   Ces ouvertures sont des artefacts de rejeu : elles\r\n                    \/\/   traduisent un etat transitoire, pas une intention.\r\n                    \/\/   Le verrou existe deja et sert exactement a cela :\r\n                    \/\/   _sync651EnCours, celui que pb781 lit pour filtrer les\r\n                    \/\/   poussees d'origine non utilisateur. On s'en sert ici pour\r\n                    \/\/   les OUVERTURES seulement \u2014 les fermetures restent\r\n                    \/\/   autorisees (elles vont dans le sens de l'etat final et ne\r\n                    \/\/   font jamais reapparaitre une etape).\r\n                    \/\/   La derniere passe, hors verrou, ouvrira la vraie cible.\r\n                    \/\/   Revert : window._viaPb2172Off = true.\r\n                    \/\/ ========================================================\r\n                    if (window._viaPb2172Off === true ? false : (window._sync651EnCours === true)) {\r\n                        \/\/ ====================================================\r\n                        \/\/ pb2173 : DIFFERER N EST PAS ANNULER.\r\n                        \/\/   Constat JF : avec pb2172 seul, l'etape Dates ne\r\n                        \/\/   s'ouvre plus du tout. Le log le montre \u2014 la DERNIERE\r\n                        \/\/   passe porte encore \u00ab OUVRE-differe \u00bb : le verrou\r\n                        \/\/   _sync651EnCours est toujours pose quand le sequenceur\r\n                        \/\/   rend la main, donc l'ouverture legitime n'a jamais\r\n                        \/\/   lieu. pb2172 supprimait le rejeu ET la vraie ouverture.\r\n                        \/\/   RATTRAPAGE : on attend la LEVEE du verrou, puis on\r\n                        \/\/   relance majEtapes631 \u2014 qui recalcule la cible sur\r\n                        \/\/   l'etat FINAL et ouvre ce qu'il faut, une seule fois.\r\n                        \/\/   On ne memorise pas la cle a rouvrir : elle serait\r\n                        \/\/   perimee. C'est la decision qu'on rejoue, pas le geste.\r\n                        \/\/   Latch unique + plafond (20 x 150 ms = 3 s) : un verrou\r\n                        \/\/   qui ne retomberait pas ne laisse pas de minuteur vivant.\r\n                        \/\/   Revert : window._viaPb2173Off = true.\r\n                        \/\/ ====================================================\r\n                        if (window._viaPb2173Off === true ? false : !window._viaAttente2173) {\r\n                            window._viaAttente2173 = true;\r\n                            var _self2173 = this;\r\n                            var _n2173 = 0;\r\n                            var _tick2173 = setInterval(function () {\r\n                                _n2173 = _n2173 + 1;\r\n                                if (window._sync651EnCours === true) {\r\n                                    if (_n2173 < 20) { return; }\r\n                                    clearInterval(_tick2173);\r\n                                    window._viaAttente2173 = false;\r\n                                    console.warn('[pb2173] verrou sync651EnCours toujours pose apres '\r\n                                        + (_n2173 * 150) + 'ms -> rattrapage abandonne');\r\n                                    return;\r\n                                }\r\n                                clearInterval(_tick2173);\r\n                                window._viaAttente2173 = false;\r\n                                console.log('[pb2173] verrou leve apres ' + (_n2173 * 150)\r\n                                    + 'ms -> sequenceur rejoue (ouverture de la vraie cible)');\r\n                                try { _self2173.majEtapes631(); }\r\n                                catch (_e2173) { console.warn('[pb2173] ' + _e2173.message); }\r\n                            }, 150);\r\n                        }\r\n                        return;\r\n                    }\r\n                    this.setSection632(c.cle, true);\r\n                } else {\r\n                    this.fermerSmooth647(c.cle);\r\n                }           \/\/ fermeture animee, comme avant\r\n            });\r\n            console.log('[pb1036] completions ' + sig + ' -> \u00e9tape ouverte : '\r\n                + (cible || '(aucune, tout compl\u00e9t\u00e9)')\r\n                + (window._viaManuel1036 ? ' [choix manuel]' : ''));\r\n            \/* REGLE 5.4 : c'est ici, sur l'etape dates, que \u00ab attendre 1 mn \u00bb\r\n               a ete diagnostique \u2014 pb1956 puis pb1964. L'enonce complet est en\r\n               tete de yearbook-media.js. La sonde pb1963 qui l'a etabli est\r\n               retiree par pb2225 ; la regle, elle, reste. *\/\r\n        } catch (_e1036) { console.warn('[pb1036]', _e1036.message); }\r\n    }\r\n\r\n    majBoutonEtape644f(toutComplete) {\r\n        const $btn = $('#PopupTarifsBoutonContinuerResaTexte, .PopupTarifsBoutonContinuerResaTexte').first();\r\n        if ($btn.length === 0) { return; }\r\n        const el = $btn[0];\r\n        \/\/ memoriser la couleur d'origine au tout premier passage (trace : plus\r\n        \/\/   utilisee pour le rendu depuis que les deux teintes sont explicites)\r\n        if (!el.dataset.couleurInit644) {\r\n            const c = getComputedStyle(el).color;\r\n            el.dataset.couleurInit644 = c || 'rgb(33, 56, 100)';\r\n        }\r\n        const ROUGE = '#fb5e2a';\r\n        \/\/ pb718 : couleur PAR DEFAUT (etat non actif) : le bleu #225DA9 devient\r\n        \/\/   le gris #808080, le meme que les titres d'etape inactifs (pb682).\r\n        \/\/   Le rouge d'appel a l'action est inchange.\r\n        const DEFAUT = '#808080';\r\n        \/\/ rouge seulement si tout est complete ET pas encore clique\r\n        \/\/ pb737c : le bouton garde sa regle d'origine (rouge = tout complete ET pas\r\n        \/\/   encore clique). Le recap, lui, passe par _accesRecap737 : les deux\r\n        \/\/   conditions ont diverge, elles ne partagent donc plus de helper.\r\n        const rouge = toutComplete ? !window._resaClique644f : false;\r\n        this._autoContinuer845(toutComplete);   \/\/ pb845\r\n        \/\/ pb738 : quand la consigne \"Merci de choisir un espace publicitaire\" est\r\n        \/\/   affichee, elle impose sa propre couleur. majBoutonEtape644f est rejoue\r\n        \/\/   a chaque majEtapes631 et ecraserait le rouge sinon.\r\n        const _consigne738 = (el.dataset.actif738 === '1') ? (window._viaPb738Off !== true) : false;\r\n        const couleur = _consigne738 ? '#fb5e2a' : (rouge ? ROUGE : DEFAUT);\r\n        el.style.setProperty('color', couleur, 'important');\r\n        $btn.find('*').each(function() {\r\n            this.style.setProperty('color', couleur, 'important');\r\n        });\r\n    }\r\n\r\n    \/\/ pb688 : libelle du bouton \"Continuer la reservation\". majBoutonEtape644f\r\n    \/\/   ci-dessus ne touche QUE la couleur : le texte pose ici n'est pas ecrase\r\n    \/\/   par les rejeux de majEtapes631. Le libelle d'origine est memorise en\r\n    \/\/   dataset au premier passage, pour pouvoir le restaurer si besoin.\r\n    majTexteBouton688(html) {\r\n        const $btn = $('#PopupTarifsBoutonContinuerResaTexte, .PopupTarifsBoutonContinuerResaTexte').first();\r\n        if ($btn.length === 0) { console.warn('[pb688] bouton introuvable'); return; }\r\n        const el = $btn[0];\r\n        if (!el.dataset.txtInit688) { el.dataset.txtInit688 = (el.textContent || '').trim(); }\r\n        \/\/ pb690 : libelle sur DEUX lignes -> innerHTML (le <br> est un noeud, il ne\r\n        \/\/   peut pas passer par textContent). L'idempotence ne peut donc plus se\r\n        \/\/   tester sur textContent (qui recollerait les deux lignes sans separateur) :\r\n        \/\/   on memorise le HTML pose dans un dataset dedie.\r\n        if (el.dataset.txt688 === html) { return; }\r\n        el.innerHTML = html;\r\n        el.dataset.txt688 = html;\r\n        \/\/ le retour a la ligne n'apparait pas si un parent impose nowrap\r\n        el.style.setProperty('white-space', 'normal', 'important');\r\n        this._style738(el, html);   \/\/ pb738\r\n        this._msgOrdi850(html);     \/\/ pb850\r\n        console.log('[pb688] libelle bouton -> \"' + html + '\" (origine : \"' + el.dataset.txtInit688 + '\")');\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb850 : DESKTOP \u2014 #PopupTarifsBoutonContinuerResaOrdiMessageConteiner remplace\r\n    \/\/   visuellement le bouton masque par pb845. Il porte les MEMES textes, dans les\r\n    \/\/   MEMES conditions :\r\n    \/\/     espace non reserve -> \"Merci de choisir un espace publicitaire\", rouge #fb5e2a\r\n    \/\/     espace reserve     -> \"Reservation en cours\", gris #808080\r\n    \/\/   Branche sur majTexteBouton688, le writer UNIQUE du libelle : les deux zones\r\n    \/\/   ne peuvent pas diverger, et un futur libelle sera repercute sans intervention.\r\n    \/\/   Le conteneur est masque par Elementor (elementor-hidden-*) : on retire ces\r\n    \/\/   classes ET on pose display en inline !important \u2014 une classe seule ne suffit\r\n    \/\/   pas face a un display:none !important de la feuille (lecon pb694, pb766).\r\n    \/\/   Affiche UNIQUEMENT apres le clic simule (drapeau pose par pb845) : avant, il\r\n    \/\/   n'y a rien a dire et le conteneur doit rester invisible.\r\n    \/\/   Revert : window._viaPb850Off = true.\r\n    \/\/ ================================================================\r\n    _msgOrdi850(html) {\r\n        if (window._viaPb850Off === true) { return; }\r\n        if (window.outerWidth < 1000) { return; }        \/\/ desktop uniquement\r\n        if (window._viaClicSimule850 !== true) { return; }   \/\/ pas encore declenche\r\n        try {\r\n            \/\/ pb851 : AUTONOMIE. Appele sans texte, le message calcule le sien.\r\n            \/\/   Il dependait de majLibelleResa738, qui sort des que _resaClique644f\r\n            \/\/   repasse a false \u2014 ce que fait onFormulaireChange au moindre champ\r\n            \/\/   modifie apres le clic. Le message restait alors fige sur \"Merci de\r\n            \/\/   choisir un espace publicitaire\" et ne passait jamais au gris.\r\n            \/\/   Le seul etat qui compte ici est _espaceReserve738 : on le lit\r\n            \/\/   directement, comme le fait pb738b, plutot que d'heriter d'un arbitre\r\n            \/\/   dont la condition d'entree est plus restrictive.\r\n            if (html === undefined) {\r\n                html = this._espaceReserve738()\r\n                    ? this._texteResaEnCours738()\r\n                    : this._texteMerci738();\r\n            }\r\n            const $c850 = $('#PopupTarifsBoutonContinuerResaOrdiMessageConteiner,'\r\n                + ' .PopupTarifsBoutonContinuerResaOrdiMessageConteiner');\r\n            if ($c850.length === 0) {\r\n                console.warn('[pb850] PopupTarifsBoutonContinuerResaOrdiMessageConteiner introuvable');\r\n                return;\r\n            }\r\n            \/\/ cible du texte : un enfant dedie s'il existe, sinon le conteneur Elementor\r\n            let $t850 = $c850.find('[id*=\"OrdiMessage\"][id*=\"Texte\"]').first();\r\n            if ($t850.length === 0) { $t850 = $c850.find('.elementor-widget-container').first(); }\r\n            if ($t850.length === 0) { $t850 = $c850.first(); }\r\n            const _reserve850 = this._espaceReserve738();\r\n            const _couleur850 = _reserve850 ? '#808080' : '#fb5e2a';\r\n            \/\/ ================================================================\r\n            \/\/ pb1268 : NE PAS REAFFICHER CE MESSAGE quand le catalogue a quitte\r\n            \/\/   le popup Tarifs (achat express en 3 colonnes).\r\n            \/\/   Constat user : le conteneur reste visible malgre le masquage pose\r\n            \/\/   par pb1266. Le HTML le montre en display:block !important \u2014 c'est\r\n            \/\/   CETTE ligne qui le repose, et un inline !important ne se laisse\r\n            \/\/   pas battre par un autre inline pose plus tot.\r\n            \/\/   Deux writers pour une propriete : on corrige celui qui ecrit en\r\n            \/\/   dernier, pas celui qui subit. Ce message accompagne le bouton du\r\n            \/\/   popup Tarifs ; hors de ce popup, il n'a plus d'objet.\r\n            \/\/   Revert : window._viaPb1268Off = true.\r\n            \/\/ ================================================================\r\n            var _hors1268 = (window._viaPb1268Off === true)\r\n                ? false\r\n                : (window._viaCatalogueDeplace1264 === true);\r\n            if (_hors1268) {\r\n                $c850.each(function () {\r\n                    if (this.style.getPropertyValue('display') !== 'none') {\r\n                        this.style.setProperty('display', 'none', 'important');\r\n                    }\r\n                });\r\n                if (window._viaSig1268b !== 'masque') {\r\n                    window._viaSig1268b = 'masque';\r\n                    console.log('[pb1268] message ordi masqu\u00e9 (catalogue hors du popup Tarifs)');\r\n                }\r\n                return;\r\n            }\r\n            $c850.each(function () {\r\n                this.classList.remove('elementor-hidden-desktop', 'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                this.style.setProperty('display', 'block', 'important');\r\n            });\r\n            \/\/ pb852 : dans le message ORDI, \"Reservation en cours\" tient sur UNE ligne.\r\n            \/\/   Le <br> vient de pb690, pose pour le BOUTON qui est etroit ; ce\r\n            \/\/   conteneur ne l'est pas. On le retire ici seulement \u2014 le libelle du\r\n            \/\/   bouton, masque sur desktop mais visible sur mobile, garde ses deux\r\n            \/\/   lignes.\r\n            const _html852 = String(html || '').replace(\/<br\\s*\\\/?>\/gi, ' ');\r\n            const _el850 = $t850[0];\r\n            if (_el850.dataset.txt850 !== _html852) {\r\n                _el850.innerHTML = _html852;\r\n                _el850.dataset.txt850 = _html852;\r\n            }\r\n            _el850.style.setProperty('color', _couleur850, 'important');\r\n            _el850.style.setProperty('white-space', 'normal', 'important');\r\n            $t850.find('*').each(function () {\r\n                this.style.setProperty('color', _couleur850, 'important');\r\n            });\r\n            if (window._viaSig850 !== _html852 + '|' + _couleur850) {\r\n                window._viaSig850 = _html852 + '|' + _couleur850;\r\n                console.log('[pb850\/pb852] message ordi -> \"' + _html852 + '\" | '\r\n                    + (_reserve850 ? 'gris (espace reserve)' : 'rouge (espace a choisir)'));\r\n            }\r\n        } catch (_e850) { console.warn('[pb850]', _e850.message); }\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb738 : l'etat \"Reservation en cours\" (pose par pb688\/pb690) devient\r\n    \/\/   \"Merci de choisir un espace publicitaire\" : c'est une CONSIGNE, pas un\r\n    \/\/   statut. Police 1px sous la taille courante (pb738c), texte rouge #fb5e2a.\r\n    \/\/   Le libelle est substitue dans majTexteBouton688, writer UNIQUE du texte :\r\n    \/\/   l'appelant (L1943) n'a pas a connaitre la regle, et un futur appelant en\r\n    \/\/   heritera automatiquement.\r\n    \/\/   La taille de base est mesuree UNE fois et memorisee en dataset : sans ca,\r\n    \/\/   chaque passe retrancherait 2px de plus (idempotence, motif pb722b).\r\n    \/\/   Le rouge est pose ici en inline important, donc APRES majBoutonEtape644f\r\n    \/\/   qui ecrit la couleur d'etat ; mais celle-ci est rejouee a chaque\r\n    \/\/   majEtapes631, d'ou la re-application ci-dessous a chaque passe.\r\n    \/\/   Revert : window._viaPb738Off = true.\r\n    \/\/ ================================================================\r\n    _texteResaEnCours738() { return 'R\\u00e9servation<br>en cours'; }\r\n\r\n    _style738(el, html) {\r\n        if (window._viaPb738Off === true) { return; }\r\n        if (!el.dataset.fsBase738) {\r\n            var _fs738 = parseFloat(getComputedStyle(el).fontSize);\r\n            if (_fs738 > 0) { el.dataset.fsBase738 = String(_fs738); }\r\n        }\r\n        var _actif738 = (html === this._texteMerci738());\r\n        if (_actif738) {\r\n            if (el.dataset.fsBase738) {\r\n                \/\/ pb738c : ecart ramene de 2px a 1px.\r\n                el.style.setProperty('font-size', (parseFloat(el.dataset.fsBase738) - 1) + 'px', 'important');\r\n            }\r\n            el.style.setProperty('color', '#fb5e2a', 'important');\r\n            $(el).find('*').each(function () { this.style.setProperty('color', '#fb5e2a', 'important'); });\r\n        } else {\r\n            el.style.removeProperty('font-size');\r\n        }\r\n        el.dataset.actif738 = _actif738 ? '1' : '0';\r\n        console.log('[pb738] etat=' + (_actif738 ? 'ACTIF' : 'inactif')\r\n            + ' | base=' + (el.dataset.fsBase738 || '?') + 'px');\r\n    }\r\n\r\n    _texteMerci738() { return 'Merci de choisir un espace publicitaire'; }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb740 : apres le clic sur \"Continuer la reservation\", les etapes Secteurs et\r\n    \/\/   Recap se rouvraient toutes seules. Deux ouvreurs AUTOMATIQUES en cause :\r\n    \/\/     - secteurs : afficherListeSecteurs615 termine par etatSecteurs618(true)\r\n    \/\/       (L3359). rejouerSync635, appele au Continuer, resynchronise le secteur\r\n    \/\/       ou l'article et repasse par ce chemin.\r\n    \/\/     - recap : majRecap737 forcait setSection632('recap', true) des que\r\n    \/\/       _resaClique644f etait vrai (pb737c).\r\n    \/\/   Les deux sont neutralises ici. L'ouverture MANUELLE reste possible : le\r\n    \/\/   handler de clic sur les titres n'appelle pas ce verrou.\r\n    \/\/   Revert : window._viaPb740Off = true.\r\n    \/\/ ================================================================\r\n    _verrouApresContinuer740() {\r\n        if (window._viaPb740Off === true) { return false; }\r\n        return window._resaClique644f === true;\r\n    }\r\n\r\n    \/\/ pb738b : un espace pub est-il REELLEMENT reserve ? Critere aligne sur celui\r\n    \/\/   de Panier_manager (L902\/L1080\/L1125), source unique de la notion :\r\n    \/\/     estReserveEffective === true  OU  statut === 'complete'\r\n    \/\/   On interroge l'item ACTIF ; a defaut d'item actif, aucun espace n'est\r\n    \/\/   reserve. Aucune regle dupliquee, aucun flag maison.\r\n    _espaceReserve738() {\r\n        try {\r\n            const _p = window.VIA_Panier;\r\n            if (!_p) { return false; }\r\n            if (!_p.state) { return false; }\r\n            const _id = _p.state.itemActif;\r\n            if (!_id) { return false; }\r\n            const _it = (_p.state.items || []).find(function (i) { return i.id === _id; });\r\n            if (!_it) { return false; }\r\n            return _it.estReserveEffective === true ? true : _it.statut === 'complete';\r\n        } catch (_e738b) { console.warn('[pb738b]', _e738b.message); return false; }\r\n    }\r\n\r\n    \/\/ pb738b : arbitre le libelle a poser une fois le Continuer clique.\r\n    \/\/     espace NON reserve -> consigne rouge, 2px de moins  (pb738)\r\n    \/\/     espace reserve     -> 'Reservation en cours', taille et gris normaux\r\n    \/\/   Rejoue a chaque majEtapes631 : l'etat est DEDUIT, jamais enchaine (pb631).\r\n    majLibelleResa738() {\r\n        if (window._resaClique644f !== true) { return; }   \/\/ Continuer pas encore clique\r\n        if (window._viaPb738Off === true) { this.majTexteBouton688(this._texteResaEnCours738()); return; }\r\n        const _res738 = this._espaceReserve738();\r\n        this.majTexteBouton688(_res738 ? this._texteResaEnCours738() : this._texteMerci738());\r\n        this._msgOrdi850(_res738 ? this._texteResaEnCours738() : this._texteMerci738());   \/\/ pb850\r\n    }\r\n\r\n    \/\/ pb644 : sous chaque titre d'etape COMPLETEE et dont l'accordeon est FERME,\r\n    \/\/   afficher la donnee renseignee en vert, 11px. Etat accordeon lu depuis\r\n    \/\/   window._via632 (jamais depuis le rendu, cf regle pb632).\r\n    valeurEtape644(cle) {\r\n        const s = this.state;\r\n        if (cle === 'annonceur') {\r\n            return ($('input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]').val() || '').trim();\r\n        }\r\n        if (cle === 'pays') {\r\n            \/\/ pb644c : le pays du SITE = cartouche selectionne dans la liste\r\n            \/\/   (.v290-row.v290-on), pas state.paysSelectionne (qui peut porter\r\n            \/\/   le pays de l'annonceur ou une valeur obsolete).\r\n            const $on = $('#PopupTarifsListePays .v290-row.v290-on[data-kind=\"pays\"]').first();\r\n            if ($on.length) { return ($on.text() || '').trim(); }\r\n            return '';\r\n        }\r\n        if (cle === 'dates') {\r\n            const d = $('#form-field-PopupTarifsDebutCampagne').val()\r\n                   || $('input[name=\"form_fields[PopupTarifsDebutCampagne]\"]').val() || '';\r\n            const f = $('#form-field-PopupTarifsFinCampagne').val()\r\n                   || $('input[name=\"form_fields[PopupTarifsFinCampagne]\"]').val() || '';\r\n            const n = s.dureeJours || 0;\r\n            return (d && f) ? ('Du ' + d + ' au ' + f + ' (' + n + ' jours)') : '';\r\n        }\r\n        if (cle === 'tarifs') {\r\n            const cl = s.tarifSelectionne;\r\n            if (!cl) { return ''; }\r\n            const m = TARIF_MAPPING[cl];\r\n            if (!m) { return ''; }\r\n            \/\/ ================================================================\r\n            \/\/ pb1057 : LIBELLES DE POSITION LISIBLES (demande user).\r\n            \/\/   Le sous-titre vert affichait le code interne : \"Parrainage \u2014 cdp\r\n            \/\/   Autres P. \u2014 566 EUR\". \"cdp Autres P.\" est la cle technique de\r\n            \/\/   TARIF_MAPPING, pas un libelle destine au client \u2014 la grille\r\n            \/\/   tarifaire, elle, dit \"Sur Autres Pages en Corps de page\".\r\n            \/\/   On traduit donc a l'AFFICHAGE, sans toucher a TARIF_MAPPING : ces\r\n            \/\/   cles servent aussi de parametre a l'API de calcul (position) et de\r\n            \/\/   critere ailleurs (suffixes HP\/PP). Les renommer casserait le calcul\r\n            \/\/   des tarifs \u2014 l'affichage et la donnee doivent rester distincts.\r\n            \/\/   Les six libelles sont ceux de la grille affichee a l'ecran, pour que\r\n            \/\/   le client retrouve mot pour mot la ligne qu'il a choisie.\r\n            \/\/   Repli : si une cle inconnue apparait, on garde la valeur d'origine\r\n            \/\/   plutot que d'afficher un vide.\r\n            \/\/   Revert : window._viaPb1057Off = true.\r\n            \/\/ ================================================================\r\n            var _posLib1057 = m.position;\r\n            if (window._viaPb1057Off !== true) {\r\n                \/\/ ============================================================\r\n                \/\/ pb1398 : LIBELLES ALIGNES SUR LA GRILLE SIMPLIFIEE (demande user).\r\n                \/\/   pb1396 a retire \u00ab Autres Pages \u00bb et \u00ab Homepage \u00bb des libelles de\r\n                \/\/   la grille : le sous-titre vert doit dire la meme chose, sinon il\r\n                \/\/   nomme une ligne que l'utilisateur ne voit plus sous ce nom.\r\n                \/\/     avant : \u00ab Parrainage \u2014 Sur Autres Pages en Haut de page \u2014 374 EUR \u00bb\r\n                \/\/     apres : \u00ab Parrainage \u2014 Haut de page \u2014 374 EUR \u00bb\r\n                \/\/   Le raisonnement de pb1057 tient toujours et c'est pourquoi la\r\n                \/\/   traduction reste ICI, a l'affichage : les cles de TARIF_MAPPING\r\n                \/\/   servent de parametre a l'API de calcul et de critere ailleurs\r\n                \/\/   (suffixes HP\/PP). Les renommer casserait le calcul.\r\n                \/\/   La page reste identifiee \u2014 elle est deja nommee a l'etape secteur,\r\n                \/\/   juste au-dessus dans la meme colonne : la repeter ici n'apportait\r\n                \/\/   rien et allongeait une ligne qui doit tenir sur mobile.\r\n                \/\/   Repli inchange : cle inconnue -> valeur d'origine, jamais un vide.\r\n                \/\/   Revert : window._viaPb1398Off = true (libelles longs de pb1057).\r\n                \/\/ ============================================================\r\n                var _map1057 = (window._viaPb1398Off === true)\r\n                    ? {\r\n                        'Pop-up Homepage':  'Pop-up sur Home Page',\r\n                        'Pop-up Autres P.': 'Pop-up sur Autres Pages',\r\n                        'hdp Home P.':      'Sur Home Page en Haut de page',\r\n                        'cdp Home P.':      'Sur Home Page en Corps de page',\r\n                        'hdp Autres P.':    'Sur Autres Pages en Haut de page',\r\n                        'cdp Autres P.':    'Sur Autres Pages en Corps de page'\r\n                    }\r\n                    : {\r\n                        'Pop-up Homepage':  'Pop-up',\r\n                        'Pop-up Autres P.': 'Pop-up',\r\n                        'hdp Home P.':      'Haut de page',\r\n                        'cdp Home P.':      'Corps de page',\r\n                        'hdp Autres P.':    'Haut de page',\r\n                        'cdp Autres P.':    'Corps de page'\r\n                    };\r\n                if (_map1057[m.position]) { _posLib1057 = _map1057[m.position]; }\r\n            }\r\n            let txt = m.format + ' \\u2014 ' + _posLib1057;\r\n            if (this._tarifMontant644) {\r\n                const mt = (typeof window.VIA_App !== 'undefined' ? window.VIA_App.formaterMontant : null);\r\n                const somme = mt ? window.VIA_App.formaterMontant(this._tarifMontant644, this._tarifDevise644, 0)\r\n                                 : (Math.round(this._tarifMontant644) + ' ' + this._tarifDevise644);\r\n                txt += ' \\u2014 ' + somme;\r\n            }\r\n            return txt;\r\n        }\r\n        \/\/ pb767 : sous-titre du RECAP, comme les autres etapes une fois repliee :\r\n        \/\/   \"TJM 86 EUR - Tarif 777 EUR - 9 jours\".\r\n        \/\/   Les trois valeurs viennent des memes sources que les champs du popup\r\n        \/\/   (pb612b L1512-1518) : montant converti dans la devise d'affichage,\r\n        \/\/   memorise en _tarifMontant644 \/ _tarifDevise644, et duree state.dureeJours.\r\n        \/\/   Le TJM est RECALCULE ici plutot que relu dans #PopUpTarifsTJM : lire le\r\n        \/\/   rendu au lieu de la donnee est ce qui a coute pb734 et pb766.\r\n        \/\/   Une seule valeur manquante -> pas de sous-titre du tout (un resume\r\n        \/\/   partiel serait trompeur). Remplace le retour vide de pb736.\r\n        if (cle === 'recap') {\r\n            const _mt767 = this._tarifMontant644;\r\n            const _dv767 = this._tarifDevise644;\r\n            const _du767 = s.dureeJours || 0;\r\n            if (!_mt767 ? true : (_du767 <= 0)) { return ''; }\r\n            const _fmt767 = (typeof window.VIA_App !== 'undefined')\r\n                ? window.VIA_App.formaterMontant : null;\r\n            const _tjm767 = _mt767 \/ _du767;\r\n            const _sTjm767 = _fmt767 ? window.VIA_App.formaterMontant(_tjm767, _dv767, 0)\r\n                                     : (Math.round(_tjm767) + ' ' + _dv767);\r\n            const _sTar767 = _fmt767 ? window.VIA_App.formaterMontant(_mt767, _dv767, 0)\r\n                                     : (Math.round(_mt767) + ' ' + _dv767);\r\n            const _sJrs767 = _du767 === 1 ? '1 jour' : (_du767 + ' jours');   \/\/ convention L1316\r\n            return 'TJM ' + _sTjm767 + ' - Tarif ' + _sTar767 + ' - ' + _sJrs767;\r\n        }\r\n        if (cle === 'secteurs') {\r\n            \/\/ pb644i : un titre d'article a-t-il ete choisi dans le popup ? La source\r\n            \/\/   fiable PENDANT le popup est _sync635.articleTitre (pb640), memorise\r\n            \/\/   au clic sur l'article \u2014 SelectedPageType='ArtType' n'est pose qu'au\r\n            \/\/   Continuer. On l'utilise en priorite.\r\n            const artTitre = (this._sync635 ? this._sync635.articleTitre : '')\r\n                          || (sessionStorage.getItem('SelectedPageType') === 'ArtType'\r\n                                ? (sessionStorage.getItem('Commande_Article') || '') : '');\r\n            if (artTitre) {\r\n                \/\/ pb701 : meme regle que le bandeau secteur de la regie (pb638\/pb700) \u2014\r\n                \/\/   titre d'article tronque a 50 caracteres, sans couper les mots, + ...\r\n                \/\/   On reutilise _tronquer638, exposee sur window par yearbook-media.js :\r\n                \/\/   une seule implementation de la coupe pour les DEUX contextes.\r\n                \/\/   NB : c'est le 3e appelant de cette fonction (les 2 autres sont dans\r\n                \/\/   yearbook-media.js, ~L4005 et ~L24814) \u2014 a changer ENSEMBLE.\r\n                \/\/   Repli sans troncature si la fonction n'est pas encore chargee.\r\n                return (window._tronquer638 ? window._tronquer638(artTitre, 50) : artTitre);\r\n            }\r\n            \/\/ sinon : nom du secteur choisi\r\n            const $on = $('#PopupTarifsListeSecteurs .v290-row.v290-on[data-kind=\"secteur\"]').first();\r\n            if ($on.length) { return ($on.text() || '').trim(); }\r\n            \/\/ pb1348 : la deduction \u00ab tarif Home P. -> Homepage \u00bb passe APRES l'etat.\r\n            \/\/   Elle datait de l'ordre inverse, ou le tarif seul pouvait designer la\r\n            \/\/   homepage. Depuis pb1346 c'est le secteur qui la designe, et pb1345 la\r\n            \/\/   rend cliquable : l'etat fait foi, le tarif n'est plus qu'un repli pour\r\n            \/\/   les reservations anterieures.\r\n            if (window._viaPb1348Off !== true) {\r\n                const _n1348 = this.nomSecteur1339();\r\n                if (_n1348) { return _n1348; }\r\n            }\r\n            \/\/ Home P. -> pas de secteur nomme\r\n            const cl = s.tarifSelectionne;\r\n            if (cl ? cl.endsWith('HP') : false) { return 'Homepage'; }\r\n            \/\/ ================================================================\r\n            \/\/ pb1339 : SOUS-TITRE VERT DU SECTEUR \u2014 meme angle mort que pb1337.\r\n            \/\/   Constat user : le secteur choisi trop tot n'apparait pas en vert\r\n            \/\/   sous son titre, alors que les quatre autres etapes affichent bien\r\n            \/\/   leur valeur et que le recapitulatif dit \u00ab Sect. Culture \u00bb.\r\n            \/\/   Cause : la ligne au-dessus lit le DOM \u2014 la classe v290-on \u2014 et ce\r\n            \/\/   marquage ne survit pas aux reinitialisations du catalogue. C'est\r\n            \/\/   exactement ce que pb1337 a corrige pour secteurChoisi628 ; le\r\n            \/\/   sous-titre etait le troisieme lecteur a ne pas en avoir beneficie.\r\n            \/\/   Place APRES la branche Home P. : un tarif Home Page garde son\r\n            \/\/   libelle \u00ab Homepage \u00bb, aucune bascule possible de ce cote.\r\n            \/\/   Revert : window._viaPb1339Off = true (DOM seul).\r\n            \/\/ ================================================================\r\n            if (window._viaPb1339Off !== true) {\r\n                const _n1339 = this.nomSecteur1339();\r\n                if (_n1339) {\r\n                    if (window._viaSig1339 !== _n1339) {\r\n                        window._viaSig1339 = _n1339;\r\n                        console.log('[pb1339] secteur absent du DOM -> sous-titre'\r\n                            + ' repris de l\\'\u00e9tat : ' + _n1339);\r\n                    }\r\n                    return _n1339;\r\n                }\r\n            }\r\n            return '';\r\n        }\r\n        return '';\r\n    }\r\n\r\n    \/\/ ====================================================================\r\n    \/\/ pb2222 : l'etape \u00ab Vos Reservations \u00bb est-elle l'etape ACTIVE ?\r\n    \/\/   Lu sur l'accordeon, jamais sur un drapeau. Pour chaque section de\r\n    \/\/   config632() on prend la hauteur de la copie la PLUS HAUTE : le selecteur\r\n    \/\/   peut designer plusieurs copies dont la premiere est masquee, et\r\n    \/\/   querySelector rendrait celle-la (regle du carnet).\r\n    \/\/   Retourne vrai si recap est deployee ET qu'au moins une autre est repliee.\r\n    \/\/   pb2223 : cette methode avait ete posee dans CountryAutocomplete, alors\r\n    \/\/   que son unique appelant majSousTitres644 vit dans GrilleTarifaire \u2014\r\n    \/\/   d'ou \u00ab this._recapActif2222 is not a function \u00bb a chaque passe, et la\r\n    \/\/   cascade d'erreurs qui suit (pb1912, pb651, pb1036, pb2173 : tous des\r\n    \/\/   appelants de majEtapes631). Une methode doit etre posee dans la CLASSE\r\n    \/\/   de son appelant, pas a cote de la derniere methode ecrite.\r\n    \/\/ ====================================================================\r\n    _recapActif2222(etat) {\r\n        \/\/ ================================================================\r\n        \/\/ pb2224 : L'ETAT SE LIT SUR _via632, PAS SUR LE DOM.\r\n        \/\/   Log JF : \u00ab recap=ferm \u00bb sur les HUIT lignes, alors que la capture\r\n        \/\/   montre \u00ab Vos reservations \u00bb deployee avec sa carte de reservation\r\n        \/\/   affichee. Ma mesure etait donc fausse : #PopupTarifsRecapContainer\r\n        \/\/   ne porte pas la hauteur du contenu rendu.\r\n        \/\/   Or la bonne source etait sous la main, deux lignes plus bas dans\r\n        \/\/   majSousTitres644 : \u00ab const ferme = etat[c.cle] === false \u00bb. C'est\r\n        \/\/   window._via632, et c'est deja LUI qui decide si un sous-titre est\r\n        \/\/   pose. Je suis alle chercher une seconde source de verite au lieu\r\n        \/\/   d'utiliser celle que le code voisin tient pour vraie \u2014 et les deux\r\n        \/\/   se sont contredites, comme il fallait s'y attendre.\r\n        \/\/   L'etat est donc transmis en argument : un seul lecteur, une seule\r\n        \/\/   verite, et aucun risque de divergence avec la ligne \u00ab ferme \u00bb.\r\n        \/\/   Second temoin conserve : au moins une AUTRE etape repliee, ce qui\r\n        \/\/   ecarte l'etat initial ou initAccordeons632 pose les six a true.\r\n        \/\/ ================================================================\r\n        const cfg = this.config632();\r\n        const _e2224 = etat || window._via632 || {};\r\n        let _recapOuvert2222 = false;\r\n        let _autresFermees2222 = 0;\r\n        const _detail2222 = [];\r\n        for (let _i2222 = 0; _i2222 < cfg.length; _i2222++) {\r\n            const _cle2222 = cfg[_i2222].cle;\r\n            \/\/ meme lecture, au caractere pres, que la ligne \u00ab ferme \u00bb de\r\n            \/\/   majSousTitres644 : false = ferme, tout le reste = ouvert.\r\n            const _ouv2222 = (_e2224[_cle2222] !== false);\r\n            if (_cle2222 === 'recap') { _recapOuvert2222 = _ouv2222; }\r\n            else if (!_ouv2222) { _autresFermees2222++; }\r\n            _detail2222.push(_cle2222 + (_ouv2222 ? '=ouv' : '=ferm'));\r\n        }\r\n        let _actif2222 = false;\r\n        if (_recapOuvert2222) {\r\n            if (_autresFermees2222 > 0) { _actif2222 = true; }\r\n        }\r\n        const _sig2222 = _detail2222.join(',');\r\n        if (window._viaSig2222 !== _sig2222) {\r\n            window._viaSig2222 = _sig2222;\r\n            console.log('[pb2224] accordeon (_via632) : ' + _sig2222\r\n                + ' | recap ' + (_recapOuvert2222 ? 'DEPLOYE' : 'replie')\r\n                + ', autres repliees=' + _autresFermees2222\r\n                + ' -> sous-titres verts ' + (_actif2222 ? 'RETIRES' : 'CONSERVES'));\r\n        }\r\n        return _actif2222;\r\n    }\r\n\r\n    majSousTitres644(faits) {\r\n        const cfg = this.config632();\r\n        const etat = window._via632 || {};\r\n        \/\/ faits[] est dans l'ordre de etapes631() == ordre de config632()\r\n        cfg.forEach((c, i) => {\r\n            const $ti = this._titre632(c);\r\n            if ($ti.length === 0) { return; }\r\n            \/\/ retirer l'ancien sous-titre eventuel\r\n            $ti.next('.v644-sub').remove();\r\n            const complete = faits[i] === true;\r\n            const ferme = etat[c.cle] === false;   \/\/ false = ferme (cf setSection632)\r\n            if (!complete ? true : !ferme) { return; }\r\n            \/\/ ================================================================\r\n            \/\/ pb1401 : EN 3 COLONNES, PAS DE SOUS-TITRE VERT (demande user).\r\n            \/\/   Pendant de pb1399\/pb1400 pour l'achat express : la carte de\r\n            \/\/   reservation porte deja annonceur, site, page, format, dates et\r\n            \/\/   tarif ; les repeter sous chaque titre d'etape fait doublon et\r\n            \/\/   allonge une colonne deja etroite.\r\n            \/\/   La sortie est placee ICI, AVANT la construction du noeud \u2014 pas apres\r\n            \/\/   coup avec un display:none. Deux raisons : le sous-titre est retire\r\n            \/\/   puis recree a chaque passe (ligne $ti.next('.v644-sub').remove()\r\n            \/\/   juste au-dessus), donc masquer reviendrait a masquer un noeud neuf a\r\n            \/\/   chaque fois ; et un writer qui n'ecrit pas ne peut pas etre contredit,\r\n            \/\/   alors qu'un display:none pose apres coup se serait battu avec le\r\n            \/\/   display:block !important de la ligne ~3569 \u2014 c'est exactement ce qui\r\n            \/\/   a fait echouer pb1399 sur les deux etapes pilotees par pb915.\r\n            \/\/   En sortant des 3 colonnes, la passe suivante recree le sous-titre :\r\n            \/\/   rien a restaurer.\r\n            \/\/   Le critere vient de _viaMode3col943, expose par pb1400 \u2014 une seule\r\n            \/\/   definition du mode pour tous ses consommateurs. Repli : sans lui, on\r\n            \/\/   affiche (comportement d'avant), jamais l'inverse.\r\n            \/\/   Revert : window._viaPb1401Off = true.\r\n            \/\/ ================================================================\r\n            \/\/ ================================================================\r\n            \/\/ pb2222 : SUR DESKTOP, LA REGLE EST \u00ab VOS RESERVATIONS ACTIVE \u00bb,\r\n            \/\/          ET RIEN D'AUTRE.\r\n            \/\/   Demande JF, deux fois formulee. pb2220 n'a pas suffi, et la\r\n            \/\/   capture dit pourquoi \u2014 deux causes, pas une :\r\n            \/\/     1. il restait SUBORDONNE a _tri1401 (_mode3col943). Or pb945 a\r\n            \/\/        retire .via-col-popup de ce critere ; quand la colonne est\r\n            \/\/        sortie en popup \u2014 exactement la configuration de la capture,\r\n            \/\/        #via-col-ColonneGauche \u2014 le critere peut valoir faux et toute\r\n            \/\/        la branche etait sautee sans rien journaliser. La regle\r\n            \/\/        desktop ne doit donc plus dependre du mode 3 colonnes.\r\n            \/\/     2. il lisait window._viaCible1036, qui n'est PAS l'etat de\r\n            \/\/        l'accordeon : initAccordeons632 pose les six sections a true\r\n            \/\/        avant tout sequencement, et la cible vaut null quand tout est\r\n            \/\/        complete sur desktop (pb1036b ne force 'recap' qu'en mobile).\r\n            \/\/        Sur la capture les six etapes sont completees et le recap est\r\n            \/\/        deploye : la cible ne pouvait pas dire 'recap'.\r\n            \/\/   On lit donc l'ACCORDEON, c'est-a-dire ce que JF voit. Deux temoins,\r\n            \/\/   tous deux mesures, aucun deduit :\r\n            \/\/     - la section recap est deployee ;\r\n            \/\/     - au moins une autre section est repliee, ce qui ecarte l'etat\r\n            \/\/       initial ou les six sont ouvertes sans qu'aucune ne soit active.\r\n            \/\/   setSection632 ferme en posant display:none !important : une section\r\n            \/\/   fermee a donc une hauteur nulle. C'est getBoundingClientRect().height\r\n            \/\/   qui fait foi, jamais display (regle pb2092).\r\n            \/\/   Aiguillage et non surcouche : sur desktop la branche pb1401 n'est\r\n            \/\/   plus evaluee du tout, au lieu d'etre corrigee apres coup.\r\n            \/\/   Mobile inchange : il garde son calendrier pb1406\/1407\/1408 via pb1401.\r\n            \/\/   Revert : window._viaPb2222Off = true (retour a pb1401 seul).\r\n            \/\/ ================================================================\r\n            var _mob2222 = (navigator.maxTouchPoints > 0)\r\n                ? true : (window.innerWidth < 1000);\r\n            var _regle2222 = false;\r\n            if (!_mob2222) {\r\n                if (window._viaPb2222Off !== true) { _regle2222 = true; }\r\n            }\r\n            if (_regle2222) {\r\n                if (this._recapActif2222(etat)) { return; }   \/\/ recap actif -> aucun sous-titre\r\n            } else if (window._viaPb1401Off !== true) {\r\n                var _tri1401 = false;\r\n                try {\r\n                    \/\/ pb1402 : critere commun \u2014 3 colonnes sur desktop, page web\r\n                    \/\/   affichee sur mobile. Repli sur l'ancien test si le helper\r\n                    \/\/   n'est pas encore charge (ordre des snippets).\r\n                    if (typeof window._viaInfosDansResa1402 === 'function') {\r\n                        _tri1401 = window._viaInfosDansResa1402();\r\n                    } else if (typeof window._viaMode3col943 === 'function') {\r\n                        _tri1401 = window._viaMode3col943();\r\n                    }\r\n                } catch (_e1401) {\r\n                    console.warn('[pb1401] crit\u00e8re illisible : ' + _e1401.message);\r\n                }\r\n                if (_tri1401) {\r\n                    if (window._viaSig1401 !== c.cle) {\r\n                        window._viaSig1401 = c.cle;\r\n                        console.log('[pb1401] 3 colonnes -> sous-titre \u00ab ' + c.cle\r\n                            + ' \u00bb non pos\u00e9 (la carte de r\u00e9servation porte l\\'info)');\r\n                    }\r\n                    return;\r\n                }\r\n            }\r\n            const val = this.valeurEtape644(c.cle);\r\n            if (!val) { return; }\r\n            const $sub = $('<div class=\"v644-sub\"><\/div>');\r\n            $sub.text(val);\r\n            $sub[0].style.setProperty('color', '#56BE50', 'important');\r\n            \/\/ pb1237b : TAILLE POSEE ICI, a la source.\r\n            \/\/   Constat user (HTML) : .v644-sub reste a 11px malgre pb1237.\r\n            \/\/   Cause : ce writer cree le sous-titre et pose 11px en !important a\r\n            \/\/   chaque construction. Ma passe posterieure etait effacee au sous-titre\r\n            \/\/   suivant \u2014 je corrigeais un symptome au lieu de la valeur.\r\n            \/\/   13px sur desktop, 11px sur mobile (inchange).\r\n            \/\/   Revert : window._viaPb1237Off = true.\r\n            var _fs1237 = ((window._viaPb1237Off !== true) ? (window.outerWidth >= 1000) : false)\r\n                ? '13px' : '11px';\r\n            $sub[0].style.setProperty('font-size', _fs1237, 'important');\r\n            $sub[0].style.setProperty('font-weight', '600', 'important');\r\n            $sub[0].style.setProperty('line-height', '1.2', 'important');\r\n            \/\/ pb644e : pour l'etape tarifs uniquement, remonter le sous-titre de 5px\r\n            \/\/ pb644g : ajustements verticaux par etape (base 2px).\r\n            \/\/   tarifs : +5px vers le bas (7px) ; secteurs : -5px vers le haut (-3px).\r\n            var _mt644 = '2px';\r\n            if (c.cle === 'tarifs') { _mt644 = '2px'; }   \/\/ pb644j : remonte de 5px (7->2)\r\n            else if (c.cle === 'secteurs') {\r\n                \/\/ pb644k : desktop -3px ; mobile 3px plus bas (-3 + 3 = 0px)\r\n                var _mob644 = (navigator.maxTouchPoints > 0) ? true : (window.innerWidth < 1000);\r\n                _mt644 = _mob644 ? '0px' : '-3px';\r\n            }\r\n            $sub[0].style.setProperty('margin-top', _mt644, 'important');\r\n            \/\/ pb644b : centrer SOUS le titre (et non a droite). Le titre est dans\r\n            \/\/   un conteneur flex -> forcer pleine largeur + saut de ligne flex.\r\n            $sub[0].style.setProperty('display', 'block', 'important');\r\n            $sub[0].style.setProperty('width', '100%', 'important');\r\n            $sub[0].style.setProperty('flex', '0 0 100%', 'important');\r\n            $sub[0].style.setProperty('text-align', 'center', 'important');\r\n            \/\/ pb644h : etape dates uniquement -> decaler le texte de 10px a droite\r\n            if (c.cle === 'dates') {\r\n                $sub[0].style.setProperty('padding-left', '20px', 'important');\r\n            }\r\n            $ti.after($sub);\r\n        });\r\n    }\r\n\r\n    \/\/ pb628 : au clic sur \"Continuer la reservation\", un tarif \"Autres P.\"\r\n    \/\/   impose d'avoir choisi un secteur. Sinon message\r\n    \/\/   PopupTarifsListeSecteursMessageTexte2 (masque par Elementor).\r\n    \/\/ pb656 : message d'info quand \"Articles\" est choisi sans titre d'article.\r\n    messageArticles656(afficher) {\r\n        const $msg = $('#PopupTarifsListeSecteursMessageTexte3, .PopupTarifsListeSecteursMessageTexte3').first();\r\n        if ($msg.length === 0) { return; }\r\n        $msg[0].style.setProperty('display', afficher ? 'block' : 'none', 'important');\r\n    }\r\n\r\n    messageSecteurs628(afficher) {\r\n        const $msg = $('#PopupTarifsListeSecteursMessageTexte2, .PopupTarifsListeSecteursMessageTexte2').first();\r\n        if ($msg.length === 0) { return; }\r\n        $msg[0].style.setProperty('display', afficher ? 'block' : 'none', 'important');\r\n    }\r\n\r\n    \/\/ ====================================================================\r\n    \/\/ pb1337 : LE SECTEUR SE LIT SUR L'ETAT, PAS SUR LE MARQUAGE VISUEL.\r\n    \/\/   Constat user (achat express) : un secteur choisi AVANT le tarif n'est\r\n    \/\/   pas pris en compte \u2014 \u00ab Merci de selectionner un secteur \u00bb s'affiche alors\r\n    \/\/   que la resa porte bien \u00ab Sect. Peche \u00bb. Le log donne les deux verdicts\r\n    \/\/   contradictoires, a quelques lignes d'ecart :\r\n    \/\/     [pb630] Secteur\/article choisi sans tarif Autres P. -> message\r\n    \/\/     [pb628] tarif Autres P. sans secteur -> message, reservation bloquee\r\n    \/\/   Cause : deux sources de verite pour la meme question. secteurChoisi628\r\n    \/\/   n'interrogeait que le DOM \u2014 la classe v290-on posee sur la ligne \u2014 alors\r\n    \/\/   que pb630, pb631 et pb771 lisent l'ETAT. Or ce marquage est retire par les\r\n    \/\/   reinitialisations du catalogue (l. ~4417) : le choix survit dans l'etat,\r\n    \/\/   pas dans la classe CSS. C'est la lecon pb734, deja ecrite dans ce fichier :\r\n    \/\/   lire la cle LOGIQUE, pas le visuel.\r\n    \/\/   pb771 avait fait exactement ce raisonnement pour secteurOk (~l.2114) et\r\n    \/\/   ajoute le repli sur la resa active ; secteurChoisi628 n'en avait jamais\r\n    \/\/   beneficie. On lui donne les MEMES signaux, dans le meme ordre.\r\n    \/\/   Le blocage legitime est preserve : sans secteur nulle part, tout est faux.\r\n    \/\/   'Homepage' ne compte pas \u2014 un tarif \u00ab Autres P. \u00bb exige un vrai secteur,\r\n    \/\/   c'est deja le critere de pb771.\r\n    \/\/   Revert : window._viaPb1337Off = true (DOM seul, comportement d'avant).\r\n    \/\/ ====================================================================\r\n    \/\/ ====================================================================\r\n    \/\/ pb1339 : LE NOM du secteur, lu sur l'etat quand le DOM ne le porte plus.\r\n    \/\/   secteurRenseigne1337 repond \u00ab oui \/ non \u00bb ; le sous-titre vert a besoin\r\n    \/\/   du LIBELLE. Memes sources, meme ordre, meme raison : le marquage v290-on\r\n    \/\/   ne survit pas aux reinitialisations du catalogue, le choix si.\r\n    \/\/   'Displayed' d'abord (il porte les accents : \u00ab P\u00eache \u00bb et non \u00ab Peche \u00bb).\r\n    \/\/   'Homepage' est exclu : ce cas a sa propre branche, en amont.\r\n    \/\/ ====================================================================\r\n    nomSecteur1339() {\r\n        try {\r\n            const _sy1339 = this._sync635 || {};\r\n            const _s1339 = _sy1339.secteur || '';\r\n            \/\/ pb1348 : \u00ab Homepage \u00bb est un libelle affichable comme un autre depuis\r\n            \/\/   pb1345 \u2014 il doit apparaitre dans le sous-titre vert de l'etape.\r\n            var _hpLib1348 = (window._viaPb1348Off === true) ? false : true;\r\n            if (_s1339 ? (_hpLib1348 ? true : (_s1339 !== 'Homepage')) : false) { return _s1339; }\r\n        } catch (_e1339a) {\r\n            console.warn('[pb1339] _sync635 illisible : ' + _e1339a.message);\r\n        }\r\n        try {\r\n            const _st1339 = window.VIA_Panier ? (window.VIA_Panier.state || null) : null;\r\n            const _it1339 = _st1339\r\n                ? (_st1339.items || []).find(i => i.id === _st1339.itemActif)\r\n                : null;\r\n            if (_it1339) {\r\n                const _r1339 = _it1339.selectedPageSecteurDisplayed\r\n                    || _it1339.selectedPageSecteur || '';\r\n                if (_r1339 ? (_hpLib1348 ? true : (_r1339 !== 'Homepage')) : false) { return _r1339; }\r\n            }\r\n        } catch (_e1339b) {\r\n            console.warn('[pb1339] r\u00e9sa active illisible : ' + _e1339b.message);\r\n        }\r\n        try {\r\n            const _ss1339 = sessionStorage.getItem('SelectedPageSecteurDisplayed')\r\n                || sessionStorage.getItem('SelectedPageSecteur') || '';\r\n            if (_ss1339 ? (_hpLib1348 ? true : (_ss1339 !== 'Homepage')) : false) { return _ss1339; }\r\n        } catch (_e1339c) {\r\n            console.warn('[pb1339] sessionStorage illisible : ' + _e1339c.message);\r\n        }\r\n        return '';\r\n    }\r\n\r\n    \/\/ ====================================================================\r\n    \/\/ pb1347 : FAMILLE DE LIGNES imposee par le secteur choisi.\r\n    \/\/   'HP' = homepage -> seules les lignes \u00ab ... Home Page \u00bb ont un sens ;\r\n    \/\/   'PP' = un secteur ou un article -> seules les lignes \u00ab ... Autres Pages \u00bb.\r\n    \/\/   '' = rien de choisi -> aucun filtre (la grille ne s'affiche pas encore).\r\n    \/\/   Memes sources que nomSecteur1339, mais 'Homepage' n'est pas exclu ici :\r\n    \/\/   c'est justement la valeur qui nous interesse.\r\n    \/\/ ====================================================================\r\n    _familleSecteur1347() {\r\n        if (window._viaPb1347Off === true) { return ''; }\r\n        var _lu1347 = '';\r\n        try {\r\n            var _sy1347 = this._sync635 || {};\r\n            _lu1347 = _sy1347.secteur || '';\r\n            if (!_lu1347) { _lu1347 = _sy1347.articleTitre ? 'Articles' : ''; }\r\n        } catch (_e1347a) {\r\n            console.warn('[pb1347] _sync635 illisible : ' + _e1347a.message);\r\n        }\r\n        if (!_lu1347) {\r\n            try {\r\n                var _st1347 = window.VIA_Panier ? (window.VIA_Panier.state || null) : null;\r\n                var _it1347 = _st1347\r\n                    ? (_st1347.items || []).find(i => i.id === _st1347.itemActif)\r\n                    : null;\r\n                if (_it1347) {\r\n                    _lu1347 = _it1347.selectedPageSecteurDisplayed\r\n                        || _it1347.selectedPageSecteur || '';\r\n                }\r\n            } catch (_e1347b) {\r\n                console.warn('[pb1347] r\u00e9sa active illisible : ' + _e1347b.message);\r\n            }\r\n        }\r\n        if (!_lu1347) {\r\n            try {\r\n                _lu1347 = sessionStorage.getItem('SelectedPageSecteurDisplayed')\r\n                    || sessionStorage.getItem('SelectedPageSecteur') || '';\r\n            } catch (_e1347c) {\r\n                console.warn('[pb1347] sessionStorage illisible : ' + _e1347c.message);\r\n            }\r\n        }\r\n        if (!_lu1347) { return ''; }\r\n        return (this._norm1347(_lu1347) === 'homepage') ? 'HP' : 'PP';\r\n    }\r\n\r\n    _norm1347(_t) {\r\n        var _s1347 = String(_t || '');\r\n        if (_s1347.normalize) {\r\n            _s1347 = _s1347.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '');\r\n        }\r\n        return _s1347.toLowerCase().replace(\/[^a-z]\/g, '');\r\n    }\r\n\r\n    \/\/ ====================================================================\r\n    \/\/ pb1347 : ne montrer que les lignes compatibles avec le secteur choisi.\r\n    \/\/   Demande user, consequence de l'inversion pb1346 : le secteur precede\r\n    \/\/   le tarif, il doit donc restreindre les lignes proposees.\r\n    \/\/   Les rangees sont reperees par LEUR LIBELLE, pas par un index : les six\r\n    \/\/   libelles sont ceux du mapping deja present dans ce fichier (~l.3145).\r\n    \/\/   Garde : une rangee qui contient les DEUX familles est un conteneur,\r\n    \/\/   pas une ligne \u2014 on n'y touche pas. Sans cette garde, un englobant\r\n    \/\/   ferait disparaitre toute la grille.\r\n    \/\/   On ne masque que ce qu'on a marque (data-via1347) et on ne restaure\r\n    \/\/   que cela : le display d'origine n'est jamais devine.\r\n    \/\/   Revert : window._viaPb1347Off = true.\r\n    \/\/ ====================================================================\r\n    \/\/ ====================================================================\r\n    \/\/ pb1386 : LIBELLES D'EMPLACEMENT SUR DEUX LIGNES EN MOBILE (demande user).\r\n    \/\/   Les six libelles \u2014 \u00ab Pop-up \u2013 Home Page \u00bb, \u00ab Home Page \u2013 Haut de page \u00bb,\r\n    \/\/   etc. \u2014 viennent du template Elementor mobile, pas du JS : rien a modifier\r\n    \/\/   en amont, le remplacement se fait sur le rendu.\r\n    \/\/   Le separateur vise est le tiret CADRATIN entoure d'espaces (U+2013). Le\r\n    \/\/   trait d'union de \u00ab Pop-up \u00bb est un caractere different (U+002D) et n'est\r\n    \/\/   donc jamais touche \u2014 c'est tout l'interet de cibler U+2013 plutot qu'un\r\n    \/\/   tiret generique.\r\n    \/\/   On n'ecrit que dans les feuilles textuelles (aucun enfant element) qui\r\n    \/\/   portent a la fois le separateur et un nom de page connu : une cellule de\r\n    \/\/   donnees ou un intitule de colonne ne peut pas etre atteint par erreur.\r\n    \/\/   Marquage data-via1386 : on ne repasse jamais deux fois sur la meme\r\n    \/\/   cellule, et le libelle d'origine est conserve dans l'attribut pour qu'un\r\n    \/\/   revert soit exact plutot que reconstruit.\r\n    \/\/   pb1347 n'est pas gene : il normalise en lettres seules, donc\r\n    \/\/   \u00ab Pop-up<br>Home Page \u00bb lui donne toujours \u00ab popuphomepage \u00bb.\r\n    \/\/   Revert : window._viaPb1386Off = true.\r\n    \/\/ ====================================================================\r\n    _libellesMobile1386() {\r\n        if (window._viaPb1386Off === true) { return; }\r\n        var _mob1386 = (navigator.maxTouchPoints > 0) ? true : (window.innerWidth < 1000);\r\n        if (!_mob1386) { return; }\r\n        try {\r\n            var _sep1386 = \/\\s*\\u2013\\s*\/;\r\n            var _rg1386 = document.querySelectorAll('.TarifsFormats');\r\n            var _n1386 = 0;\r\n            for (var _i1386 = 0; _i1386 < _rg1386.length; _i1386++) {\r\n                var _f1386 = _rg1386[_i1386].querySelectorAll('*');\r\n                for (var _j1386 = 0; _j1386 < _f1386.length; _j1386++) {\r\n                    var _e1386 = _f1386[_j1386];\r\n                    if (_e1386.children.length > 0) { continue; }      \/\/ pas une feuille\r\n                    if (_e1386.getAttribute('data-via1386')) { continue; }\r\n                    var _t1386 = (_e1386.textContent || '').trim();\r\n                    if (!_sep1386.test(_t1386)) { continue; }\r\n                    var _norm1386 = this._norm1347(_t1386);\r\n                    var _page1386 = (_norm1386.indexOf('homepage') !== -1)\r\n                        ? true : (_norm1386.indexOf('autrespages') !== -1);\r\n                    if (!_page1386) { continue; }\r\n                    var _parts1386 = _t1386.split(_sep1386);\r\n                    if (_parts1386.length < 2) { continue; }\r\n                    _e1386.setAttribute('data-via1386', _t1386);\r\n                    _e1386.innerHTML = _parts1386\r\n                        .map(function (_p) {\r\n                            return _p.replace(\/&\/g, '&amp;')\r\n                                     .replace(\/<\/g, '&lt;')\r\n                                     .replace(\/>\/g, '&gt;');\r\n                        })\r\n                        .join('<br>');\r\n                    _n1386++;\r\n                    \/\/ ============================================================\r\n                    \/\/ pb1389 : CELUI QUI AGRANDIT LA RANGEE EN ASSUME LA MARGE.\r\n                    \/\/   Constat user : _viaPb1388Off et _viaMargeRangee1318 n'ont\r\n                    \/\/   aucun effet sur le chevauchement. La raison est dans la garde\r\n                    \/\/   de pb1318 (~l.2849) : il ne s'execute QUE si\r\n                    \/\/   _viaCatalogueDeplace1264 est vrai. Hors de ce cas \u2014 et c'est\r\n                    \/\/   celui de la capture \u2014 la marge negative appliquee vient du\r\n                    \/\/   TEMPLATE Elementor (-15px), pas de pb1318. Mon pb1388 corrigeait\r\n                    \/\/   donc un writer qui ne tournait pas.\r\n                    \/\/   Ces -15px supposent un libelle d'UNE ligne. En le passant sur\r\n                    \/\/   deux, c'est ce code-ci qui rend le resserrement intenable : il\r\n                    \/\/   doit donc neutraliser la marge lui-meme, ici, sans dependre du\r\n                    \/\/   contexte ni d'un autre correctif.\r\n                    \/\/   La valeur d'origine est conservee dans data-via1389 : on ne\r\n                    \/\/   retire que ce qu'on a pose, et un revert la restituerait\r\n                    \/\/   exactement.\r\n                    \/\/   Knob : window._viaMargeRangee1389 (0 par defaut).\r\n                    \/\/   Revert : window._viaPb1389Off = true.\r\n                    \/\/ ============================================================\r\n                }\r\n            }\r\n            \/\/ ================================================================\r\n            \/\/ pb1393 : LA PREMIERE RANGEE **VISIBLE**, ET ELLE SEULE.\r\n            \/\/   Retour d'experience, dans l'ordre :\r\n            \/\/     pb1389 mettait la marge a 0 sur TOUTES les rangees reformatees ->\r\n            \/\/       chevauchement corrige, mais deux inter-espaces en trop ;\r\n            \/\/     pb1390 voulait ne garder que la premiere -> plus rien ne marchait.\r\n            \/\/   Le log pb1392 dit pourquoi : \u00ab 1re rang\u00e9e h=0 \u00bb. Ma \u00ab premiere \u00bb etait\r\n            \/\/   une rangee MASQUEE par le filtre pb1347 \u2014 les lignes Home Page restent\r\n            \/\/   dans le DOM, en display:none, avant les lignes Autres Pages. Chercher\r\n            \/\/   par voisinage revenait a designer une rangee invisible.\r\n            \/\/   On repart de ce qui marchait (pb1389) en ne retenant que les rangees\r\n            \/\/   REELLEMENT AFFICHEES : pb1347 marque celles qu'il cache avec\r\n            \/\/   data-via1347 \u2014 un temoin fiable meme quand la grille entiere est\r\n            \/\/   encore masquee et que toutes les hauteurs valent 0.\r\n            \/\/   La premiere visible passe a 0 ; les suivantes retrouvent la marge\r\n            \/\/   d'origine relue dans data-via1389, jamais reconstruite.\r\n            \/\/   Knob : window._viaMargeRangee1389 (0). Revert : _viaPb1389Off = true.\r\n            \/\/ ================================================================\r\n            if (_n1386) {\r\n                console.log('[pb1386] ' + _n1386 + ' libell\u00e9(s) d\\'emplacement pass\u00e9(s)'\r\n                    + ' sur deux lignes (mobile)');\r\n            }\r\n        } catch (_e1386b) {\r\n            console.warn('[pb1386] mise en forme des libell\u00e9s : ' + _e1386b.message);\r\n        }\r\n    }\r\n\r\n    \/\/ ====================================================================\r\n    \/\/ pb1396 : FIGER LA FAMILLE D'UNE RANGEE AVANT DE TOUCHER A SON LIBELLE.\r\n    \/\/   L'utilisateur demande de masquer \u00ab Autres Pages \u00bb et \u00ab Homepage \u00bb dans les\r\n    \/\/   six libelles \u2014 et signale lui-meme le piege : ce sont ces mots qui servent\r\n    \/\/   a reconnaitre les lignes (pb1347). Les retirer du texte reviendrait a\r\n    \/\/   scier la branche.\r\n    \/\/   La famille est donc DEDUITE UNE FOIS, avant toute reecriture, et conservee\r\n    \/\/   dans data-viafam1396. Tous les lecteurs passent ensuite par cet attribut :\r\n    \/\/   le libelle peut etre reduit, traduit ou reformate sans qu'aucun repere ne\r\n    \/\/   se perde. C'est le principe deja retenu ici \u2014 l'etat semantique porte\r\n    \/\/   l'information, jamais le rendu (pb734, pb1337-1340).\r\n    \/\/   'MIXTE' marque un conteneur qui contient les deux familles : ce n'est pas\r\n    \/\/   une ligne, et le filtre doit le laisser tranquille.\r\n    \/\/ ====================================================================\r\n    _familleRangee1396(_row1396) {\r\n        try {\r\n            var _memo1396 = _row1396.getAttribute('data-viafam1396');\r\n            if (_memo1396) { return _memo1396; }\r\n            var _t1396 = this._norm1347(_row1396.textContent);\r\n            var _hp1396 = (_t1396.indexOf('homepage') !== -1);\r\n            var _pp1396 = (_t1396.indexOf('autrespages') !== -1);\r\n            var _f1396 = (_hp1396 ? (_pp1396 ? 'MIXTE' : 'HP') : (_pp1396 ? 'PP' : ''));\r\n            if (_f1396) { _row1396.setAttribute('data-viafam1396', _f1396); }\r\n            return _f1396;\r\n        } catch (_e1396) {\r\n            console.warn('[pb1396] famille illisible : ' + _e1396.message);\r\n            return '';\r\n        }\r\n    }\r\n\r\n    \/\/ ====================================================================\r\n    \/\/ pb1396 : MASQUER \u00ab Autres Pages \u00bb \/ \u00ab Homepage \u00bb DANS LES LIBELLES.\r\n    \/\/   Demande user, achat express UNIQUEMENT : la recherche est bornee a\r\n    \/\/   #TarifsCatalogueConteneur, comme pb1286 le fait deja pour le meme motif \u2014\r\n    \/\/   le process classique affiche la meme grille et ne doit pas etre touche.\r\n    \/\/   Le libelle est decoupe sur le tiret cadratin ; les segments qui SONT un nom\r\n    \/\/   de page disparaissent, les autres restent :\r\n    \/\/     \u00ab Pop-up \u2013 Autres Pages \u00bb        -> \u00ab Pop-up \u00bb\r\n    \/\/     \u00ab Autres Pages \u2013 Haut de page \u00bb  -> \u00ab Haut de page \u00bb\r\n    \/\/     \u00ab Autres Pages \u2013 Corps de page \u00bb -> \u00ab Corps de page \u00bb\r\n    \/\/   La famille ayant ete figee juste avant, le filtrage pb1347 continue de\r\n    \/\/   fonctionner sur un texte d'ou le mot a disparu.\r\n    \/\/   Le libelle d'origine est conserve dans data-via1396 : un revert le\r\n    \/\/   restituerait exactement plutot que de le reconstruire.\r\n    \/\/   Effet de bord assume et traite : le libelle n'a plus qu'un segment, donc\r\n    \/\/   pb1386 ne le passera plus sur deux lignes \u2014 et la marge posee par pb1393\r\n    \/\/   sur la premiere rangee n'a plus lieu d'etre. Elle est rendue ici.\r\n    \/\/   Revert : window._viaPb1396Off = true.\r\n    \/\/ ====================================================================\r\n    \/\/ ====================================================================\r\n    \/\/ pb1397 : LA PREMIERE RANGEE DE TARIFS NE DOIT PAS REMONTER SOUS L'EN-TETE.\r\n    \/\/   Le chevauchement est revenu des que pb1396 a reduit les libelles. J'en\r\n    \/\/   avais tire la mauvaise conclusion a deux reprises : ce n'est pas le libelle\r\n    \/\/   sur deux lignes qui deborde, c'est l'EN-TETE \u2014 \u00ab Formats, tarifs &\r\n    \/\/   emplacements \u00bb, sur deux lignes dans le template Elementor, bien avant nos\r\n    \/\/   modifications. La marge negative de la premiere rangee la fait alors\r\n    \/\/   remonter par-dessus.\r\n    \/\/   La correction ne doit donc dependre NI du reformatage pb1386, NI du\r\n    \/\/   masquage pb1396 : elle vaut des qu'il y a une rangee de tarifs sous\r\n    \/\/   l'en-tete. C'est ce que pb1393 faisait bien, mais adosse au mauvais critere.\r\n    \/\/   Le bon repere est data-viafam1396, pose sur les seules rangees de TARIFS :\r\n    \/\/   l'en-tete n'en a pas (ni \u00ab Home Page \u00bb ni \u00ab Autres Pages \u00bb dans son texte),\r\n    \/\/   et il survit a toute reecriture de libelle puisqu'il est fige avant.\r\n    \/\/   Les rangees masquees par pb1347 sont ignorees \u2014 la lecon du tour precedent :\r\n    \/\/   les lignes Home Page restent dans le DOM en display:none.\r\n    \/\/   Knob : window._viaMargeRangee1389. Revert : window._viaPb1389Off = true.\r\n    \/\/ ====================================================================\r\n    _margePremiereRangee1397() {\r\n        if (window._viaPb1389Off === true) { return; }\r\n        try {\r\n            var _rows1397 = document.querySelectorAll('.TarifsFormats');\r\n            var _vus1397 = 0;\r\n            for (var _r1397 = 0; _r1397 < _rows1397.length; _r1397++) {\r\n                var _ro1397 = _rows1397[_r1397];\r\n                var _fam1397 = _ro1397.getAttribute('data-viafam1396');\r\n                if (_fam1397 ? (_fam1397 === 'MIXTE') : true) { continue; }\r\n                if (_ro1397.getAttribute('data-via1347') === '1') { continue; }\r\n                _vus1397++;\r\n                var _pose1397 = _ro1397.getAttribute('data-via1389');\r\n                if (_vus1397 === 1) {\r\n                    if (!_pose1397) {\r\n                        var _mt1397 = parseFloat(\r\n                            window.getComputedStyle(_ro1397).marginTop) || 0;\r\n                        if (_mt1397 < 0) {\r\n                            var _cible1397 = (typeof window._viaMargeRangee1389 === 'number')\r\n                                ? window._viaMargeRangee1389 : 0;\r\n                            _ro1397.setAttribute('data-via1389', String(_mt1397));\r\n                            _ro1397.style.setProperty('margin-top',\r\n                                _cible1397 + 'px', 'important');\r\n                            console.log('[pb1397] 1re rang\u00e9e de tarifs : marge '\r\n                                + _mt1397 + 'px -> ' + _cible1397\r\n                                + 'px (chevauchement sous l\\'en-t\u00eate supprim\u00e9)');\r\n                        }\r\n                    }\r\n                } else if (_pose1397) {\r\n                    _ro1397.style.setProperty('margin-top', _pose1397 + 'px', 'important');\r\n                    _ro1397.removeAttribute('data-via1389');\r\n                    console.log('[pb1397] rang\u00e9e ' + _vus1397 + ' : marge '\r\n                        + _pose1397 + 'px rendue (resserrement conserv\u00e9)');\r\n                }\r\n            }\r\n        } catch (_e1397) {\r\n            console.warn('[pb1397] marges impossibles : ' + _e1397.message);\r\n        }\r\n    }\r\n\r\n    _masquerTermesPage1396() {\r\n        if (window._viaPb1396Off === true) { return; }\r\n        try {\r\n            var _cat1396 = document.getElementById('TarifsCatalogueConteneur');\r\n            if (!_cat1396) { return; }   \/\/ hors achat express : rien a faire\r\n            var _rows1396 = _cat1396.querySelectorAll('.TarifsFormats');\r\n            var _sep1396 = \/\\s*\\u2013\\s*\/;\r\n            var _n1396 = 0;\r\n            for (var _i1396 = 0; _i1396 < _rows1396.length; _i1396++) {\r\n                var _ro1396 = _rows1396[_i1396];\r\n                this._familleRangee1396(_ro1396);   \/\/ fige AVANT de reecrire\r\n                var _f1396 = _ro1396.querySelectorAll('*');\r\n                for (var _j1396 = 0; _j1396 < _f1396.length; _j1396++) {\r\n                    var _el1396 = _f1396[_j1396];\r\n                    if (_el1396.children.length > 0) { continue; }\r\n                    if (_el1396.getAttribute('data-via1396')) { continue; }\r\n                    var _t1396 = (_el1396.textContent || '').trim();\r\n                    if (!_sep1396.test(_t1396)) { continue; }\r\n                    var _self1396 = this;\r\n                    var _restants1396 = _t1396.split(_sep1396).filter(function (_seg) {\r\n                        var _ns = _self1396._norm1347(_seg);\r\n                        return (_ns === 'autrespages') ? false : (_ns !== 'homepage');\r\n                    });\r\n                    if (_restants1396.length === 0) { continue; }\r\n                    if (_restants1396.length === _t1396.split(_sep1396).length) { continue; }\r\n                    _el1396.setAttribute('data-via1396', _t1396);\r\n                    _el1396.textContent = _restants1396.join(' \\u2013 ');\r\n                    \/\/ pb1397 : NE PAS rendre la marge ici. pb1396 le faisait, en\r\n                    \/\/   supposant que le chevauchement venait des libelles sur deux\r\n                    \/\/   lignes. Il n'en venait pas : c'est l'EN-TETE (\u00ab Formats, tarifs\r\n                    \/\/   & emplacements \u00bb, sur deux lignes dans le template) qui deborde\r\n                    \/\/   sur la rangee suivante. Reduire les libelles n'y change rien,\r\n                    \/\/   et rendre la marge a fait revenir le chevauchement aussitot.\r\n                    _n1396++;\r\n                }\r\n            }\r\n            if (_n1396) {\r\n                console.log('[pb1396] ' + _n1396 + ' libell\u00e9(s) r\u00e9duit(s) \u2014 \u00ab Autres Pages \u00bb'\r\n                    + ' \/ \u00ab Homepage \u00bb masqu\u00e9(s) (achat express)');\r\n            }\r\n        } catch (_e1396b) {\r\n            console.warn('[pb1396] masquage des termes : ' + _e1396b.message);\r\n        }\r\n    }\r\n\r\n    \/\/ ========================================================================\r\n    \/\/ pb1913 : DANS LE POPUP DES SITES PAYS, L'EMPLACEMENT EST DEJA CHOISI.\r\n    \/\/   Constat user (capture + log) : trois rangees s'affichent \u2014 Pop-up, Haut de\r\n    \/\/   page, Corps de page \u2014 alors que l'utilisateur a clique l'espace Ele1A, dont\r\n    \/\/   l'item porte deja la position calculee : \u00ab hdp Home P. \u00bb.\r\n    \/\/   pb1347 filtrait bien, mais sur la seule FAMILLE de page (HP \/ PP) : les six\r\n    \/\/   rangees etaient reduites aux trois \u00ab Home Page \u00bb. Il manquait la seconde\r\n    \/\/   dimension, la POSITION \u2014 et elle n'existe que dans ce parcours, ou l'espace\r\n    \/\/   precede la grille au lieu de la suivre.\r\n    \/\/   La position vient de l'ITEM et de nulle part ailleurs : item.position est\r\n    \/\/   pose par VIA_Panier.calculerPosition(rank, typePage) au moment de la\r\n    \/\/   creation, et le releve pb1903 l'a confirmee exacte. On ne la recalcule pas\r\n    \/\/   ici \u2014 une valeur derivee ne devient jamais sa propre source (pb1750).\r\n    \/\/   Le rapprochement se fait sur le LIBELLE de la rangee, comme le fait deja\r\n    \/\/   _familleRangee1396, et non sur un index : les six rangees sont un contenu\r\n    \/\/   Elementor, leur ordre peut changer. Le creneau est fige dans\r\n    \/\/   data-viaslot1913 des la premiere lecture \u2014 pb1396 reecrit les libelles pour\r\n    \/\/   en retirer \u00ab Home Page \u00bb \/ \u00ab Autres Pages \u00bb, et une lecture posterieure\r\n    \/\/   resterait juste, mais on ne s'appuie pas sur cette chance.\r\n    \/\/   Revert : window._viaPb1913Off = true (filtrage par famille seul).\r\n    \/\/ ========================================================================\r\n    _slotPosition1913(_pos1913) {\r\n        var _p1913 = this._norm1347(_pos1913);\r\n        if (!_p1913) { return ''; }\r\n        if (_p1913.indexOf('popup') !== -1) { return 'popup'; }\r\n        if (_p1913.indexOf('hdp') !== -1) { return 'hdp'; }\r\n        if (_p1913.indexOf('cdp') !== -1) { return 'cdp'; }\r\n        if (_p1913.indexOf('hautdepage') !== -1) { return 'hdp'; }\r\n        if (_p1913.indexOf('corpsdepage') !== -1) { return 'cdp'; }\r\n        return '';\r\n    }\r\n\r\n    _slotRangee1913(_row1913) {\r\n        try {\r\n            var _memo1913 = _row1913.getAttribute('data-viaslot1913');\r\n            if (_memo1913 !== null) { return _memo1913; }\r\n            var _t1913 = this._norm1347(_row1913.textContent);\r\n            var _s1913 = (_t1913.indexOf('popup') !== -1) ? 'popup'\r\n                : ((_t1913.indexOf('hautdepage') !== -1) ? 'hdp'\r\n                    : ((_t1913.indexOf('corpsdepage') !== -1) ? 'cdp' : ''));\r\n            _row1913.setAttribute('data-viaslot1913', _s1913);\r\n            return _s1913;\r\n        } catch (_e1913) {\r\n            console.warn('[pb1913] creneau illisible : ' + _e1913.message);\r\n            return '';\r\n        }\r\n    }\r\n\r\n    \/\/ Creneau IMPOSE par l'espace deja reserve, ou '' si rien n'est impose.\r\n    \/\/   Hors popup pays, cette methode rend '' : la regie n'est pas touchee.\r\n    _slotImpose1913() {\r\n        if (window._viaPb1913Off === true) { return ''; }\r\n        try {\r\n            if (typeof window._viaPopupPays1905 !== 'function') { return ''; }\r\n            if (!window._viaPopupPays1905()) { return ''; }\r\n            var _st1913 = window.VIA_Panier ? (window.VIA_Panier.state || null) : null;\r\n            var _it1913 = _st1913\r\n                ? (_st1913.items || []).filter(function (_i) { return _i.id === _st1913.itemActif; })[0]\r\n                : null;\r\n            if (!_it1913) { return ''; }\r\n            var _pos1913 = _it1913.position\r\n                || (_it1913.donneesIframe ? _it1913.donneesIframe.PositionDataVosCampagnes : '')\r\n                || '';\r\n            var _slot1913 = this._slotPosition1913(_pos1913);\r\n            if (window._viaSig1913 !== _slot1913) {\r\n                window._viaSig1913 = _slot1913;\r\n                console.log('[pb1913] emplacement impose par la resa : position=\"'\r\n                    + (_pos1913 || '(vide)') + '\" -> creneau=' + (_slot1913 || 'AUCUN')\r\n                    + ' | espace=' + (_it1913.emplacementPageWeb || '?'));\r\n            }\r\n            return _slot1913;\r\n        } catch (_eI1913) {\r\n            console.warn('[pb1913] creneau impose illisible : ' + _eI1913.message);\r\n            return '';\r\n        }\r\n    }\r\n\r\n    _filtrerLignes1347() {\r\n        if (window._viaPb1347Off === true) { return; }\r\n        try {\r\n            var _fam1347 = this._familleSecteur1347();\r\n            var _slotCible1913 = this._slotImpose1913();   \/\/ pb1913\r\n            var _rg1347 = document.querySelectorAll('.TarifsFormats');\r\n            var _cache1347 = 0;\r\n            var _rendu1347 = 0;\r\n            for (var _i1347 = 0; _i1347 < _rg1347.length; _i1347++) {\r\n                var _e1347 = _rg1347[_i1347];\r\n                var _fam1396 = this._familleRangee1396(_e1347);\r\n                var _hp1347 = (_fam1396 === 'HP');\r\n                var _pp1347 = (_fam1396 === 'PP');\r\n                if (_fam1396 === 'MIXTE') { _hp1347 = true; _pp1347 = true; }\r\n                if (_hp1347 ? _pp1347 : false) { continue; }   \/\/ conteneur, pas une ligne\r\n                if (_hp1347 ? false : !_pp1347) { continue; }  \/\/ ni l'un ni l'autre (en-tete)\r\n                var _garder1347 = _fam1347\r\n                    ? (_fam1347 === 'HP' ? _hp1347 : _pp1347)\r\n                    : true;\r\n                \/\/ pb1913 : seconde dimension du filtre \u2014 le creneau. On l'ajoute DANS\r\n                \/\/   ce filtre plutot que d'en ecrire un second : deux ecrivains sur le\r\n                \/\/   meme display, avec chacun son attribut de memoire, est exactement\r\n                \/\/   ce que ce projet passe son temps a demeler. Un filtre, un attribut\r\n                \/\/   (data-via1347), une restauration.\r\n                if (_garder1347) {\r\n                    if (_slotCible1913) {\r\n                        _garder1347 = (this._slotRangee1913(_e1347) === _slotCible1913);\r\n                    }\r\n                }\r\n                if (_garder1347) {\r\n                    if (_e1347.getAttribute('data-via1347') === '1') {\r\n                        _e1347.removeAttribute('data-via1347');\r\n                        _e1347.style.removeProperty('display');\r\n                        _rendu1347++;\r\n                    }\r\n                } else {\r\n                    if (_e1347.getAttribute('data-via1347') !== '1') {\r\n                        _e1347.setAttribute('data-via1347', '1');\r\n                        _e1347.style.setProperty('display', 'none', 'important');\r\n                        _cache1347++;\r\n                    }\r\n                }\r\n            }\r\n            if (_cache1347 + _rendu1347 > 0) {\r\n                console.log('[pb1347] lignes filtr\u00e9es | secteur=' + (_fam1347 || '(aucun)')\r\n                    + ' | cr\u00e9neau pb1913=' + (_slotCible1913 || '(aucun)')\r\n                    + ' | masqu\u00e9es=' + _cache1347 + ' | rendues=' + _rendu1347\r\n                    + ' | rang\u00e9es examin\u00e9es=' + _rg1347.length);\r\n            }\r\n        } catch (_e1347d) {\r\n            console.warn('[pb1347] filtrage impossible : ' + _e1347d.message);\r\n        }\r\n    }\r\n\r\n    \/\/ ====================================================================\r\n    \/\/ pb1347 : un tarif devenu incompatible est VIDE et l'etape rouverte.\r\n    \/\/   Demande user : \u00ab on le vide et on rouvre l'etape tarif avec les\r\n    \/\/   nouveaux tarifs \u00bb. Le cas se produit quand l'utilisateur revient sur\r\n    \/\/   l'etape secteur apres avoir deja choisi un tarif d'une autre famille.\r\n    \/\/   On reprend le meme geste que la reinitialisation du catalogue\r\n    \/\/   (~l.4593) : etat interne + demarquage pb785 par data-col785.\r\n    \/\/ ====================================================================\r\n    _viderTarifIncompatible1347() {\r\n        if (window._viaPb1347Off === true) { return false; }\r\n        try {\r\n            var _cl1347 = this.state ? this.state.tarifSelectionne : null;\r\n            if (!_cl1347) { return false; }\r\n            var _fam1347 = this._familleSecteur1347();\r\n            if (!_fam1347) { return false; }\r\n            var _famTarif1347 = String(_cl1347).endsWith('HP') ? 'HP' : 'PP';\r\n            if (_famTarif1347 === _fam1347) { return false; }\r\n            this.state.tarifSelectionne = null;\r\n            this._tarifMontant644 = null;\r\n            var _mq1347 = document.querySelectorAll('[data-col785]');\r\n            for (var _m1347 = 0; _m1347 < _mq1347.length; _m1347++) {\r\n                try { this._teinte785(_mq1347[_m1347], false, false); }\r\n                catch (_eT1347) { console.warn('[pb1347] d\u00e9marquage : ' + _eT1347.message); }\r\n            }\r\n            console.log('[pb1347] tarif ' + _cl1347 + ' (' + _famTarif1347\r\n                + ') incompatible avec le secteur (' + _fam1347 + ') -> vid\u00e9,'\r\n                + ' \u00e9tape tarif rouverte');\r\n            return true;\r\n        } catch (_e1347e) {\r\n            console.warn('[pb1347] vidage impossible : ' + _e1347e.message);\r\n            return false;\r\n        }\r\n    }\r\n\r\n    secteurRenseigne1337() {\r\n        if (window._viaPb1337Off === true) { return false; }\r\n        if (window._viaEtape5Ok631 === true) { return true; }\r\n        try {\r\n            const _sy1337 = this._sync635 || {};\r\n            const _sec1337 = _sy1337.secteur || '';\r\n            \/\/ pb1348 : \u00ab Homepage \u00bb compte desormais. pb1337 l'excluait parce qu'elle\r\n            \/\/   n'etait pas selectionnable dans la liste (filtre pb862) ; pb1345 l'y a\r\n            \/\/   remise, c'est un choix de page a part entiere.\r\n            var _hpOk1348 = (window._viaPb1348Off === true) ? false : true;\r\n            \/\/ ============================================================\r\n            \/\/ pb1353 : \u00ab Articles \u00bb SANS titre n'est pas un choix termine.\r\n            \/\/   Constat user : au clic sur \u00ab Articles \u00bb, l'etape secteur se\r\n            \/\/   referme et l'on ne peut plus atteindre la liste des titres.\r\n            \/\/   Le log en donne la chaine complete :\r\n            \/\/     [pb617] choix clique: Articles | secteur: Aerien\r\n            \/\/     [pb631] etapes 111100          <- le 4e chiffre passe a 1\r\n            \/\/     [pb1036] completions 111100 -> \u00e9tape ouverte : tarifs\r\n            \/\/     [pb647] etape auto-fermee (smooth): secteurs\r\n            \/\/   \u00ab Articles \u00bb est un choix INTERMEDIAIRE : il ouvre la liste des\r\n            \/\/   titres, il ne la conclut pas. Le compter comme fait declenchait\r\n            \/\/   le sequenceur, qui passait a l'etape suivante et repliait\r\n            \/\/   celle-ci \u2014 emportant la liste que l'utilisateur devait lire.\r\n            \/\/   pb656 tenait deja ce raisonnement au Continuer (\u00ab secteur\r\n            \/\/   Articles sans titre choisi -> bloque \u00bb) ; il manquait ici.\r\n            \/\/   Revert : window._viaPb1353Off = true.\r\n            \/\/ ============================================================\r\n            var _artSeul1353 = (window._viaPb1353Off === true)\r\n                ? false\r\n                : ((_sec1337 === 'Articles') ? !_sy1337.articleTitre : false);\r\n            if (_artSeul1353) { return false; }\r\n            if (_sec1337 ? (_hpOk1348 ? true : (_sec1337 !== 'Homepage')) : false) { return true; }\r\n            if (_sy1337.articleTitre) { return true; }\r\n        } catch (_e1337a) {\r\n            console.warn('[pb1337] _sync635 illisible : ' + _e1337a.message);\r\n        }\r\n        try {\r\n            const _st1337 = window.VIA_Panier ? (window.VIA_Panier.state || null) : null;\r\n            const _it1337 = _st1337\r\n                ? (_st1337.items || []).find(i => i.id === _st1337.itemActif)\r\n                : null;\r\n            if (_it1337) {\r\n                const _r1337 = _it1337.selectedPageSecteurDisplayed\r\n                    || _it1337.selectedPageSecteur || '';\r\n                if (_r1337 ? (_hpOk1348 ? true : (_r1337 !== 'Homepage')) : false) { return true; }\r\n                if (_it1337.articleTitre) { return true; }\r\n            }\r\n        } catch (_e1337b) {\r\n            console.warn('[pb1337] r\u00e9sa active illisible : ' + _e1337b.message);\r\n        }\r\n        return false;\r\n    }\r\n\r\n    secteurChoisi628() {\r\n        const $host = $('#PopupTarifsListeSecteurs, .PopupTarifsListeSecteurs').first();\r\n        const _dom1337 = ($host.length === 0)\r\n            ? false\r\n            : ($host.find('.v290-row.v290-on[data-kind=\"secteur\"]').length > 0);\r\n        if (_dom1337) { return true; }\r\n        \/\/ pb1337 : le marquage visuel manque -> interroger l'etat.\r\n        const _sem1337 = this.secteurRenseigne1337();\r\n        if (_sem1337) {\r\n            if (window._viaSig1337 !== true) {\r\n                window._viaSig1337 = true;\r\n                console.log('[pb1337] secteur non marqu\u00e9 dans le DOM mais renseign\u00e9'\r\n                    + ' dans l\\'\u00e9tat -> pris en compte');\r\n            }\r\n        }\r\n        return _sem1337;\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb845 : sur DESKTOP, le bouton \"Continuer la reservation\" est masque et son\r\n    \/\/   clic simule des que les CINQ etapes sont completees.\r\n    \/\/   Une seule fois par RESERVATION : le declenchement est memorise par id\r\n    \/\/   d'item. pb648 remet le bouton actif a chaque nouveau tarif \u2014 sans cette\r\n    \/\/   memoire, on obtiendrait clic -> resync -> nouveau tarif -> clic, soit la\r\n    \/\/   boucle infinie de pb780.\r\n    \/\/   Le clic passe par le HANDLER EXISTANT (capture sur document, L ci-dessous) :\r\n    \/\/   aucune logique dupliquee, et ses gardes pb628\/pb656 s'appliquent \u2014 un tarif\r\n    \/\/   \"Autres P.\" sans secteur reste bloque, comme pour un clic humain.\r\n    \/\/   Le clic est SYNTHETIQUE : isTrusted vaudra false, ce que pb777\/pb781\/pb782\r\n    \/\/   savent deja distinguer.\r\n    \/\/   MOBILE ET DVM INCHANGES : le bouton y reste visible et manuel.\r\n    \/\/   Revert : window._viaPb845Off = true.\r\n    \/\/ ================================================================\r\n    _autoContinuer845(toutComplete) {\r\n        if (window._viaPb845Off === true) { return; }\r\n        if (window.outerWidth < 1000) { return; }   \/\/ desktop uniquement\r\n        try {\r\n            \/\/ 1) masquer le conteneur \u2014 messages compris (choix utilisateur)\r\n            const $b845 = $('#PopupTarifsBoutonContinuerResa, .PopupTarifsBoutonContinuerResa');\r\n            $b845.each(function () {\r\n                if (getComputedStyle(this).display !== 'none') {\r\n                    this.style.setProperty('display', 'none', 'important');\r\n                }\r\n                \/\/ pb845b : masquer aussi le CONTENEUR PARENT. Masquer le seul bouton\r\n                \/\/   laissait son conteneur Elementor occuper la place (e-con-full en\r\n                \/\/   flex, avec ses propres marges) \u2014 l'espace restait reserve.\r\n                \/\/   GARDE : on ne masque le parent que s'il ne contient QUE ce bouton.\r\n                \/\/   Un conteneur partage emporterait ses voisins, et Elementor\r\n                \/\/   reorganise ces imbrications d'une revision a l'autre.\r\n                const _par845 = this.parentElement;\r\n                if (!_par845) { return; }\r\n                if (_par845.children.length !== 1) {\r\n                    console.log('[pb845b] parent non masque : il contient '\r\n                        + _par845.children.length + ' elements');\r\n                    return;\r\n                }\r\n                if (getComputedStyle(_par845).display !== 'none') {\r\n                    _par845.style.setProperty('display', 'none', 'important');\r\n                    console.log('[pb845b] conteneur parent masque : '\r\n                        + (_par845.getAttribute('data-id') || _par845.className.split(' ')[1] || '?'));\r\n                }\r\n            });\r\n            \/\/ ================================================================\r\n            \/\/ pb1906 : DANS LE POPUP DES SITES PAYS, PAS DE CLIC AUTOMATIQUE.\r\n            \/\/   Reponse user : \u00ab Continuer la reservation n'est plus necessaire, le\r\n            \/\/   clic sur le tarif suffit \u00bb. La resa existe deja (creee par\r\n            \/\/   popupLateParams), la page est celle que l'utilisateur regarde, et\r\n            \/\/   #ColonneGauche est masquee par pb1905 : rejouerSync635 cliquerait des\r\n            \/\/   cartouches invisibles et DisplayPageWeb ouvrirait un VLP dont\r\n            \/\/   personne n'a besoin.\r\n            \/\/   La sortie est placee ICI, APRES le masquage du bouton (etape 1\r\n            \/\/   ci-dessus) et AVANT le clic : on garde ce que pb845\/pb845b font de\r\n            \/\/   juste \u2014 le bouton et son conteneur disparaissent \u2014 et on abandonne le\r\n            \/\/   seul geste qui n'a plus de sens. La sonde pb1903 a confirme que ce\r\n            \/\/   masquage tourne deja dans ce contexte (bouton a display:none).\r\n            \/\/   Revert : window._viaPb1906Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1906Off !== true) {\r\n                if ((typeof window._viaPopupPays1905 === 'function')\r\n                    ? window._viaPopupPays1905() : false) {\r\n                    if (window._viaSig1906 !== 'auto') {\r\n                        window._viaSig1906 = 'auto';\r\n                        console.log('[pb1906] popup pays : bouton Continuer masque,'\r\n                            + ' clic automatique NON arme (le clic sur un tarif suffit)');\r\n                    }\r\n                    return;\r\n                }\r\n            }\r\n            if (!toutComplete) { return; }\r\n            \/\/ 2) une seule fois par reservation\r\n            \/\/ ================================================================\r\n            \/\/ pb849 : NE PAS exiger de reservation active.\r\n            \/\/   pb845 sortait sur 'aucune resa active' \u2014 or dans l'achat express la\r\n            \/\/   resa n'existe pas encore : c'est PRECISEMENT ce clic qui la cree\r\n            \/\/   (le handler pb628 s'en charge). J'avais confondu la condition de\r\n            \/\/   declenchement avec la cle de memorisation.\r\n            \/\/   La memoire 'une fois par reservation' se rabat donc sur une\r\n            \/\/   SIGNATURE des cinq etapes quand aucun item n'existe : meme\r\n            \/\/   selection -> un seul clic. Des qu'une resa existe, son id reprend\r\n            \/\/   la main et la garantie redevient exacte.\r\n            \/\/   Sans cette borne, chaque passe de majEtapes631 recliquerait :\r\n            \/\/   c'est la boucle de pb780 qu'il faut eviter.\r\n            \/\/ ================================================================\r\n            const _st845 = window.VIA_Panier ? (window.VIA_Panier.state || null) : null;\r\n            const _id845 = _st845 ? _st845.itemActif : null;\r\n            let _cle845 = _id845;\r\n            if (!_cle845) {\r\n                _cle845 = 'sansresa|' + [\r\n                    sessionStorage.getItem('ContinentPaysTitre') || '',\r\n                    sessionStorage.getItem('SelectedPageSecteur') || '',\r\n                    sessionStorage.getItem('FormatSelect') || '',\r\n                    $('#form-field-PopupTarifsDebutCampagne').val() || '',\r\n                    $('#form-field-PopupTarifsFinCampagne').val() || '',\r\n                    $('input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]').val() || ''\r\n                ].join('|');\r\n            }\r\n            window._viaAutoClic845 = window._viaAutoClic845 || {};\r\n            if (window._viaAutoClic845[_cle845]) { return; }\r\n            window._viaAutoClic845[_cle845] = true;\r\n            if (!$b845.length) {\r\n                console.warn('[pb845] bouton Continuer introuvable -> clic impossible');\r\n                return;\r\n            }\r\n            console.log('[pb845\/pb849] 5 etapes completees -> clic simule sur Continuer'\r\n                + ' (bouton masque, desktop) | cle=' + _cle845\r\n                + (_id845 ? '' : ' \u2014 aucune resa : le clic va la creer'));\r\n            \/\/ differe : laisser la passe de majEtapes631 s'achever avant de relancer\r\n            \/\/   toute la chaine de reservation depuis l'interieur de cette meme passe.\r\n            const _self846 = this;\r\n            setTimeout(function () {\r\n                try { $b845[0].click(); window._viaClicSimule850 = true; }   \/\/ pb850\r\n                catch (_eC845) { console.warn('[pb845] clic:', _eC845.message); }\r\n                \/\/ ================================================================\r\n                \/\/ pb846 : REPLIER les etapes apres le clic simule.\r\n                \/\/   Le handler pb628 ferme deja Secteurs et Recap (pb740d), mais le\r\n                \/\/   repli des etapes AMONT \u2014 annonceur, pays, dates, tarifs \u2014 vient\r\n                \/\/   normalement de replierEtapesAmont633, appele par\r\n                \/\/   calculerEtAfficherGrille, donc d'un enchainement que le clic\r\n                \/\/   simule ne provoque pas toujours.\r\n                \/\/   On passe par setSection632, l'entonnoir unique : aucune\r\n                \/\/   manipulation directe de display, et l'etat logique reste juste.\r\n                \/\/   Le RECAP n'est pas touche : pb737c decide seul de son affichage\r\n                \/\/   selon que l'espace est reserve ou non.\r\n                \/\/   Differe de 400ms : laisser la chaine du clic s'achever, sinon on\r\n                \/\/   replierait avant qu'elle ne rouvre.\r\n                \/\/   Revert : window._viaPb846Off = true.\r\n                \/\/ ================================================================\r\n                if (window._viaPb846Off === true) { return; }\r\n                setTimeout(function () {\r\n                    try {\r\n                        \/\/ ================================================================\r\n                        \/\/ pb848 : POUSSER dates et annonceur vers la resa.\r\n                        \/\/   Dans l'achat express, l'utilisateur renseigne l'annonceur et les\r\n                        \/\/   dates AVANT que la reservation n'existe. La direction B\r\n                        \/\/   (syncVersResa651) sort alors sur 'if (!itemActif) return' \u2014 le\r\n                        \/\/   push est perdu, et rien ne le rejoue ensuite.\r\n                        \/\/   Log : \"synchroniserEtape1 ... tarifHT actuel: null\", puis\r\n                        \/\/   \"statut: anticipee\" avec un recap sans dates ni annonceur.\r\n                        \/\/   La resa vient d'etre creee par le clic : on rejoue donc la\r\n                        \/\/   direction B, qui trouve cette fois un item actif.\r\n                        \/\/   Rejoue AVANT le repli des etapes : replier declenche des passes\r\n                        \/\/   de majEtapes631 qui liraient un item encore incomplet.\r\n                        \/\/   Revert : window._viaPb848Off = true.\r\n                        \/\/ ================================================================\r\n                        if (window._viaPb848Off !== true) {\r\n                            const _pa848 = window.VIA_Panier;\r\n                            const _id848 = _pa848 ? (_pa848.state ? _pa848.state.itemActif : null) : null;\r\n                            if (_id848) {\r\n                                console.log('[pb848] rejeu direction B vers ' + _id848\r\n                                    + ' (dates + annonceur saisis avant la creation de la resa)');\r\n                                _self846.syncVersResa651();\r\n                            } else {\r\n                                console.warn('[pb848] aucun item actif -> dates et annonceur non transmis');\r\n                            }\r\n                        }\r\n                        \/\/ ================================================================\r\n                        \/\/ pb1055 : RESPECTER une etape ouverte A LA MAIN entre-temps.\r\n                        \/\/   Constat user : apres avoir choisi tarif et article, cliquer\r\n                        \/\/   sur le titre \"annonceur\" ne l'ouvre pas \u2014 il faut cliquer\r\n                        \/\/   une seconde fois.\r\n                        \/\/   Le log donne l'ordre exact :\r\n                        \/\/     [pb845\/pb849] 5 etapes completees -> clic simule sur Continuer\r\n                        \/\/     [pb632] annonceur deplie          <- le clic de l'utilisateur\r\n                        \/\/     [pb846] etapes repliees apres le clic simule\r\n                        \/\/   pb846 est differe de 400ms pour laisser la chaine du clic\r\n                        \/\/   s'achever. Dans cet intervalle, l'utilisateur a le temps\r\n                        \/\/   d'ouvrir une etape \u2014 et pb846 la referme aussitot, sans savoir\r\n                        \/\/   qu'elle vient d'etre ouverte deliberement. Le second clic\r\n                        \/\/   fonctionne parce que le differe est alors ecoule.\r\n                        \/\/   pb1036 memorise deja l'etape ouverte manuellement dans\r\n                        \/\/   _viaManuel1036 (option B : le clic manuel prime). On la saute\r\n                        \/\/   donc ici, plutot que d'inventer un second marqueur.\r\n                        \/\/   Revert : window._viaPb1055Off = true.\r\n                        \/\/ ================================================================\r\n                        var _manuel1055 = null;\r\n                        if (window._viaPb1055Off !== true) {\r\n                            _manuel1055 = window._viaManuel1036 || null;\r\n                        }\r\n                        ['annonceur', 'pays', 'dates', 'tarifs', 'secteurs'].forEach(function (_cle846) {\r\n                            if (_cle846 === _manuel1055) { return; }   \/\/ pb1055\r\n                            _self846.setSection632(_cle846, false);\r\n                        });\r\n                        console.log('[pb846] etapes repliees apres le clic simule'\r\n                            + ' (annonceur, pays, dates, tarifs, secteurs \u2014 recap laisse a pb737)'\r\n                            + (_manuel1055 ? ' | [pb1055] \"' + _manuel1055 + '\" laiss\u00e9e ouverte (clic manuel)' : ''));\r\n                    } catch (_eR846) { console.warn('[pb846]', _eR846.message); }\r\n                }, 400);\r\n            }, 200);\r\n        } catch (_e845) { console.warn('[pb845]', _e845.message); }\r\n    }\r\n\r\n    brancherContinuerResa628() {\r\n        if (window._viaContinuerResa628) { return; }\r\n        window._viaContinuerResa628 = true;\r\n        \/\/ capture : s'execute AVANT les handlers du bouton, pour pouvoir bloquer\r\n        document.addEventListener('click', (e) => {\r\n            const btn = e.target.closest\r\n                ? e.target.closest('#PopupTarifsBoutonContinuerResa, .PopupTarifsBoutonContinuerResa')\r\n                : null;\r\n            if (!btn) { return; }\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1906 : le Continuer n'a plus d'objet dans le popup des sites pays.\r\n            \/\/   Ce handler cree la resa, rejoue pays -> secteur -> format sur les\r\n            \/\/   cartouches du process et ouvre la page web. Les trois sont sans\r\n            \/\/   objet ici : la resa existe, les cartouches sont masques, la page est\r\n            \/\/   deja a l'ecran. On arrete le clic net plutot que de laisser la chaine\r\n            \/\/   partir a moitie.\r\n            \/\/   Le bouton est de toute facon masque par pb845\/pb1906 ; ce garde\r\n            \/\/   couvre un clic qui passerait quand meme (mobile, ou masquage defait\r\n            \/\/   par un rendu Elementor). Il journalise : une sortie muette coute un\r\n            \/\/   aller-retour (lecon pb1858).\r\n            \/\/   Revert : window._viaPb1906Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1906Off !== true) {\r\n                if ((typeof window._viaPopupPays1905 === 'function')\r\n                    ? window._viaPopupPays1905() : false) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    console.log('[pb1906] popup pays : clic Continuer ignore'\r\n                        + ' (ni rejouerSync635 ni DisplayPageWeb)');\r\n                    return;\r\n                }\r\n            }\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1348 : le blocage porte sur l'ABSENCE DE PAGE, plus sur la famille\r\n            \/\/   du tarif. \u00ab Un tarif Autres P. impose un secteur \u00bb decrivait l'ancien\r\n            \/\/   ordre. Aujourd'hui le secteur est l'etape 4 : il est requis dans TOUS\r\n            \/\/   les cas \u2014 homepage comprise, elle est devenue selectionnable (pb1345).\r\n            \/\/   L'ancienne condition laissait passer un Continuer avec un tarif\r\n            \/\/   Home P. et aucune page choisie, ce qui n'est plus un etat valide.\r\n            \/\/   Revert : window._viaPb1348Off = true.\r\n            \/\/ ================================================================\r\n            var _reqSect1348 = (window._viaPb1348Off === true)\r\n                ? this.tarifAutresPagesSelectionne622()\r\n                : true;\r\n            if (_reqSect1348 ? !this.secteurChoisi628() : false) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                this.messageSecteurs628(true);\r\n                console.log('[pb628\/pb1348] aucune page choisie -> message, r\u00e9servation bloqu\u00e9e');\r\n                return;\r\n            }\r\n            this.messageSecteurs628(false);\r\n\r\n            \/\/ pb656 : secteur = \"Articles\" mais AUCUN titre d'article choisi ->\r\n            \/\/   bloquer et afficher le message d'info #PopupTarifsListeSecteursMessageTexte3\r\n            \/\/   (sinon le rejeu ouvrait le vieux popup pb140 CartoucheArticles).\r\n            var _s656 = this._sync635 || {};\r\n            if ((_s656.secteur === 'Articles') ? !_s656.articleTitre : false) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                this.messageArticles656(true);\r\n                console.log('[pb656] secteur Articles sans titre choisi -> message 3, reservation bloquee');\r\n                return;\r\n            }\r\n            this.messageArticles656(false);\r\n\r\n            \/\/ pb644f : la reservation est lancee -> le bouton repasse au bleu initial\r\n            window._resaClique644f = true;\r\n            \/\/ pb740d : FERMER explicitement Secteurs et Recap au Continuer. Les logs\r\n            \/\/   pb740c ont montre 'avant=true' sans aucune ouverture loguee : ces\r\n            \/\/   sections n'etaient jamais rouvertes, elles n'avaient jamais ete\r\n            \/\/   FERMEES logiquement (initAccordeons632 les initialise a true, et le\r\n            \/\/   verrou pb740 affichait le recap 'selon l'etat courant' -> true).\r\n            \/\/   La fermeture passe par setSection632 (entonnoir, trace pb740c) ; le\r\n            \/\/   verrou pb740 bloque ensuite les reouvertures automatiques de la\r\n            \/\/   synchro A (hook setItemActif -> syncDepuisResa651, qui reclique\r\n            \/\/   cartouches et tarif). L'ouverture MANUELLE reste libre.\r\n            if (window._viaPb740Off !== true) {\r\n                this.setSection632('secteurs', false);\r\n                this.setSection632('recap', false);\r\n                console.log('[pb740d] secteurs + recap fermes au Continuer');\r\n            }\r\n            \/\/ pb1056 : marquer DURABLEMENT qu'un Continuer a eu lieu.\r\n            \/\/   pb1054 s'appuyait sur _resaClique644f \u2014 a tort : ce drapeau est remis\r\n            \/\/   a false des qu'on touche au formulaire (onFormulaireChange, L1277) ou\r\n            \/\/   qu'un nouveau tarif arrive (pb648, L1848). Changer le pays de\r\n            \/\/   l'annonceur le remet donc a false, et la garde tombait. Le log le\r\n            \/\/   montre : 'resaTransmise=true' au Continuer, puis 'false' juste avant\r\n            \/\/   la reouverture des secteurs.\r\n            \/\/   Ce drapeau-ci ne repond qu'a une question : le Continuer a-t-il eu\r\n            \/\/   lieu ? Il n'a donc aucune raison de retomber, et il est pose ICI, a\r\n            \/\/   l'endroit meme ou le Continuer agit.\r\n            window._viaContinuerFait1056 = true;\r\n            \/\/ pb1302 : la nouvelle reservation est lancee -> le s\u00e9lecteur de\r\n            \/\/   tarif peut de nouveau etre masque par pb1300.\r\n            window._viaNouvelleResaExpress1302 = false;\r\n            \/\/ ================================================================\r\n            \/\/ pb1307 : FIGER LA SELECTION VALIDEE.\r\n            \/\/   Demande user : en achat express, la page web ne doit s'ouvrir\r\n            \/\/   qu'apres le choix d'un tarif ET le clic sur Continuer \u2014 pas des\r\n            \/\/   qu'un site pays et des dates sont saisis.\r\n            \/\/   Un simple drapeau ne suffit pas : il resterait vrai apres coup,\r\n            \/\/   et une nouvelle selection rouvrirait la page trop tot. On\r\n            \/\/   memorise donc la SIGNATURE des valeurs au moment du Continuer.\r\n            \/\/   Tant que la signature courante lui est identique, la selection\r\n            \/\/   est celle qui a ete validee ; des qu'elle change \u2014 nouveau site,\r\n            \/\/   nouvelles dates, autre tarif \u2014 elle ne l'est plus, et la page web\r\n            \/\/   attend le prochain Continuer.\r\n            \/\/ ================================================================\r\n            try {\r\n                window._viaValeursExpress1307 = () => this._valeurs1269();\r\n                window._viaSigContinuer1307 = this._valeurs1269();\r\n                \/\/ ============================================================\r\n                \/\/ pb1313 : DRAPEAU au lieu de SIGNATURE.\r\n                \/\/   Constat user : apres le Continuer de la 1re reservation,\r\n                \/\/   l'etape page web ne revient pas et le recapitulatif devient\r\n                \/\/   actif \u2014 donc pb1312 la laisse hors du sequenceur, donc le\r\n                \/\/   critere reste \u00ab en attente \u00bb.\r\n                \/\/   Cause : la signature est figee ICI, mais rejouerSync635 court\r\n                \/\/   juste apres et renseigne le secteur et le tarif sur l'item.\r\n                \/\/   _valeurs1269 change donc immediatement, et la comparaison\r\n                \/\/   redevient fausse alors que rien n'a ete modifie par\r\n                \/\/   l'utilisateur.\r\n                \/\/   Ce projet sait deja dire \u00ab la selection a change \u00bb : c'est\r\n                \/\/   pb1064b, qui restaure pour cela le libelle du bouton. On\r\n                \/\/   s'appuie donc sur lui \u2014 un drapeau leve ici, abaisse la-bas \u2014\r\n                \/\/   au lieu d'une signature que nos propres synchros font bouger.\r\n                \/\/   La signature reste calculee : elle sert de repli si le\r\n                \/\/   drapeau n'a jamais ete pose.\r\n                \/\/ ============================================================\r\n                window._viaExpressValide1313 = true;\r\n                console.log('[pb1307] s\u00e9lection valid\u00e9e m\u00e9moris\u00e9e');\r\n            } catch (_e1307) { console.warn('[pb1307]', _e1307.message); }\r\n            \/\/ ================================================================\r\n            \/\/ pb1298 : MOBILE \u2014 remplacer les etapes du process par celles de\r\n            \/\/   l'achat express (demande user). C'est ICI le moment : le\r\n            \/\/   Continuer est le seul point ou l'on sait que la selection est\r\n            \/\/   complete, et c'est lui qui ferme le popup.\r\n            \/\/   La routine vit dans yearbook-media.js, avec le reste des\r\n            \/\/   deplacements de colonnes ; elle est sans effet sur desktop, ou\r\n            \/\/   pb1264 s'en charge deja au passage en 3 colonnes.\r\n            \/\/ ================================================================\r\n            try {\r\n                if (typeof window._viaDeplacerCatalogueMobile1298 === 'function') {\r\n                    window._viaDeplacerCatalogueMobile1298();\r\n                }\r\n            } catch (_e1298) { console.warn('[pb1298]', _e1298.message); }\r\n            \/\/ ================================================================\r\n            \/\/ pb1387 : MOBILE \u2014 DEROULER LA PAGE PARENT APRES LA FERMETURE\r\n            \/\/   (demande user). Meme moment que pb1298, pour la meme raison : le\r\n            \/\/   Continuer est le seul point ou la selection est complete, et c'est\r\n            \/\/   lui qui ferme le popup.\r\n            \/\/   Deux passes, et c'est delibere : la premiere suit la fermeture du\r\n            \/\/   popup, la seconde le deplacement du catalogue par pb1298 \u2014 qui\r\n            \/\/   change la hauteur du document juste apres. Scroller une seule fois\r\n            \/\/   viserait un bas de page qui n'est pas encore le bon.\r\n            \/\/   La hauteur est relue A CHAQUE passe plutot que memorisee : c'est\r\n            \/\/   precisement ce qui bouge entre les deux.\r\n            \/\/   Revert : window._viaPb1387Off = true.\r\n            \/\/   Delais ajustables : window._viaDelaisScroll1387 = [400, 900].\r\n            \/\/ ================================================================\r\n            if (window._viaPb1387Off !== true) {\r\n                var _mob1387 = (navigator.maxTouchPoints > 0)\r\n                    ? true : (window.innerWidth < 1000);\r\n                if (_mob1387) {\r\n                    var _n1387 = 0;\r\n                    var _scroll1387 = function () {\r\n                        _n1387++;\r\n                        try {\r\n                            \/\/ ====================================================\r\n                            \/\/ pb1416 : VISER LE TITRE, PAS LE BAS DE PAGE (demande user).\r\n                            \/\/   pb1387 descendait au bas du document. Le repere utile\r\n                            \/\/   est le titre \u00ab Choisir les espaces publicitaires \u00bb\r\n                            \/\/   (#PageWebMobileEtape) : c'est la que l'utilisateur\r\n                            \/\/   reprend, et le bas de page depend d'un contenu qui\r\n                            \/\/   n'a rien a voir avec lui.\r\n                            \/\/   Repli sur l'ancien comportement si l'element manque :\r\n                            \/\/   mieux vaut un scroll approximatif qu'aucun.\r\n                            \/\/   Les deux passes de pb1387 restent utiles \u2014 la hauteur\r\n                            \/\/   et la position du titre bougent apres le deplacement\r\n                            \/\/   du catalogue.\r\n                            \/\/   Revert : window._viaPb1416Off = true.\r\n                            \/\/ ====================================================\r\n                            var _cible1416 = (window._viaPb1416Off === true)\r\n                                ? null : document.getElementById('PageWebMobileEtape');\r\n                            if (_cible1416) {\r\n                                _cible1416.scrollIntoView({ behavior: 'smooth', block: 'start' });\r\n                                console.log('[pb1416] scroll vers #PageWebMobileEtape (passe '\r\n                                    + _n1387 + ') | haut='\r\n                                    + Math.round(_cible1416.getBoundingClientRect().top));\r\n                                return;\r\n                            }\r\n                            var _h1387 = Math.max(\r\n                                document.body ? document.body.scrollHeight : 0,\r\n                                document.documentElement ? document.documentElement.scrollHeight : 0);\r\n                            window.scrollTo({ top: _h1387, behavior: 'smooth' });\r\n                            console.log('[pb1387] #PageWebMobileEtape absent -> scroll bas'\r\n                                + ' de page (passe ' + _n1387 + ') -> ' + _h1387 + 'px');\r\n                        } catch (_eS1387) {\r\n                            console.warn('[pb1387] scroll impossible : ' + _eS1387.message);\r\n                        }\r\n                    };\r\n                    var _d1387 = Array.isArray(window._viaDelaisScroll1387)\r\n                        ? window._viaDelaisScroll1387 : [400, 900];\r\n                    _d1387.forEach(function (_ms1387) {\r\n                        setTimeout(_scroll1387, _ms1387);\r\n                    });\r\n                }\r\n            }\r\n            \/\/ pb656 : verrou anti-reset (les synchros post-clic rappellent\r\n            \/\/   onFormulaireChange et re-rougissaient le bouton).\r\n            window._resaVerrou656 = true;\r\n            setTimeout(function() { window._resaVerrou656 = false; }, 3000);\r\n            this.majBoutonEtape644f(false);\r\n\r\n            \/\/ pb635b : c'est SEULEMENT ICI qu'on synchronise les bandeaux (ce qui\r\n            \/\/   ouvre le popup page web). Rejouer les choix memorises dans l'ordre\r\n            \/\/   pays -> secteur -> format (le format vient du tarif selectionne).\r\n            this.rejouerSync635();\r\n\r\n            \/\/ pb688 : cas POSITIF uniquement. Les deux gardes ci-dessus (pb628 tarif\r\n            \/\/   Autres P. sans secteur, pb656 Articles sans titre) font return AVANT\r\n            \/\/   ce point : on n'y arrive que si la reservation part vraiment. Appel\r\n            \/\/   place APRES rejouerSync635(), qui ouvre le popup page web -> si elle\r\n            \/\/   levait, le libelle resterait inchange.\r\n            \/\/ pb738 : \"Reservation en cours\" remplace par la consigne.\r\n            this.majTexteBouton688(window._viaPb738Off === true\r\n                ? this._texteResaEnCours738()\r\n                : this._texteMerci738());\r\n\r\n            \/\/ pb654 : MOBILE \u2014 reduire le popup Express checking et reposer le VLP\r\n            \/\/   page web dessous (la fonction gere le timing d'ouverture du VLP).\r\n            if (typeof window.viaReduireEtReposer654 === 'function') {\r\n                window.viaReduireEtReposer654();\r\n            }\r\n        }, true);\r\n    }\r\n\r\n    \/\/ pb622 : un secteur choisi n'a de sens qu'avec un tarif \"Autres P.\"\r\n    \/\/   (les positions Home Page n'ont pas de secteur). Si un secteur est\r\n    \/\/   selectionne sans tarif Autres P., on affiche\r\n    \/\/   PopupTarifsListeSecteursMessageTexte (masque par Elementor).\r\n    tarifAutresPagesSelectionne622() {\r\n        const c = this.state.tarifSelectionne;\r\n        return (typeof c === 'string') ? c.endsWith('PP') : false;\r\n    }\r\n\r\n    messageSecteurs622(afficher) {\r\n        const $msg = $('#PopupTarifsListeSecteursMessageTexte, .PopupTarifsListeSecteursMessageTexte').first();\r\n        if ($msg.length === 0) { return; }\r\n        $msg[0].style.setProperty('display', afficher ? 'block' : 'none', 'important');\r\n    }\r\n\r\n    \/\/ pb630b : le message PopupTarifsListeSecteursMessageTexte s'affiche quand\r\n    \/\/   \"Secteur\" OU un titre d'article est selectionne SANS tarif \"Autres P.\".\r\n    \/\/   La selection reste libre (pas de refus) ; le message disparait des que\r\n    \/\/   le tarif Autres P. est choisi. Etat memorise puis reevalue (jamais\r\n    \/\/   deduit d'un enchainement).\r\n    evaluerMessage630() {\r\n        \/\/ ================================================================\r\n        \/\/ pb1348 : CE MESSAGE N'A PLUS D'OBJET (constat user).\r\n        \/\/   Il disait \u00ab un secteur est choisi mais pas de tarif Autres Pages \u00bb \u2014\r\n        \/\/   un reproche qui n'avait de sens que dans l'ANCIEN ordre, ou le tarif\r\n        \/\/   etait choisi EN PREMIER : selectionner ensuite un secteur avec un\r\n        \/\/   tarif Home P. etait contradictoire.\r\n        \/\/   Depuis pb1346, le secteur precede le tarif. Au moment ou il est\r\n        \/\/   choisi, aucun tarif n'existe encore : le message s'afficherait donc\r\n        \/\/   SYSTEMATIQUEMENT, et reprocherait a l'utilisateur de ne pas avoir\r\n        \/\/   fait une etape qu'on ne lui a pas encore proposee.\r\n        \/\/   La contradiction qu'il signalait est par ailleurs devenue impossible :\r\n        \/\/   pb1347 ne presente que les lignes de la famille du secteur retenu.\r\n        \/\/   On le masque donc au lieu de l'evaluer \u2014 le texte Elementor peut etre\r\n        \/\/   supprime, plus rien ne l'affiche.\r\n        \/\/   Revert : window._viaPb1348Off = true (ancienne evaluation).\r\n        \/\/ ================================================================\r\n        if (window._viaPb1348Off !== true) {\r\n            this.messageSecteurs622(false);\r\n            return;\r\n        }\r\n        const choisi = (window._viaEtape5Ok631 === true);\r\n        const afficher = choisi ? !this.tarifAutresPagesSelectionne622() : false;\r\n        this.messageSecteurs622(afficher);\r\n        if (afficher) { console.log('[pb630] Secteur\/article choisi sans tarif Autres P. -> message'); }\r\n    }\r\n\r\n    \/\/ ====================================================================\r\n    \/\/ pb1347 : geste commun a tout choix de secteur \u2014 filtrer les lignes, vider\r\n    \/\/   un tarif devenu incompatible, et rouvrir l'etape tarif dans ce cas.\r\n    \/\/   Un seul endroit pour les trois chemins (secteur, article, homepage).\r\n    \/\/ ====================================================================\r\n    \/\/ ====================================================================\r\n    \/\/ pb1363 : POSER LES CLES CANONIQUES DE LA PAGE, ICI ET MAINTENANT.\r\n    \/\/   Constat user : apres un passage homepage -> page secteur, le choix d'un\r\n    \/\/   tarif \u00ab Autres Pages \u00bb invalide la page et affiche \u00ab Merci de\r\n    \/\/   selectionner une autre page \u00bb. Le log donne le noeud du probleme :\r\n    \/\/     [pb65] DisplayPageWeb -> _vlpOpen | url: ...\/Agro-industries\r\n    \/\/            | titre: Homepage \u2013 Cameroun | type: HPType\r\n    \/\/     SessionStorage globales : commandePage 'Homepage',\r\n    \/\/            SelectedPageType 'HPType', SelectedPageSecteur 'Homepage'\r\n    \/\/   L'URL a suivi le nouveau choix, les CLES sont restees sur la homepage.\r\n    \/\/   pb1058 fait alors correctement son travail \u2014 tarif PP contre page HP,\r\n    \/\/   c'est incoherent \u2014 mais sur une donnee perimee : la page EST une page\r\n    \/\/   secteur. La regle sanctionne une contradiction qu'elle a elle-meme lue\r\n    \/\/   de travers.\r\n    \/\/   Cote catalogue, ces cles etaient posees par ricochet : _noter749 pousse\r\n    \/\/   vers la vignette, dont le handler (Click Secteurs) les ecrit. Un relais\r\n    \/\/   qui n'aboutit pas laisse l'etat a moitie mis a jour \u2014 c'est ce qui\r\n    \/\/   arrive ici. On les ecrit donc directement, au moment du choix, plutot\r\n    \/\/   que d'esperer qu'un autre chemin le fasse (lecon pb1281).\r\n    \/\/   Memes valeurs et meme mapping que pb1277 (yearbook-media.js ~l.12831),\r\n    \/\/   seule autre source qui les calcule.\r\n    \/\/   Revert : window._viaPb1363Off = true.\r\n    \/\/ ====================================================================\r\n    _poserClesPage1363() {\r\n        if (window._viaPb1363Off === true) { return; }\r\n        try {\r\n            const _sy1363 = this._sync635 || {};\r\n            const _sec1363 = _sy1363.secteur || '';\r\n            if (!_sec1363) { return; }\r\n            let _type1363 = 'PTType';\r\n            let _cmd1363 = 'Page sectorielle';\r\n            let _val1363 = _sec1363;\r\n            if (_sec1363 === 'Homepage') {\r\n                _type1363 = 'HPType'; _cmd1363 = 'Homepage'; _val1363 = 'Homepage';\r\n            } else if (_sec1363 === 'Articles') {\r\n                if (!_sy1363.articleTitre) { return; }   \/\/ choix pas encore termine\r\n                _type1363 = 'ArtType';\r\n            }\r\n            const _av1363 = (sessionStorage.getItem('SelectedPageType') || '')\r\n                + '\/' + (sessionStorage.getItem('SelectedPageSecteur') || '');\r\n            sessionStorage.setItem('SelectedPageType', _type1363);\r\n            sessionStorage.setItem('commandePage', _cmd1363);\r\n            if (_type1363 === 'ArtType') {\r\n                sessionStorage.setItem('Commande_Article', _sy1363.articleTitre);\r\n            } else {\r\n                sessionStorage.removeItem('Commande_Article');\r\n                sessionStorage.setItem('SelectedPageSecteur', _val1363);\r\n                sessionStorage.setItem('SelectedPageSecteurDisplayed', _val1363);\r\n                \/\/ ============================================================\r\n                \/\/ pb1378 : UN SECTEUR REMPLACE UN ARTICLE \u2014 il ne s'y ajoute pas.\r\n                \/\/   Constat user : d'un article vers une page secteur, le VLP suit,\r\n                \/\/   mais la carte affiche toujours \u00ab Art. Les agro-industries\u2026 \u00bb et\r\n                \/\/   le sous-titre de l'etape secteurs aussi. Le log l'isole :\r\n                \/\/     [pb693] selectedPageType=PTType | estArticle=false\r\n                \/\/             | Commande_Article=\"\"   | secteurDisplayed=Assurances\r\n                \/\/             | item.articleTitre=Cameroun \u2013 Agro-industries \u2013 \u2026\r\n                \/\/   Tout a bascule SAUF articleTitre. pb1363 nettoyait bien la cle\r\n                \/\/   globale Commande_Article, mais l'article vit a trois autres\r\n                \/\/   endroits : _sync635, l'item, et la cle indexee. Les trois sont\r\n                \/\/   nettoyes ici, dans le meme geste que la pose du secteur.\r\n                \/\/   Le titre affiche vient de la, pas d'un writer fautif : personne\r\n                \/\/   n'avait dit a l'article qu'il n'etait plus le choix courant.\r\n                \/\/   Revert : window._viaPb1378Off = true.\r\n                \/\/ ============================================================\r\n                if (window._viaPb1378Off !== true) {\r\n                    if (_sy1363.articleTitre) {\r\n                        console.log('[pb1378] secteur ' + _val1363 + ' choisi ->'\r\n                            + ' article \u00ab ' + _sy1363.articleTitre + ' \u00bb abandonn\u00e9');\r\n                    }\r\n                    _sy1363.articleTitre = null;\r\n                    _sy1363.articleUrl = null;\r\n                }\r\n            }\r\n            const _ap1363 = _type1363 + '\/' + (sessionStorage.getItem('SelectedPageSecteur') || '');\r\n            if (_av1363 !== _ap1363) {\r\n                console.log('[pb1363] cl\u00e9s de page mises \u00e0 jour : ' + _av1363\r\n                    + ' -> ' + _ap1363);\r\n            }\r\n            \/\/ ================================================================\r\n            \/\/ pb1369 : METTRE L'ITEM A JOUR AUSSI \u2014 sinon il les remet.\r\n            \/\/   pb1363 ne posait que les cles GLOBALES. Le traceur montre la\r\n            \/\/   suite immediate :\r\n            \/\/     [pb1365] SET SelectedPageType : \"PTType\" -> \"HPType\"\r\n            \/\/              | par _copier1368 <- GetURLCommandeFromItem\r\n            \/\/   GetURLCommandeFromItem restaure les globales depuis les cles\r\n            \/\/   INDEXEES de l'item \u2014 qui, elles, portent encore l'ancienne page.\r\n            \/\/   pb1368 a bien empeche l'effacement par du vide, mais ici la valeur\r\n            \/\/   recopiee n'est pas vide : elle est PERIMEE. Un correctif qui protege\r\n            \/\/   du vide ne protege pas du faux.\r\n            \/\/   Puis pb1058 lit HPType, juge le tarif \u00ab Autres Pages \u00bb incoherent, et\r\n            \/\/   _invaliderPage1058 supprime les trois cles \u2014 ce sont les DEL du log.\r\n            \/\/   L'item est la source dont tout redescend : c'est lui qu'il faut\r\n            \/\/   mettre a jour, pas seulement son reflet. syncItemToSessionStorage\r\n            \/\/   reecrit ensuite les cles indexees, et GetURLCommandeFromItem n'a plus\r\n            \/\/   rien de perime a restaurer.\r\n            \/\/   Revert : window._viaPb1369Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1369Off !== true) {\r\n                try {\r\n                    const _st1369 = window.VIA_Panier ? (window.VIA_Panier.state || null) : null;\r\n                    const _it1369 = _st1369\r\n                        ? (_st1369.items || []).find(i => i.id === _st1369.itemActif)\r\n                        : null;\r\n                    if (_it1369) {\r\n                        const _avI1369 = (_it1369.selectedPageType || '') + '\/'\r\n                            + (_it1369.selectedPageSecteur || '');\r\n                        _it1369.selectedPageType = _type1363;\r\n                        _it1369.commandePage = _cmd1363;\r\n                        if (_type1363 === 'ArtType') {\r\n                            _it1369.articleTitre = _sy1363.articleTitre;\r\n                        } else {\r\n                            _it1369.selectedPageSecteur = _val1363;\r\n                            _it1369.selectedPageSecteurDisplayed = _val1363;\r\n                            \/\/ pb1378 : l'item porte aussi l'article \u2014 c'est lui que\r\n                            \/\/   la carte affiche (\u00ab Art. \u2026 \u00bb) tant qu'il subsiste.\r\n                            if (window._viaPb1378Off !== true) {\r\n                                _it1369.articleTitre = null;\r\n                                _it1369.articleUrl = null;\r\n                            }\r\n                        }\r\n                        const _apI1369 = _type1363 + '\/' + (_it1369.selectedPageSecteur || '');\r\n                        if (_avI1369 !== _apI1369) {\r\n                            console.log('[pb1369] item ' + _it1369.id + ' : ' + _avI1369\r\n                                + ' -> ' + _apI1369);\r\n                        }\r\n                        \/\/ ========================================================\r\n                        \/\/ pb1372 : ECRIRE LES CLES INDEXEES DIRECTEMENT \u2014 casser la boucle.\r\n                        \/\/   Le log montre un cycle qui se reproduit indefiniment :\r\n                        \/\/     [pb1363] cl\u00e9s de page : HPType\/Homepage -> PTType\/Agro-industries\r\n                        \/\/     [pb1369] item ... -> PTType\/Agro-industries\r\n                        \/\/     [pb1365] SET SelectedPageType : \"PTType\" -> \"HPType\"\r\n                        \/\/              | par _copier1368 <- GetURLCommandeFromItem\r\n                        \/\/     [pb1365] SET SelectedPageSecteur : \"Agro-industries\" -> \"Homepage\"\r\n                        \/\/     ... puis remplirItemPartiel relit sessionStorage et REECRIT\r\n                        \/\/         l'item en HPType\/Homepage, et le sync ecrit\r\n                        \/\/         \u00ab SelectedPageType1 = HPType \u00bb \u2014 retour a la case depart.\r\n                        \/\/   Le maillon faible : GetURLCommandeFromItem restaure les globales\r\n                        \/\/   depuis les cles INDEXEES, qui n'avaient pas encore ete\r\n                        \/\/   rafraichies. pb1369 s'en remettait a syncItemToSessionStorage \u2014\r\n                        \/\/   un relais de plus, et le log ne montre aucun\r\n                        \/\/   \u00ab SelectedPageType1 = PTType \u00bb : il n'a pas abouti.\r\n                        \/\/   On ecrit donc les cles indexees NOUS-MEMES, dans le meme geste\r\n                        \/\/   que l'item. Plus de relais, plus de fenetre ou la copie indexee\r\n                        \/\/   contredit l'objet dont elle derive. C'est la lecon pb1281 :\r\n                        \/\/   ne pas esperer qu'un autre chemin le fasse.\r\n                        \/\/   Le sync reste appele ensuite pour le reste des champs.\r\n                        \/\/   Revert : window._viaPb1372Off = true.\r\n                        \/\/ ========================================================\r\n                        if (window._viaPb1372Off !== true) {\r\n                            try {\r\n                                const _idx1372 = _it1369.sessionStorageIndex;\r\n                                if (_idx1372) {\r\n                                    sessionStorage.setItem('SelectedPageType' + _idx1372, _type1363);\r\n                                    sessionStorage.setItem('commandePage' + _idx1372, _cmd1363);\r\n                                    if (_type1363 === 'ArtType') {\r\n                                        sessionStorage.setItem('Commande_Article' + _idx1372,\r\n                                            _sy1363.articleTitre || '');\r\n                                    } else {\r\n                                        sessionStorage.setItem('SelectedPageSecteur' + _idx1372, _val1363);\r\n                                        sessionStorage.setItem('SelectedPageSecteurDisplayed' + _idx1372, _val1363);\r\n                                        \/\/ pb1378 : sinon GetURLCommandeFromItem restaure\r\n                                        \/\/   l'article depuis la cle indexee (cf pb1372).\r\n                                        if (window._viaPb1378Off !== true) {\r\n                                            sessionStorage.removeItem('Commande_Article' + _idx1372);\r\n                                        }\r\n                                    }\r\n                                    console.log('[pb1372] cl\u00e9s index\u00e9es ' + _idx1372\r\n                                        + ' align\u00e9es : ' + _type1363 + '\/' + _val1363);\r\n                                } else {\r\n                                    console.warn('[pb1372] item sans sessionStorageIndex ->'\r\n                                        + ' cl\u00e9s index\u00e9es non align\u00e9es');\r\n                                }\r\n                            } catch (_e1372) {\r\n                                console.warn('[pb1372] \u00e9criture des cl\u00e9s index\u00e9es : '\r\n                                    + _e1372.message);\r\n                            }\r\n                        }\r\n                        var _sync1369 = (window.VIA_Panier\r\n                            ? (typeof window.VIA_Panier.syncItemToSessionStorage === 'function')\r\n                            : false)\r\n                            ? window.VIA_Panier\r\n                            : ((window.VIA_Adaptateur\r\n                                ? (typeof window.VIA_Adaptateur.syncItemToSessionStorage === 'function')\r\n                                : false) ? window.VIA_Adaptateur : null);\r\n                        if (_sync1369) {\r\n                            _sync1369.syncItemToSessionStorage(_it1369.id);\r\n                        } else {\r\n                            console.warn('[pb1369] syncItemToSessionStorage introuvable'\r\n                                + ' (ni VIA_Panier ni VIA_Adaptateur)');\r\n                        }\r\n                    }\r\n                } catch (_e1369) {\r\n                    console.warn('[pb1369] mise \u00e0 jour de l\\'item impossible : '\r\n                        + _e1369.message);\r\n                }\r\n            }\r\n        } catch (_e1363) {\r\n            console.warn('[pb1363] pose des cl\u00e9s impossible : ' + _e1363.message);\r\n        }\r\n    }\r\n\r\n    _appliquerSecteur1347() {\r\n        if (window._viaPb1347Off === true) { return; }\r\n        this._poserClesPage1363();   \/\/ pb1363 : AVANT tout le reste, les cles font foi\r\n        const _vide1347 = this._viderTarifIncompatible1347();\r\n        this._filtrerLignes1347();\r\n        if (_vide1347) {\r\n            try { this.setSection632('tarifs', true); }\r\n            catch (_e1347f) { console.warn('[pb1347] r\u00e9ouverture tarifs : ' + _e1347f.message); }\r\n        }\r\n        this.majEtapes631();\r\n    }\r\n\r\n    onSecteurChoisi622(info) {\r\n        \/\/ ================================================================\r\n        \/\/ pb1347 : \u00ab Homepage \u00bb (pb1345) \u2014 choix complet en un clic, sans\r\n        \/\/   sous-ligne Secteur\/Articles. L'etape 4 est terminee immediatement\r\n        \/\/   et la grille se restreint aux lignes Home Page.\r\n        \/\/ ================================================================\r\n        if (info ? (info.homepage === true) : false) {\r\n            this.messageSecteurs628(false);\r\n            window._viaEtape5Ok631 = true;   \/\/ pb631\r\n            this._sync635 = this._sync635 || {};\r\n            this._sync635.secteur = 'Homepage';\r\n            this._sync635.articleTitre = null;\r\n            this._sync635.articleUrl = null;\r\n            this._ts749('secteur', 'popup');\r\n            this._noter749('secteur', 'Homepage');\r\n            this._appliquerSecteur1347();\r\n            this.evaluerMessage630();\r\n            this.fermerSmooth647('secteurs');   \/\/ pb647 : choix fait -> replier\r\n            return;\r\n        }\r\n        \/\/ ================================================================\r\n        \/\/ pb1061 : une PAGE vient d'etre choisie -> retirer le message pb1058b.\r\n        \/\/   Le message \"Merci de selectionner une autre page\" restait affiche apres\r\n        \/\/   la selection du secteur : il n'etait retire que par la regle 3\r\n        \/\/   (_selectionnerHomepage1058), jamais par le chemin normal.\r\n        \/\/   Ici, un secteur ou un article vient d'etre choisi : la demande est\r\n        \/\/   satisfaite, le message n'a plus lieu d'etre.\r\n        \/\/   Place en TETE : quel que soit le sous-cas traite plus bas (article,\r\n        \/\/   fin de chargement, secteur), une page a ete designee.\r\n        \/\/ ================================================================\r\n        if (window._viaPb1058Off !== true) {\r\n            if (typeof this._messageSecteurs1058 === 'function') { this._messageSecteurs1058(''); }\r\n        }\r\n        \/\/ pb623 : fin du chargement des articles -> scroll bas de popup\r\n        if (info ? (info.articlesCharges === true) : false) {\r\n            const $liste = this._elt618('PopupTarifsListeSecteurs');\r\n            setTimeout(() => this.scrollVersBas623($liste[0]), 120);\r\n            return;\r\n        }\r\n\r\n        \/\/ titre d'article selectionne\r\n        if (info ? (info.article !== undefined) : false) {\r\n            this.messageSecteurs628(false);\r\n            window._viaEtape5Ok631 = true;   \/\/ pb631\r\n            this.majEtapes631();\r\n            this.evaluerMessage630();\r\n            \/\/ pb640 : memoriser l'ARTICLE precis (titre + url) pour le synchroniser\r\n            \/\/   directement au Continuer, sans rouvrir le popup pb140.\r\n            \/\/ pb749 : article precis -> memorise puis pousse (viaSyncArticle635).\r\n            this._sync635 = this._sync635 || {};\r\n            this._sync635.secteur = 'Articles';\r\n            this._sync635.articleTitre = info.article;\r\n            this._sync635.articleUrl = info.url;\r\n            this._ts749('secteur', 'popup');\r\n            this._pousser749('article', { titre: info.article, url: info.url });\r\n            this._appliquerSecteur1347();   \/\/ pb1347\r\n            this.messageArticles656(false);   \/\/ pb656 : titre choisi -> masquer le message 3\r\n            this.fermerSmooth647('secteurs');   \/\/ pb647 : article choisi -> replier\r\n            return;\r\n        }\r\n\r\n        \/\/ choix de la sous-ligne : \"Secteur\" complete l'etape ; \"Articles\" attend\r\n        \/\/   la selection d'un titre\r\n        if (info ? (info.choix !== undefined) : false) {\r\n            if (info.choix === 'Secteur') {\r\n                this.messageSecteurs628(false);\r\n                window._viaEtape5Ok631 = true;   \/\/ pb631\r\n                if (info.val) { this._noter749('secteur', info.val); }   \/\/ pb635b + pb749\r\n                this._appliquerSecteur1347();   \/\/ pb1347\r\n            } else if (info.choix === 'Articles') {\r\n                this._sync635 = this._sync635 || {}; this._sync635.secteur = 'Articles';   \/\/ pb635b\r\n            }\r\n            \/\/ pb647 : \"Secteur\" replie l'etape ; \"Articles\" attend le titre\r\n            if (info.choix === 'Secteur') { this.fermerSmooth647('secteurs'); }\r\n            this.majEtapes631();\r\n            this.evaluerMessage630();\r\n            return;\r\n        }\r\n\r\n        \/\/ clic sur un secteur : remise a zero, le choix n'est pas encore fait\r\n        window._viaEtape5Ok631 = false;   \/\/ pb631\r\n        \/\/ pb647 : nouvelle selection en cours -> re-armer l'auto-fermeture secteurs\r\n        if (window._autoFerme647) { window._autoFerme647['secteurs'] = false; }\r\n        this.majEtapes631();\r\n        this.evaluerMessage630();\r\n    }\r\n\r\n    \/\/ pb620 : un SITE PAYS est-il selectionne dans la liste du haut ?\r\n    sitePaysSelectionne620() {\r\n        const $host = $('#PopupTarifsListePays, .PopupTarifsListePays').first();\r\n        if ($host.length === 0) { return true; }   \/\/ liste absente -> ne pas bloquer\r\n        return $host.find('.v290-row.v290-on').length > 0;\r\n    }\r\n\r\n    messageSitePays620(afficher) {\r\n        const $msg = $('#PopupTarifsSitePaysMessageTexte, .PopupTarifsSitePaysMessageTexte').first();\r\n        if ($msg.length === 0) { return; }\r\n        $msg[0].style.setProperty('display', afficher ? 'block' : 'none', 'important');\r\n    }\r\n\r\n    \/\/ pb619 : message \"renseigner le pays de l'annonceur\", affiche quand les deux\r\n    \/\/   dates sont saisies mais le pays absent. Conteneur masque par Elementor.\r\n    messageAnnonceur619(afficher) {\r\n        const $msg = $('#PopupTarifsAnnonceurMessageTexte, .PopupTarifsAnnonceurMessageTexte').first();\r\n        if ($msg.length === 0) { return; }\r\n        $msg[0].style.setProperty('display', afficher ? 'block' : 'none', 'important');\r\n    }\r\n\r\n    \/\/ pb619 : centrer le placeholder ET la saisie du champ pays de l'annonceur.\r\n    \/\/   Le champ est un input Elementor : style inline en important, pose une\r\n    \/\/   seule fois (flag) mais re-tentable si le formulaire est re-rendu.\r\n    centrerChampPays619() {\r\n        const $inp = $('input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]');\r\n        if ($inp.length === 0) { return; }\r\n        $inp.each(function() {\r\n            if (this.dataset.center619) { return; }\r\n            this.dataset.center619 = '1';\r\n            this.style.setProperty('text-align', 'center', 'important');\r\n        });\r\n    }\r\n\r\n    \/\/ ========================================================================\r\n    \/\/ pb1922 : LES CHEVRONS SUIVENT LES TITRES.\r\n    \/\/   pb1566 agrandit titres ET chevrons parce que pb913 vise explicitement\r\n    \/\/   iconeUp \/ iconeDown, des icones Elementor pilotees par font-size ou par\r\n    \/\/   width\/height.\r\n    \/\/   Dans le popup Tarifs il n'y a pas d'icone : pb632 trace le chevron en\r\n    \/\/   ::before, avec width\/height 7px et des bordures de 2px ecrites en dur. Il\r\n    \/\/   ne suit donc NI la font-size du titre, NI le delta pb1922 pose au-dessus.\r\n    \/\/   Un pseudo-element ne s'atteint pas en inline : il faut une feuille. Elle\r\n    \/\/   est posee APRES celle de pb632 dans le head, donc a specificite egale elle\r\n    \/\/   l'emporte \u2014 et on ajoute !important par surete.\r\n    \/\/   Le chevron grandit du MEME nombre de pixels que les titres, pas d'un\r\n    \/\/   pourcentage : c'est ce que fait pb1566 cote process, et c'est ce qui garde\r\n    \/\/   les deux lisibles ensemble.\r\n    \/\/   Knob : window._viaPb1922Delta (partage avec les titres, defaut 1).\r\n    \/\/   Revert : window._viaPb1922Off = true.\r\n    \/\/ ========================================================================\r\n    _feuilleExpress1922() {\r\n        if (window._viaPb1922Off === true) { return; }\r\n        try {\r\n            \/* pb1922b : DELTA PORTE DE 1 A 2 PX, ET LE TRAIT DU CHEVRON EPAISSI\r\n               (demande user). Meme demarche que pb1879 -> pb1880 -> pb1881 cote\r\n               process : on ne cree pas de regle concurrente, on change le DEFAUT de\r\n               la variable existante. Un seul writer, une seule valeur a suivre.\r\n               Le cote du chevron suit le delta BRUT, comme depuis pb1922 : 7 + 2 = 9 px.\r\n               pb1922c : il ne suit PAS le retrait desktop de 0.5 px pose sur les\r\n               titres \u2014 demande user, \u00ab ne touche pas aux chevrons \u00bb. Ce bloc lit\r\n               donc _viaPb1922Delta sans le corriger, mobile comme desktop.\r\n               L'EPAISSEUR est un reglage a part : pb632 trace le chevron avec\r\n               border-right \/ border-bottom de 2px en raccourci. On surcharge les\r\n               seules LARGEURS de bordure \u2014 pas le raccourci \u2014 pour ne toucher ni au\r\n               style ni au currentColor, dont pb631 se sert pour teinter le chevron\r\n               en meme temps que son titre.\r\n               Knobs : window._viaPb1922Delta (2), window._viaPb1922Gras (1). *\/\r\n            var _d1922 = (typeof window._viaPb1922Delta === 'number')\r\n                ? window._viaPb1922Delta : 2;\r\n            var _gras1922 = (typeof window._viaPb1922Gras === 'number')\r\n                ? window._viaPb1922Gras : 1;\r\n            var _cote1922 = 7 + _d1922;\r\n            var _trait1922 = 2 + _gras1922;\r\n            var _st1922 = document.getElementById('via-express-pays-1922');\r\n            var _css1922 = 'body.via-express-pays-1922 .via632-titre::before {'\r\n                + ' width: ' + _cote1922 + 'px !important;'\r\n                + ' height: ' + _cote1922 + 'px !important;'\r\n                + ' border-right-width: ' + _trait1922 + 'px !important;'\r\n                + ' border-bottom-width: ' + _trait1922 + 'px !important; }';\r\n            if (!_st1922) {\r\n                _st1922 = document.createElement('style');\r\n                _st1922.id = 'via-express-pays-1922';\r\n                _st1922.textContent = _css1922;\r\n                document.head.appendChild(_st1922);\r\n                console.log('[pb1922b] feuille chevrons inject\u00e9e (c\u00f4t\u00e9 ' + _cote1922\r\n                    + 'px, trait ' + _trait1922 + 'px)');\r\n            } else if (_st1922.textContent !== _css1922) {\r\n                \/* le knob a bouge a chaud : la feuille suit sans redeploiement *\/\r\n                _st1922.textContent = _css1922;\r\n                console.log('[pb1922b] chevrons -> c\u00f4t\u00e9 ' + _cote1922\r\n                    + 'px, trait ' + _trait1922 + 'px');\r\n            }\r\n            if (!document.body) { return; }\r\n            var _doit1922 = (typeof window._viaPopupPays1905 === 'function')\r\n                ? window._viaPopupPays1905() : false;\r\n            var _deja1922 = document.body.classList.contains('via-express-pays-1922');\r\n            if (_doit1922 === _deja1922) { return; }\r\n            document.body.classList[_doit1922 ? 'add' : 'remove']('via-express-pays-1922');\r\n            console.log('[pb1922] chevrons agrandis -> '\r\n                + (_doit1922 ? 'ACTIF (popup pays, mobile et desktop)' : 'retir\u00e9'));\r\n        } catch (_e1922) { console.warn('[pb1922] ' + _e1922.message); }\r\n    }\r\n\r\n    \/\/ ========================================================================\r\n    \/\/ pb1925 : #TarifsPublicitaireListe A 90 % ET CENTRE (demande user).\r\n    \/\/   REMPLACE pb1919 (marges laterales de .TarifsConteneur), reverte a la meme\r\n    \/\/   demande. Je n'empile pas les deux : reverter, c'est retirer, et laisser\r\n    \/\/   coexister deux cadrages du meme bloc serait exactement le genre de writers\r\n    \/\/   concurrents que ce fichier passe son temps a demeler. Le knob\r\n    \/\/   _viaMargeGrille1919 et la classe via-mob-pays-1919 disparaissent avec lui.\r\n    \/\/   La cible descend d'un cran : #TarifsPublicitaireListe est le conteneur de la\r\n    \/\/   LISTE des tarifs \u2014 l'un des cinq enfants de #TarifsCatalogueConteneur, et\r\n    \/\/   celui que _CONT1236 designe deja pour l'etape \u00ab tarifs \u00bb. pb1236 n'y ecrit\r\n    \/\/   que des marges HAUTE et BASSE : aucun conflit avec la largeur ni avec les\r\n    \/\/   marges laterales posees ici.\r\n    \/\/   Centrage par marges automatiques : elles fonctionnent aussi bien si le\r\n    \/\/   parent est un bloc que s'il est en flex, contrairement a un align-self qui\r\n    \/\/   ne vaudrait que dans le second cas.\r\n    \/\/   Feuille + classe sur <body>, comme pb1917 et pb1922 : la grille est\r\n    \/\/   reconstruite a chaque affichage (constat pb1240c), un inline pose sur les\r\n    \/\/   elements d'avant partirait avec eux.\r\n    \/\/   Portee inchangee : MOBILE et popup pays, via _viaPopupPaysMobile1918.\r\n    \/\/   Knob : window._viaLargeur1925 (90). Revert : window._viaPb1925Off = true.\r\n    \/\/ ========================================================================\r\n    _feuilleMobilePays1925() {\r\n        if (window._viaPb1925Off === true) { return; }\r\n        try {\r\n            var _lg1925 = (typeof window._viaLargeur1925 === 'number')\r\n                ? window._viaLargeur1925 : 90;\r\n            var _css1925 = 'body.via-mob-pays-1925 #TarifsPublicitaireListe {'\r\n                + ' width: ' + _lg1925 + '% !important;'\r\n                + ' margin-left: auto !important;'\r\n                + ' margin-right: auto !important; }';\r\n            var _st1925 = document.getElementById('via-mobile-pays-1925');\r\n            if (!_st1925) {\r\n                _st1925 = document.createElement('style');\r\n                _st1925.id = 'via-mobile-pays-1925';\r\n                _st1925.textContent = _css1925;\r\n                document.head.appendChild(_st1925);\r\n                console.log('[pb1925] feuille mobile pays inject\u00e9e'\r\n                    + ' | #TarifsPublicitaireListe ' + _lg1925 + '% centr\u00e9');\r\n            } else if (_st1925.textContent !== _css1925) {\r\n                \/* le knob a bouge a chaud : la feuille suit, comme celle de pb1922 *\/\r\n                _st1925.textContent = _css1925;\r\n                console.log('[pb1925] largeur -> ' + _lg1925 + '%');\r\n            }\r\n            if (!document.body) { return; }\r\n            var _doit1925 = window._viaPopupPaysMobile1918\r\n                ? window._viaPopupPaysMobile1918() : false;\r\n            var _deja1925 = document.body.classList.contains('via-mob-pays-1925');\r\n            if (_doit1925 === _deja1925) { return; }\r\n            document.body.classList[_doit1925 ? 'add' : 'remove']('via-mob-pays-1925');\r\n            console.log('[pb1925] #TarifsPublicitaireListe 90 % centr\u00e9 -> '\r\n                + (_doit1925 ? 'ACTIF (mobile, popup pays)' : 'retir\u00e9'));\r\n        } catch (_e1925) { console.warn('[pb1925] ' + _e1925.message); }\r\n    }\r\n\r\n    \/\/ ========================================================================\r\n    \/\/ pb1920 : LE CHAMP ANNONCEUR A TAILLE NORMALE, SANS ZOOM iOS.\r\n    \/\/   Demande user : le champ est trop grand, parce qu'il doit rester au-dessus\r\n    \/\/   du seuil au-dela duquel iOS zoome la page a la mise au point.\r\n    \/\/   Le projet a deja tranche cette question, en pb1890 : \u00ab iOS zoome sous\r\n    \/\/   16 px RENDUS et decide sur la taille CALCULEE, pas sur le transform \u00bb.\r\n    \/\/   On garde donc une font-size de 16 px \u2014 le champ n'appelle plus le zoom \u2014\r\n    \/\/   et on le REDUIT VISUELLEMENT par un transform. La taille calculee reste\r\n    \/\/   16, la taille vue vaut 16 x echelle.\r\n    \/\/   COMPENSATION DU VIDE, lecon pb1891 : \u00ab offsetHeight ne change pas avec\r\n    \/\/   scale \u00bb. Un champ de hauteur h reduit a k laisse h x (1 - k) de vide en\r\n    \/\/   dessous ; on le reprend en marge basse negative. Sans cela le champ\r\n    \/\/   flotterait au milieu d'un trou.\r\n    \/\/   transform-origin en HAUT et CENTRE : le champ est centre par pb619, la\r\n    \/\/   reduction doit donc se faire autour de son axe vertical, et depuis le\r\n    \/\/   haut pour que la compensation basse soit exacte.\r\n    \/\/   Base MEMORISEE dans data-viafs1920 avant toute ecriture, et toujours relue\r\n    \/\/   depuis elle : l'operation ne cumule jamais, quel que soit le nombre de\r\n    \/\/   passages (lecon pb913 \/ pb1234).\r\n    \/\/   Ecriture conditionnee au changement : cette methode est appelee depuis\r\n    \/\/   majEtapes631, qui passe tres souvent.\r\n    \/\/   Knobs : window._viaTaille1920 (taille VUE, defaut 12.5 px)\r\n    \/\/           window._viaFsPlancher1920 (seuil iOS, defaut 16)\r\n    \/\/   Revert : window._viaPb1920Off = true.\r\n    \/\/ ========================================================================\r\n    _echelleAnnonceur1920() {\r\n        if (window._viaPb1920Off === true) { return; }\r\n        try {\r\n            if (!window._viaPopupPaysMobile1918) { return; }\r\n            if (!window._viaPopupPaysMobile1918()) { return; }\r\n            var _el1920 = document.querySelector(\r\n                'input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]');\r\n            if (!_el1920) { return; }\r\n            var _plancher1920 = (typeof window._viaFsPlancher1920 === 'number')\r\n                ? window._viaFsPlancher1920 : 16;\r\n            var _vue1920 = (typeof window._viaTaille1920 === 'number')\r\n                ? window._viaTaille1920 : 12.5;\r\n            var _base1920 = _el1920.getAttribute('data-viafs1920');\r\n            if (_base1920 === null) {\r\n                _base1920 = String(parseFloat(window.getComputedStyle(_el1920).fontSize) || 0);\r\n                _el1920.setAttribute('data-viafs1920', _base1920);\r\n            }\r\n            var _k1920 = _vue1920 \/ _plancher1920;\r\n            if (_k1920 > 1) { _k1920 = 1; }\r\n            var _fs1920 = _plancher1920 + 'px';\r\n            var _tr1920 = 'scale(' + _k1920.toFixed(4) + ')';\r\n            var _chg1920 = false;\r\n            if (_el1920.style.getPropertyValue('font-size') !== _fs1920) {\r\n                _el1920.style.setProperty('font-size', _fs1920, 'important');\r\n                _chg1920 = true;\r\n            }\r\n            if (_el1920.style.getPropertyValue('transform') !== _tr1920) {\r\n                _el1920.style.setProperty('transform', _tr1920, 'important');\r\n                _el1920.style.setProperty('transform-origin', 'top center', 'important');\r\n                _chg1920 = true;\r\n            }\r\n            \/\/ pb1891 : reprendre le vide laisse sous un element reduit.\r\n            var _h1920 = _el1920.offsetHeight || 0;\r\n            var _comp1920 = Math.round(_h1920 * (1 - _k1920));\r\n            var _mb1920 = (-_comp1920) + 'px';\r\n            if (_h1920 > 0) {\r\n                if (_el1920.style.getPropertyValue('margin-bottom') !== _mb1920) {\r\n                    _el1920.style.setProperty('margin-bottom', _mb1920, 'important');\r\n                    _chg1920 = true;\r\n                }\r\n            }\r\n            if (_chg1920) {\r\n                console.log('[pb1920] champ annonceur | base=' + _base1920 + 'px'\r\n                    + ' -> font-size=' + _plancher1920 + 'px (pas de zoom iOS)'\r\n                    + ' x scale ' + _k1920.toFixed(4) + ' = ' + _vue1920 + 'px vus'\r\n                    + ' | hauteur=' + _h1920 + ' -> compensation ' + _mb1920);\r\n            }\r\n        } catch (_e1920) { console.warn('[pb1920] ' + _e1920.message); }\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb635 : SYNCHRONISATION popup Tarifs -> bandeaux (pays\/secteur\/format), live.\r\n    \/\/   Reutilise les fonctions du popup 290 exposees par yearbook-media.js.\r\n    \/\/   Regie uniquement (dans l'iframe pays ces fonctions n'existent pas).\r\n    \/\/ ================================================================\r\n    \/\/ ================================================================\r\n    \/\/ pb735 : renseigner #PopUpTarifsDuree avec la duree de campagne calculee.\r\n    \/\/   state.dureeJours a TROIS writers (L1148 reset, L1211 calcul, L2490 reset\r\n    \/\/   global). Plutot que de dupliquer l'affichage aux trois endroits, on les\r\n    \/\/   fait tous passer par ce setter unique -- sinon un reset oublie laisserait\r\n    \/\/   une duree perimee a l'ecran (motif recurrent : pb694, pb700\/701, pb705).\r\n    \/\/   Libelle : convention deja en place a la L1316 ('1 jour' \/ 'N jours').\r\n    \/\/   Duree nulle -> champ vide.\r\n    \/\/   Revert : window._viaPb735Off = true.\r\n    \/\/ ================================================================\r\n    _setDuree735(duree) {\r\n        this.state.dureeJours = duree;\r\n        if (window._viaPb735Off === true) { return; }\r\n        try {\r\n            const $d735 = $('#PopUpTarifsDuree, .PopUpTarifsDuree');\r\n            if ($d735.length === 0) {\r\n                console.warn('[pb735] #PopUpTarifsDuree introuvable');\r\n                return;\r\n            }\r\n            const _n735 = duree || 0;\r\n            const _txt735 = (_n735 > 0) ? (_n735 === 1 ? '1 jour' : _n735 + ' jours') : '';\r\n            $d735.text(_txt735);\r\n            console.log('[pb735] duree -> \"' + _txt735 + '\" | elements=' + $d735.length);\r\n        } catch (e735) { console.warn('[pb735]', e735.message); }\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb749 : SYNCHRONISATION COMPLETE popup Tarifs <-> process d'achat.\r\n    \/\/   Decisions utilisateur :\r\n    \/\/     (1) poussee EN DIRECT vers le process (et non au seul Continuer),\r\n    \/\/     (2) l'arbitrage se fait sur la DERNIERE VALEUR MODIFIEE.\r\n    \/\/   D'ou un registre d'horodatage par champ. Sans lui, \"le plus recent gagne\"\r\n    \/\/   n'a aucun sens : les deux cotes ne portent que des valeurs, pas leur age.\r\n    \/\/   Champs suivis : pays, secteur, format, dates, annonceur, tarif, emplacement.\r\n    \/\/   Revert : window._viaPb749Off = true (retour au rejeu au Continuer seul).\r\n    \/\/ ================================================================\r\n    _ts749(champ, source) {\r\n        window._viaTs749 = window._viaTs749 || {};\r\n        window._viaTs749[champ] = { ts: Date.now(), src: source || 'popup' };\r\n        console.log('[pb749] horodate ' + champ + ' <- ' + (source || 'popup'));\r\n    }\r\n\r\n    \/\/   Le popup peut-il ecraser ce champ ? Non si la resa l'a modifie plus tard.\r\n    _popupGagne749(champ) {\r\n        if (window._viaPb749Off === true) { return true; }\r\n        const _r = (window._viaTs749 || {})[champ];\r\n        \/\/ pb751 : sans horodatage, c'est la RESA qui fait foi. Le defaut inverse\r\n        \/\/   (pb749) empechait le sens A de remplir un champ que le popup n'avait\r\n        \/\/   jamais touche \u2014 a la premiere ouverture, plus rien n'etait repris.\r\n        \/\/   \"Derniere valeur modifiee gagne\" ne s'applique qu'a un vrai conflit,\r\n        \/\/   c'est-a-dire quand les deux cotes ont ecrit.\r\n        if (!_r) { return false; }\r\n        return _r.src !== 'resa';\r\n    }\r\n\r\n    \/\/   Poussee DIRECTE d'un champ du popup vers le process. Reutilise les voies\r\n    \/\/   deja eprouvees de rejouerSync635 : aucune nouvelle facon de piloter le\r\n    \/\/   process n'est inventee, seul le MOMENT change.\r\n    \/\/ pb781 : un GESTE UTILISATEUR n'est jamais un echo \u2014 il ne doit pas etre filtre.\r\n    \/\/   Les verrous existent pour empecher A et B de se repondre en boucle. Mais les\r\n    \/\/   quatre appelants de _noter749 sont des callbacks du popup qui servent AUSSI\r\n    \/\/   aux clics programmes par la synchro A : l'appelant ne renseigne donc pas\r\n    \/\/   l'origine. Le seul discriminant fiable est l'EVENEMENT \u2014 event.isTrusted vaut\r\n    \/\/   true pour un geste physique, false pour un .click() programme. C'est ce qui a\r\n    \/\/   permis a pb777 d'identifier le toggle.\r\n    \/\/   pb780 avait tente de REJOUER plus tard les poussees filtrees : boucle infinie,\r\n    \/\/   puisque cela reinjecte l'action dans la boucle meme que les verrous protegent.\r\n    \/\/   Ici on ne rejoue rien : on laisse simplement passer ce qui n'est pas un echo.\r\n    \/\/   GARDE-FOU : au plus une derogation par champ toutes les 400 ms. Un humain ne\r\n    \/\/   clique pas plus vite, et cela borne strictement tout emballement.\r\n    \/\/   Revert : window._viaPb781Off = true.\r\n    _gesteUtilisateur781(champ) {\r\n        if (window._viaPb781Off === true) { return false; }\r\n        let _ev781 = null;\r\n        try { _ev781 = (typeof event !== 'undefined') ? event : null; } catch (_e) { _ev781 = null; }\r\n        if (!_ev781 ? true : _ev781.isTrusted !== true) { return false; }\r\n        window._viaDerog781 = window._viaDerog781 || {};\r\n        const _t781 = Date.now();\r\n        const _prec781 = window._viaDerog781[champ] || 0;\r\n        if ((_t781 - _prec781) < 400) {\r\n            console.warn('[pb781] derogation refusee pour ' + champ\r\n                + ' \u2014 moins de 400 ms depuis la precedente');\r\n            return false;\r\n        }\r\n        window._viaDerog781[champ] = _t781;\r\n        return true;\r\n    }\r\n\r\n    _pousser749(champ, valeur) {\r\n        if (window._viaPb749Off === true) { return; }\r\n        const _verrou781 = window._sync651EnCours ? 'sync651EnCours'\r\n            : (window._sync651AClic ? 'sync651AClic'\r\n            : (window._viaResetPopup710 ? 'resetPopup710' : ''));\r\n        if (_verrou781) {\r\n            if (!this._gesteUtilisateur781(champ)) {\r\n                console.log('[pb781] poussee ' + champ + ' filtree (verrou ' + _verrou781\r\n                    + ', origine non utilisateur)');\r\n                return;\r\n            }\r\n            console.log('[pb781] verrou ' + _verrou781 + ' outrepasse pour ' + champ\r\n                + ' \u2014 clic UTILISATEUR (isTrusted)');\r\n        }\r\n        try {\r\n            if (champ === 'pays') { this.syncPays635(valeur); }\r\n            else if (champ === 'secteur') { this.syncSecteur635(valeur); }\r\n            else if (champ === 'format') { this.syncFormat635(valeur); }\r\n            else if (champ === 'article') {\r\n                if (typeof window.viaSyncArticle635 === 'function') {\r\n                    window.viaSyncArticle635(valeur.titre, valeur.url);\r\n                }\r\n            }\r\n            console.log('[pb749] pousse EN DIRECT ' + champ + ' ->', valeur);\r\n        } catch (_e749) { console.warn('[pb749] poussee ' + champ + ' :', _e749.message); }\r\n    }\r\n\r\n    \/\/   Writer UNIQUE de _sync635 : memorise, horodate, pousse. Les six points\r\n    \/\/   d'ecriture d'origine passent tous par ici -> impossible d'en oublier un.\r\n    _noter749(champ, valeur, pousseChamp, pousseValeur) {\r\n        this._sync635 = this._sync635 || {};\r\n        this._sync635[champ] = valeur;\r\n        this._ts749(champ, 'popup');\r\n        this._pousser749(pousseChamp || champ, pousseValeur !== undefined ? pousseValeur : valeur);\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb752 : ADAPTER le tarif deja selectionne au nouveau type de page.\r\n    \/\/   syncDepuisResa651 deduit la ligne de grille de item.format + item.position.\r\n    \/\/   Or pb745 purge ces deux champs des qu'on change de pays ou de secteur\r\n    \/\/   (log pb750 : \"format=(vide) | position=(vide)\") -> plus rien a deduire, et\r\n    \/\/   le popup restait sur \"Banniere - hdp Home P.\" alors que la page etait\r\n    \/\/   devenue une page secteur.\r\n    \/\/   La classe encode tout : Tarif7 + format(3) + position(3) + famille de page\r\n    \/\/   (HP = Home Page, PP = autres Pages). Changer de type de page ne change donc\r\n    \/\/   QUE le suffixe : format et position choisis par l'utilisateur sont conserves.\r\n    \/\/   Revert : window._viaPb752Off = true.\r\n    \/\/ ================================================================\r\n    _adapterTarifPageType752(item) {\r\n        if (window._viaPb752Off === true) { return null; }\r\n        const _cur752 = this.state.tarifSelectionne;\r\n        if (!_cur752) {\r\n            console.log('[pb752] aucun tarif selectionne dans le popup -> rien a adapter');\r\n            return null;\r\n        }\r\n        \/\/ famille de page cible\r\n        const _spt752 = sessionStorage.getItem('SelectedPageType');\r\n        let _fam752 = null;\r\n        if (_spt752 === 'HPType') { _fam752 = 'HP'; }\r\n        else if (_spt752 === 'PTType') { _fam752 = 'PP'; }\r\n        else if (_spt752 === 'PATType') { _fam752 = 'PP'; }\r\n        else if (item ? item.commandePage === 'Homepage' : false) { _fam752 = 'HP'; }\r\n        else if (item ? !!item.commandePage : false) { _fam752 = 'PP'; }\r\n        if (!_fam752) {\r\n            console.log('[pb752] type de page indetermine | SelectedPageType=' + _spt752\r\n                + ' | commandePage=' + (item ? item.commandePage : '?'));\r\n            return null;\r\n        }\r\n        if (_cur752.slice(-2) === _fam752) {\r\n            console.log('[pb752] tarif deja dans la bonne famille (' + _fam752 + ') : ' + _cur752);\r\n            return null;\r\n        }\r\n        \/\/ ====================================================================\r\n        \/\/ pb1060 : PAGE Homepage + TARIF Autres Pages -> ne PAS adapter le tarif.\r\n        \/\/   Constat user : la regle 2 (pb1058) se declenche bien \u2014 le log le\r\n        \/\/   montre \u2014 mais son effet est annule juste apres :\r\n        \/\/     [pb1058] tarif \"Autres Pages\" mais page = Homepage -> page invalidee\r\n        \/\/     [pb752]  tarif adapte au type de page : Tarif7VidPoPPP -> ...PoPHP\r\n        \/\/   Les deux regles sont en opposition frontale : pb752 dit \"la PAGE prime,\r\n        \/\/   on aligne le tarif\", la regle 2 dit \"le TARIF prime, on redemande la\r\n        \/\/   page\". pb752 tranchant en dernier, le tarif choisi par l'utilisateur\r\n        \/\/   etait silencieusement remplace (1621 EUR -> 2228 EUR dans le log).\r\n        \/\/   Arbitrage retenu (option (a), demande user) : dans ce sens precis \u2014\r\n        \/\/   page Homepage, tarif Autres Pages \u2014 le tarif prime et pb752 s'abstient.\r\n        \/\/   C'est coherent avec la regle 3, ou le tarif Home Page IMPOSE la page :\r\n        \/\/   dans les deux cas l'utilisateur choisit le tarif, la page suit.\r\n        \/\/   L'autre sens de pb752 est CONSERVE : il reste utile quand la page\r\n        \/\/   change et qu'aucune regle de pb1058 ne s'applique.\r\n        \/\/   Revert : window._viaPb1060Off = true.\r\n        \/\/ ====================================================================\r\n        if (window._viaPb1060Off !== true) {\r\n            if (_fam752 === 'HP') {\r\n                if (_cur752.slice(-2) === 'PP') {\r\n                    console.log('[pb1060] page Homepage + tarif Autres Pages -> tarif CONSERV\u00c9 ('\r\n                        + _cur752 + ') ; c est la page qui sera redemand\u00e9e (pb1058)');\r\n                    return null;\r\n                }\r\n            }\r\n        }\r\n        const _nouv752 = _cur752.slice(0, -2) + _fam752;\r\n        if (typeof TARIF_MAPPING !== 'undefined' ? !TARIF_MAPPING[_nouv752] : false) {\r\n            console.warn('[pb752] classe adaptee absente de TARIF_MAPPING : ' + _nouv752);\r\n            return null;\r\n        }\r\n        console.log('[pb752] tarif adapte au type de page : ' + _cur752 + ' -> ' + _nouv752\r\n            + ' (' + _fam752 + ')');\r\n        return _nouv752;\r\n    }\r\n\r\n    syncPays635(paysRow) {\r\n        if (typeof window.viaSyncPays635 !== 'function') { return; }\r\n        try { window.viaSyncPays635(paysRow.val, paysRow.lang, paysRow.siteId); console.log('[pb635] pays ->', paysRow.val); }\r\n        catch (e) { console.warn('[pb635] sync pays:', e.message); }\r\n    }\r\n    syncSecteur635(val) {\r\n        if (typeof window.viaSyncSecteur635 !== 'function') { return; }\r\n        try { window.viaSyncSecteur635(val); console.log('[pb635] secteur ->', val); }\r\n        catch (e) { console.warn('[pb635] sync secteur:', e.message); }\r\n    }\r\n    syncFormat635(classe) {\r\n        if (typeof window.viaSyncFormat635 !== 'function') { return; }\r\n        const m = TARIF_MAPPING[classe];\r\n        if (!m) { return; }\r\n        try { window.viaSyncFormat635(m.format); console.log('[pb635] format ->', m.format); }\r\n        catch (e) { console.warn('[pb635] sync format:', e.message); }\r\n    }\r\n\r\n    \/\/ pb635b : rejoue les synchronisations memorisees, au clic \"Continuer\".\r\n    \/\/   Ordre pays -> secteur -> format ; le tarif selectionne sert de repli au\r\n    \/\/   format s'il n'a pas ete memorise separement.\r\n    rejouerSync635() {\r\n        \/\/ pb648 : signaler au systeme natif (yearbook-media.js) que l'affichage est\r\n        \/\/   gere par pb636 pendant ce rejeu \u2014 il ne doit PAS ouvrir son layout\r\n        \/\/   3 colonnes (recap\/colonnes) qui ecraserait les 3 popups.\r\n        window._viaExpressCheckout648 = true;\r\n        setTimeout(() => { window._viaExpressCheckout648 = false; }, 2500);\r\n        \/\/ pb657 : flag durable -> l'etape 1 de la resa (deja pre-remplie) sera\r\n        \/\/   auto-validee. Consomme one-shot au deploiement (Panier_manager).\r\n        window._viaExpressResaAutoValider657 = true;\r\n        \/\/ pb695 : horodatage. Panier_manager ne consomme plus le flag au premier\r\n        \/\/   deploiement mais attend la resa EFFECTIVE (item avec emplacement) :\r\n        \/\/   sans borne de temps, un flag oublie auto-validerait une resa ulterieure.\r\n        window._viaExpressResaAutoValider657At = Date.now();\r\n        const s = this._sync635 || {};\r\n        if (s.pays) { this.syncPays635(s.pays); }\r\n        \/\/ ================================================================\r\n        \/\/ pb732 : le format ne s'appliquait PAS sur les ARTICLES, alors qu'il\r\n        \/\/   s'appliquait sur les homepages et les pages secteur. La difference\r\n        \/\/   tient a l'ORDRE, pas au format lui-meme :\r\n        \/\/     - branche secteur  : syncSecteur635 clique un cartouche ; le rendu\r\n        \/\/       de la page vient APRES, donc apres syncFormat635 -> il lit un\r\n        \/\/       sessionStorage.FormatSelect deja renseigne.\r\n        \/\/     - branche article  : viaSyncArticle635 appelle SelectionPageWeb()\r\n        \/\/       IMMEDIATEMENT (yearbook-media L25473). La page et les espaces pub\r\n        \/\/       sont donc rendus AVANT que syncFormat635 (3 lignes plus bas) n'ait\r\n        \/\/       pose quoi que ce soit -> SelectionPageWeb lit un FormatSelect vide\r\n        \/\/       (L4152) et ne grise pas l'etape ChoixFormat.\r\n        \/\/   Correctif : PRE-SEMER sessionStorage.FormatSelect avant la branche\r\n        \/\/   article, pour que le rendu dispose de l'information. L'appel a\r\n        \/\/   syncFormat635 plus bas est CONSERVE tel quel : il clique le cartouche\r\n        \/\/   quand celui-ci existe, et son propre repli sessionStorage devient\r\n        \/\/   redondant sans etre nuisible.\r\n        \/\/   On n'inverse PAS l'ordre des appels : sur la branche secteur, le\r\n        \/\/   cartouche de format n'existe pas encore avant la selection du secteur.\r\n        \/\/   Revert : window._viaPb732Off = true.\r\n        \/\/ ================================================================\r\n        if (window._viaPb732Off !== true) {\r\n            const _fmt732 = s.format || this.state.tarifSelectionne;\r\n            const _map732 = _fmt732 ? TARIF_MAPPING[_fmt732] : null;\r\n            if (_map732 && _map732.format) {\r\n                try {\r\n                    sessionStorage.setItem('FormatSelect', _map732.format);\r\n                    console.log('[pb732] FormatSelect pre-seme avant ouverture:', _map732.format,\r\n                        '| classe=' + _fmt732 + ' | branche=' + ((s.articleTitre ? s.articleUrl : false) ? 'ARTICLE' : 'secteur'));\r\n                } catch (_e732) { console.warn('[pb732] sessionStorage:', _e732.message); }\r\n            } else {\r\n                \/\/ pb732 : instrumenter la branche muette. syncFormat635 fait un\r\n                \/\/   \"if (!m) return\" sans log : un tarif hors TARIF_MAPPING\r\n                \/\/   disparaissait sans trace (lecon pb693\/pb657).\r\n                console.warn('[pb732] format NON pre-seme | classe=' + _fmt732\r\n                    + ' | mapping=' + (_map732 ? 'trouve mais sans .format' : 'ABSENT de TARIF_MAPPING'));\r\n            }\r\n        }\r\n        \/\/ pb640 : un article precis a ete choisi -> le synchroniser directement\r\n        \/\/   (pose des cles + SelectionPageWeb), SANS cliquer .CartoucheArticles\r\n        \/\/   qui rouvrirait le vieux popup pb140.\r\n        if (s.articleTitre ? s.articleUrl : false) {\r\n            if (typeof window.viaSyncArticle635 === 'function') {\r\n                window.viaSyncArticle635(s.articleTitre, s.articleUrl);\r\n            }\r\n        } else if (s.secteur) {\r\n            this.syncSecteur635(s.secteur);\r\n        }\r\n        const fmt = s.format || this.state.tarifSelectionne;\r\n        if (fmt) { this.syncFormat635(fmt); }\r\n        console.log('[pb635b] synchronisation rejouee au Continuer');\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb632 : ACCORDEONS GENERIQUES du popup Tarifs.\r\n    \/\/   5 sections {titre -> contenu}, chevron CSS sur le titre (currentColor :\r\n    \/\/   il suit la couleur d'avancement pb631), etat memorise par section,\r\n    \/\/   plusieurs sections ouvertes autorisees, etat initial : tout deplie.\r\n    \/\/   Le display d'origine du contenu est memorise a la fermeture pour etre\r\n    \/\/   restaure a l'ouverture (les sections melangent e-con flex et blocs).\r\n    \/\/ ================================================================\r\n    config632() {\r\n        return [\r\n            \/\/ NB : la config transmise pointait le titre Dates sur lui-meme ;\r\n            \/\/ cible : .PopupTarifsDates (classe, pb632 maj).\r\n            \/\/ pb1899 : 'annonceur' passe APRES 'dates' \u2014 MEME ORDRE que etapes631().\r\n            \/\/   _sequenceur1036 lit config632()[actif].cle, ou 'actif' est un index\r\n            \/\/   dans etapes631() : les deux listes doivent rester alignees rang\r\n            \/\/   pour rang, sans quoi le sequenceur ouvre l'etape voisine.\r\n            \/\/ pb2408 : 'annonceur' en tete \u2014 MEME ORDRE que etapes631().\r\n            { cle: 'annonceur', titre: 'PopupTarifsAnnonceurTitreTexte',     section: '#PopupTarifsAnnonceur' },\r\n            { cle: 'pays',      titre: 'PopupTarifsListePaysTitreTexte',     section: '#PopupTarifsListePays' },\r\n            { cle: 'secteurs',  titre: 'PopupTarifsListeSecteursTitreTexte', section: '#PopupTarifsListeSecteurs' },\r\n            { cle: 'dates',     titre: 'PopupTarifsDatesTitreTexte',         section: '.PopupTarifsDates' },\r\n            { cle: 'tarifs',    titre: 'PopupTarifsTarifsTexte',             section: '.TarifsConteneur' },\r\n            \/\/ pb736 : 6e section, le recapitulatif. Selecteur double id+classe :\r\n            \/\/   les elements Elementor de ce popup existent tantot en id tantot en\r\n            \/\/   classe (meme precaution que _titre632).\r\n            { cle: 'recap',     titre: 'PopupTarifsRecapTitreTexte',         section: '#PopupTarifsRecapContainer, .PopupTarifsRecapContainer' }\r\n        ];\r\n    }\r\n\r\n    _titre632(c) { return $('#' + c.titre + ', .' + c.titre).first(); }\r\n\r\n    \/\/ ========================================================================\r\n    \/\/ pb1237 : phrases vertes .v644-sub a 13px sur DESKTOP (demande user).\r\n    \/\/   Ecrit en inline !important, comme les couleurs de ce fichier : une\r\n    \/\/   feuille se ferait battre par les regles Elementor.\r\n    \/\/   Mobile inchange \u2014 la regle ne vise que le desktop.\r\n    \/\/   Revert : window._viaPb1237Off = true.\r\n    \/\/ ========================================================================\r\n    _taillePhrases1237() {\r\n        if (window._viaPb1237Off === true) { return; }\r\n        if (window.outerWidth < 1000) { return; }\r\n        try {\r\n            $('.v644-sub').each(function () {\r\n                this.style.setProperty('font-size', '13px', 'important');\r\n            });\r\n        } catch (_e1237) {}\r\n    }\r\n\r\n    \/\/ ========================================================================\r\n    \/\/ pb1240 : +1px sur les items SITE PAYS et sur les MONTANTS, en DESKTOP\r\n    \/\/   (demande user).\r\n    \/\/   Base memorisee dans data-viafs1240 a la premiere rencontre, puis toujours\r\n    \/\/   relue depuis elle : le delta ne se cumule pas, meme si cette fonction\r\n    \/\/   repasse a chaque mise a jour des etapes.\r\n    \/\/   Un attribut plutot qu'une propriete JS : les lignes .v290-row sont\r\n    \/\/   reconstruites, et cloneNode ne copie pas les proprietes.\r\n    \/\/   Revert : window._viaPb1240Off = true.\r\n    \/\/ ========================================================================\r\n    _tailleItems1240() {\r\n        if (window._viaPb1240Off === true) { return; }\r\n        \/* ====================================================================\r\n         * pb1959 : +1 PX SUR LES ITEMS DES DEUX LISTES, SITES PAYS, MOBILE ET DESKTOP.\r\n         *   Demande user. Les items des etapes \u00ab site pays \u00bb et \u00ab secteurs \u00bb sont les\r\n         *   memes noeuds : .v290-row, produits par viaRenderPays613 et\r\n         *   viaRenderSecteurs615. Un seul selecteur les couvre tous les deux.\r\n         *   pb1240 les dimensionne deja, et il est le SEUL a le faire \u2014 base\r\n         *   memorisee dans data-viafs1240, delta pose au bout. On ajoute donc notre\r\n         *   pixel a son delta plutot que d'ecrire une seconde regle : la base ne\r\n         *   bouge pas, rien ne se cumule, et le jour ou la taille se discute il n'y\r\n         *   a qu'un endroit a lire. C'est ce que pb1566 puis pb1922 ont fait pour\r\n         *   les titres.\r\n         *   DEUX CHANGEMENTS, ET DEUX SEULEMENT :\r\n         *     - la sortie mobile de pb1240 (outerWidth < 1000) s'ouvre pour les sites\r\n         *       pays, puisque la demande vaut sur les deux tailles d'ecran. Sur la\r\n         *       regie mobile, elle continue de sortir, inchangee ;\r\n         *     - le delta des .v290-row passe de 1 a 2 dans ce contexte.\r\n         *   Les MONTANTS ne sont pas concernes : .PricingAmount garde son delta\r\n         *   _viaDeltaMontant1367, la demande ne portait que sur les items.\r\n         *   outerWidth et non innerWidth : dans l'iframe du popup, innerWidth vaut 0\r\n         *   (regle du projet, pb1538\/pb1677).\r\n         *   Knob : window._viaPb1959Delta (1). Revert : window._viaPb1959Off = true.\r\n         * ==================================================================== *\/\r\n        var _pays1959 = (window._viaPb1959Off === true)\r\n            ? false\r\n            : ((typeof window._viaPopupPays1905 === 'function')\r\n                ? window._viaPopupPays1905() : false);\r\n        if (window.outerWidth < 1000) {\r\n            if (!_pays1959) { return; }\r\n        }\r\n        try {\r\n            \/\/ pb1240b : +1px SUPPLEMENTAIRE pour les montants (demande user) \u2014\r\n            \/\/   .PricingAmount passe a +2, .v290-row reste a +1.\r\n            \/\/   Le delta depend donc de l'element ; la base, elle, reste celle\r\n            \/\/   memorisee au premier passage, donc aucun cumul.\r\n            \/\/ pb1367 : +1px de plus sur les montants (demande user) -> +3 au total.\r\n            \/\/   La base data-viafs1240 est inchangee : c'est le DELTA qui bouge, donc\r\n            \/\/   la nouvelle taille est absolue et ne s'ajoute pas a la precedente,\r\n            \/\/   meme si cette fonction repasse a chaque mise a jour des etapes.\r\n            \/\/   Ajustable sans redeploiement : window._viaDeltaMontant1367.\r\n            \/\/   Revert : window._viaDeltaMontant1367 = 2 (valeur pb1240b).\r\n            var _dMontant1367 = (typeof window._viaDeltaMontant1367 === 'number')\r\n                ? window._viaDeltaMontant1367 : 3;\r\n            if (_pays1959) {\r\n                if (window._viaSig1959 !== true) {\r\n                    window._viaSig1959 = true;\r\n                    console.log('[pb1959] sites pays : items .v290-row +'\r\n                        + (1 + ((typeof window._viaPb1959Delta === 'number')\r\n                            ? window._viaPb1959Delta : 1))\r\n                        + 'px (site pays et secteurs) | outerWidth=' + window.outerWidth);\r\n                }\r\n            }\r\n            $('.v290-row, .PricingAmount').each(function () {\r\n                var _b = this.getAttribute('data-viafs1240');\r\n                if (_b === null) {\r\n                    var _fs = parseFloat(window.getComputedStyle(this).fontSize);\r\n                    if (!(_fs > 0)) { return; }\r\n                    this.setAttribute('data-viafs1240', _fs);\r\n                    _b = String(_fs);\r\n                }\r\n                var _base = parseFloat(_b);\r\n                if (!(_base > 0)) { return; }\r\n                var _d1240 = this.classList.contains('PricingAmount') ? _dMontant1367 : 1;\r\n                \/\/ ============================================================\r\n                \/\/ pb2151 : MONTANTS EN DESKTOP \u2014 +0.7px de taille et +5px vers\r\n                \/\/   le bas (demande JF, desktop uniquement).\r\n                \/\/   Pose ICI, dans le writer qui detient deja la taille des\r\n                \/\/   montants (pb1240\/pb1367) et sa base gelee data-viafs1240 :\r\n                \/\/   un second writer aurait recalcule une base deja modifiee.\r\n                \/\/   Le delta s'ajoute a la BASE, jamais a la taille courante \u2014\r\n                \/\/   aucun cumul, quel que soit le nombre de repasses.\r\n                \/\/   DISCRIMINANT outerWidth >= 1000 et non une media query : en\r\n                \/\/   sites pays mobile cette fonction continue de tourner\r\n                \/\/   (pb1959), et innerWidth vaut 0 dans l'iframe du popup\r\n                \/\/   (pb1538\/pb1677). Le mobile garde donc exactement l'existant.\r\n                \/\/   La marge s'ecrit en !important : la feuille ci-dessus pose\r\n                \/\/   margin-top:5px !important, qu'un inline nu ne battrait pas.\r\n                \/\/   Knobs : window._viaPb2151Fs (0.7) \/ window._viaPb2151Mg (10).\r\n                \/\/   Revert : window._viaPb2151Off = true.\r\n                \/\/ ============================================================\r\n                if (this.classList.contains('PricingAmount')\r\n                    ? (window._viaPb2151Off === true ? false : (window.outerWidth >= 1000))\r\n                    : false) {\r\n                    _d1240 = _d1240 + ((typeof window._viaPb2151Fs === 'number')\r\n                        ? window._viaPb2151Fs : 0.7);\r\n                    \/\/ pb2153 : +2px supplementaires (JF) -> 5 (feuille) + 5 + 2 = 12.\r\n                    var _mg2151 = (typeof window._viaPb2151Mg === 'number')\r\n                        ? window._viaPb2151Mg : 12;\r\n                    this.style.setProperty('margin-top', _mg2151 + 'px', 'important');\r\n                    if (window._viaSig2151 !== true) {\r\n                        window._viaSig2151 = true;\r\n                        console.log('[pb2151] montants desktop : taille +'\r\n                            + ((typeof window._viaPb2151Fs === 'number') ? window._viaPb2151Fs : 0.7)\r\n                            + 'px et margin-top ' + _mg2151 + 'px | outerWidth=' + window.outerWidth);\r\n                    }\r\n                }\r\n                if (_pays1959) {\r\n                    if (!this.classList.contains('PricingAmount')) {\r\n                        _d1240 = _d1240 + ((typeof window._viaPb1959Delta === 'number')\r\n                            ? window._viaPb1959Delta : 1);   \/\/ pb1959\r\n                    }\r\n                }\r\n                var _cible = Math.round((_base + _d1240) * 100) \/ 100;\r\n                if (Math.abs(parseFloat(window.getComputedStyle(this).fontSize) - _cible) > 0.1) {\r\n                    this.style.setProperty('font-size', _cible + 'px', 'important');\r\n                }\r\n            });\r\n        } catch (_e1240) {\r\n            \/\/ pb1367 : ce catch etait muet. Une taille qui ne s'applique pas serait\r\n            \/\/   restee sans trace, et le diagnostic aurait porte sur le CSS.\r\n            console.warn('[pb1240] taille des items\/montants : ' + _e1240.message);\r\n        }\r\n    }\r\n    _section632(c) { return $(c.section); }   \/\/ pb644d : tous les elements (classe multiple)\r\n\r\n    \/\/ pb652 DIAG (temporaire) : lister les conteneurs qui scrollent verticalement,\r\n    \/\/   dans #popup3 ET parmi ses ancetres, pour identifier la double barre mobile.\r\n    _diag652() {\r\n        if (window._diag652Fait) { return; }   \/\/ une fois par session suffit\r\n        try {\r\n            var _p3 = document.getElementById('popup3');\r\n            if (!_p3) { console.log('[pb652] #popup3 introuvable'); return; }\r\n            window._diag652Fait = true;\r\n            var _res = [];\r\n            function _scan(_el, _tag) {\r\n                var _cs = getComputedStyle(_el);\r\n                var _oy = _cs.overflowY;\r\n                var _scrollable = (_oy === 'auto' ? true : _oy === 'scroll');\r\n                var _reel = _el.scrollHeight > (_el.clientHeight + 2);\r\n                _res.push(_tag + ' ' + (_el.id ? '#' + _el.id : '')\r\n                    + ' .' + String(_el.className || '').slice(0, 50)\r\n                    + ' | oY=' + _oy + (_scrollable ? (_reel ? ' SCROLLE' : ' (pas de debord)') : '')\r\n                    + ' | sh=' + _el.scrollHeight + ' ch=' + _el.clientHeight);\r\n            }\r\n            \/\/ descendants scrollables de popup3\r\n            var _all = _p3.querySelectorAll('*');\r\n            for (var _i = 0; _i < _all.length; _i++) {\r\n                var _el = _all[_i];\r\n                var _oy = getComputedStyle(_el).overflowY;\r\n                if ((_oy === 'auto' ? true : _oy === 'scroll') ? (_el.scrollHeight > _el.clientHeight + 2) : false) {\r\n                    _scan(_el, 'IN');\r\n                }\r\n            }\r\n            \/\/ ancetres de popup3 (la 2e barre peut venir d'un parent)\r\n            var _anc = _p3.parentElement, _n = 0;\r\n            while (_anc ? _n < 8 : false) {\r\n                var _oy2 = getComputedStyle(_anc).overflowY;\r\n                if ((_oy2 === 'auto' ? true : _oy2 === 'scroll') ? (_anc.scrollHeight > _anc.clientHeight + 2) : false) {\r\n                    _scan(_anc, 'ANC');\r\n                }\r\n                _anc = _anc.parentElement; _n++;\r\n            }\r\n            \/\/ document scrollant ?\r\n            var _de = document.documentElement;\r\n            if (_de.scrollHeight > _de.clientHeight + 2) {\r\n                _res.push('DOC html | sh=' + _de.scrollHeight + ' ch=' + _de.clientHeight);\r\n            }\r\n            console.log('[pb652 DIAG] conteneurs scrollants trouves =', _res.length);\r\n            for (var _k = 0; _k < _res.length; _k++) { console.log('[pb652]', _res[_k]); }\r\n        } catch (_e) { console.warn('[pb652 DIAG]', _e.message); }\r\n    }\r\n\r\n    \/\/ ================= pb651 : synchro resa <-> popup Tarifs =================\r\n    \/\/ Direction A (resa -> popup) : appelee par le hook setItemActif (Panier_manager)\r\n    \/\/   et a l'ouverture du popup. Pousse annonceur, dates, site pays, tarif.\r\n    \/\/ Direction B (popup -> resa) : live, si un item actif existe (sinon rien,\r\n    \/\/   le Continuer creera l'item). Garde anti-boucle _sync651EnCours.\r\n    syncDepuisResa651(item) {\r\n        if (!item) { return; }\r\n        if (window._sync651EnCours) { return; }   \/\/ anti-reentrance (B en cours)\r\n        window._sync651EnCours = true;\r\n        try {\r\n            console.log('[pb651 A] resa -> popup |', item.id, '| pays:', item.pays,\r\n                '| dates:', item.dateDebut, '->', item.dateFin,\r\n                '| format:', item.format, '| position:', item.position);\r\n\r\n            \/\/ --- annonceur ---\r\n            \/\/ pb749 : \"la derniere valeur modifiee gagne\". Si le popup a touche ce\r\n            \/\/   champ APRES la resa, on ne l'ecrase pas. _popupGagne749 le dit.\r\n            \/\/ pb773 : lire item.paysAnnonceur, PAS item.pays.\r\n            \/\/   Sonde pb772 : \"ANNONCEUR ecrit : Burkina Faso -> Congo | auteurs:\r\n            \/\/   syncDepuisResa651\". Les deux champs sont distincts et documentes dans\r\n            \/\/   Panier_manager L4944 : item.pays = pays PUBLICITAIRE (le site),\r\n            \/\/   item.paysAnnonceur = nationalite de la societe (saisie utilisateur).\r\n            \/\/   Le process lit deja paysAnnonceur pour ce meme champ (L4605) : on\r\n            \/\/   s'aligne sur lui au lieu d'inventer une seconde convention.\r\n            \/\/   Revert : window._viaPb773Off = true (retour a item.pays).\r\n            const _ann773 = (window._viaPb773Off === true) ? item.pays : item.paysAnnonceur;\r\n            if (_ann773 ? !this._popupGagne749('annonceur') : false) {\r\n                $('input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]').val(_ann773);\r\n                this._ts749('annonceur', 'resa');\r\n                console.log('[pb773] annonceur <- item.paysAnnonceur = \"' + _ann773\r\n                    + '\" (item.pays = \"' + (item.pays || '') + '\", site, non utilise)');\r\n            } else if (_ann773) {\r\n                console.log('[pb749] annonceur conserve (popup plus recent)');\r\n            } else {\r\n                console.log('[pb773] pas de paysAnnonceur sur l item -> champ inchange');\r\n            }\r\n\r\n            \/\/ --- dates (datepickers du popup) ---\r\n            const $deb = $('#form-field-PopupTarifsDebutCampagne');\r\n            const $fin = $('#form-field-PopupTarifsFinCampagne');\r\n            const _datesResa749 = !this._popupGagne749('dates');\r\n            if (item.dateDebut ? ($deb.length ? _datesResa749 : false) : false) {\r\n                $deb.val(item.dateDebut);\r\n                try { $deb.datepicker('setDate', item.dateDebut); } catch (e) {}\r\n            }\r\n            if (item.dateFin ? ($fin.length ? _datesResa749 : false) : false) {\r\n                $fin.val(item.dateFin);\r\n                try { $fin.datepicker('setDate', item.dateFin); } catch (e) {}\r\n            }\r\n\r\n            \/\/ --- site pays (depuis l'URL de la page de l'item) ---\r\n            if (!this._popupGagne749('pays')) {\r\n                this._selectionnerSitePays651(item.linkSecteurPage);\r\n                this._ts749('pays', 'resa');\r\n            } else { console.log('[pb749] site pays conserve (popup plus recent)'); }\r\n\r\n            \/\/ --- type de page (pb651c) : homepage \/ secteur \/ article ---\r\n            if (!this._popupGagne749('secteur')) {\r\n                this._selectionnerPageResa651(item);\r\n                this._ts749('secteur', 'resa');\r\n            } else { console.log('[pb749] secteur\/article conserve (popup plus recent)'); }\r\n\r\n            \/\/ --- tarif (format + position -> classe grille) ---\r\n            \/\/   Position absente -> AUCUNE selection (decision user pb651).\r\n            \/\/   pb651b : memoriser la classe, la selectionner APRES calcul grille.\r\n            let _classe651 = null;\r\n            if (item.format ? item.position : false) {\r\n                const c = this.getClasseFromParams(item.format, item.position);\r\n                if (c ? (typeof TARIF_MAPPING !== 'undefined' ? !!TARIF_MAPPING[c] : true) : false) {\r\n                    _classe651 = c;\r\n                }\r\n            }\r\n            \/\/ pb752 : item.format \/ item.position purges par pb745 -> deduire la\r\n            \/\/   nouvelle ligne du tarif DEJA choisi dans le popup, en ne changeant que\r\n            \/\/   la famille de page. Le choix de l'utilisateur (format, hdp\/cdp\/pop-up)\r\n            \/\/   est ainsi preserve au lieu d'etre perdu.\r\n            if (!_classe651) {\r\n                _classe651 = this._adapterTarifPageType752(item);\r\n            }\r\n\r\n            \/\/ recalcul (durree + grille) avec les nouvelles valeurs\r\n            this.onFormulaireChange();\r\n\r\n            \/\/ pb651b : selectionner le tarif une fois la grille calculee (polling)\r\n            if (_classe651) {\r\n                let _n651 = 0;\r\n                const _tryTarif651 = () => {\r\n                    const tc = this.state.tarifsCalcules;\r\n                    \/\/ pb651k : attendre que le recalcul soit TERMINE (isCalculating=false)\r\n                    \/\/   ET une valeur presente -> sinon on lit l'ancien tarif.\r\n                    const calcFini = !this.state.isCalculating;\r\n                    const aValeur = tc ? (tc[_classe651] !== undefined ? tc[_classe651] !== null : false) : false;\r\n                    const pret = calcFini ? aValeur : false;\r\n                    if (pret ? true : (++_n651 > 20)) {\r\n                        if (pret) { this._selectionnerTarif651(_classe651); }\r\n                        else { console.warn('[pb651 A] tarif non calcule apres attente:', _classe651); }\r\n                        return;\r\n                    }\r\n                    setTimeout(_tryTarif651, 150);\r\n                };\r\n                setTimeout(_tryTarif651, 200);\r\n            }\r\n        } catch (e651a) {\r\n            console.warn('[pb651 A] erreur:', e651a.message);\r\n        } finally {\r\n            \/\/ liberer apres le cycle courant (les handlers async du formulaire\r\n            \/\/   peuvent tourner juste apres)\r\n            setTimeout(() => { window._sync651EnCours = false; }, 400);\r\n        }\r\n    }\r\n\r\n    \/\/ site pays : URL -> sous-domaine -> cartouche de la liste (clic idempotent pb640b)\r\n    _selectionnerSitePays651(url) {\r\n        if (!url) { return; }\r\n        let sub = '';\r\n        try { sub = new URL(url).hostname.split('.')[0]; } catch (e) { return; }\r\n        if (!sub) { return; }\r\n        const $rows = $('#PopupTarifsListePays .v290-row[data-kind=\"pays\"], .PopupTarifsListePays .v290-row[data-kind=\"pays\"]');\r\n        if ($rows.length === 0) { return; }\r\n        const cible = sub.toLowerCase().replace(\/-(en|fr)$\/, '');\r\n        let $match = null;\r\n        $rows.each(function() {\r\n            const txt = ($(this).text() || '').trim().toLowerCase()\r\n                .normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '');\r\n            if (txt.indexOf(cible) !== -1 || cible.indexOf(txt) !== -1) { $match = $(this); return false; }\r\n        });\r\n        if ($match) {\r\n            if ($match.hasClass('v290-on')) { return; }   \/\/ deja selectionne (idempotent)\r\n            $match.trigger('click');\r\n            console.log('[pb651 A] site pays selectionne:', cible);\r\n        }\r\n    }\r\n\r\n    \/\/ pb651c : synchroniser le TYPE DE PAGE (homepage \/ secteur \/ article) depuis\r\n    \/\/   la resa vers l'etape secteurs du popup. Reutilise les .v290-row rendues\r\n    \/\/   par viaRenderSecteurs615 (memes clics que la selection manuelle).\r\n    _selectionnerPageResa651(item) {\r\n        const type = item.selectedPageType || '';\r\n        \/\/ ====================================================================\r\n        \/\/ pb1912 : \u00ab RIEN A CLIQUER \u00bb N'EST PLUS VRAI DEPUIS pb1345.\r\n        \/\/   Cette branche datait du temps ou la homepage etait IMPLIQUEE par un\r\n        \/\/   tarif Home Page : il n'y avait effectivement rien a choisir. Depuis\r\n        \/\/   pb1345 la Homepage est un CHOIX de l'etape secteur, et pb1348 en a tire\r\n        \/\/   la consequence pour le blocage du Continuer \u2014 mais pas ici.\r\n        \/\/   Resultat mesure (sonde pb1903) : page = Homepage sur l'item, et\r\n        \/\/   pourtant _viaEtape5Ok631=false, secteurRenseigne1337=false,\r\n        \/\/   _sync635={} \u2014 l'etape secteur reste incompletee, le sequenceur s'arrete\r\n        \/\/   dessus et n'ouvre jamais les Dates.\r\n        \/\/   On passe donc par le chemin EXISTANT, celui du clic utilisateur sur\r\n        \/\/   \u00ab Homepage \u00bb : onSecteurChoisi622({ homepage: true }). Il pose\r\n        \/\/   _viaEtape5Ok631, renseigne _sync635.secteur, horodate la source,\r\n        \/\/   applique le filtre de famille pb1347 et replie l'etape \u2014 donc aussi la\r\n        \/\/   phrase verte sous le titre (pb644). Aucune strate nouvelle : c'est\r\n        \/\/   exactement ce que fait un clic, joue depuis la resa.\r\n        \/\/   Le type de page vient de item.selectedPageType quand il est renseigne,\r\n        \/\/   et de item.commandePage a defaut : dans le popup des sites pays, le\r\n        \/\/   releve montre commandePage='Homepage' avec selectedPageSecteur vide.\r\n        \/\/   Revert : window._viaPb1912Off = true (ancien return muet).\r\n        \/\/ ====================================================================\r\n        var _hp1912 = (type === 'HPType');\r\n        if (window._viaPb1912Off !== true) {\r\n            if (!_hp1912) { _hp1912 = (item.commandePage === 'Homepage'); }\r\n        }\r\n        if (_hp1912) {\r\n            if (window._viaPb1912Off === true) {\r\n                console.log('[pb651c] page = Homepage (pas de secteur a choisir)');\r\n                return;\r\n            }\r\n            console.log('[pb1912] page = Homepage -> etape secteur completee par le'\r\n                + ' chemin pb1345 | selectedPageType=' + (type || '(vide)')\r\n                + ' | commandePage=' + (item.commandePage || '(vide)'));\r\n            try { this.onSecteurChoisi622({ homepage: true }); }\r\n            catch (_e1912) { console.warn('[pb1912] ' + _e1912.message); }\r\n            return;\r\n        }\r\n        const secteur = item.selectedPageSecteur || item.selectedPageSecteurDisplayed || '';\r\n        const estArticle = (type === 'ArtType');\r\n        \/\/ la liste des secteurs est rendue en differe -> polling sur les .v290-row\r\n        let n = 0;\r\n        const trySecteur = () => {\r\n            const $host = $('#PopupTarifsListeSecteurs').first();\r\n            const $rows = $host.find('.v290-row[data-kind=\"secteur\"]');\r\n            if ($rows.length === 0 ? (++n <= 25) : false) { setTimeout(trySecteur, 150); return; }\r\n            if ($rows.length === 0) { console.warn('[pb651c] secteurs non rendus'); return; }\r\n            \/\/ trouver le cartouche du secteur\r\n            let $cible = null;\r\n            if (secteur) {\r\n                const cibleTxt = String(secteur).trim().toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '');\r\n                $rows.each(function() {\r\n                    const v = ($(this).attr('data-val') || $(this).text() || '').trim().toLowerCase()\r\n                        .normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '');\r\n                    if (v === cibleTxt ? true : (v.indexOf(cibleTxt) !== -1 ? cibleTxt.length > 0 : false)) {\r\n                        $cible = $(this); return false;\r\n                    }\r\n                });\r\n            }\r\n            if (!$cible) { console.warn('[pb651c] secteur introuvable dans la liste:', secteur); return; }\r\n            \/\/ 1) cliquer le secteur -> fait apparaitre la sous-ligne Secteur\/Articles\r\n            if (!$cible.hasClass('v290-on')) { $cible[0].click(); }\r\n            console.log('[pb651c] secteur clique:', secteur, '| article=', estArticle);\r\n            \/\/ 2) choisir la sous-ligne\r\n            setTimeout(() => {\r\n                const $choix = $host.find('.v617-choix[data-choix=\"' + (estArticle ? 'Articles' : 'Secteur') + '\"]').first();\r\n                if ($choix.length === 0) { console.warn('[pb651c] sous-ligne absente'); return; }\r\n                $choix[0].click();\r\n                console.log('[pb651c] sous-ligne cliquee:', estArticle ? 'Articles' : 'Secteur');\r\n                \/\/ 3) si article : attendre la liste puis matcher par URL\r\n                if (estArticle) { this._selectionnerArticleParUrl651(item.linkSecteurPage, $host); }\r\n            }, 250);\r\n        };\r\n        setTimeout(trySecteur, 200);\r\n    }\r\n\r\n    \/\/ pb651c : la liste d'articles se charge en AJAX -> matcher l'URL de l'item.\r\n    _selectionnerArticleParUrl651(url, $host) {\r\n        if (!url) { console.warn('[pb651c] pas d URL article'); return; }\r\n        const cible = String(url).replace(\/\\\/$\/, '').toLowerCase();\r\n        let n = 0;\r\n        const tryArt = () => {\r\n            const $arts = $host.find('.v617-articles a');\r\n            if ($arts.length === 0 ? (++n <= 30) : false) { setTimeout(tryArt, 200); return; }\r\n            if ($arts.length === 0) { console.warn('[pb651c] articles non charges'); return; }\r\n            let $match = null;\r\n            $arts.each(function() {\r\n                const href = String($(this).attr('href') || '').replace(\/\\\/$\/, '').toLowerCase();\r\n                if (href === cible ? true : (href.indexOf(cible) !== -1 ? cible.length > 0 : false)) {\r\n                    $match = $(this); return false;\r\n                }\r\n            });\r\n            if (!$match) { console.warn('[pb651c] article introuvable pour URL:', url); return; }\r\n            $match[0].click();\r\n            console.log('[pb651c] article selectionne par URL:', url);\r\n        };\r\n        setTimeout(tryArt, 300);\r\n    }\r\n\r\n    \/\/ tarif : selectionner la cellule de la grille correspondant a la classe\r\n    _selectionnerTarif651(classe) {\r\n        \/\/ pb651e : NE PAS court-circuiter si la classe est deja selectionnee \u2014 quand\r\n        \/\/   seule la duree change (modif dates en direction A), la classe reste la\r\n        \/\/   meme mais le MONTANT affiche (#PopUpTarifsCampagneSelect) doit etre\r\n        \/\/   recalcule. Re-cliquer le lien relance le handler qui met a jour le montant.\r\n        \/\/ le handler de selection est sur a.via-tarif-lien-612, pas le div .Tarif7*\r\n        const $cell = $('.' + classe).first();\r\n        if ($cell.length === 0) { console.warn('[pb651 A] case tarif absente:', classe); return; }\r\n        let $lien = $cell.find('a.via-tarif-lien-612').first();\r\n        if ($lien.length === 0) { $lien = $cell.closest('[class*=\"Tarif7\"]').find('a.via-tarif-lien-612').first(); }\r\n        if ($lien.length === 0) { console.warn('[pb651 A] lien tarif absent:', classe); return; }\r\n        \/\/ pb651j : verrou anti-boucle -> B ne repoussera pas suite a ce clic A\r\n        window._sync651AClic = true;\r\n        $lien[0].click();\r\n        console.log('[pb651 A] tarif selectionne (clic lien):', classe);\r\n        setTimeout(() => { window._sync651AClic = false; }, 500);\r\n    }\r\n\r\n    \/\/ Direction B : pousser les infos du popup vers l'item ACTIF (live).\r\n    \/\/   Appele apres chaque modif du formulaire popup. Ne fait rien sans item actif.\r\n    syncVersResa651() {\r\n        \/\/ pb710 : pendant la reinitialisation, ne RIEN pousser vers la resa. Sans ce\r\n        \/\/   verrou, le vidage des champs se propagerait a l'item actif et effacerait\r\n        \/\/   la reservation existante - l'inverse de l'option (a) retenue.\r\n        if (window._viaResetPopup710) { return; }\r\n        if (window._sync651EnCours) { return; }   \/\/ A en cours -> ne pas reboucler\r\n        if (window._sync651AClic) { return; }   \/\/ pb651j : clic A en cours -> ne pas reboucler\r\n        const panier = window.VIA_Panier;\r\n        if (!panier) { return; }\r\n        const itemActif = panier.state ? panier.state.itemActif : null;\r\n        if (!itemActif) { return; }   \/\/ pas d'item -> le Continuer creera\r\n        \/\/ reutiliser la voie officielle pb637 : synchroniserAvecEtape1 lit les\r\n        \/\/   champs Etape1 \u2014 ici on pousse directement les valeurs du POPUP.\r\n        const dateDebut = $('#form-field-PopupTarifsDebutCampagne').val();\r\n        const dateFin = $('#form-field-PopupTarifsFinCampagne').val();\r\n        const pays = $('input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]').val();\r\n        const duree = this.state.dureeJours || null;\r\n        if (!dateDebut ? !dateFin ? !pays : false : false) { return; }   \/\/ rien a pousser\r\n        \/\/ pb751 : horodater les saisies FAITES DANS LE POPUP. pb749 n'horodatait que\r\n        \/\/   pays\/secteur\/format : dates et annonceur n'avaient aucune trace, donc\r\n        \/\/   aucun moyen de gagner un arbitrage contre la resa.\r\n        if (dateDebut ? true : !!dateFin) { this._ts749('dates', 'popup'); }\r\n        if (pays) { this._ts749('annonceur', 'popup'); }\r\n        window._sync651EnCours = true;\r\n        try {\r\n            if (typeof panier.mettreAJourItem === 'function') {\r\n                const maj = {};\r\n                if (pays) { maj.pays = pays; maj.paysAnnonceur = pays; }\r\n                if (dateDebut) { maj.dateDebut = dateDebut; }\r\n                if (dateFin) { maj.dateFin = dateFin; }\r\n                if (duree) { maj.duree = duree; }\r\n                panier.mettreAJourItem(itemActif, maj);\r\n                \/\/ pb651g : mettre a jour les CHAMPS visibles de l'Etape 1 (resa)\r\n                \/\/   -> mettreAJourItem ne rafraichit pas les inputs affiches.\r\n                if (dateDebut) { $('#form-field-DebutCampagne').val(dateDebut); }\r\n                if (dateFin) { $('#form-field-FinCampagne').val(dateFin); }\r\n                \/\/ pb651p : input pays de l'Etape 1 (resa)\r\n                if (pays) {\r\n                    $('#form-field-Nationalite_Societe').val(pays);\r\n                    try {\r\n                        if (typeof window.viaSetSelectedCountry === 'function') {\r\n                            window.viaSetSelectedCountry(pays);\r\n                        }\r\n                    } catch (eSC651) {}\r\n                }\r\n                console.log('[pb651 B] popup -> resa', itemActif, maj);\r\n            }\r\n        } catch (e651b) {\r\n            console.warn('[pb651 B] erreur:', e651b.message);\r\n        } finally {\r\n            setTimeout(() => { window._sync651EnCours = false; }, 200);\r\n        }\r\n    }\r\n\r\n    \/\/ pb647 : fermeture AUTOMATIQUE et SMOOTH d'une etape a sa completion.\r\n    \/\/   Anime hauteur+opacite de la\/les section(s) puis appelle setSection632(false).\r\n    \/\/   Garde _autoFerme647 : on ne referme qu'UNE fois par completion, pour ne pas\r\n    \/\/   lutter si l'utilisateur rouvre l'etape manuellement ensuite.\r\n    \/\/ ================================================================\r\n    \/\/ pb710 : REINITIALISATION du popup Tarifs (lien du header).\r\n    \/\/   Option (a) : on ne touche PAS a la reservation existante. On DETACHE\r\n    \/\/   simplement l'item actif - syncVersResa651 documente ce comportement :\r\n    \/\/   \"if (!itemActif) return; \/\/ pas d'item -> le Continuer creera\". Une saisie\r\n    \/\/   ulterieure donnera donc bien une NOUVELLE resa.\r\n    \/\/   Le verrou _viaResetPopup710 neutralise la direction B pendant l'operation,\r\n    \/\/   sinon le vidage des champs serait pousse dans l'item avant le detachement.\r\n    \/\/ ================================================================\r\n    reinitialiserPopup710() {\r\n        window._viaResetPopup710 = true;\r\n        try {\r\n            \/\/ 1. champs de saisie\r\n            $('input[name=\"form_fields[Nationalite_Societe_Tarifs]\"]').val('');\r\n            const $d = $('#form-field-PopupTarifsDebutCampagne');\r\n            const $f = $('#form-field-PopupTarifsFinCampagne');\r\n            $d.val(''); $f.val('');\r\n            try { $d.datepicker('setDate', null); $f.datepicker('setDate', null); } catch (_e1) {}\r\n            try { $f.datepicker('option', 'minDate', null); } catch (_e2) {}\r\n\r\n            \/\/ 2. selections dans les listes (site pays, secteurs)\r\n            $('#PopupTarifsListePays .v290-row, .PopupTarifsListePays .v290-row').removeClass('v290-on');\r\n            $('#PopupTarifsListeSecteurs .v290-row').removeClass('v290-on');\r\n\r\n            \/\/ 3. etat interne\r\n            this.state.paysSelectionne = null;\r\n            this.state.tarifSelectionne = null;\r\n            this.state.startDate = null;\r\n            this.state.endDate = null;\r\n            this._setDuree735(0);   \/\/ pb735 (etait : this.state.dureeJours = 0)\r\n            this.state.validSelection = false;\r\n            this.state.deviseAffichage = 'EUR';   \/\/ pb710 : devise remise a EUR\r\n            this._sync635 = {};\r\n            this._tarifMontant644 = null;\r\n            window._viaEtape5Ok631 = false;\r\n            window._resaClique644f = false;\r\n            window._viaReplie633 = false;\r\n            window._autoFerme647 = {};\r\n\r\n            \/\/ 4. grille + liste secteurs masquees\r\n            this._afficherGrilleTarifaire703(false);\r\n            \/\/ pb710 : masquer AUSSI .TarifsConteneur. Le helper ci-dessus ne cible que\r\n            \/\/   .GrilleTarifaire : si les deux classes ne sont pas portees par le meme\r\n            \/\/   noeud, le conteneur restait visible (grille vide). Ecriture en\r\n            \/\/   !important, comme setSection632, pour ne pas etre battue par lui.\r\n            $('.TarifsConteneur').each(function() {\r\n                this.style.setProperty('display', 'none', 'important');\r\n            });\r\n            \/\/ etat d'accordeon coherent avec ce masquage\r\n            window._via632 = window._via632 || {};\r\n            window._via632.tarifs = false;\r\n            console.log('[pb710] .TarifsConteneur masque x' + $('.TarifsConteneur').length);\r\n            \/\/ pb710 : masquer aussi le bloc du tarif SELECTIONNE. pb612b le revele au\r\n            \/\/   clic sur un tarif, en display:flex !important (il est masque par\r\n            \/\/   Elementor au depart) : on doit donc ecrire none en !important pour le\r\n            \/\/   refermer, et vider les montants qu'il porte, sinon un tarif obsolete\r\n            \/\/   resterait affiche apres reinitialisation.\r\n            const $selC710 = $('#PopUpTarifsTarifsSelectContainer');\r\n            if ($selC710.length) {\r\n                $selC710[0].style.setProperty('display', 'none', 'important');\r\n            }\r\n            $('#PopUpTarifsCampagneSelect').text('');\r\n            $('#PopUpTarifsTJM').text('');\r\n            console.log('[pb710] PopUpTarifsTarifsSelectContainer masque x' + $selC710.length);\r\n            this.masquerListeSecteurs615();\r\n            this._titreSecteursTexte708(false);\r\n\r\n            \/\/ 5. messages effaces\r\n            try { this.messageAnnonceur619(false); } catch (_e3) {}\r\n            try { this.messageSitePays620(false); } catch (_e4) {}\r\n            try { this.messageSecteurs622(false); } catch (_e5) {}\r\n            try { this.messageSecteurs628(false); } catch (_e6) {}\r\n            try { this.messageArticles656(false); } catch (_e7) {}\r\n            this._messageTarifs707('');\r\n\r\n            \/\/ 6. libelle du bouton Continuer (pb688) restaure\r\n            try {\r\n                const $b = $('#PopupTarifsBoutonContinuerResaTexte, .PopupTarifsBoutonContinuerResaTexte').first();\r\n                if ($b.length ? $b[0].dataset.txtInit688 : false) {\r\n                    $b[0].innerHTML = $b[0].dataset.txtInit688;\r\n                    delete $b[0].dataset.txt688;\r\n                }\r\n            } catch (_e8) {}\r\n\r\n            \/\/ 7. etapes DEPLIEES, comme a la premiere ouverture \u2014 SAUF 'tarifs'.\r\n            \/\/    Sa section EST .TarifsConteneur : la rouvrir ici annulerait le\r\n            \/\/    masquage de l'etape 4 (setSection632 ecrit display en !important,\r\n            \/\/    et s'execute apres). Coherent avec pb707 : sans prerequis, une\r\n            \/\/    ouverture manuelle de Tarifs serait de toute facon refusee.\r\n            this.config632().forEach((c) => {\r\n                if (c.cle === 'tarifs') { return; }\r\n                this.setSection632(c.cle, true);\r\n            });\r\n\r\n            \/\/ 8. devise : re-marquer EUR comme active\r\n            try { this.marquerDeviseActive613(); } catch (_e9) {}\r\n\r\n            \/\/ 9. DETACHER la resa : l'item existant reste INTACT, mais le popup ne lui\r\n            \/\/    est plus rattache -> une saisie ulterieure creera une nouvelle resa.\r\n            let _detache = 'aucun item actif';\r\n            try {\r\n                const _p = window.VIA_Panier;\r\n                if (_p ? _p.state : null) {\r\n                    _detache = _p.state.itemActif || 'aucun item actif';\r\n                    _p.state.itemActif = null;\r\n                }\r\n            } catch (_e10) {}\r\n\r\n            this.majEtapes631();\r\n            console.log('[pb710] popup reinitialise | resa detachee : ' + _detache);\r\n        } catch (_e710) {\r\n            console.warn('[pb710] erreur :', _e710.message);\r\n        }\r\n        \/\/ relacher le verrou APRES le cycle courant : les handlers change des\r\n        \/\/   datepickers et de l'autocomplete se declenchent en differe.\r\n        setTimeout(function() { window._viaResetPopup710 = false; }, 600);\r\n    }\r\n\r\n    \/\/ pb710 : branchement du lien du header. Delegation sur document : le header vit\r\n    \/\/   dans le widget HTML des redactionnels, hors de ce script, et peut etre\r\n    \/\/   (re)construit apres son execution.\r\n    \/\/ pb710 : confirmation + reinitialisation. Expose sur window car le lien vit\r\n    \/\/   dans le widget HTML des redactionnels, qui possede sa propre liaison tactile\r\n    \/\/   (voir _brancherLienReset710 la-bas, calquee sur pb655).\r\n    \/\/   Garde de re-entrance : sur mobile, touchend ET click peuvent tous deux\r\n    \/\/   aboutir ici \u2014 sans elle, deux confirmations s'enchaineraient.\r\n    \/\/ pb713 : popup de CONFIRMATION au design du module Validation Sequentielle\r\n    \/\/   (cadre blanc, bordure 3px #A2C6F3, rayon 10px, bouton #D4E6F9\/#4B689B).\r\n    \/\/   Ce module n'expose pas son afficherPopupValidation (window.VIA_ValidationProcess\r\n    \/\/   ne publie que les etapes et les verifications) et sa popup est INFORMATIVE :\r\n    \/\/   un seul bouton, auto-fermeture a 5 s. On en reprend donc les styles ici, en\r\n    \/\/   ajoutant le second bouton et en retirant l'auto-fermeture, qui n'a pas de sens\r\n    \/\/   pour une confirmation.\r\n    \/\/   z-index 99999 : au-dessus du popup Tarifs, dont l'echelle plafonne vers 10000\r\n    \/\/   (cf pb663\/pb665).\r\n    _confirmer713(message, onOui) {\r\n        const _old = document.getElementById('VIA_Confirm713');\r\n        if (_old ? _old.parentNode : null) { _old.parentNode.removeChild(_old); }\r\n        const _oldOv = document.getElementById('VIA_Confirm713Overlay');\r\n        if (_oldOv ? _oldOv.parentNode : null) { _oldOv.parentNode.removeChild(_oldOv); }\r\n\r\n        const isMobile = window.innerWidth <= 767;\r\n        \/\/ pb713 : mobile elargi de 40% (45% -> 63%) pour que les DEUX boutons tiennent\r\n        \/\/   sur une meme ligne. La popup d'origine n'en avait qu'un, d'ou son 45%.\r\n        const popupWidth = isMobile ? '63%' : '420px';\r\n        const popupPadding = isMobile ? '20px 15px' : '30px 40px';\r\n        const fontSize = isMobile ? '14px' : '16px';\r\n        const btnFontSize = isMobile ? '14px' : '16px';\r\n        const btnPadding = isMobile ? '10px 20px' : '12px 30px';\r\n\r\n        const overlay = document.createElement('div');\r\n        overlay.id = 'VIA_Confirm713Overlay';\r\n        overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.4);z-index:99998;opacity:0;transition:opacity 0.25s ease;';\r\n\r\n        const popup = document.createElement('div');\r\n        popup.id = 'VIA_Confirm713';\r\n        popup.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%) scale(0.9);background:#FFFFFF;border:3px solid #A2C6F3;border-radius:10px;padding:' + popupPadding + ';z-index:99999;box-shadow:0 10px 30px rgba(0,0,0,0.25);width:' + popupWidth + ';max-width:420px;text-align:center;box-sizing:border-box;opacity:0;transition:opacity 0.25s ease, transform 0.25s ease;';\r\n\r\n        const textEl = document.createElement('p');\r\n        textEl.style.cssText = 'margin:0 0 20px;font-size:' + fontSize + ';color:#333;line-height:1.5;font-family:inherit;';\r\n        textEl.textContent = message;\r\n\r\n        const _lang = (sessionStorage.getItem('SiteLangue') === 'EN') ? 'EN' : 'FR';\r\n        \/\/ pb713 : white-space nowrap -> un libelle ne se coupe jamais en deux lignes,\r\n        \/\/   ce qui desalignerait verticalement les deux boutons.\r\n        const _styleBtn = 'display:inline-block;background:#D4E6F9;color:#4B689B;padding:' + btnPadding + ';border-radius:5px;text-decoration:none;font-weight:500;font-size:' + btnFontSize + ';font-family:inherit;cursor:pointer;transition:background 0.2s;border:none;margin:0 6px;white-space:nowrap;vertical-align:middle;';\r\n\r\n        const btnOui = document.createElement('a');\r\n        btnOui.href = '#';\r\n        btnOui.style.cssText = _styleBtn;\r\n        btnOui.textContent = (_lang === 'EN') ? 'Confirm' : 'Valider';\r\n        btnOui.onmouseover = function() { btnOui.style.background = '#A2C6F3'; };\r\n        btnOui.onmouseout = function() { btnOui.style.background = '#D4E6F9'; };\r\n\r\n        const btnNon = document.createElement('a');\r\n        btnNon.href = '#';\r\n        btnNon.style.cssText = _styleBtn;\r\n        btnNon.textContent = (_lang === 'EN') ? 'Cancel' : 'Annuler';\r\n        btnNon.onmouseover = function() { btnNon.style.background = '#A2C6F3'; };\r\n        btnNon.onmouseout = function() { btnNon.style.background = '#D4E6F9'; };\r\n\r\n        popup.appendChild(textEl);\r\n        popup.appendChild(btnNon);\r\n        popup.appendChild(btnOui);\r\n        document.body.appendChild(overlay);\r\n        document.body.appendChild(popup);\r\n        requestAnimationFrame(function() {\r\n            overlay.style.opacity = '1';\r\n            popup.style.opacity = '1';\r\n            popup.style.transform = 'translate(-50%,-50%) scale(1)';\r\n        });\r\n\r\n        const _fermer = function() {\r\n            popup.style.opacity = '0';\r\n            popup.style.transform = 'translate(-50%,-50%) scale(0.9)';\r\n            overlay.style.opacity = '0';\r\n            setTimeout(function() {\r\n                if (popup.parentNode) { popup.parentNode.removeChild(popup); }\r\n                if (overlay.parentNode) { overlay.parentNode.removeChild(overlay); }\r\n            }, 250);\r\n        };\r\n        \/\/ touchend en plus du click : le popup Tarifs est draggable, et sur mobile le\r\n        \/\/   click de synthese peut etre avale (meme cause qu'en pb655\/pb710).\r\n        const _brancher = function(el, action) {\r\n            ['click', 'touchend'].forEach(function(ev) {\r\n                el.addEventListener(ev, function(e) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    _fermer();\r\n                    if (action) { action(); }\r\n                }, true);\r\n            });\r\n        };\r\n        _brancher(btnOui, onOui);\r\n        _brancher(btnNon, function() { console.log('[pb710] reinitialisation annulee'); });\r\n        overlay.addEventListener('click', function() {\r\n            _fermer();\r\n            console.log('[pb710] reinitialisation annulee (clic hors popup)');\r\n        });\r\n    }\r\n\r\n    demanderReinitialisation710() {\r\n        if (window._viaReset710EnCours) { return; }\r\n        window._viaReset710EnCours = true;\r\n        setTimeout(function() { window._viaReset710EnCours = false; }, 800);\r\n        const _lang = (sessionStorage.getItem('SiteLangue') === 'EN') ? 'EN' : 'FR';\r\n        const _q = (_lang === 'EN')\r\n            ? 'Please confirm the reset of the express purchase'\r\n            : 'Merci de confirmer la r\\u00e9initialisation de l\\u2019achat express';\r\n        this._confirmer713(_q, () => this.reinitialiserPopup710());\r\n    }\r\n\r\n    brancherReinitialiser710() {\r\n        if (window._viaReset710Bound) { return; }\r\n        window._viaReset710Bound = true;\r\n        \/\/ expose pour la liaison tactile du widget HTML (mobile)\r\n        window.viaReinitialiserPopup710 = () => this.demanderReinitialisation710();\r\n        \/\/ repli desktop : delegation classique. Si la liaison dediee du widget est\r\n        \/\/   active, elle stoppe la propagation et ce handler ne se declenche pas.\r\n        $(document).on('click', '#popup3 .handle-reset-710', (e) => {\r\n            e.preventDefault();\r\n            e.stopPropagation();\r\n            this.demanderReinitialisation710();\r\n        });\r\n        console.log('[pb710] lien Reinitialiser branche (+ window.viaReinitialiserPopup710)');\r\n    }\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb737 : le RECAPITULATIF n'a de sens qu'une fois le process complet.\r\n    \/\/   Regle : tant que \"Continuer la reservation\" n'est pas ROUGE,\r\n    \/\/   #PopupTarifsRecapContainer reste masque. Ouverture manuelle du titre ->\r\n    \/\/   message d'information dans #PopupTarifsRecapMessageTexte.\r\n    \/\/   Meme mecanique que pb707\/pb709 pour l'etape Tarifs ; seule difference,\r\n    \/\/   le message va dans un element EXISTANT du template au lieu d'un noeud\r\n    \/\/   cree (.v707-msg).\r\n    \/\/   Revert : window._viaPb737Off = true (tout le bloc)\r\n    \/\/ ================================================================\r\n    \/\/   Condition d'ACCES AU RECAP. Distincte de la couleur du bouton.\r\n    \/\/   pb737c : une fois la reservation transmise (_resaClique644f), le bouton\r\n    \/\/   Continuer repasse au gris (pb644f) mais le recapitulatif doit rester\r\n    \/\/   affiche EN PERMANENCE. L'acces ne depend donc que de la completude des\r\n    \/\/   cinq etapes ; le flag \"deja clique\" n'entre plus en jeu.\r\n    \/\/   majBoutonEtape644f, lui, conserve la regle d'origine : le bouton\r\n    \/\/   redevient gris apres le clic, comportement inchange.\r\n    _accesRecap737(toutComplete) {\r\n        return toutComplete ? true : false;\r\n    }\r\n\r\n    \/\/   Renvoie '' si le recap peut s'ouvrir, sinon le message a afficher.\r\n    \/\/   Reutilise etapesCompletees631() : source unique de l'avancement, aucune\r\n    \/\/   regle de validation dupliquee. Toutes les branches loguent (le\u00e7on pb693).\r\n    _prerequisRecap737() {\r\n        const _lang = (sessionStorage.getItem('SiteLangue') === 'EN') ? 'EN' : 'FR';\r\n        const _f = this.etapesCompletees631();\r\n        \/\/ pb737b : libelles simplifies (demande user).\r\n        \/\/ ================================================================\r\n        \/\/ pb1899 : CINQUIEME liste indexee par l'ordre des etapes.\r\n        \/\/   Ordre desormais : site pays, secteur, dates, annonceur, tarif.\r\n        \/\/   pb1366 avait du corriger cette liste apres coup, oubliee par pb1346 :\r\n        \/\/   quand une etape manquait, l'utilisateur lisait le message d'une autre.\r\n        \/\/   Les cinq messages suivent donc la permutation, dans le meme pb.\r\n        \/\/   Le libelle du secteur reste aligne sur celui d'Elementor (pb1348) :\r\n        \/\/   depuis pb1345 la homepage est un choix de cette etape, \u00ab secteur ou\r\n        \/\/   article \u00bb ne la couvrait pas.\r\n        \/\/   Celui de l'annonceur est aligne sur la maquette (demande user) :\r\n        \/\/   \u00ab le pays de la SOCIETE de l'annonceur \u00bb.\r\n        \/\/ ================================================================\r\n        \/\/ pb2408 : annonceur en tete, dates en 4e \u2014 meme permutation que etapes631().\r\n        const _msgs737 = [\r\n            { fr: 'Merci de renseigner le pays de la soci\\u00e9t\\u00e9 de l\\u2019annonceur',\r\n              en: 'Please enter the advertiser company\\u2019s country' },\r\n            { fr: 'Merci de s\\u00e9lectionner un site pays',\r\n              en: 'Please select a country site' },\r\n            { fr: 'Merci de s\\u00e9lectionner une page : homepage, th\\u00e8me, secteur ou article',\r\n              en: 'Please select a page: homepage, theme, sector or article' },\r\n            { fr: 'Merci de renseigner les dates de campagne',\r\n              en: 'Please enter the campaign dates' },\r\n            { fr: 'Merci de choisir un format et un tarif',\r\n              en: 'Please choose a format and a rate' }\r\n        ];\r\n        for (let _i737 = 0; _i737 < _msgs737.length; _i737++) {\r\n            if (!_f[_i737]) {\r\n                console.log('[pb737] recap bloque | etape manquante index=' + _i737\r\n                    + ' | faits=' + _f.map(x => x ? 1 : 0).join(''));\r\n                return (_lang === 'EN') ? _msgs737[_i737].en : _msgs737[_i737].fr;\r\n            }\r\n        }\r\n        \/\/ pb737c : les cinq etapes sont completes -> acces accorde, sans condition\r\n        \/\/   supplementaire. Plus aucun message a ce stade.\r\n        console.log('[pb737] recap AUTORISE | resaTransmise=' + (window._resaClique644f === true));\r\n        return '';\r\n    }\r\n\r\n    \/\/   Ecrit le message dans l'element EXISTANT #PopupTarifsRecapMessageTexte.\r\n    \/\/   Texte vide = masquage. L'element est masque par Elementor au repos, d'ou\r\n    \/\/   le display en inline !important (une classe elementor-hidden-* poserait\r\n    \/\/   display:none !important, qu'un .show() jQuery ne battrait pas \u2014 pb694).\r\n    _messageRecap737(texte) {\r\n        const $m = $('#PopupTarifsRecapMessageTexte, .PopupTarifsRecapMessageTexte');\r\n        if ($m.length === 0) { console.warn('[pb737] #PopupTarifsRecapMessageTexte introuvable'); return; }\r\n        $m.each(function () {\r\n            this.classList.remove('elementor-hidden-desktop', 'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n            if (texte) {\r\n                this.textContent = texte;\r\n                this.style.setProperty('display', 'block', 'important');\r\n                this.style.setProperty('color', '#fb5e2a', 'important');\r\n                this.style.setProperty('font-size', '11px', 'important');\r\n                this.style.setProperty('font-weight', '600', 'important');\r\n                this.style.setProperty('line-height', '1.2', 'important');\r\n                this.style.setProperty('text-align', 'center', 'important');\r\n                this.style.setProperty('width', '100%', 'important');\r\n            } else {\r\n                this.style.setProperty('display', 'none', 'important');\r\n            }\r\n        });\r\n        console.log('[pb737] message recap -> \"' + texte + '\" | elements=' + $m.length);\r\n    }\r\n\r\n    \/\/   Affiche ou masque #PopupTarifsRecapContainer. Meme technique que pb703.\r\n    _afficherRecap737(visible) {\r\n        const $c = $('#PopupTarifsRecapContainer, .PopupTarifsRecapContainer');\r\n        if ($c.length === 0) { return; }\r\n        $c.each(function () {\r\n            this.classList.remove('elementor-hidden-desktop', 'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n            if (!visible) {\r\n                this.style.setProperty('display', 'none', 'important');\r\n                return;\r\n            }\r\n            \/\/ pb737d : le conteneur est un flex Elementor (classes e-con \/ e-flex).\r\n            \/\/   pb737 y ecrivait display:block !important, ce qui ANNULAIT le flex :\r\n            \/\/   les enfants s'empilaient verticalement. On restitue donc le display\r\n            \/\/   natif du conteneur au lieu de le forcer en block.\r\n            var _flex737 = this.classList.contains('e-flex') ? true : this.classList.contains('e-con');\r\n            this.style.setProperty('display', _flex737 ? 'flex' : 'block', 'important');\r\n            if (_flex737) {\r\n                \/\/ pb737d : disposition HORIZONTALE demandee. Elementor pose souvent\r\n                \/\/   flex-direction:column sur les e-con : on force la ligne.\r\n                \/\/   wrap pour que le contenu retombe proprement en mobile plutot que\r\n                \/\/   de deborder ou d'ecraser les colonnes.\r\n                this.style.setProperty('flex-direction', 'row', 'important');\r\n                this.style.setProperty('flex-wrap', 'wrap', 'important');\r\n                this.style.setProperty('align-items', 'center', 'important');\r\n            }\r\n        });\r\n        console.log('[pb737] .PopupTarifsRecapContainer x' + $c.length + ' -> ' + (visible ? 'AFFICHE' : 'masque')\r\n            + (visible ? ' | display=' + ($c[0] ? getComputedStyle($c[0]).display : '?')\r\n                + ' direction=' + ($c[0] ? getComputedStyle($c[0]).flexDirection : '?') : ''));\r\n    }\r\n\r\n    \/\/   Recalcule l'etat du recap. Appele a chaque majEtapes631 : l'etat est\r\n    \/\/   toujours DEDUIT, jamais enchaine (principe pb631).\r\n    majRecap737() {\r\n        if (window._viaPb737Off === true) { return; }\r\n        const _bloque = this._prerequisRecap737();\r\n        if (_bloque) {\r\n            this._afficherRecap737(false);\r\n            \/\/ pb737b : cette methode ne POSE plus jamais le message. Il est pose\r\n            \/\/   UNIQUEMENT par le handler de clic, c'est-a-dire quand l'utilisateur\r\n            \/\/   TENTE d'ouvrir l'etape. On ne l'efface pas non plus ici tant que le\r\n            \/\/   blocage dure : majEtapes631 est rejoue a chaque evenement du\r\n            \/\/   formulaire et effacerait le message dans la foulee du clic.\r\n            return;\r\n        }\r\n        this._messageRecap737('');\r\n        \/\/ pb737c\/pb740 : le recapitulatif reste affiche TOUT LE TEMPS une fois la\r\n        \/\/   reservation EFFECTIVE (espace pub reserve), et non des le clic sur\r\n        \/\/   Continuer : au moment du clic il n'y a encore rien a recapituler, et\r\n        \/\/   forcer l'ouverture rouvrait l'etape que l'utilisateur venait de quitter.\r\n        \/\/   Meme critere que pb738b (_espaceReserve738), source unique.\r\n        if (this._espaceReserve738()) {\r\n            if ((window._via632 ? window._via632.recap : true) === false) {\r\n                this.setSection632('recap', true);\r\n            }\r\n            this._afficherRecap737(true);\r\n            return;\r\n        }\r\n        \/\/ pb740 : apres le clic Continuer et tant que rien n'est reserve, on\r\n        \/\/   n'ouvre pas le recap de force ; on respecte l'etat courant.\r\n        if (this._verrouApresContinuer740()) {\r\n            this._afficherRecap737((window._via632 ? window._via632.recap : false) === true);\r\n            return;\r\n        }\r\n        const _ouvert737 = (window._via632 ? window._via632.recap : true) !== false;\r\n        this._afficherRecap737(_ouvert737);\r\n    }\r\n\r\n    \/\/ pb707 : l'etape Tarifs n'a de sens que si la grille est affichee. Renvoie ''\r\n    \/\/   si tout est pret, sinon le texte de l'etape a renseigner EN PREMIER.\r\n    \/\/   On reutilise etapesCompletees631() (source unique de l'avancement) : ses\r\n    \/\/   3 premiers indices sont annonceur \/ site pays \/ dates, soit exactement les\r\n    \/\/   prerequis de la grille. On ne duplique donc aucune regle de validation.\r\n    _prerequisTarifs707() {\r\n        const _lang = (sessionStorage.getItem('SiteLangue') === 'EN') ? 'EN' : 'FR';\r\n        const _faits = this.etapesCompletees631();\r\n        \/\/ pb709 diag : etat COMPLET au moment de la decision. On loggue AVANT tout\r\n        \/\/   return, pour qu'aucune branche ne soit muette (le\u00e7on pb693\/pb657).\r\n        \/\/   _memeElement dit si .GrilleTarifaire et .TarifsConteneur sont le MEME\r\n        \/\/   noeud : si oui, le repli manuel masque la grille, ce qui expliquerait\r\n        \/\/   un faux \"calcul en cours\".\r\n        try {\r\n            const _g709 = document.querySelector('.GrilleTarifaire');\r\n            const _tc709 = document.querySelector('.TarifsConteneur');\r\n            console.log('[pb709] prerequis | faits=' + _faits.map(f => f ? 1 : 0).join('')\r\n                + ' (annonceur\/pays\/secteur\/dates\/tarif)'   \/\/ pb1899, pb2408\r\n                + ' | grilleCalculee=' + window._viaGrilleCalculee709\r\n                + ' | via632.tarifs=' + ((window._via632 || {}).tarifs)\r\n                + ' | .GrilleTarifaire n=' + document.querySelectorAll('.GrilleTarifaire').length\r\n                + ' display=' + (_g709 ? getComputedStyle(_g709).display : 'absent')\r\n                + ' | .TarifsConteneur n=' + document.querySelectorAll('.TarifsConteneur').length\r\n                + ' display=' + (_tc709 ? getComputedStyle(_tc709).display : 'absent')\r\n                + ' | memeElement=' + (_g709 ? (_g709 === _tc709) : 'n\/a'));\r\n        } catch (_e709) { console.warn('[pb709] diag', _e709.message); }\r\n        \/\/ ================================================================\r\n        \/\/ pb1899 : LES INDICES ONT BOUGE \u2014 TROISIEME LECTURE POSITIONNELLE.\r\n        \/\/   Ordre : 0 site pays, 1 secteur, 2 dates, 3 annonceur. Les quatre\r\n        \/\/   messages suivent, sinon l'etape Tarifs reclamerait ce qui est deja\r\n        \/\/   saisi et se tairait sur ce qui manque.\r\n        \/\/   L'annonceur reste un PREREQUIS des tarifs, et il le restera : le\r\n        \/\/   tarif depend de son pays (cf _signatureGrille1359). Il precede\r\n        \/\/   toujours l'etape Tarifs \u2014 index 3 contre index 4.\r\n        \/\/   Le secteur reste lui aussi prerequis (choix user pb1366) : il ne\r\n        \/\/   change pas le calcul du tarif mais il commande le FILTRAGE des lignes\r\n        \/\/   (pb1347). Ouvrir la grille sans lui reviendrait a montrer des lignes\r\n        \/\/   Home Page a quelqu'un qui a choisi un secteur.\r\n        \/\/ ================================================================\r\n        \/\/ pb2408 : 0 annonceur, 1 site pays, 2 secteur, 3 dates \u2014 les quatre\r\n        \/\/   messages suivent la permutation.\r\n        if (!_faits[0]) {\r\n            return (_lang === 'EN')\r\n                ? 'Please first enter the advertiser company\\u2019s country'\r\n                : 'Merci de renseigner le pays de la soci\\u00e9t\\u00e9 de l\\u2019annonceur';\r\n        }\r\n        if (!_faits[1]) {\r\n            return (_lang === 'EN')\r\n                ? 'Please first select a country site'\r\n                : 'Merci de s\\u00e9lectionner un site pays';\r\n        }\r\n        if (!_faits[2]) {\r\n            return (_lang === 'EN')\r\n                ? 'Please first select a page: homepage, theme, sector or article'\r\n                : 'Merci de s\\u00e9lectionner une page : homepage, th\\u00e8me, secteur ou article';\r\n        }\r\n        if (!_faits[3]) {\r\n            return (_lang === 'EN')\r\n                ? 'Please first enter the campaign dates'\r\n                : 'Merci de renseigner les dates de campagne';\r\n        }\r\n        \/\/ pb709 : les 3 prerequis sont remplis -> on regarde si la grille est CALCULEE,\r\n        \/\/   pas si elle est VISIBLE. Le test precedent lisait\r\n        \/\/   getComputedStyle('.GrilleTarifaire').display : or un repli manuel de\r\n        \/\/   l'etape Tarifs masque cet element (il porte aussi .TarifsConteneur), si\r\n        \/\/   bien qu'une grille pourtant calculee etait annoncee \"en cours de calcul\"\r\n        \/\/   et l'etape refusait de se rouvrir.\r\n        if (window._viaGrilleCalculee709 === true) { return ''; }\r\n        \/\/ ================================================================\r\n        \/\/ pb1359 : PAS DE \u00ab calcul en cours \u00bb POUR UN CHANGEMENT DE PAGE.\r\n        \/\/   Constat user : en 3 colonnes, passer d'une page secteur a une autre\r\n        \/\/   met bien le VLP a jour (pb1358), mais fait apparaitre .v707-msg.\r\n        \/\/   Chaine : le clic secteur rejoue onFormulaireChange, qui appelle\r\n        \/\/   _afficherGrilleTarifaire703(false) le temps du recalcul \u2014 le drapeau\r\n        \/\/   pb709 retombe a false, et ce return annonce un calcul en cours.\r\n        \/\/   Or le secteur n'entre pas dans le tarif (cf _signatureGrille1359) :\r\n        \/\/   la grille affichee reste exacte, il n'y a rien a annoncer.\r\n        \/\/   On compare donc la signature courante a celle memorisee quand la\r\n        \/\/   grille est devenue disponible. Identiques -> rien n'a change de ce\r\n        \/\/   qui la determine, pas de message. Differentes (dates, devise, pays\r\n        \/\/   annonceur) -> le message garde tout son sens et s'affiche.\r\n        \/\/   Revert : window._viaPb1359Off = true.\r\n        \/\/ ================================================================\r\n        if (window._viaPb1359Off !== true) {\r\n            try {\r\n                const _mem1359 = window._viaSigneGrille1359 || '';\r\n                if (_mem1359 ? (_mem1359 === this._signatureGrille1359()) : false) {\r\n                    if (window._viaSig1359 !== _mem1359) {\r\n                        window._viaSig1359 = _mem1359;\r\n                        console.log('[pb1359] grille masqu\u00e9e mais toujours valable ('\r\n                            + _mem1359 + ') -> message de calcul non affich\u00e9');\r\n                    }\r\n                    return '';\r\n                }\r\n            } catch (_e1359b) {\r\n                console.warn('[pb1359] comparaison impossible : ' + _e1359b.message);\r\n            }\r\n        }\r\n        \/\/ grille non calculee : calcul en vol, ou duree hors bornes (dans ce dernier\r\n        \/\/   cas un message dedie est deja affiche par ailleurs).\r\n        return (_lang === 'EN') ? 'Rates are being calculated\\u2026' : 'Calcul des tarifs en cours\\u2026';\r\n    }\r\n\r\n    \/\/ ====================================================================\r\n    \/\/ pb1359 : CE QUI DETERMINE LA GRILLE \u2014 et ce qui ne la determine pas.\r\n    \/\/   Un tarif depend du pays de l'ANNONCEUR, de la duree et de la devise.\r\n    \/\/   Le SECTEUR n'y entre pas : le log du calcul le dit lui-meme,\r\n    \/\/   \u00ab Calcul grille: Togo 15 jours \u00bb \u2014 ni page, ni secteur.\r\n    \/\/   Changer de page secteur ne perime donc pas la grille affichee.\r\n    \/\/ ====================================================================\r\n    _signatureGrille1359() {\r\n        const _p1359 = this.state ? (this.state.paysSelectionne || null) : null;\r\n        const _lbl1359 = _p1359 ? (_p1359.label || _p1359.code || '') : '';\r\n        const _d1359 = this.state ? (this.state.dureeJours || 0) : 0;\r\n        const _dev1359 = this.state ? (this.state.deviseAffichage || '') : '';\r\n        return _lbl1359 + '|' + _d1359 + '|' + _dev1359;\r\n    }\r\n\r\n    \/\/ pb707 : message d'information rouge sous le titre Tarifs. Texte vide = retrait.\r\n    \/\/   Insere APRES le titre, avec sa propre classe : pb644 gere son sous-titre vert\r\n    \/\/   via .v644-sub et ne touchera donc pas a celui-ci.\r\n    _messageTarifs707(texte) {\r\n        const _c = this.config632().find(x => x.cle === 'tarifs');\r\n        if (!_c) { return; }\r\n        const $ti = this._titre632(_c);\r\n        if ($ti.length === 0) { return; }\r\n        $ti.nextAll('.v707-msg').remove();\r\n        if (!texte) { return; }\r\n        const $m = $('<div class=\"v707-msg\"><\/div>');\r\n        $m.text(texte);\r\n        $m[0].style.setProperty('color', '#fb5e2a', 'important');\r\n        $m[0].style.setProperty('font-size', '11px', 'important');\r\n        $m[0].style.setProperty('font-weight', '600', 'important');\r\n        $m[0].style.setProperty('line-height', '1.2', 'important');\r\n        $m[0].style.setProperty('margin-top', '2px', 'important');\r\n        \/\/ pb707 : message CENTRE. text-align seul ne suffit pas si le conteneur parent\r\n        \/\/   est un flex Elementor : la boite du message y est dimensionnee au contenu\r\n        \/\/   et reste calee a gauche. On force donc aussi la largeur et les marges auto,\r\n        \/\/   plus align-self pour le cas d'un parent en flex-column.\r\n        $m[0].style.setProperty('text-align', 'center', 'important');\r\n        $m[0].style.setProperty('width', '100%', 'important');\r\n        $m[0].style.setProperty('margin-left', 'auto', 'important');\r\n        $m[0].style.setProperty('margin-right', 'auto', 'important');\r\n        $m[0].style.setProperty('align-self', 'center', 'important');\r\n        $ti.after($m);\r\n    }\r\n\r\n    \/\/ pb703 : affichage des elements .GrilleTarifaire, pilote par la validite des\r\n    \/\/   dates. Classe Elementor du template (aucune trace en JS) : elle peut porter\r\n    \/\/   les classes elementor-hidden-desktop\/tablet\/mobile, qui appliquent\r\n    \/\/   display:none !important \u2014 un .show() jQuery (inline SANS important) y\r\n    \/\/   perdrait, comme constate sur .ArticleTitre en pb694. On retire donc les\r\n    \/\/   classes ET on ecrit display en !important.\r\n    \/\/   Log inconditionnel, avec le nombre d'elements touches.\r\n    \/\/ pb706 : parametres fondu + callback, pour remplacer a l'identique les\r\n    \/\/   fadeIn(300, cb) qui portaient sur #TarifsPublicitaireListe.\r\n    \/\/   On n'utilise PAS jQuery.fadeIn : il ecrit display en inline SANS important\r\n    \/\/   et perdrait contre le display:none !important pose par le masquage.\r\n    \/\/   On anime donc l'opacite, display restant en !important.\r\n    _afficherGrilleTarifaire703(visible, fondu, apres) {\r\n        const $g = $('.GrilleTarifaire');\r\n        if ($g.length === 0) { console.warn('[pb703] .GrilleTarifaire introuvable'); return; }\r\n        \/* ================================================================\r\n         * pb2180 : PAS DE REVELATION SANS CALCUL ABOUTI.\r\n         *   Verdict de la sonde pb2179 : DEUX revelations au premier\r\n         *   affichage, la premiere portant \u00ab signature=(aucune) \u00bb. Or la\r\n         *   signature (_viaSigneGrille1359 : pays|duree|devise) n est posee\r\n         *   qu une fois le calcul termine. Cette premiere revelation montre\r\n         *   donc les montants restes dans les cellules \u2014 ceux du template ou\r\n         *   d un calcul precedent : les \u00ab faux tarifs \u00bb constates par JF, qui\r\n         *   se corrigent a la seconde revelation.\r\n         *   REGLE : tant qu aucune signature n existe, la grille n est pas\r\n         *   montree. L ecran reste blanc un instant \u2014 c est explicitement ce\r\n         *   que JF prefere a des montants faux.\r\n         *   La signature est le seul temoin fiable d un calcul abouti ; se\r\n         *   fier a la presence de cellules ne dirait rien de leur fraicheur.\r\n         *   Ne bloque QUE la revelation : les masquages passent toujours, et\r\n         *   le rappel \u00ab apres \u00bb est honore pour ne pas laisser un appelant en\r\n         *   attente d une suite qui ne viendrait jamais.\r\n         *   Revert : window._viaPb2180Off = true.\r\n         * ================================================================ *\/\r\n        \/* ====================================================================\r\n         * pb2192 : pb2180 SE BLOQUAIT LUI-MEME.\r\n         *   Constat JF : GT-pb2191 bien servi, et AUCUN log pb2191 ni pb2189 \u2014\r\n         *   donc le code de devoilement n est jamais atteint.\r\n         *   Cause : la garde pb2180 exige une signature (_viaSigneGrille1359)\r\n         *   qui n est posee QUE plus bas dans cette meme methode (l.8344),\r\n         *   apres la boucle. Tant qu elle est vide, on sort avant d y arriver :\r\n         *   elle ne peut donc JAMAIS etre posee. Verrou circulaire, de ma main.\r\n         *   L intention de pb2180 reste juste \u2014 ne pas montrer des montants qui\r\n         *   ne viennent pas d un calcul abouti \u2014 mais son temoin etait mal\r\n         *   choisi : la signature est une CONSEQUENCE de l affichage, pas une\r\n         *   condition prealable.\r\n         *   Nouveau temoin, independant de cette methode : le drapeau pose par\r\n         *   le calcul lui-meme, _viaGrilleCalculee709, complete par la presence\r\n         *   d au moins une cellule GARNIE (un montant non vide). Les deux\r\n         *   ensemble disent \u00ab un calcul a abouti et ses valeurs sont la \u00bb,\r\n         *   sans dependre de ce que cette methode va ecrire ensuite.\r\n         *   Revert : window._viaPb2192Off = true (ancien temoin, signature).\r\n         * ==================================================================== *\/\r\n        var _pret2192 = false;\r\n        try {\r\n            var _cel2192 = document.querySelectorAll('.PricingAmount');\r\n            for (var _i2192 = 0; _i2192 < _cel2192.length; _i2192++) {\r\n                var _t2192 = (_cel2192[_i2192].textContent || '').trim();\r\n                if (_t2192 ? (_t2192 !== '-') : false) { _pret2192 = true; break; }\r\n            }\r\n        } catch (_e2192) { _pret2192 = true; }\r\n        if (window._viaPb2192Off === true) { _pret2192 = !!window._viaSigneGrille1359; }\r\n        if (visible ? (window._viaPb2180Off !== true) : false) {\r\n            if (!_pret2192) {\r\n                \/* ============================================================\r\n                 * pb2182 : REFUSER L AFFICHAGE N EST PAS SAUTER LA MISE EN FORME.\r\n                 *   Constat JF : pb2180 court-circuitait le code qui remplace\r\n                 *   \u00ab Home Page \u2013 Haut de page \u00bb par \u00ab Haut de page \u00bb.\r\n                 *   Cause : mon return sortait AVANT le bloc de mise en forme de\r\n                 *   cette methode \u2014 _filtrerLignes1347, _masquerTermesPage1396\r\n                 *   (c est lui qui retire le prefixe), _libellesMobile1386 et\r\n                 *   _margePremiereRangee1397. Ces traitements preparent le\r\n                 *   contenu ; ils n ont rien a voir avec le fait de le montrer.\r\n                 *   On les joue donc AVANT de renoncer, dans l ordre impose par\r\n                 *   pb1396 (filtrer fige la famille, masquer retire les termes,\r\n                 *   reformater lit les libelles reduits) \u2014 le meme ordre que la\r\n                 *   branche normale, pas une variante.\r\n                 *   Seule la REVELATION reste differee : la grille est prete et\r\n                 *   masquee, la revelation suivante n aura plus qu a la montrer.\r\n                 * ============================================================ *\/\r\n                try {\r\n                    this._filtrerLignes1347();\r\n                    this._masquerTermesPage1396();\r\n                    this._libellesMobile1386();\r\n                    this._margePremiereRangee1397();\r\n                } catch (_ef2182) { console.warn('[pb2182] mise en forme : ' + _ef2182.message); }\r\n                console.log('[pb2180] revelation REFUSEE : aucune cellule garnie'\r\n                    + ' -> grille laissee masquee | [pb2182] mise en forme appliquee'\r\n                    + ' | [pb2192] temoin=cellules garnies (signature='\r\n                    + (window._viaSigneGrille1359 || 'vide') + ')');\r\n                if (typeof apres === 'function') {\r\n                    try { apres(); } catch (_ea2180) { console.warn('[pb2180] rappel : ' + _ea2180.message); }\r\n                }\r\n                return;\r\n            }\r\n        }\r\n        \/\/ pb1347 : la grille est reconstruite a chaque affichage (pb1240c le note\r\n        \/\/   deja) \u2014 le filtre doit donc etre repose ici, pas une fois pour toutes.\r\n        if (visible) {\r\n            \/\/ pb1396 : l'ordre compte \u2014 filtrer fige la famille de chaque rangee,\r\n            \/\/   masquer retire ensuite les termes, reformater ne voit plus de tiret\r\n            \/\/   a couper sur les libelles reduits. Inverser masquerait la famille\r\n            \/\/   avant qu'elle ait ete lue.\r\n            this._filtrerLignes1347();\r\n            this._masquerTermesPage1396();\r\n            this._libellesMobile1386();   \/\/ pb1386 : la grille est reconstruite a chaque affichage\r\n            this._margePremiereRangee1397();   \/\/ pb1397 : en dernier, quand les libelles sont figes\r\n            \/\/ ================================================================\r\n            \/\/ pb1392 : MESURER QUAND LA GRILLE EST VISIBLE, PAS AVANT.\r\n            \/\/   Le diagnostic pb1391 est revenu avec des geometries toutes nulles :\r\n            \/\/     marginTop=0px | hauteur=0 | en-t\u00eate=0px, bas=0 | haut rang\u00e9e=0\r\n            \/\/   La grille est encore masquee a cet instant \u2014 pb703 la cache pendant\r\n            \/\/   le calcul et la revele juste apres. Mesurer ici, c'est mesurer un\r\n            \/\/   element sans mise en page : la lecon pb1257\/pb1258, que je viens de\r\n            \/\/   refaire.\r\n            \/\/   Une information reste pourtant exploitable, car elle vient du style\r\n            \/\/   calcule et non de la geometrie : la PREMIERE rangee a marginTop=0px,\r\n            \/\/   les suivantes -15px. Le chevauchement sous l'en-tete ne peut donc pas\r\n            \/\/   venir d'une marge negative sur cette rangee-la.\r\n            \/\/   On repasse apres affichage \u2014 deux frames puis un delai \u2014 pour obtenir\r\n            \/\/   des hauteurs reelles et savoir d'ou vient le recouvrement.\r\n            \/\/   Revert : window._viaPb1392Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1392Off !== true) {\r\n                var _self1392 = this;\r\n                var _mesurer1392 = function (_quand1392) {\r\n                    try {\r\n                        var _rg1392 = document.querySelectorAll('.TarifsFormats');\r\n                        if (_rg1392.length < 2) { return; }\r\n                        var _prem1392 = null;\r\n                        var _hdr1392 = null;\r\n                        for (var _i1392 = 0; _i1392 < _rg1392.length; _i1392++) {\r\n                            if (_rg1392[_i1392].querySelector('[data-via1386]')) {\r\n                                _prem1392 = _rg1392[_i1392];\r\n                                break;\r\n                            }\r\n                            _hdr1392 = _rg1392[_i1392];\r\n                        }\r\n                        if (!_prem1392 ? true : !_hdr1392) { return; }\r\n                        var _rh1392 = _hdr1392.getBoundingClientRect();\r\n                        var _rp1392 = _prem1392.getBoundingClientRect();\r\n                        if (_rh1392.height === 0) { return; }   \/\/ toujours masquee\r\n                        var _chev1392 = Math.round(_rh1392.bottom - _rp1392.top);\r\n                        var _txt1392 = _quand1392\r\n                            + ' | en-t\u00eate h=' + Math.round(_rh1392.height)\r\n                            + ' bas=' + Math.round(_rh1392.bottom)\r\n                            + ' | 1re rang\u00e9e h=' + Math.round(_rp1392.height)\r\n                            + ' haut=' + Math.round(_rp1392.top)\r\n                            + ' marginTop=' + window.getComputedStyle(_prem1392).marginTop\r\n                            + ' | recouvrement=' + _chev1392 + 'px'\r\n                            + (_chev1392 > 0 ? '  <-- CHEVAUCHEMENT' : '');\r\n                        if (window._viaSig1392 !== _txt1392) {\r\n                            window._viaSig1392 = _txt1392;\r\n                            console.log('[pb1392] ' + _txt1392);\r\n                        }\r\n                    } catch (_e1392) {\r\n                        console.warn('[pb1392] mesure impossible : ' + _e1392.message);\r\n                    }\r\n                };\r\n                requestAnimationFrame(function () {\r\n                    requestAnimationFrame(function () { _mesurer1392('apr\u00e8s 2 frames'); });\r\n                });\r\n                setTimeout(function () { _mesurer1392('apr\u00e8s 600 ms'); }, 600);\r\n            }\r\n        }\r\n        \/\/ ================================================================\r\n        \/\/ pb766 : DEUX ECRIVAINS sur le display de .GrilleTarifaire.\r\n        \/\/   Le HTML fourni par l'utilisateur est sans appel :\r\n        \/\/     <div id=\"PopupTarifsTarifsTexte\" class=\"... via632-ferme\">      <- titre FERME\r\n        \/\/     <div class=\"... TarifsConteneur GrilleTarifaire ...\"\r\n        \/\/          style=\"display: block !important\" data-display632=\"block\">  <- contenu VISIBLE\r\n        \/\/   L'accordeon avait bien ferme l'etape (classe via632-ferme, display\r\n        \/\/   memorise dans data-display632) ; pb703 la rouvre ensuite en !important,\r\n        \/\/   sans savoir que l'utilisateur l'a repliee.\r\n        \/\/   L'accordeon est l'AUTORITE sur la visibilite d'une etape : pb703 ne fait\r\n        \/\/   qu'exprimer \"la grille est calculee et disponible\". Le flag logique\r\n        \/\/   pb709 est donc mis a jour normalement, seul l'affichage est retenu.\r\n        \/\/   Des que l'utilisateur rouvre l'etape, setSection632 restaure le display\r\n        \/\/   memorise et la grille reparait \u2014 sans nouveau calcul.\r\n        \/\/   Revert : window._viaPb766Off = true.\r\n        \/\/ ================================================================\r\n        if (visible ? (window._viaPb766Off !== true) : false) {\r\n            const _etape766 = (window._via632 || {}).tarifs;\r\n            if (_etape766 === false) {\r\n                window._viaGrilleCalculee709 = true;   \/\/ la grille EST calculee\r\n                console.log('[pb766] affichage grille retenu \u2014 etape Tarifs repliee par'\r\n                    + ' l utilisateur (via632.tarifs=false) | grilleCalculee709=true');\r\n                if (typeof apres === 'function') { setTimeout(apres, 0); }\r\n                return;\r\n            }\r\n        }\r\n        const _diag703 = [];\r\n        var _aDevoiler2196 = [];   \/\/ pb2196 : elements prepares, a devoiler ensemble\r\n        $g.each(function() {\r\n            if (visible) {\r\n                \/\/ etat AVANT : dire par quel mecanisme Elementor masquait, plutot que\r\n                \/\/   de le supposer. Les trois pistes possibles sont couvertes ci-dessous.\r\n                const _cls = ['desktop', 'tablet', 'mobile'].filter(function(b) {\r\n                    return this.classList.contains('elementor-hidden-' + b);\r\n                }, this).join('+');\r\n                _diag703.push('classes=' + (_cls || 'aucune')\r\n                    + ' inline=\"' + (this.style.display || 'vide') + '\"'\r\n                    + ' calcule=' + getComputedStyle(this).display);\r\n                \/\/ 1) classes elementor-hidden-* : display:none !important en feuille\r\n                this.classList.remove('elementor-hidden-desktop');\r\n                this.classList.remove('elementor-hidden-tablet');\r\n                this.classList.remove('elementor-hidden-mobile');\r\n                \/\/ 2) display:none pose en INLINE dans le template\r\n                \/\/ 3) regle de feuille sur l'id\/la classe -> l'inline !important la bat\r\n                \/\/ ============================================================\r\n                \/\/ pb2189 : ON N ATTEND PLUS UNE DUREE, ON ATTEND LA STABILITE.\r\n                \/\/   Constat JF : meme a 250 ms (pb2183b), des mises en forme se\r\n                \/\/   voient encore apres l affichage. Un delai fixe ne peut pas\r\n                \/\/   savoir quand les writers ont fini \u2014 il est toujours trop\r\n                \/\/   court sur une machine lente, toujours trop long sinon.\r\n                \/\/   METHODE, celle de pb1860 : on rend la grille MESURABLE sans\r\n                \/\/   la rendre visible (display:block + visibility:hidden), on\r\n                \/\/   echantillonne sa geometrie ET son contenu toutes les 60 ms,\r\n                \/\/   et on ne la devoile qu apres trois releves IDENTIQUES\r\n                \/\/   d affilee. Masquee en display:none, elle ne se mesurerait\r\n                \/\/   pas (lecon pb1392\/pb1593 : geometries nulles) ; en\r\n                \/\/   visibility:hidden elle occupe sa place definitive, donc\r\n                \/\/   aucun saut de mise en page au devoilement.\r\n                \/\/   PLAFOND DUR : au-dela, on devoile quoi qu il arrive. Une\r\n                \/\/   grille qui ne s affiche jamais serait pire que le defaut.\r\n                \/\/   Reglages : window._viaPb2189Calme (3 releves)\r\n                \/\/              window._viaPb2189Max   (2500 ms)\r\n                \/\/   Revert : window._viaPb2189Off = true (pose immediate).\r\n                \/\/ ============================================================\r\n                \/* pb2197 : plus de visibility inline \u2014 la feuille masque, la\r\n                   classe revele. On prepare seulement : display et mesure. *\/\r\n                var _elA2183 = this;\r\n                _elA2183.style.setProperty('display', 'block', 'important');\r\n                _elA2183.style.removeProperty('visibility');\r\n                if (window._viaPb2197Off === true) {\r\n                    _elA2183.classList.add('via-grille-prete');\r\n                } else if (!_elA2183.classList.contains('via-grille-prete')) {\r\n                    _aDevoiler2196.push(_elA2183);\r\n                }\r\n            } else {\r\n                \/\/ pb2183 : un masquage annule une pose differee en attente, sinon la\r\n                \/\/   grille reapparaitrait 250 ms apres avoir ete cachee.\r\n                if (this._viaAff2183) {\r\n                    clearInterval(this._viaAff2183);   \/\/ pb2189 : c'est un interval\r\n                    this._viaAff2183 = null;\r\n                }\r\n                this.style.removeProperty('visibility');   \/\/ pb2189\r\n                this.classList.remove('via-grille-prete');   \/\/ pb2197\r\n                this._viaDevoile2189 = false;   \/\/ pb2194 : un masquage reel autorise un nouveau cycle\r\n                window._viaSig2194 = null;\r\n                this.style.setProperty('display', 'none', 'important');\r\n            }\r\n        });\r\n        \/* pb2196 : UNE seule veille pour tout l ensemble, posee apres la boucle. *\/\r\n        if (_aDevoiler2196.length ? !window._viaVeille2196 : false) {\r\n            window._viaVeille2196 = true;\r\n            var _lot2196 = _aDevoiler2196.slice();\r\n            var _fondu2196 = fondu;\r\n            var _t02196 = Date.now();\r\n            var _sig2196 = null;\r\n            var _n2196 = 0;\r\n            var _need2196 = (typeof window._viaPb2189Calme === 'number') ? window._viaPb2189Calme : 3;\r\n            var _max2196 = (typeof window._viaPb2189Max === 'number') ? window._viaPb2189Max : 2500;\r\n            var _signature2196 = function () {\r\n                var _t = [];\r\n                for (var _k = 0; _k < _lot2196.length; _k++) {\r\n                    var _r = _lot2196[_k].getBoundingClientRect();\r\n                    _t.push(Math.round(_r.width) + 'x' + Math.round(_r.height));\r\n                    var _c = _lot2196[_k].querySelectorAll('.PricingAmount, .TarifsFormats');\r\n                    _t.push(_c.length);\r\n                    for (var _j = 0; _j < _c.length; _j++) {\r\n                        var _rc = _c[_j].getBoundingClientRect();\r\n                        _t.push(Math.round(_rc.top) + ':' + Math.round(_rc.height)\r\n                            + ':' + (_c[_j].textContent || '').trim().slice(0, 12));\r\n                    }\r\n                }\r\n                return _t.join('|');\r\n            };\r\n            var _devoilerLot2196 = function (_motif) {\r\n                for (var _m = 0; _m < _lot2196.length; _m++) {\r\n                    var _e = _lot2196[_m];\r\n                    _e._viaDevoile2189 = true;\r\n                    _e.classList.add('via-grille-prete');   \/\/ pb2197\r\n                    _e.style.removeProperty('visibility');\r\n                    if (_fondu2196) {\r\n                        _e.style.setProperty('opacity', '0', 'important');\r\n                        _e.style.setProperty('transition', 'opacity .3s ease', 'important');\r\n                    } else {\r\n                        _e.style.removeProperty('opacity');\r\n                    }\r\n                }\r\n                if (_fondu2196) {\r\n                    requestAnimationFrame(function () {\r\n                        for (var _q = 0; _q < _lot2196.length; _q++) {\r\n                            _lot2196[_q].style.setProperty('opacity', '1', 'important');\r\n                        }\r\n                    });\r\n                    setTimeout(function () {\r\n                        for (var _w = 0; _w < _lot2196.length; _w++) {\r\n                            _lot2196[_w].style.removeProperty('transition');\r\n                        }\r\n                    }, 350);\r\n                }\r\n                window._viaVeille2196 = false;\r\n                console.log('[pb2196] ' + _lot2196.length + ' grille(s) devoilee(s) ENSEMBLE apres '\r\n                    + (Date.now() - _t02196) + 'ms | ' + _motif);\r\n            };\r\n            var _tick2196 = setInterval(function () {\r\n                try {\r\n                    var _ec = Date.now() - _t02196;\r\n                    var _s = _signature2196();\r\n                    if (_s === _sig2196) { _n2196 = _n2196 + 1; } else { _sig2196 = _s; _n2196 = 1; }\r\n                    if (_n2196 >= _need2196 ? true : (_ec >= _max2196)) {\r\n                        clearInterval(_tick2196);\r\n                        _devoilerLot2196(_n2196 >= _need2196\r\n                            ? (_need2196 + ' releves identiques (stable)')\r\n                            : 'PLAFOND atteint');\r\n                    }\r\n                } catch (_ei2196) {\r\n                    clearInterval(_tick2196);\r\n                    _devoilerLot2196('erreur : ' + _ei2196.message);\r\n                }\r\n            }, 60);\r\n            console.log('[pb2196] veille UNIQUE armee sur ' + _lot2196.length\r\n                + ' element(s) | calme=' + _need2196 + ' | plafond=' + _max2196 + 'ms');\r\n        }\r\n        \/\/ pb709 : etat LOGIQUE de la grille (calculee et disponible), distinct de son\r\n        \/\/   etat VISUEL. Tous les masquages\/affichages passent par cette methode\r\n        \/\/   (pb705\/pb706), le flag est donc fiable. Un repli MANUEL de l'etape Tarifs,\r\n        \/\/   lui, ne passe pas ici : il masque l'element sans invalider la grille.\r\n        window._viaGrilleCalculee709 = visible ? true : false;\r\n        \/\/ pb1359 : au moment ou la grille devient disponible, memoriser CE QUI la\r\n        \/\/   determine. Sert a distinguer \u00ab la grille est perimee \u00bb de \u00ab on l'a\r\n        \/\/   simplement masquee le temps d'autre chose \u00bb. Voir _prerequisTarifs707.\r\n        if (visible) {\r\n            try { window._viaSigneGrille1359 = this._signatureGrille1359(); }\r\n            catch (_e1359a) { console.warn('[pb1359] signature : ' + _e1359a.message); }\r\n        }\r\n        console.log('[pb709] grilleCalculee709 = ' + window._viaGrilleCalculee709\r\n            + ' (appel _afficherGrilleTarifaire703(' + visible + '))');\r\n        \/\/ pb707 : la grille s'affiche -> le message de prerequis n'a plus lieu d'etre\r\n        if (visible) { this._messageTarifs707(''); }\r\n        if (visible ? (typeof apres === 'function') : false) {\r\n            setTimeout(apres, fondu ? 300 : 0);\r\n        }\r\n        console.log('[pb703] .GrilleTarifaire x' + $g.length + ' -> ' + (visible ? 'AFFICHEE' : 'masquee')\r\n            + (_diag703.length ? ' | avant : ' + _diag703.join(' ; ') : ''));\r\n    }\r\n\r\n    fermerSmooth647(cle) {\r\n        window._autoFerme647 = window._autoFerme647 || {};\r\n        \/* pb2225 : ces deux sorties etaient muettes avant pb1963. La sonde est\r\n           retiree, PAS ces deux lignes : elles appliquent la regle 5.2 (aucune\r\n           sortie silencieuse), qui est permanente et non un instrument de\r\n           diagnostic. Elles sont donc renommees pb647, du nom de la fonction\r\n           qu'elles decrivent, et ne dependent plus d'aucun knob de sonde. *\/\r\n        if (window._autoFerme647[cle]) {\r\n            console.log('[pb647] fermerSmooth647(' + cle + ') SORT :'\r\n                + ' _autoFerme647 deja pose | _via632=' + String((window._via632 || {})[cle]));\r\n            return;\r\n        }          \/\/ deja auto-ferme\r\n        if ((window._via632 || {})[cle] === false) {\r\n            console.log('[pb647] fermerSmooth647(' + cle + ') SORT : _via632 deja false');\r\n            return;\r\n        } \/\/ deja fermee\r\n        window._autoFerme647[cle] = true;\r\n        \/\/ pb2169 : horodater l'auto-fermeture (lu par setSection632, voir pb2169).\r\n        window._viaFerme647At = window._viaFerme647At || {};\r\n        window._viaFerme647At[cle] = Date.now();\r\n\r\n        const c = this.config632().find(x => x.cle === cle);\r\n        if (!c) { return; }\r\n        const $sec = this._section632(c);\r\n        if ($sec.length === 0) { this.setSection632(cle, false); return; }\r\n\r\n        $sec.each(function() {\r\n            const el = this;\r\n            const h = el.scrollHeight;\r\n            \/\/ memoriser le display d'origine pour setSection632\r\n            const cur = getComputedStyle(el).display;\r\n            if (cur !== 'none') { el.dataset.display632 = cur; }\r\n            el.style.setProperty('overflow', 'hidden', 'important');\r\n            el.style.setProperty('height', h + 'px', 'important');\r\n            el.style.setProperty('transition', 'height .28s ease, opacity .28s ease', 'important');\r\n            \/\/ forcer un reflow puis animer vers 0\r\n            void el.offsetHeight;\r\n            requestAnimationFrame(() => {\r\n                el.style.setProperty('height', '0px', 'important');\r\n                el.style.setProperty('opacity', '0', 'important');\r\n            });\r\n        });\r\n        \/* pb1964 : le minuteur est MEMORISE. Sans identifiant, la fermeture\r\n           animee n'est pas annulable : une ouverture survenue pendant les\r\n           300 ms se faisait rattraper par ce rappel, qui refermait ce qui\r\n           venait d'etre ouvert. Une animation qu'on ne peut pas interrompre\r\n           n'est pas un etat, c'est une promesse. *\/\r\n        window._viaTimer647 = window._viaTimer647 || {};\r\n        \/\/ a la fin de l'animation : masquage propre + nettoyage des styles inline\r\n        window._viaTimer647[cle] = setTimeout(() => {\r\n            window._viaTimer647[cle] = null;\r\n            this.setSection632(cle, false);\r\n            $sec.each(function() {\r\n                this.style.removeProperty('height');\r\n                this.style.removeProperty('opacity');\r\n                this.style.removeProperty('overflow');\r\n                this.style.removeProperty('transition');\r\n            });\r\n            console.log('[pb647] etape auto-fermee (smooth):', cle);\r\n        }, 300);\r\n    }\r\n\r\n    setSection632(cle, ouvert) {\r\n        const c = this.config632().find(x => x.cle === cle);\r\n        if (!c) { return; }\r\n        \/\/ pb740b : setSection632 est l'ENTONNOIR UNIQUE d'ouverture\/fermeture.\r\n        \/\/   pb740 n'a produit aucun log -> afficherListeSecteurs615 n'est pas le\r\n        \/\/   chemin de reouverture. On identifie donc l'appelant reel plutot que de\r\n        \/\/   tenter un autre candidat a l'aveugle : la pile d'appel donne la reponse\r\n        \/\/   en une manipulation. Limite a secteurs\/recap et aux OUVERTURES pour ne\r\n        \/\/   pas noyer la console.\r\n        window._via632 = window._via632 || {};\r\n        window._via632[cle] = ouvert;\r\n\r\n\r\n        \/* pb1964 : annuler la fermeture EN COURS avant d'ouvrir. Sans cela, le\r\n           rappel de fermerSmooth647 encore en vol referme la section 300 ms\r\n           plus tard, et le nettoyage ci-dessous serait defait par lui. Un etat\r\n           ne se corrige pas si son ancien ecrivain a encore la main. *\/\r\n        var _res1964 = [];\r\n        if (window._viaPb1964Off !== true) {\r\n            if (ouvert) {\r\n                window._viaTimer647 = window._viaTimer647 || {};\r\n                if (window._viaTimer647[cle]) {\r\n                    clearTimeout(window._viaTimer647[cle]);\r\n                    window._viaTimer647[cle] = null;\r\n                    _res1964.push('minuteur annule');\r\n                }\r\n            }\r\n        }\r\n        const $sec = this._section632(c);\r\n        if ($sec.length) {\r\n            \/\/ pb644d : la section peut correspondre a PLUSIEURS elements (ex.\r\n            \/\/   .PopupTarifsDates present 3x) -> agir sur chacun, sinon .first()\r\n            \/\/   masquait un element deja invisible en laissant les autres.\r\n            $sec.each(function() {\r\n                if (ouvert) {\r\n                    const d = this.dataset.display632 || 'flex';\r\n                    this.style.setProperty('display', d, 'important');\r\n                    \/* ========================================================\r\n                     * pb1964 : OUVRIR, C'EST AUSSI DEFAIRE L'ANIMATION DE FERMETURE.\r\n                     *   >>> Famille (a) de la REGLE 5.4 (\u00ab les deux horloges \u00bb),\r\n                     *   enoncee en tete de yearbook-media.js : un etat trouve en\r\n                     *   cours d'animation parce que le scenario demarre a un autre\r\n                     *   instant que le module.\r\n                     *   Mesure JF (releve pb1963, cas \u00ab avec attente \u00bb) :\r\n                     *     .PopupTarifsDates | rendu 585x0 | display=flex\r\n                     *       | opacity=0 | height inline=\"0px\"\r\n                     *   contre, cas \u00ab sans attente \u00bb, rendu 650x49, opacity=1,\r\n                     *   height inline vide. Meme _via632, meme display : seuls\r\n                     *   les residus different.\r\n                     *   fermerSmooth647 pose height:0 et opacity:0 des la frame\r\n                     *   suivante et ne les efface qu'au bout de ses 300 ms. Une\r\n                     *   ouverture survenue entre les deux ne restaurait que le\r\n                     *   display : section ouverte, hauteur nulle, invisible.\r\n                     *   La correction est ICI parce que setSection632 est\r\n                     *   l'entonnoir unique d'ouverture (pb740b) et qu'elle y\r\n                     *   rearme deja _autoFerme647 : c'est le meme travail, pas\r\n                     *   une strate de plus.\r\n                     *   Revert : window._viaPb1964Off = true.\r\n                     * ======================================================== *\/\r\n                    if (window._viaPb1964Off !== true) {\r\n                        if (this.style.height ? true : (this.style.opacity !== '')) {\r\n                            _res1964.push(String(this.style.height || '-')\r\n                                + '\/' + String(this.style.opacity || '-'));\r\n                        }\r\n                        this.style.removeProperty('height');\r\n                        this.style.removeProperty('opacity');\r\n                        this.style.removeProperty('overflow');\r\n                        this.style.removeProperty('transition');\r\n                    }\r\n                } else {\r\n                    const cur = getComputedStyle(this).display;\r\n                    if (cur !== 'none') { this.dataset.display632 = cur; }\r\n                    this.style.setProperty('display', 'none', 'important');\r\n                }\r\n            });\r\n        } else {\r\n            console.warn('[pb632] section introuvable:', c.section);\r\n        }\r\n\r\n        \/\/ pb709 diag : verifier que l'ouverture a REELLEMENT pris sur le rendu\r\n        if (cle === 'tarifs') {\r\n            const _s709 = $sec[0];\r\n            console.log('[pb709] setSection632(tarifs, ' + ouvert + ') | sections=' + $sec.length\r\n                + ' | display apres=' + (_s709 ? getComputedStyle(_s709).display : 'absent')\r\n                + ' | inline=\"' + (_s709 ? _s709.style.display : '') + '\"'\r\n                + ' | dataset.display632=' + (_s709 ? _s709.dataset.display632 : ''));\r\n        }\r\n        if (_res1964.length) {\r\n            console.log('[pb1964] ' + cle + ' : residus de fermeture defaits -> '\r\n                + _res1964.join(', '));\r\n        }\r\n        const $ti = this._titre632(c);\r\n        if ($ti.length) { $ti.toggleClass('via632-ferme', !ouvert); }\r\n        \/\/ pb647 : rouverture manuelle -> re-armer la garde (permet une future\r\n        \/\/   auto-fermeture si l'etape est re-completee).\r\n        \/\/ ================================================================\r\n        \/\/ pb2169 : BOUCLE INFINIE SUR LE RECAP \u2014 le re-armement n'est plus\r\n        \/\/   automatique. Cycle releve par JF, indefiniment repete :\r\n        \/\/     [pb737] .PopupTarifsRecapContainer -> AFFICHE\r\n        \/\/     [pb647] etape auto-fermee (smooth): recap\r\n        \/\/     [pb1964] recap : residus de fermeture defaits\r\n        \/\/     ... et de nouveau AFFICHE.\r\n        \/\/   Mecanique : pb737 ouvre le recap -> setSection632(recap, true) ->\r\n        \/\/   la ligne ci-dessus RE-ARME _autoFerme647 -> majEtapes631 conclut\r\n        \/\/   \u00ab complete \u00bb -> fermerSmooth647 referme (sa garde one-shot vient\r\n        \/\/   d'etre levee) -> pb737 rouvre. Les deux ecrivains se relancent\r\n        \/\/   mutuellement, chacun faisant correctement son travail.\r\n        \/\/   La ligne d'origine suppose que TOUTE ouverture vient de\r\n        \/\/   l'utilisateur. Elle est vraie pour un clic, fausse pour une\r\n        \/\/   ouverture automatique survenant dans la foulee de la fermeture.\r\n        \/\/   DISCRIMINANT : le temps. Une reouverture MOINS d'une seconde apres\r\n        \/\/   l'auto-fermeture n'est pas un geste humain \u2014 c'est le rebond. On\r\n        \/\/   ne re-arme donc pas dans ce cas, la garde one-shot tient, et la\r\n        \/\/   boucle s'arrete a son premier tour : l'etape reste OUVERTE, comme\r\n        \/\/   pb737 le demande.\r\n        \/\/   Une reouverture plus tardive (l'utilisateur revient sur l'etape)\r\n        \/\/   re-arme comme avant : le comportement voulu par pb647 est intact.\r\n        \/\/   Seuil ajustable a chaud : window._viaPb2169Ms (defaut 1000).\r\n        \/\/   Revert : window._viaPb2169Off = true.\r\n        \/\/ ================================================================\r\n        if (ouvert && window._autoFerme647) {\r\n            var _seuil2169 = (typeof window._viaPb2169Ms === 'number') ? window._viaPb2169Ms : 1000;\r\n            var _at2169 = (window._viaFerme647At || {})[cle] || 0;\r\n            var _delta2169 = _at2169 ? (Date.now() - _at2169) : Infinity;\r\n            \/\/ ================================================================\r\n            \/\/ pb2174 : LE REFUS DE RE-ARMEMENT NE VAUT QUE POUR \u00ab recap \u00bb.\r\n            \/\/   Regression introduite par pb2169, constatee par JF : l'etape\r\n            \/\/   Dates renseignee ne se referme plus. Le log la nomme \u2014\r\n            \/\/   \u00ab fermerSmooth647(dates) SORT : _autoFerme647 deja pose \u00bb.\r\n            \/\/   Le refus de re-armement gelait la garde one-shot : une fois\r\n            \/\/   posee et jamais levee, elle interdit toute fermeture ULTERIEURE,\r\n            \/\/   y compris celle, legitime, qui suit la saisie des dates.\r\n            \/\/   La boucle que pb2169 devait casser oppose pb737 (qui force le\r\n            \/\/   recap ouvert) au sequenceur (qui veut le fermer) : elle est\r\n            \/\/   propre au RECAP. Les secteurs sont traites depuis par pb2170,\r\n            \/\/   qui agit sur l'ouvreur et non sur la garde.\r\n            \/\/   Le remede est donc rendu a son perimetre : recap seulement.\r\n            \/\/   Toutes les autres cles retrouvent le comportement d'origine \u2014\r\n            \/\/   re-armement systematique a l'ouverture.\r\n            \/\/   Revert du perimetre : window._viaPb2174Off = true (pb2169\r\n            \/\/   s'applique de nouveau a toutes les cles).\r\n            \/\/ ================================================================\r\n            var _concerne2174 = (window._viaPb2174Off === true) ? true : (cle === 'recap');\r\n            if (window._viaPb2169Off === true ? false\r\n                : (_concerne2174 ? (_delta2169 < _seuil2169) : false)) {\r\n                if (window._viaSig2169 !== cle) {\r\n                    window._viaSig2169 = cle;\r\n                    console.warn('[pb2169] ' + cle + ' : re-armement REFUSE (rebond, fermeture il y a '\r\n                        + Math.round(_delta2169) + 'ms < ' + _seuil2169 + 'ms) -> boucle interrompue');\r\n                }\r\n            } else {\r\n                window._autoFerme647[cle] = false;\r\n                window._viaSig2169 = null;\r\n            }\r\n        }\r\n        \/\/ pb644 : l'etat ferme\/ouvert change -> recalculer les sous-titres\r\n        this.majEtapes631();\r\n\r\n        \/\/ secteurs : rendu paresseux a l'ouverture si le conteneur est vide (ex pb618c)\r\n        if (cle === 'secteurs' && ouvert && $sec.length && $sec[0].children.length === 0) {\r\n            if (typeof window.viaRenderSecteurs615 === 'function') {\r\n                window.viaRenderSecteurs615($sec[0], (info) => this.onSecteurChoisi622(info));\r\n                setTimeout(() => this.scrollVersBas623($sec[0]), 120);\r\n            }\r\n        }\r\n    }\r\n\r\n    initAccordeons632() {\r\n        if (window._via632Init) { return; }\r\n        window._via632Init = true;\r\n\r\n        \/\/ chevron CSS (injecte une fois) : \u2227 ouvert, \u2228 ferme, couleur = currentColor\r\n        if (!document.getElementById('via632-style')) {\r\n            const st = document.createElement('style');\r\n            st.id = 'via632-style';\r\n            st.textContent = [\r\n                \/\/ pb632b : chevron A GAUCHE du titre. Le titre est un widget dont\r\n                \/\/ le contenu (span\/a) occupe toute la largeur : un ::after passait\r\n                \/\/ a la ligne. ::before absolu, ancre au bord gauche, centre en\r\n                \/\/ hauteur -> il reste sur la ligne du titre quel que soit le flux.\r\n                '.via632-titre{cursor:pointer;position:relative;padding-left:20px;}',\r\n                \/\/ meme translateY(-50%) dans les DEUX etats (le -30% du ferme le\r\n                \/\/ faisait descendre) ; la rotation pivote autour du centre, seule\r\n                \/\/ la pointe change de sens, la position ne bouge pas.\r\n                \/\/ ajustement optique : ouvert (pointe en haut) 3px plus bas,\r\n                \/\/ ferme (pointe en bas) 3px plus haut\r\n                '.via632-titre::before{content:\"\";position:absolute;left:6px;top:50%;width:7px;height:7px;',\r\n                '  border-right:2px solid currentColor;border-bottom:2px solid currentColor;',\r\n                '  transform-origin:center;transform:translateY(calc(-50% + 3px)) rotate(-135deg);transition:transform .15s;}',\r\n                '.via632-titre.via632-ferme::before{transform:translateY(calc(-50% - 1px)) rotate(45deg);}'\r\n            ].join('\\n');\r\n            document.head.appendChild(st);\r\n        }\r\n\r\n        const selecteursTitres = [];\r\n        this.config632().forEach((c) => {\r\n            const $ti = this._titre632(c);\r\n            if ($ti.length === 0) { console.warn('[pb632] titre introuvable:', c.titre); return; }\r\n            $ti.addClass('via632-titre');\r\n            selecteursTitres.push('#' + c.titre, '.' + c.titre);\r\n            window._via632 = window._via632 || {};\r\n            if (window._via632[c.cle] === undefined) { window._via632[c.cle] = true; }\r\n        });\r\n\r\n        if (selecteursTitres.length === 0) { return; }\r\n        $(document).on('click', selecteursTitres.join(', '), (e) => {\r\n            const el = e.currentTarget;\r\n            const c = this.config632().find(x => (el.id === x.titre) ? true : el.classList.contains(x.titre));\r\n            if (!c) { return; }\r\n            \/\/ pb742 : ce handler est DELEGUE sur document. Le clic sur \"Continuer la\r\n            \/\/   reservation\" remonte en bulle jusqu'ici et matche le titre qui le\r\n            \/\/   contient : pb740d venait de fermer Secteurs et Recap, ce handler les\r\n            \/\/   BASCULE donc aussitot -> reouverture. Diagnostic pb740c, pile\r\n            \/\/   'HTMLDivElement.<anonymous> <- dispatch <- v.handle' sur\r\n            \/\/   setSection632(recap, true) avec avant=false.\r\n            \/\/   Un clic sur un CONTROLE interne n'est pas un clic sur le titre : on\r\n            \/\/   l'ignore. Le bouton Continuer est le cas avere ; on couvre aussi les\r\n            \/\/   autres elements interactifs, pour lesquels le raisonnement est le meme.\r\n            \/\/   Revert : window._viaPb742Off = true.\r\n            if (window._viaPb742Off !== true) {\r\n                const _src742 = e.target;\r\n                \/\/ pb756 : 'a' et 'button' RETIRES du selecteur. Quand un titre repasse\r\n                \/\/   en rouge, son texte est enveloppe dans un <a> \u2014 le garde pb742 le\r\n                \/\/   prenait pour un controle interne et bloquait la bascule : seul le\r\n                \/\/   chevron, hors du lien, repondait encore.\r\n                \/\/   Le cas reel que pb742 devait traiter est le bouton \"Continuer\", vise\r\n                \/\/   nommement ci-dessous. Les champs de saisie restent exclus : cliquer\r\n                \/\/   dans une date ou dans l'autocomplete pays ne doit pas replier l'etape.\r\n                const _ctrl742 = (_src742 ? (_src742.closest ? _src742.closest(\r\n                    '#PopupTarifsBoutonContinuerResa, .PopupTarifsBoutonContinuerResa,'\r\n                    + ' #PopupTarifsBoutonContinuerResaTexte, .PopupTarifsBoutonContinuerResaTexte,'\r\n                    + ' input, select, textarea') : null) : null);\r\n                if (_ctrl742) {\r\n                    console.log('[pb742] clic sur un controle interne au titre ' + c.cle\r\n                        + ' -> bascule ignoree (' + (_ctrl742.id || _ctrl742.className || _ctrl742.tagName) + ')');\r\n                    return;\r\n                }\r\n            }\r\n            e.preventDefault();\r\n            e.stopPropagation();\r\n            const ouvert = (window._via632 ? window._via632[c.cle] : true) === true;\r\n            \/\/ pb707 : ouverture MANUELLE de l'etape Tarifs -> n'ouvrir .TarifsConteneur\r\n            \/\/   que si .GrilleTarifaire est reellement affichee. Sinon on bloque et on\r\n            \/\/   indique l'etape a renseigner. Le repli (ouvert -> ferme) reste libre.\r\n            if (c.cle === 'tarifs') {\r\n                console.log('[pb709] clic titre Tarifs | etat via632=' + ouvert\r\n                    + ' -> action=' + (ouvert ? 'REPLI' : 'OUVERTURE'));\r\n            }\r\n            \/\/ pb737 : ouverture MANUELLE du Recap -> autorisee seulement si le\r\n            \/\/   bouton Continuer est rouge. Sinon on affiche le message et on\r\n            \/\/   bascule quand meme l'etat d'ouverture du TITRE (chevron), pour que\r\n            \/\/   l'utilisateur voie une reaction ; seul le CONTENU reste masque.\r\n            if ((c.cle === 'recap') ? !ouvert : false) {\r\n                const _msg737 = this._prerequisRecap737();\r\n                if (_msg737) {\r\n                    this.setSection632(c.cle, true);\r\n                    this._afficherRecap737(false);\r\n                    this._messageRecap737(_msg737);\r\n                    console.log('[pb737] ouverture Recap BLOQUEE :', _msg737);\r\n                    return;\r\n                }\r\n            }\r\n            if ((c.cle === 'recap') ? ouvert : false) { this._messageRecap737(''); }\r\n            if ((c.cle === 'tarifs') ? !ouvert : false) {\r\n                const _msg707 = this._prerequisTarifs707();\r\n                if (_msg707) {\r\n                    this._messageTarifs707(_msg707);\r\n                    console.log('[pb707] ouverture Tarifs BLOQUEE :', _msg707);\r\n                    return;\r\n                }\r\n                console.log('[pb709] ouverture Tarifs AUTORISEE');\r\n            }\r\n            this._messageTarifs707('');\r\n            this.setSection632(c.cle, !ouvert);\r\n            \/\/ pb1036 : memoriser le choix MANUEL. Il prime sur le sequenceur\r\n            \/\/   jusqu'au prochain changement de completion (option B). Un repli\r\n            \/\/   manuel efface la memoire : plus aucune etape n'est imposee.\r\n            if (window._viaPb1036Off !== true) {\r\n                window._viaManuel1036 = ouvert ? null : c.cle;\r\n                window._viaCible1036 = window._viaManuel1036;\r\n            }\r\n            console.log('[pb632]', c.cle, ouvert ? 'replie' : 'deplie');\r\n        });\r\n    }\r\n\r\n    \/\/ pb633 : la grille des tarifs s'affiche -> replier les sections amont\r\n    \/\/   (annonceur + liste des pays), chevrons mis a jour par setSection632.\r\n    \/\/   Garde d'idempotence par affichage : le chemin unitaire remplit les 30\r\n    \/\/   cases en salve, on ne replie qu'une fois \u2014 et l'utilisateur peut ensuite\r\n    \/\/   rouvrir manuellement sans etre re-ferme par la case suivante.\r\n    replierEtapesAmont633() {\r\n        \/\/ pb1036 : sans objet desormais \u2014 le sequenceur ne laisse ouverte que\r\n        \/\/   l'etape courante, les etapes amont sont donc deja fermees.\r\n        if (window._viaPb1036Off !== true) { return; }\r\n        if (window._viaReplie633) { return; }\r\n        window._viaReplie633 = true;\r\n        this.setSection632('annonceur', false);\r\n        this.setSection632('pays', false);\r\n        console.log('[pb633] sections annonceur + pays repliees');\r\n    }\r\n\r\n    \/\/ pb618 (refondu pb632) : la logique metier (pb615) continue d'appeler\r\n    \/\/   etatSecteurs618 ; elle delegue simplement au moteur d'accordeons.\r\n    _elt618(nom) {\r\n        return $('#' + nom + ', .' + nom).first();\r\n    }\r\n\r\n    etatSecteurs618(ouvert) {\r\n        this.setSection632('secteurs', ouvert);\r\n    }\r\n\r\n    \/\/ le titre s'affiche avec la grille. Les icones Elementor Up\/Down ont ete\r\n    \/\/ supprimees : plus rien a basculer, le chevron CSS pb632 s'en charge.\r\n    \/\/ pb708 : PopupTarifsListeSecteursContainer est desormais masque par defaut cote\r\n    \/\/   Elementor. Il ne doit apparaitre que pour un tarif \"Autres P.\" (suffixe PP),\r\n    \/\/   seul cas ou un secteur a un sens : une position Home Page n'en a pas.\r\n    \/\/   Trois noms voisins coexistent, a ne pas confondre :\r\n    \/\/     - PopupTarifsListeSecteursContainer      -> CE bloc (pb708)\r\n    \/\/     - PopupTarifsListeSecteursTitreContaineur -> afficherTitreSecteurs618, affiche\r\n    \/\/       a chaque rendu de grille, sans condition de type de tarif\r\n    \/\/     - PopupTarifsListeSecteurs               -> l'hote de la liste (pb615)\r\n    \/\/   Comme pour .GrilleTarifaire (pb703), on retire les classes elementor-hidden-*\r\n    \/\/   avant de poser display : un .show() jQuery perdrait contre leur !important.\r\n    _titreSecteursTexte708(visible) {\r\n        const $t = this._elt618('PopupTarifsListeSecteursContainer');\r\n        if ($t.length === 0) { console.warn('[pb708] PopupTarifsListeSecteursContainer introuvable'); return; }\r\n        const el = $t[0];\r\n        if (visible) {\r\n            el.classList.remove('elementor-hidden-desktop');\r\n            el.classList.remove('elementor-hidden-tablet');\r\n            el.classList.remove('elementor-hidden-mobile');\r\n            el.style.setProperty('display', 'block', 'important');\r\n        } else {\r\n            el.style.setProperty('display', 'none', 'important');\r\n        }\r\n        console.log('[pb708] PopupTarifsListeSecteursContainer -> ' + (visible ? 'AFFICHE' : 'masque'));\r\n    }\r\n\r\n    afficherTitreSecteurs618() {\r\n        const $titre = this._elt618('PopupTarifsListeSecteursTitreContaineur');\r\n        if ($titre.length) {\r\n            $titre[0].style.setProperty('display', 'flex', 'important');\r\n        }\r\n    }\r\n\r\n    \/\/ pb615 : liste des secteurs dans PopupTarifsListeSecteurs \u2014 affichee quand\r\n    \/\/   un tarif est selectionne. Meme API cote yearbook-media.js.\r\n    \/\/ ========================================================================\r\n    \/\/ pb1058 : INVALIDER la page selectionnee et inviter a en choisir une autre.\r\n    \/\/   Quatre effets, demandes ensemble : effacer la page, fermer le VLP qui\r\n    \/\/   l'affiche, rouvrir l'etape Secteurs, afficher le message.\r\n    \/\/   Le VLP est ferme parce qu'il montre une page qui n'est plus retenue :\r\n    \/\/   le laisser ouvert donnerait a croire qu'elle l'est encore.\r\n    \/\/   La fermeture passe par le PARENT (postMessage) : le popup Tarifs vit dans\r\n    \/\/   le document regie, le VLP est gere la-bas \u2014 on ne manipule pas son DOM\r\n    \/\/   d'ici.\r\n    \/\/ ========================================================================\r\n    _invaliderPage1058(message) {\r\n        try {\r\n            \/\/ ================================================================\r\n            \/\/ pb1251 : LIBERER LE CHOIX MANUEL avant de rouvrir les secteurs.\r\n            \/\/   Constat user : au clic sur un tarif \"Autres Pages\", l'etape Secteurs\r\n            \/\/   reste fermee. Le log le dit :\r\n            \/\/     [pb1036] completions 111100 -> etape ouverte : tarifs [choix manuel]\r\n            \/\/     [pb647] etape auto-fermee (smooth): secteur\r\n            \/\/   Le clic sur la grille a pose _viaManuel1036 = 'tarifs' (option B), et\r\n            \/\/   ce choix prime sur le calcul automatique : le sequenceur maintient\r\n            \/\/   Tarifs ouverte et referme Secteurs aussitot apres notre reouverture.\r\n            \/\/   Le choix manuel exprime une intention de l'utilisateur ; ici, une\r\n            \/\/   autre intention plus recente lui succede \u2014 il choisit un tarif qui\r\n            \/\/   invalide sa page. On efface donc le drapeau, comme le fait deja le\r\n            \/\/   sequenceur a chaque changement de completion.\r\n            \/\/   Revert : window._viaPb1251Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1251Off !== true) {\r\n                \/\/ pb1251b : effacer le choix manuel NE SUFFIT PAS.\r\n                \/\/   Constat user : le log affiche toujours \"[choix manuel]\" apres\r\n                \/\/   pb1251. Le handler du clic sur la grille repose\r\n                \/\/   _viaManuel1036 = 'tarifs' APRES notre effacement \u2014 l'ordre des\r\n                \/\/   deux ecritures n'est pas garanti, et nous perdons la course.\r\n                \/\/   On pose donc une demande EXPLICITE d'ouverture des secteurs, que\r\n                \/\/   le sequenceur consomme au passage suivant : elle prime sur le\r\n                \/\/   choix manuel, quel que soit l'ordre d'ecriture. Une intention\r\n                \/\/   plus recente l'emporte sur une plus ancienne.\r\n                window._viaManuel1036 = null;\r\n                window._viaForceSecteurs1251 = true;\r\n                console.log('[pb1251] page invalid\u00e9e -> ouverture des Secteurs demand\u00e9e');\r\n            }\r\n            \/\/ 1. oublier la page, cote popup et cote cles globales\r\n            this._sync635 = this._sync635 || {};\r\n            this._sync635.secteur = null;\r\n            this._sync635.article = null;\r\n            ['SelectedPageSecteur', 'SelectedPageSecteurDisplayed', 'SelectedPageType',\r\n             'LinkSecteurPage', 'LinkSecteurPageDisplayed', 'Commande_Article']\r\n                .forEach(function (_k) { try { sessionStorage.removeItem(_k); } catch (_e) {} });\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1061b : invalider aussi la PAGE SUR L'ITEM.\r\n            \/\/   Le log montre le recap toujours sur \"Homepage\" apres le choix\r\n            \/\/   d'Elevage, et 'SelectedPageType1 = HPType' alors que\r\n            \/\/   'commandePage1 = Page sectorielle' : incoherent.\r\n            \/\/   Cause : je n'effacais que les cles GLOBALES. Or le recap\r\n            \/\/   (_majRecap793) et syncItemToSessionStorage lisent d'abord les\r\n            \/\/   champs de l'ITEM \u2014 item.selectedPageType, selectedPageSecteur...\r\n            \/\/   Restes a 'HPType'\/'Homepage', ils reimposaient l'ancienne page\r\n            \/\/   aux cles indexees, quel que soit le secteur choisi ensuite.\r\n            \/\/   On efface donc les deux, l'item etant la source qui prime.\r\n            \/\/ ================================================================\r\n            try {\r\n                var _pa1061 = window.VIA_Panier;\r\n                var _st1061 = _pa1061 ? _pa1061.state : null;\r\n                var _id1061 = _st1061 ? _st1061.itemActif : null;\r\n                if (_id1061) {\r\n                    var _it1061 = (_st1061.items || []).find(function (_x) { return _x.id === _id1061; });\r\n                    if (_it1061) {\r\n                        _it1061.selectedPageType = null;\r\n                        _it1061.selectedPageSecteur = null;\r\n                        _it1061.selectedPageSecteurDisplayed = null;\r\n                        _it1061.commandePage = null;\r\n                        _it1061.linkSecteurPage = null;\r\n                        _it1061.articleTitre = null;\r\n                        if (_it1061.donneesIframe) { _it1061.donneesIframe.LoadedPageUrl = null; }\r\n                        console.log('[pb1061b] page invalid\u00e9e aussi sur l item ' + _id1061);\r\n                    }\r\n                }\r\n            } catch (_e1061) { console.warn('[pb1061b]', _e1061.message); }\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1063 : NE PLUS FERMER LE VLP (constat user a l'usage).\r\n            \/\/   La fermeture faisait partie de la demande initiale, au motif que\r\n            \/\/   le VLP montrait une page qui n'etait plus retenue. A l'essai, le\r\n            \/\/   comportement est MEILLEUR sans : la page reste visible pendant que\r\n            \/\/   l'utilisateur choisit la nouvelle, ce qui lui garde un repere et\r\n            \/\/   evite un ecran vide au milieu du parcours.\r\n            \/\/   Le VLP sera de toute facon remplace des qu'une page sera choisie\r\n            \/\/   (pb744 s'en charge, dans le perimetre de la resa depuis pb1013) :\r\n            \/\/   il n'y a donc rien a nettoyer ici.\r\n            \/\/   La regle 3, elle, continue de fermer avant d'ouvrir la homepage \u2014\r\n            \/\/   la, c'est necessaire, sans quoi l'invariant pb827 verrait deux VLP\r\n            \/\/   pour la meme resa (cf pb1062).\r\n            \/\/   Revert : window._viaPb1063Off = true (retablit la fermeture).\r\n            \/\/ ================================================================\r\n            if (window._viaPb1063Off === true) {\r\n                try {\r\n                    if (window.parent !== window) {\r\n                        window.parent.postMessage({ type: 'viaFermerVlpPageInvalide1058' }, '*');\r\n                    } else if (typeof window._viaFermerVlpCourant1058 === 'function') {\r\n                        window._viaFermerVlpCourant1058();\r\n                    }\r\n                } catch (_eV) {}\r\n            }\r\n\r\n            \/\/ 3. rouvrir l'etape Secteurs pour que le choix soit possible\r\n            this.setSection632('secteurs', true);\r\n            this._titreSecteursTexte708(true);\r\n            this.rendreListeSecteurs615();\r\n\r\n            \/\/ 4. message d'invitation sous le titre Secteurs\r\n            this._messageSecteurs1058(message);\r\n        } catch (_e) { console.warn('[pb1058] invalider:', _e.message); }\r\n    }\r\n\r\n    \/\/ ========================================================================\r\n    \/\/ pb1058b : MESSAGE d'invitation sous le titre SECTEURS.\r\n    \/\/   Calque sur _messageTarifs707, qui fait la meme chose sous le titre\r\n    \/\/   Tarifs : meme insertion (apres le titre), meme classe dediee pour ne pas\r\n    \/\/   entrer en conflit avec le sous-titre vert .v644-sub de pb644, memes\r\n    \/\/   forcages de centrage (le parent est un flex Elementor, ou text-align\r\n    \/\/   seul ne suffit pas \u2014 cf le commentaire de pb707).\r\n    \/\/   Texte vide = retrait, comme pb707.\r\n    \/\/ ========================================================================\r\n    _messageSecteurs1058(texte) {\r\n        const _c = this.config632().find(x => x.cle === 'secteurs');\r\n        if (!_c) { return; }\r\n        const $ti = this._titre632(_c);\r\n        if ($ti.length === 0) { return; }\r\n        $ti.nextAll('.v1058-msg').remove();\r\n        if (!texte) { return; }\r\n        const $m = $('<div class=\"v1058-msg\"><\/div>');\r\n        $m.text(texte);\r\n        $m[0].style.setProperty('color', '#fb5e2a', 'important');\r\n        $m[0].style.setProperty('font-size', '11px', 'important');\r\n        $m[0].style.setProperty('font-weight', '600', 'important');\r\n        $m[0].style.setProperty('line-height', '1.2', 'important');\r\n        $m[0].style.setProperty('margin-top', '2px', 'important');\r\n        $m[0].style.setProperty('text-align', 'center', 'important');\r\n        $m[0].style.setProperty('width', '100%', 'important');\r\n        $m[0].style.setProperty('margin-left', 'auto', 'important');\r\n        $m[0].style.setProperty('margin-right', 'auto', 'important');\r\n        $m[0].style.setProperty('align-self', 'center', 'important');\r\n        $ti.after($m);\r\n        console.log('[pb1058b] message secteurs -> \"' + texte + '\"');\r\n    }\r\n\r\n    \/\/ pb1058 : selectionner d'office la HOMEPAGE du pays (regle 3).\r\n    \/\/   Unique par pays, donc deductible sans demander a l'utilisateur. On pose\r\n    \/\/   les cles que lisent les autres mecanismes, puis on demande au parent\r\n    \/\/   d'ouvrir la page \u2014 c'est lui qui detient le VLP et l'URL du site.\r\n    _selectionnerHomepage1058() {\r\n        try {\r\n            this._sync635 = this._sync635 || {};\r\n            this._sync635.secteur = 'Homepage';\r\n            this._messageSecteurs1058('');   \/\/ pb1058b : une page est choisie -> message retire\r\n            try {\r\n                sessionStorage.setItem('SelectedPageType', 'HPType');\r\n                sessionStorage.setItem('SelectedPageSecteur', 'Homepage');\r\n                sessionStorage.setItem('SelectedPageSecteurDisplayed', 'Homepage');\r\n                sessionStorage.removeItem('Commande_Article');\r\n            } catch (_eK) {}\r\n            if (window.parent !== window) {\r\n                window.parent.postMessage({ type: 'viaOuvrirHomepagePays1058' }, '*');\r\n            } else if (typeof window._viaOuvrirHomepagePays1058 === 'function') {\r\n                window._viaOuvrirHomepagePays1058();\r\n            }\r\n            \/\/ le tarif se recalcule par la chaine habituelle (onFormulaireChange)\r\n            if (typeof this.calculerEtAfficherGrille === 'function') {\r\n                this.calculerEtAfficherGrille();\r\n            }\r\n        } catch (_e) { console.warn('[pb1058] homepage:', _e.message); }\r\n    }\r\n\r\n    rendreListeSecteurs615() {\r\n        \/\/ pb1910 : discriminant partage, et sortie journalisee (etait un return muet).\r\n        if (!window._viaContexteRegie1910('rendreListeSecteurs615')) { return; }\r\n        if (typeof window.viaRenderSecteurs615 !== 'function') {\r\n            console.warn('[pb615] viaRenderSecteurs615 absente (yearbook-media.js pas a jour ?)');\r\n            return;\r\n        }\r\n        const $host = $('#PopupTarifsListeSecteurs, .PopupTarifsListeSecteurs').first();\r\n        if ($host.length === 0) {\r\n            console.warn('[pb615] conteneur PopupTarifsListeSecteurs introuvable');\r\n            return;\r\n        }\r\n        window.viaRenderSecteurs615($host[0], (info) => this.onSecteurChoisi622(info));\r\n        \/\/ pb740 : apres le Continuer, la liste est rendue mais l'etape reste FERMEE\r\n        \/\/   (et pas de scroll vers elle : il ramenait l'utilisateur en arriere).\r\n        if (this._verrouApresContinuer740()) {\r\n            console.log('[pb740] secteurs : reouverture auto bloquee (Continuer deja clique)');\r\n            return;\r\n        }\r\n        \/\/ ================================================================\r\n        \/\/ pb2170 : UNE ETAPE DEJA RENSEIGNEE NE SE ROUVRE PAS.\r\n        \/\/   Constat JF : en choisissant un TARIF, l'etape \u00ab secteurs \u00bb (deja\r\n        \/\/   completee) se rouvre. Pile du log, sans ambiguite :\r\n        \/\/     _selectionnerTarif651 -> rendreListeSecteurs615 -> etatSecteurs618\r\n        \/\/     -> setSection632('secteurs', true)  [pb708] ... -> AFFICHE\r\n        \/\/   Ce rendu est legitime (la liste doit exister et refleter le\r\n        \/\/   secteur), mais l'OUVERTURE qui le suit ne l'est que lorsque\r\n        \/\/   l'utilisateur a encore quelque chose a y choisir.\r\n        \/\/   pb740 couvrait deja le cas \u00ab apres le Continuer \u00bb ; il ne couvre pas\r\n        \/\/   celui-ci, ou le Continuer n'a pas encore ete clique\r\n        \/\/   (resaTransmise=false dans le meme releve).\r\n        \/\/   DISCRIMINANT : secteurRenseigne1337(), le test de reference du\r\n        \/\/   fichier pour \u00ab le secteur est connu \u00bb \u2014 le meme que lisent le\r\n        \/\/   sous-titre vert et le sequenceur. Aucune notion nouvelle.\r\n        \/\/   Le scroll part avec l'ouverture : ramener l'utilisateur sur une\r\n        \/\/   etape qu'il n'a pas demandee est le meme defaut.\r\n        \/\/   Revert : window._viaPb2170Off = true.\r\n        \/\/ ================================================================\r\n        if (window._viaPb2170Off === true ? false : this.secteurRenseigne1337()) {\r\n            console.log('[pb2170] secteurs : deja renseigne -> liste rendue, etape LAISSEE FERMEE');\r\n            return;\r\n        }\r\n        setTimeout(() => this.scrollVersBas623($host[0]), 120);   \/\/ pb623\r\n        this.etatSecteurs618(true);   \/\/ pb618 : liste ouverte -> icone Up\r\n    }\r\n\r\n    \/\/ pb615 : masquer\/vider la liste des secteurs (tarif Home Page selectionne)\r\n    masquerListeSecteurs615() {\r\n        this.etatSecteurs618(false);   \/\/ pb618 : liste fermee -> icone Down\r\n    }\r\n\r\n        \/\/ pb612 : rendre les tarifs cliquables \u2014 SITE REGIE UNIQUEMENT.\r\n    \/\/   Critere : pas dans une iframe (les sites pays chargent ce template dans\r\n    \/\/   le popup VLP en iframe ; la regie l'affiche dans le document principal).\r\n    \/\/   Cible provisoire '#' \u2014 la destination reelle sera branchee ensuite.\r\n    lierTarifs612() {\r\n        \/\/ pb1910 : discriminant partage, et sortie journalisee (etait un return muet).\r\n        if (!window._viaContexteRegie1910('lierTarifs612')) { return; }\r\n\r\n        $('.PricingAmount').each(function() {\r\n            const $cell = $(this);\r\n            if ($cell.find('a.via-tarif-lien-612').length) {\r\n                return;   \/\/ deja lie (changement de devise, recalcul...)\r\n            }\r\n            const contenu = $cell.html();\r\n            $cell.html(\r\n                '<a href=\"#\" class=\"via-tarif-lien-612\" ' +\r\n                \/* pb2151 : plus de soulignage (demande JF). Corrige a la SOURCE ;\r\n                   le curseur main reste, le tarif demeure cliquable. *\/\r\n                'style=\"color: inherit; text-decoration: none; cursor: pointer;\">' +\r\n                contenu + '<\/a>'\r\n            );\r\n        });\r\n        console.log('[pb612] liens poses sur', $('.PricingAmount a.via-tarif-lien-612').length, 'tarifs');\r\n    }\r\n\r\n    \/\/ pb623 : scroll vers le bas du popup, pour un element QUELCONQUE (grille,\r\n    \/\/   liste des secteurs, liste des articles). Remonte les ancetres reellement\r\n    \/\/   scrollables puis complete par la page hote.\r\n    scrollVersBas623(el) {\r\n        if (!el) { return; }\r\n        let p = el.parentElement;\r\n        let n = 0;\r\n        while (p && p !== document.body && n < 15) {\r\n            if (p.scrollHeight > p.clientHeight + 2) {\r\n                const cs = getComputedStyle(p);\r\n                if (cs.overflowY === 'auto' || cs.overflowY === 'scroll') {\r\n                    \/\/ ================================================\r\n                    \/\/ pb1267 : NE PAS FAIRE DEFILER LE POPUP DE PROCESS.\r\n                    \/\/   Constat user : en achat express, l'affichage se\r\n                    \/\/   termine par un scroll vers le bas du popup.\r\n                    \/\/   Cause : depuis pb1264, le catalogue tarifaire vit\r\n                    \/\/   dans .via-col-popup-body, qui est scrollable. Cette\r\n                    \/\/   fonction remonte TOUS les ancetres scrollables et les\r\n                    \/\/   defile \u2014 elle atteint donc maintenant un conteneur\r\n                    \/\/   qui ne lui appartient pas.\r\n                    \/\/   Elle a ete ecrite pour amener la grille en vue DANS\r\n                    \/\/   le popup Tarifs ; le popup de process n'a jamais fait\r\n                    \/\/   partie de son perimetre. On l'exclut, sans toucher a\r\n                    \/\/   son comportement partout ailleurs.\r\n                    \/\/   Revert : window._viaPb1267Off = true.\r\n                    \/\/ ================================================\r\n                    var _exclu1267 = false;\r\n                    if (window._viaPb1267Off !== true) {\r\n                        try {\r\n                            _exclu1267 = p.classList\r\n                                ? p.classList.contains('via-col-popup-body') : false;\r\n                        } catch (_e1267) { _exclu1267 = false; }\r\n                    }\r\n                    \/\/ ================================================\r\n                    \/\/ pb1314 : PLUS AUCUN SCROLL VERS LE BAS HORS DU POPUP.\r\n                    \/\/   Constat user : des scrolls incessants vers le bas pendant\r\n                    \/\/   la selection. pb1267 n'excluait que .via-col-popup-body,\r\n                    \/\/   le conteneur du popup droit sur desktop. Sur mobile le\r\n                    \/\/   catalogue vit dans le flux de la page : l'ancetre\r\n                    \/\/   scrollable est le document lui-meme, et cette fonction le\r\n                    \/\/   fait defiler a chaque recalcul.\r\n                    \/\/   Cette routine a ete ecrite pour amener la grille en vue\r\n                    \/\/   DANS le popup Tarifs. Des que le catalogue en est sorti,\r\n                    \/\/   elle n'a plus de perimetre \u2014 quel que soit l'ancetre.\r\n                    \/\/   Revert : window._viaPb1314Off = true.\r\n                    \/\/ ================================================\r\n                    if (window._viaPb1314Off !== true) {\r\n                        if (window._viaCatalogueDeplace1264 === true) { _exclu1267 = true; }\r\n                    }\r\n                    if (_exclu1267) {\r\n                        if (window._viaSig1267 !== 'exclu') {\r\n                            window._viaSig1267 = 'exclu';\r\n                            console.log('[pb1267] popup de process exclu du scroll vers le bas');\r\n                        }\r\n                    } else {\r\n                        try { p.scrollTo({ top: p.scrollHeight, behavior: 'smooth' }); }\r\n                        catch (e) { p.scrollTop = p.scrollHeight; }\r\n                    }\r\n                }\r\n            }\r\n            p = p.parentElement;\r\n            n++;\r\n        }\r\n        const doc = document.scrollingElement || document.documentElement;\r\n        const max = Math.max(0, doc.scrollHeight - window.innerHeight);\r\n        if (max > 0) {\r\n            try { window.scrollTo({ top: max, behavior: 'smooth' }); }\r\n            catch (e) { window.scrollTo(0, max); }\r\n        }\r\n    }\r\n\r\n    scrollVersBasGrille() {\r\n        \/\/ pb706 : cible alignee sur l'element reellement affiche (.GrilleTarifaire).\r\n        \/\/   Repli sur #TarifsPublicitaireListe si la classe est absente de la page.\r\n        const _cible706 = $('.GrilleTarifaire')[0] || $('#TarifsPublicitaireListe')[0];\r\n        this.scrollVersBas623(_cible706);\r\n    }\r\n\r\n    afficherGrille() {\r\n        \/\/ pb706 : affichage transfere vers .GrilleTarifaire.\r\n        \/\/   Etait : $('#TarifsPublicitaireListe').fadeIn(300, () => this.scrollVersBasGrille());\r\n        this._afficherGrilleTarifaire703(true, true, () => this.scrollVersBasGrille());\r\n    }\r\n    \r\n    \/\/ ================================================================\r\n    \/\/ pb768 : SYNCHRONISATION de la devise entre le popup Tarifs (achat express)\r\n    \/\/   et le process d'achat, dans les deux sens \u2014 et SURVEILLANCE du retour a EUR.\r\n    \/\/   Le popup tient sa devise dans state.deviseAffichage ; le process dans le\r\n    \/\/   select #form-field-selected_currency_visuels et la cle sessionStorage\r\n    \/\/   selected_currency_visuels. Les deux s'ignoraient completement.\r\n    \/\/   Le retour a EUR vient d'un ecrivain que je n'ai pas pu localiser : le\r\n    \/\/   handler du select est dans le script INLINE de la page WordPress, dont je\r\n    \/\/   ne dispose pas. La surveillance ci-dessous date la bascule au lieu de la\r\n    \/\/   deviner, et la corrige.\r\n    \/\/   Reverts : window._viaPb768Off = true (tout), _viaPb768NoWatch = true (veille).\r\n    \/\/ ================================================================\r\n    _deviseProcess768() {\r\n        const $s768 = $('#form-field-selected_currency_visuels, select[name=\"form_fields[selected_currency_visuels]\"]');\r\n        if (!$s768.length) { return null; }\r\n        return { $el: $s768, val: ($s768.val() || '').trim() };\r\n    }\r\n\r\n    \/\/   popup -> process\r\n    _pousserDevise768(_dev768) {\r\n        if (window._viaPb768Off === true) { return; }\r\n        if (!_dev768) { return; }\r\n        try {\r\n            sessionStorage.setItem('selected_currency_visuels', _dev768);\r\n            const _p768 = this._deviseProcess768();\r\n            if (!_p768) { console.log('[pb768] select devise du process introuvable'); return; }\r\n            if (_p768.val === _dev768) { return; }\r\n            _p768.$el.val(_dev768).trigger('change');\r\n            console.log('[pb768] devise poussee popup -> process : ' + _p768.val + ' -> ' + _dev768);\r\n            this._veillerDevise768(_dev768, 'popup');\r\n        } catch (_e768) { console.warn('[pb768]', _e768.message); }\r\n    }\r\n\r\n    \/\/   process -> popup\r\n    _tirerDevise768(_dev768, _origine768) {\r\n        if (window._viaPb768Off === true) { return; }\r\n        if (!_dev768) { return; }\r\n        if (this.state.deviseAffichage === _dev768) { return; }\r\n        console.log('[pb768] devise tiree process -> popup (' + _origine768 + ') : '\r\n            + this.state.deviseAffichage + ' -> ' + _dev768);\r\n        this.state.deviseAffichage = _dev768;\r\n        this.marquerDeviseActive613();   \/\/ pb613b : nom reel de la methode\r\n        this.convertirEtAfficherGrille();\r\n    }\r\n\r\n    \/\/   pb769 : SUIVI, et non plus restauration. Le log a etabli que le retour a EUR\r\n    \/\/   n'est pas un defaut mais une REGLE METIER :\r\n    \/\/     \"Client soumis a TVA : paiement obligatoire en EUR\"\r\n    \/\/     \"Devise globale forcee: USD -> EUR\"\r\n    \/\/   (zoneTVA=FR, clientAssujettiTVA=Yes). La veille de pb768 restaurait USD et\r\n    \/\/   combattait donc une contrainte fiscale \u2014 elle aurait pu laisser un client\r\n    \/\/   assujetti payer dans une devise interdite.\r\n    \/\/   Le process est l'AUTORITE sur la devise ; le popup le SUIT. Si la devise a\r\n    \/\/   change entre-temps, on aligne le popup au lieu de forcer le process.\r\n    _veillerDevise768(_attendue768, _origine768) {\r\n        if (window._viaPb768Off === true) { return; }\r\n        if (window._viaPb768NoWatch === true) { return; }\r\n        const _t0768 = Date.now();\r\n        [120, 400, 900, 1800, 3000].forEach((_d768) => {\r\n            setTimeout(() => {\r\n                try {\r\n                    const _p = this._deviseProcess768();\r\n                    if (!_p) { return; }\r\n                    const _cour = _p.val;\r\n                    if (_cour === this.state.deviseAffichage) { return; }   \/\/ deja aligne\r\n                    console.log('[pb769] devise du process = \"' + _cour + '\" (le popup'\r\n                        + ' affichait \"' + this.state.deviseAffichage + '\", origine '\r\n                        + _origine768 + ', T+' + (Date.now() - _t0768) + 'ms)'\r\n                        + ' \u2014 le popup suit');\r\n                    this._tirerDevise768(_cour, 'alignement pb769');\r\n                } catch (_eV768) { console.warn('[pb769]', _eV768.message); }\r\n            }, _d768);\r\n        });\r\n    }\r\n\r\n    \/\/   ecoute du select du process (le handler d'origine, inline, reste en place)\r\n    _ecouterDeviseProcess768() {\r\n        if (window._viaPb768Off === true) { return; }\r\n        if (window._viaEcouteDevise768) { return; }   \/\/ une seule fois\r\n        window._viaEcouteDevise768 = true;\r\n        $(document).on('change', '#form-field-selected_currency_visuels, select[name=\"form_fields[selected_currency_visuels]\"]',\r\n            (e768) => {\r\n                const _v768 = ($(e768.currentTarget).val() || '').trim();\r\n                this._tirerDevise768(_v768, 'change select');\r\n                this._veillerDevise768(_v768, 'process');\r\n            });\r\n        console.log('[pb768] ecoute du select devise du process armee');\r\n    }\r\n\r\n    setupDeviseListener() {\r\n        this._ecouterDeviseProcess768();   \/\/ pb768\r\n        $('.CatalogueDevises a').on('click', (e) => {\r\n            e.preventDefault();\r\n            \r\n            const nouvelleDevise = $(e.currentTarget).text().trim();\r\n            const ancienneDevise = this.state.deviseAffichage;\r\n            \r\n            if (nouvelleDevise === ancienneDevise) return;\r\n            \r\n            console.log('\ud83d\udcb1 Changement devise:', ancienneDevise, '\u2192', nouvelleDevise);\r\n            \r\n            this.state.deviseAffichage = nouvelleDevise;\r\n            this.convertirEtAfficherGrille();\r\n            this._pousserDevise768(nouvelleDevise);   \/\/ pb768\r\n        });\r\n    }\r\n    \r\n    \/\/ pb2159 : argument _montantsSeuls \u2014 convertir SANS reposer les liens ni le\r\n    \/\/   marquage de devise. Voir pb2157\/pb2159 au point d'appel : ces deux gestes\r\n    \/\/   habillent les cellules et doivent rester APRES le filtrage (pb1396 :\r\n    \/\/   l'ordre filtrer -> masquer termes -> libelles est critique).\r\n    \/\/   Sans argument, comportement d'origine strictement inchange.\r\n    convertirEtAfficherGrille(_montantsSeuls) {\r\n        const devise = this.state.deviseAffichage;\r\n        for (const [classe, tarifEUR] of Object.entries(this.state.tarifsCalcules)) {\r\n            const $element = $(`.${classe}`);\r\n            \r\n            if ($element.length && tarifEUR !== null) {\r\n                const montantConverti = window.VIA_App.convertirDevise(tarifEUR, 'EUR', devise);\r\n                $element.text(this.formaterSansDevise613(montantConverti));\r\n            }\r\n        }\r\n        \r\n        console.log('\u2705 Grille convertie en', devise);\r\n        if (_montantsSeuls === true) { return; }   \/\/ pb2159\r\n        this.lierTarifs612();   \/\/ pb612 : reposer les liens si .text() les a ecrases\r\n        this.marquerDeviseActive613();\r\n    }\r\n}\r\n\r\n\/\/ Initialisation\/\/ Compatible avec chargement AJAX et DOMContentLoaded\r\n    \/\/ pb610 : bornes de duree parametrables (Espace Via Agency), via le proxy\r\n    \/\/   via_parametres_proxy. Cascade : knob -> valeur chargee -> defaut en dur.\r\n    window.VIA_ChargeParams610 = function() {\r\n        if (window._viaParams610 || window._viaParams610Pending) { return; }\r\n        window._viaParams610Pending = true;\r\n        const u = new URLSearchParams();\r\n        u.append('action', 'via_parametres_proxy');\r\n        fetch('https:\/\/yearbook-media.com\/wp-admin\/admin-ajax.php', {\r\n            method: 'POST', credentials: 'omit',\r\n            headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n            body: u.toString()\r\n        }).then(r => r.json()).then(d => {\r\n            window._viaParams610Pending = false;\r\n            if (d && d.success) {\r\n                window._viaParams610 = { min: parseInt(d.duree_min, 10), max: parseInt(d.duree_max, 10) };\r\n                console.log('[pb610] bornes duree chargees:', window._viaParams610.min, '-', window._viaParams610.max, d.fallback ? '(fallback)' : '');\r\n            }\r\n        }).catch(e => {\r\n            window._viaParams610Pending = false;\r\n            console.warn('[pb610] bornes duree non chargees:', e.message);\r\n        });\r\n    };\r\n    window.VIA_ChargeParams610();\r\n\r\n    function initGrilleModules() {\r\n    if (window.grilleModulesInitialized) return;\r\n    window.grilleModulesInitialized = true;\r\n    \r\n    window.countryAutocomplete = new CountryAutocomplete();\r\n    window.campaignDatePickers = new CampaignDatePickers();\r\n    \r\n    const checkVIAApp = setInterval(() => {\r\n        if (typeof window.VIA_App !== 'undefined') {\r\n            clearInterval(checkVIAApp);\r\n            window.VIA_GrilleTarifaire = new GrilleTarifaire();\r\n            \/\/ pb646 : helpers spinner accessibles depuis yearbook-media.js\r\n            window.viaSpinnerCss646 = function() { GrilleTarifaire._spinnerCss646Static(); };\r\n            window.viaHtmlAttente646 = function() { return GrilleTarifaire.htmlAttente646(); };\r\n\r\n            \/\/ pb651 : Direction A \u2014 hook appele par Panier_manager.setItemActif.\r\n            \/\/   Ne synchronise que si le popup Tarifs est OUVERT.\r\n            window.viaSyncVersPopupTarifs651 = function(item) {\r\n                const p3 = document.getElementById('popup3');\r\n                const ouvert = p3 ? p3.classList.contains('active') : false;\r\n                if (!ouvert) { return; }\r\n                if (window.VIA_GrilleTarifaire) { window.VIA_GrilleTarifaire.syncDepuisResa651(item); }\r\n            };\r\n\r\n            \/\/ pb651 : Direction A declencheur 2 \u2014 a l'OUVERTURE du popup Tarifs,\r\n            \/\/   si une resa est active, la refleter. Observer classe 'active' sur\r\n            \/\/   #popup3 (plus robuste que patcher openPopup).\r\n            \/\/ ============================================================\r\n            \/\/ pb691 : dans le popup Tarifs, le lien \"CGV\" de la phrase\r\n            \/\/   \"Voir le detail des tarifs et des conditions dans les CGV\"\r\n            \/\/   ouvre le popup CGV, comme un clic sur #TitrePopUpDoc4.\r\n            \/\/   Delegation sur document en capture : le lien est rendu par un\r\n            \/\/   template Elementor a l'interieur de #popup3, donc absent du DOM\r\n            \/\/   quand ce script s'execute -> un bind direct raterait.\r\n            \/\/   EXCLUSION de #VoirCGV : yearbook-media.js (setupPopupDocuments)\r\n            \/\/   lui attache DEJA un handler appelant togglePopup('popup4').\r\n            \/\/   Le traiter ici aussi ferait DEUX bascules = ouverture puis\r\n            \/\/   fermeture immediate.\r\n            \/\/ ============================================================\r\n            (function _brancherCGV691() {\r\n                if (window._viaCGV691) { return; }\r\n                window._viaCGV691 = true;\r\n                document.addEventListener('click', function(e) {\r\n                    const a = e.target.closest ? e.target.closest('#popup3 a') : null;\r\n                    if (!a) { return; }\r\n                    if (a.id === 'VoirCGV') { return; }   \/\/ deja gere ailleurs, ne pas doubler\r\n                    const txt = (a.textContent || '').replace(\/\\s+\/g, ' ').trim().toUpperCase();\r\n                    if (txt !== 'CGV') { return; }\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    if (typeof window.togglePopup === 'function') {\r\n                        window.togglePopup('popup4');\r\n                        console.log('[pb691] lien CGV -> popup4 (togglePopup)');\r\n                    } else if (typeof window.openPopup === 'function') {\r\n                        window.openPopup('popup4');\r\n                        console.log('[pb691] lien CGV -> popup4 (openPopup, repli)');\r\n                    } else {\r\n                        console.warn('[pb691] ni togglePopup ni openPopup disponibles');\r\n                        return;\r\n                    }\r\n\r\n                    \/\/ pb692 : ORDRE des trois popups au clic sur CGV.\r\n                    \/\/   Mesure : popup4=10019 | ColonneGauche=10015 | popup3=9999\r\n                    \/\/   -> ordre obtenu CGV \/ ColonneGauche \/ Tarifs.\r\n                    \/\/   Cause : focusPopup remet TOUS les .popup-container a 9999 avant\r\n                    \/\/   de remonter le seul popup cible. popup3 (Tarifs) retombe donc\r\n                    \/\/   SOUS ColonneGauche (10015), qui est un .via-link-popup et n'est\r\n                    \/\/   pas concerne par ce reset.\r\n                    \/\/   Ordre voulu : CGV > Tarifs > ColonneGauche. On calcule donc le max\r\n                    \/\/   des AUTRES popups (colonnes, VLP) en EXCLUANT popup3 et popup4,\r\n                    \/\/   puis on les place explicitement au-dessus, a deux crans d'ecart.\r\n                    \/\/   L'exclusion supprime au passage l'auto-escalade observee\r\n                    \/\/   (10019 -> 10021 -> 10023 -> 10025 : popup4 se comptait lui-meme).\r\n                    \/\/   Meme selecteur que _vlpMaxZ663 (pb663) pour rester sur l'echelle\r\n                    \/\/   partagee par les 4 systemes de z-index.\r\n                    const _maxAutres692 = function() {\r\n                        let mx = 0;\r\n                        const els = document.querySelectorAll('.via-link-popup, .popup-container, #popup3, #via-col-ColonneDroite, .via-col-popup');\r\n                        for (let i = 0; i < els.length; i++) {\r\n                            const el = els[i];\r\n                            if (el.id === 'popup3') { continue; }\r\n                            if (el.id === 'popup4') { continue; }\r\n                            let z = parseInt(el.style.zIndex, 10);\r\n                            if (!z) { z = parseInt(getComputedStyle(el).zIndex, 10) || 0; }\r\n                            if (z > mx) { mx = z; }\r\n                        }\r\n                        return mx;\r\n                    };\r\n                    const _ordonner692 = function(_tag) {\r\n                        const p3 = document.getElementById('popup3');\r\n                        const p4 = document.getElementById('popup4');\r\n                        if (!p4) { return; }\r\n                        let base = _maxAutres692();\r\n                        if (base < 9998) { base = 9998; }\r\n                        if (p3) { p3.style.setProperty('z-index', String(base + 2), 'important'); }\r\n                        p4.style.setProperty('z-index', String(base + 4), 'important');\r\n                        const _lire = function(sel) {\r\n                            const el = document.querySelector(sel);\r\n                            return el ? (el.style.zIndex || getComputedStyle(el).zIndex) : 'absent';\r\n                        };\r\n                        console.log('[pb692] ' + _tag + ' | base(autres)=' + base\r\n                            + ' | popup4=' + (base + 4) + ' | popup3=' + (base + 2)\r\n                            + ' | ColonneGauche=' + _lire('#via-col-ColonneGauche')\r\n                            + ' | ColonneDroite=' + _lire('#via-col-ColonneDroite'));\r\n                    };\r\n                    _ordonner692('T+0');\r\n                    [60, 150, 220].forEach(function(_d) {\r\n                        setTimeout(function() { _ordonner692('T+' + _d + 'ms'); }, _d);\r\n                    });\r\n                }, true);\r\n            })();\r\n\r\n            (function _brancherOuverture651() {\r\n                const p3 = document.getElementById('popup3');\r\n                if (!p3) { return; }\r\n                let etaitOuvert = p3.classList.contains('active');\r\n                const obs = new MutationObserver(function() {\r\n                    const ouvert = p3.classList.contains('active');\r\n                    if (ouvert ? !etaitOuvert : false) {\r\n                        window._diag652Fait = false;   \/\/ pb652 : re-armer le diag a chaque ouverture\r\n                        const panier = window.VIA_Panier;\r\n                        const idActif = (panier ? panier.state : null) ? panier.state.itemActif : null;\r\n                        if (idActif ? panier.state.items : false) {\r\n                            const it = panier.state.items.find(function(i) { return i.id === idActif; });\r\n                            if (it) {\r\n                                console.log('[pb651] popup ouvert + resa active -> sync A');\r\n                                window.VIA_GrilleTarifaire.syncDepuisResa651(it);\r\n                            }\r\n                        }\r\n                    }\r\n                    etaitOuvert = ouvert;\r\n                });\r\n                obs.observe(p3, { attributes: true, attributeFilter: ['class'] });\r\n            })();\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1911 : LA SYNCHRO A N'A PAS DE TROISIEME CHANCE \u2014 ON LA RATTRAPE.\r\n            \/\/   Constat, releve pb1903 : #popup3 porte bien active=true, les 15\r\n            \/\/   lignes de sites pays sont rendues, l'item existe \u2014 et pourtant\r\n            \/\/   \u00ab lignes pays cochees : 0 \/ 15 \u00bb, etapes 000000, _sync635 vide, et\r\n            \/\/   AUCUN [pb651 A] dans tout le log. La direction A n'a jamais tourne.\r\n            \/\/   Ses deux declencheurs sont des TRANSITIONS, et toutes deux peuvent\r\n            \/\/   etre deja passees quand ils sont poses :\r\n            \/\/     - viaSyncVersPopupTarifs651, appele par setItemActif : l'item du\r\n            \/\/       popup pays est cree par popupLateParams, potentiellement AVANT\r\n            \/\/       que ce bloc n'ait defini la fonction ;\r\n            \/\/     - l'observateur de la classe 'active' de #popup3 : il memorise\r\n            \/\/       etaitOuvert A L'INSTALLATION. initGrilleModules attend VIA_App\r\n            \/\/       par scrutation a 100 ms, tandis que pb1905 ouvre #popup3 des que\r\n            \/\/       le catalogue est en place. Si l'ouverture precede l'installation,\r\n            \/\/       etaitOuvert vaut deja true et aucune transition ne sera jamais\r\n            \/\/       vue.\r\n            \/\/   \u00ab Un ecouteur qui attend un signal deja emis attend pour toujours \u00bb :\r\n            \/\/   c'est mot pour mot pb1656 dans Entete.txt, et la reponse y est la\r\n            \/\/   meme \u2014 constater l'ETAT plutot que guetter le front.\r\n            \/\/   On n'ajoute donc aucune synchro : on rappelle celle qui existe, une\r\n            \/\/   fois, quand les quatre conditions sont reunies. La liste rendue en\r\n            \/\/   fait partie : _selectionnerSitePays651 sort en silence sur\r\n            \/\/   $rows.length === 0, et ce silence est exactement ce qu'on vient de\r\n            \/\/   passer deux tours a diagnostiquer.\r\n            \/\/   Scrutation sur CONDITION, plafonnee, avec une sortie journalisee\r\n            \/\/   dans les deux cas.\r\n            \/\/   Revert : window._viaPb1911Off = true.\r\n            \/\/ ================================================================\r\n            (function _rattrapage1911() {\r\n                if (window._viaPb1911Off === true) { return; }\r\n                if (window._viaArme1911 === true) { return; }\r\n                if (typeof window._viaPopupPays1905 !== 'function') { return; }\r\n                if (!window._viaPopupPays1905()) { return; }\r\n                window._viaArme1911 = true;\r\n                var _n1911 = 0;\r\n                var _manque1911 = '';\r\n                var _t1911 = setInterval(function () {\r\n                    \/* ================================================================\r\n                     * pb1956 : LE COMPTE A REBOURS PARTAIT TROP TOT.\r\n                     *   Constat user, mot pour mot : \u00ab si j'attends 1 mn avant de\r\n                     *   Reserver, le pb initial revient \u00bb.\r\n                     *   Cette veille comptait 60 passages de 500 ms \u2014 TRENTE SECONDES \u2014\r\n                     *   a partir du CHARGEMENT du module. Si l'utilisateur clique\r\n                     *   Reserver apres, elle a deja expire : le rattrapage ne part\r\n                     *   jamais, la synchro A n'a pas lieu, les completions restent a\r\n                     *   000000, et le sequenceur garde \u00ab pays \u00bb pour cible. Tout ce que\r\n                     *   j'ai cherche en aval \u2014 accordeons, drapeaux, cibles imposees \u2014\r\n                     *   decoulait de cette seule ligne.\r\n                     *   Le compteur ne doit pas mesurer le temps depuis le chargement,\r\n                     *   mais depuis le moment ou il y a quelque chose a attendre. Il ne\r\n                     *   demarre donc qu'une fois le CATALOGUE POSE (pb1905) : avant, la\r\n                     *   scene n'est pas montee et attendre ne veut rien dire.\r\n                     *   La veille elle-meme reste bornee \u2014 10 minutes de scrutation a\r\n                     *   vide au maximum \u2014 pour ne pas laisser tourner un intervalle\r\n                     *   eternel dans un document ou le popup ne s'ouvrira jamais.\r\n                     *   Revert : window._viaPb1956Off = true (compte a rebours d'origine).\r\n                     * ================================================================ *\/\r\n                    _n1911++;\r\n                    if (window._viaPb1956Off === true) {\r\n                        if (_n1911 > 60) {\r\n                            clearInterval(_t1911);\r\n                            console.warn('[pb1911] rattrapage abandonne apres 30 s'\r\n                                + ' | derniere condition manquante : ' + (_manque1911 || '?'));\r\n                            return;\r\n                        }\r\n                    } else {\r\n                        \/* ================================================================\r\n                         * pb2055 : LE COMPTE A REBOURS PARTAIT ENCORE TROP TOT.\r\n                         *   Meme symptome que pb1956, mot pour mot : \u00ab si j'attends plus\r\n                         *   de 30 s avant de Reserver, le process s'ouvre mal \u00bb. Et le\r\n                         *   log de JF le date a la seconde :\r\n                         *     14:25:05.850 [pb1956] catalogue pose -> compte a rebours\r\n                         *     14:25:37.081 [pb1911] abandonne | manque : aucun item actif\r\n                         *     14:26:08.255 creation de l'item\r\n                         *   Trente et une secondes entre l'abandon et l'item. La synchro A\r\n                         *   n'a donc jamais lieu, les completions restent a 000000 et le\r\n                         *   sequenceur garde \u00ab pays \u00bb pour cible \u2014 c'est exactement la\r\n                         *   capture.\r\n                         *   POURQUOI pb1956 N'A PAS SUFFI : il avait deplace le depart du\r\n                         *   chargement du module vers la POSE DU CATALOGUE. Mais l'iframe\r\n                         *   du process est PRECHARGEE (pb426\/pb1656 : \u00ab iframe prechargee\r\n                         *   ADOPTEE, aucun rechargement \u00bb), et le catalogue est pose\r\n                         *   pendant ce prechargement \u2014 soit ici 62 s avant le clic. Les\r\n                         *   deux reperes sont dans la meme phase ; aucun ne mesure ce\r\n                         *   qu'on attend vraiment.\r\n                         *   LE BON REPERE est l'ouverture reelle du process, publiee par\r\n                         *   _runPopupPanierInit (pb2055, yearbook-media.js) \u2014 le point\r\n                         *   d'entree des deux chemins, direct et popupLateParams. Avant\r\n                         *   lui, attendre un item actif n'a aucun sens : il ne peut pas\r\n                         *   exister.\r\n                         *   PLAFOND TANT QUE RIEN N'EST OUVERT : 30 minutes, et non 10.\r\n                         *   L'ancien plafond datait d'un depart au chargement ; desormais\r\n                         *   la veille couvre tout le temps de navigation sur le site pays\r\n                         *   avant le clic Reserver, qui peut etre long. Les deux tests\r\n                         *   faits avant cette borne sont deux lectures de variables.\r\n                         *   Aucune sortie muette : la condition manquante est nommee dans\r\n                         *   les deux cas.\r\n                         *   Revert : window._viaPb2055Off = true (depart a la pose du\r\n                         *   catalogue, comportement pb1956).\r\n                         * ================================================================ *\/\r\n                        var _pret2055 = false;\r\n                        if (window._viaCataloguePaysPose1905 === true) {\r\n                            if (window._viaPb2055Off === true) {\r\n                                _pret2055 = true;\r\n                            } else {\r\n                                _pret2055 = (window._viaProcessArme2055 === true);\r\n                            }\r\n                        }\r\n                        if (_pret2055) {\r\n                            if (!window._viaDepart1956) {\r\n                                window._viaDepart1956 = _n1911;\r\n                                console.log('[pb2055] process d\\'achat ouvert apres ' + _n1911\r\n                                    + ' passage(s) -> le compte a rebours du rattrapage'\r\n                                    + ' demarre maintenant (catalogue pose + _viaProcessArme2055)');\r\n                            }\r\n                            if ((_n1911 - window._viaDepart1956) > 60) {\r\n                                clearInterval(_t1911);\r\n                                console.warn('[pb1911] rattrapage abandonne 30 s apres'\r\n                                    + ' l\\'ouverture du process | derniere condition'\r\n                                    + ' manquante : ' + (_manque1911 || '?'));\r\n                                return;\r\n                            }\r\n                        } else {\r\n                            _manque1911 = (window._viaCataloguePaysPose1905 === true)\r\n                                ? 'process d\\'achat pas encore ouvert (pb2055)'\r\n                                : 'catalogue pas encore pose (pb1905)';\r\n                            if (_n1911 > 3600) {\r\n                                clearInterval(_t1911);\r\n                                console.log('[pb2055] rien a rattraper apres 30 min'\r\n                                    + ' -> veille arretee | derniere condition manquante : '\r\n                                    + _manque1911);\r\n                                return;\r\n                            }\r\n                            return;\r\n                        }\r\n                    }\r\n                    var _p31911 = document.getElementById('popup3');\r\n                    if (!_p31911 ? true : !_p31911.classList.contains('active')) {\r\n                        _manque1911 = '#popup3 non actif'; return;\r\n                    }\r\n                    if (window._viaCataloguePaysPose1905 !== true) {\r\n                        _manque1911 = 'catalogue pas encore pose (pb1905)'; return;\r\n                    }\r\n                    if (document.querySelectorAll('#PopupTarifsListePays .v290-row[data-kind=\"pays\"]').length === 0) {\r\n                        _manque1911 = 'liste des sites pays non rendue'; return;\r\n                    }\r\n                    var _st1911 = window.VIA_Panier ? (window.VIA_Panier.state || null) : null;\r\n                    var _id1911 = _st1911 ? _st1911.itemActif : null;\r\n                    var _it1911 = (_st1911 ? (_id1911 ? _st1911.items : null) : null)\r\n                        ? _st1911.items.filter(function (_i) { return _i.id === _id1911; })[0]\r\n                        : null;\r\n                    if (!_it1911) { _manque1911 = 'aucun item actif'; return; }\r\n                    if (!window.VIA_GrilleTarifaire) {\r\n                        _manque1911 = 'VIA_GrilleTarifaire absent'; return;\r\n                    }\r\n                    clearInterval(_t1911);\r\n                    console.log('[pb1911] rattrapage de la synchro A (le front d\\'ouverture'\r\n                        + ' etait deja passe) | item=' + _id1911\r\n                        + ' | lien=' + (_it1911.linkSecteurPage || '(vide)')\r\n                        + ' | page=' + (_it1911.commandePage || '(vide)')\r\n                        + ' | type=' + (_it1911.selectedPageType || '(vide)'));\r\n                    try { window.VIA_GrilleTarifaire.syncDepuisResa651(_it1911); }\r\n                    catch (_e1911) { console.warn('[pb1911] synchro A : ' + _e1911.message); }\r\n                }, 500);\r\n            })();\r\n            console.log('\u2705 Tous les modules de la grille charg\u00e9s');\r\n            \/* ================================================================\r\n             * pb1967 : QUI FERME LE CALENDRIER DE LA DATE DE DEBUT ?\r\n             *   Le releve pb1966 etablit trois faits qui excluent \u00ab il ne\r\n             *   s'ouvre pas \u00bb :\r\n             *     - au focus, la dpDiv de DEBUT vaut 182x177, display=block, et\r\n             *       elle est encore la a +400 ms ;\r\n             *     - au clic qui suit, elle est display=none et le reste ;\r\n             *     - pendant tout ce temps _lastInput vaut null, alors que pour\r\n             *       FIN il porte bien l'identifiant du champ.\r\n             *   Un calendrier affiche dont jQuery UI ne se reconnait pas\r\n             *   proprietaire, puis referme : c'est un show et un hide qu'il faut\r\n             *   voir, avec leur pile. Deviner l'appelant a deja coute des tours\r\n             *   entiers sur ce projet ; les pieges qui NOMMENT gagnent.\r\n             *   On enveloppe les deux entrees de jQuery UI. Aucune n'est\r\n             *   modifiee : on journalise et on relaie l'appel d'origine.\r\n             *   Armement sur CONDITION (jQuery UI peut ne pas etre encore la),\r\n             *   une seule fois quel que soit le nombre d'instances du module.\r\n             *   A RETIRER apres releve. Knob : window._viaPb1967Off = true.\r\n             * ================================================================ *\/\r\n            (function _armer1967() {\r\n                if (window._viaPb1967Off === true) { return; }\r\n                if (window._viaArme1967 === true) { return; }\r\n                var _n1967 = 0;\r\n                var _t1967 = setInterval(function () {\r\n                    _n1967++;\r\n                    if (_n1967 > 60) {\r\n                        clearInterval(_t1967);\r\n                        console.warn('[pb1967] jQuery UI datepicker absent apres 30 s'\r\n                            + ' -> piege non pose');\r\n                        return;\r\n                    }\r\n                    var _dp = window.jQuery ? window.jQuery.datepicker : null;\r\n                    if (!_dp) { return; }\r\n                    if (typeof _dp._showDatepicker !== 'function') { return; }\r\n                    clearInterval(_t1967);\r\n                    if (window._viaArme1967 === true) { return; }\r\n                    window._viaArme1967 = true;\r\n                    var _pile1967 = function () {\r\n                        try {\r\n                            return String(new Error().stack || '').split('\\n')\r\n                                .slice(2, 8).join('\\n');\r\n                        } catch (_eP) { return '    (pile illisible)'; }\r\n                    };\r\n                    var _nom1967 = function (_e) {\r\n                        if (!_e) { return 'null'; }\r\n                        return _e.id ? _e.id : (_e.tagName || '?');\r\n                    };\r\n                    var _show1967 = _dp._showDatepicker;\r\n                    var _hide1967 = _dp._hideDatepicker;\r\n                    _dp._showDatepicker = function (_in) {\r\n                        var _c = _in ? (_in.target ? _in.target : _in) : null;\r\n                        console.log('[pb1967] _showDatepicker(' + _nom1967(_c) + ')'\r\n                            + ' | _lastInput avant=' + _nom1967(_dp._lastInput)\r\n                            + ' | showing=' + _dp._datepickerShowing\r\n                            + '\\n' + _pile1967());\r\n                        return _show1967.apply(this, arguments);\r\n                    };\r\n                    _dp._hideDatepicker = function () {\r\n                        console.log('[pb1967] _hideDatepicker'\r\n                            + ' | _lastInput avant=' + _nom1967(_dp._lastInput)\r\n                            + ' | showing=' + _dp._datepickerShowing\r\n                            + '\\n' + _pile1967());\r\n                        return _hide1967.apply(this, arguments);\r\n                    };\r\n                    console.log('[pb1967] piege pose sur _showDatepicker \/'\r\n                        + ' _hideDatepicker \u2014 reproduis le clic sur la date de debut');\r\n                }, 500);\r\n            })();\r\n\r\n            \/* ================================================================\r\n             * pb1966 : LE CALENDRIER SE MESURE AU MOMENT DU CLIC, PAS AVANT.\r\n             *   Le releve pb1965 a REFUTE mes deux hypotheses : aucun element ne\r\n             *   recouvre le champ (elementFromPoint rend le champ lui-meme pour\r\n             *   les deux), et l'etat interne de jQuery UI est propre\r\n             *   (_lastInput=null, dpDiv display=none). L'anomalie n'existe donc\r\n             *   pas AVANT le clic : elle nait pendant.\r\n             *   Or les deux champs ne sont pas configures pareil, et c'est le seul\r\n             *   ecart connu entre celui qui marche et celui qui ne marche pas :\r\n             *   le beforeShow du champ DEBUT repositionne la dpDiv en\r\n             *   position:fixed sur le rect du champ, mesure dans un setTimeout 0 ;\r\n             *   celui du champ FIN ne repositionne rien sur desktop. Une dpDiv\r\n             *   affichee hors ecran est indiscernable d'une dpDiv qui ne s'ouvre\r\n             *   pas \u2014 on mesure donc la BOITE, pas l'intention.\r\n             *   Trois instants : au clic, puis +80 ms, puis +400 ms (le\r\n             *   repositionnement passe par un setTimeout 0 suivi de l'animation).\r\n             *   Sonde : ecouteurs passifs en capture, aucune decision modifiee.\r\n             *   A RETIRER apres releve. Knob : window._viaPb1966Off = true.\r\n             * ================================================================ *\/\r\n            (function _armer1966() {\r\n                if (window._viaPb1966Off === true) { return; }\r\n                if (window._viaArme1966 === true) { return; }\r\n                window._viaArme1966 = true;\r\n                var _etat1966 = function (_quand) {\r\n                    var _dp = window.jQuery ? window.jQuery.datepicker : null;\r\n                    if (!_dp) { return _quand + ' : jQuery UI absent'; }\r\n                    var _dv = _dp.dpDiv ? _dp.dpDiv[0] : null;\r\n                    if (!_dv) { return _quand + ' : dpDiv absente'; }\r\n                    var _r = _dv.getBoundingClientRect();\r\n                    var _cs = window.getComputedStyle(_dv);\r\n                    var _li = _dp._lastInput;\r\n                    var _vu = '(boite nulle)';\r\n                    if (_r.height > 0) {\r\n                        var _t = document.elementFromPoint(\r\n                            Math.round(_r.left + _r.width \/ 2),\r\n                            Math.round(_r.top + _r.height \/ 2));\r\n                        _vu = _t ? (_t.tagName + (_t.id ? ('#' + _t.id) : '')\r\n                            + (_dv.contains(_t) ? '  <= LE CALENDRIER' : '  <= AUTRE ELEMENT'))\r\n                            : '(hors fenetre)';\r\n                    }\r\n                    return _quand\r\n                        + ' | dpDiv ' + Math.round(_r.width) + 'x' + Math.round(_r.height)\r\n                        + ' @ x=' + Math.round(_r.left) + ' y=' + Math.round(_r.top)\r\n                        + ' | display=' + _cs.display + ' position=' + _cs.position\r\n                        + ' top=' + _cs.top + ' left=' + _cs.left + ' z=' + _cs.zIndex\r\n                        + ' | fenetre ' + window.innerWidth + 'x' + window.innerHeight\r\n                        + ' | _lastInput=' + (_li ? (_li.id || _li.tagName) : 'null')\r\n                        + ' | au centre -> ' + _vu;\r\n                };\r\n                var _relever1966 = function (_ev) {\r\n                    var _t = _ev.target;\r\n                    if (!_t) { return; }\r\n                    if (!_t.id) { return; }\r\n                    if (_t.id !== 'form-field-PopupTarifsDebutCampagne') {\r\n                        if (_t.id !== 'form-field-PopupTarifsFinCampagne') { return; }\r\n                    }\r\n                    var _nom = (_t.id.indexOf('Debut') > -1) ? 'DEBUT' : 'FIN';\r\n                    console.log('[pb1966] ' + _ev.type + ' sur ' + _nom + '\\n  '\r\n                        + _etat1966('t+0'));\r\n                    setTimeout(function () {\r\n                        console.log('[pb1966] ' + _nom + '\\n  ' + _etat1966('t+80'));\r\n                    }, 80);\r\n                    setTimeout(function () {\r\n                        console.log('[pb1966] ' + _nom + '\\n  ' + _etat1966('t+400'));\r\n                    }, 400);\r\n                };\r\n                document.addEventListener('focus', _relever1966, true);\r\n                document.addEventListener('click', _relever1966, true);\r\n                console.log('[pb1966] ecouteurs poses sur les deux champs de date'\r\n                    + ' (focus + clic, en capture)');\r\n            })();\r\n\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1934 : POURQUOI L IFRAME EST \u00ab DILATEE \u00bb SUR UN APPAREIL ET PAS L AUTRE.\r\n            \/\/   Constat user : rendu correct sur son iPhone 15 (Chrome), tout est plus\r\n            \/\/   grand sur l iPhone 17 d un collegue.\r\n            \/\/   Une capture ne permet pas de trancher : QUATRE causes produisent le\r\n            \/\/   meme aspect, et chacune demande une correction differente.\r\n            \/\/     1. AUTOSIZING iOS \u2014 -webkit-text-size-adjust laisse Safari grossir le\r\n            \/\/        texte des blocs etroits. Signature : ajustement = 'auto' ET taille\r\n            \/\/        rendue superieure a la base memorisee (data-viafs1186).\r\n            \/\/     2. ZOOM VISUEL \u2014 un pincement reste actif, ou le zoom de page Safari\r\n            \/\/        est regle par site. Signature : visualViewport.scale different de 1.\r\n            \/\/     3. VIEWPORT PLUS ETROIT \u2014 l iframe rend sur moins de pixels CSS, tout\r\n            \/\/        parait donc plus gros a l ecran. Signature : innerWidth nettement\r\n            \/\/        inferieur a celui du poste de reference (430 mesure par pb1903).\r\n            \/\/     4. BASE DE POLICE DIFFERENTE \u2014 le template rend une taille de depart\r\n            \/\/        differente, et tous nos deltas s empilent dessus. Signature :\r\n            \/\/        data-viafs1186 different d un appareil a l autre.\r\n            \/\/   On mesure les quatre d un coup. Aucune ecriture, que des lectures \u2014 et\r\n            \/\/   surtout AUCUNE correction posee avant d avoir le releve : quatre causes,\r\n            \/\/   quatre corrections opposees, c est exactement la situation ou deviner\r\n            \/\/   coute quatre allers-retours.\r\n            \/\/   Manuel : window._viaSondeEchelle1934()\r\n            \/\/   Revert : window._viaPb1934Off = true (aucun releve automatique).\r\n            \/\/ ================================================================\r\n            window._viaSondeEchelle1934 = function () {\r\n                var _l34 = [];\r\n                var _d34 = function (_k, _v) { _l34.push('  ' + _k + ' : ' + _v); };\r\n                try {\r\n                    var _cs34 = window.getComputedStyle(document.documentElement);\r\n                    var _csb34 = document.body ? window.getComputedStyle(document.body) : null;\r\n                    _d34('version', window._viaGrilleVer || '(absente)');\r\n                    \/* pb1934b : dire DANS QUEL document on mesure \u2014 le releve precedent\r\n                       venait vraisemblablement de l iframe prechargee, ou rien n est\r\n                       monte. Sans cette ligne, deux relev\u00e9s se ressemblent et ne\r\n                       parlent pas de la meme chose. *\/\r\n                    _d34('contexte', 'catalogue pos\u00e9=' + (window._viaCataloguePaysPose1905 === true)\r\n                        + ' | #via-col-ColonneGauche='\r\n                        + !!document.getElementById('via-col-ColonneGauche')\r\n                        + ' | text-size-adjust pos\u00e9 par pb1935='\r\n                        + !!document.getElementById('via-tsa-1935'));\r\n                    _d34('userAgent', String(navigator.userAgent).substring(0, 130));\r\n                    \/* 3. viewport *\/\r\n                    _d34('outer \/ inner width', window.outerWidth + ' \/ ' + window.innerWidth\r\n                        + '   (reference iPhone 15 : 430 \/ 430)');\r\n                    _d34('documentElement.clientWidth', document.documentElement.clientWidth);\r\n                    _d34('devicePixelRatio', window.devicePixelRatio);\r\n                    \/* 2. zoom visuel *\/\r\n                    if (window.visualViewport) {\r\n                        _d34('visualViewport scale \/ width \/ height',\r\n                            window.visualViewport.scale + ' \/ '\r\n                            + Math.round(window.visualViewport.width) + ' \/ '\r\n                            + Math.round(window.visualViewport.height)\r\n                            + (window.visualViewport.scale !== 1\r\n                                ? '   <-- ZOOM VISUEL ACTIF' : ''));\r\n                    } else { _d34('visualViewport', 'non supporte'); }\r\n                    \/* 1. autosizing iOS *\/\r\n                    var _aj34 = _cs34.webkitTextSizeAdjust || _cs34.textSizeAdjust || '(non lu)';\r\n                    var _ajb34 = _csb34\r\n                        ? (_csb34.webkitTextSizeAdjust || _csb34.textSizeAdjust || '(non lu)')\r\n                        : '(pas de body)';\r\n                    _d34('text-size-adjust html \/ body', _aj34 + ' \/ ' + _ajb34\r\n                        + ((String(_aj34).indexOf('auto') !== -1)\r\n                            ? '   <-- AUTOSIZING iOS AUTORISE' : ''));\r\n                    \/* meta viewport du document de l iframe *\/\r\n                    var _mv34 = document.querySelector('meta[name=\"viewport\"]');\r\n                    _d34('meta viewport', _mv34 ? _mv34.getAttribute('content') : 'ABSENTE');\r\n                    \/* 4. base de police + rendu reel des titres *\/\r\n                    _d34('font-size html \/ body', _cs34.fontSize + ' \/ '\r\n                        + (_csb34 ? _csb34.fontSize : '-'));\r\n                    var _ids34 = ['PopupTarifsListePaysTitreTexte',\r\n                        'PopupTarifsDatesTitreTexte', 'PopupTarifsEtapeAnnonceurContainer'];\r\n                    for (var _i34 = 0; _i34 < _ids34.length; _i34++) {\r\n                        var _e34 = document.getElementById(_ids34[_i34])\r\n                            || document.querySelector('.' + _ids34[_i34]);\r\n                        if (!_e34) { _d34('  ' + _ids34[_i34], 'ABSENT'); continue; }\r\n                        var _b34 = _e34.getAttribute('data-viafs1186');\r\n                        var _r34 = parseFloat(window.getComputedStyle(_e34).fontSize);\r\n                        var _in34 = _e34.style.getPropertyValue('font-size');\r\n                        _d34('  ' + _ids34[_i34],\r\n                            'base=' + (_b34 === null ? '(non mesuree)' : _b34)\r\n                            + ' | inline=' + (_in34 || '(aucun)')\r\n                            + ' | RENDU=' + _r34 + 'px'\r\n                            + ((_b34 !== null ? (_r34 > (parseFloat(_b34) + 3)) : false)\r\n                                ? '   <-- RENDU BIEN AU-DESSUS DE LA BASE' : ''));\r\n                    }\r\n                    \/* le catalogue et la colonne : largeurs reellement obtenues *\/\r\n                    ['TarifsCatalogueConteneur', 'ColonneDroite', 'via-col-ColonneGauche']\r\n                        .forEach(function (_id34) {\r\n                            var _x34 = document.getElementById(_id34);\r\n                            _d34('  #' + _id34, _x34\r\n                                ? (Math.round(_x34.getBoundingClientRect().width) + 'px rendu'\r\n                                    + ' | transform=' + window.getComputedStyle(_x34).transform)\r\n                                : 'ABSENT');\r\n                        });\r\n                } catch (_e34b) { _l34.push('  SONDE INTERROMPUE : ' + _e34b.message); }\r\n                console.log('%c[pb1934] ECHELLE \/ VIEWPORT',\r\n                    'background:#8a5a00;color:#fff;padding:2px 6px;border-radius:3px');\r\n                console.log(_l34.join('\\n'));\r\n                return _l34.join('\\n');\r\n            };\r\n\r\n            \/* ================================================================\r\n             * pb1934b : SUR CONDITION, PAS SUR DELAI \u2014 MA PROPRE REGLE, VIOLEE.\r\n             *   Le premier releve de l iPhone 15 le montre :\r\n             *     #TarifsCatalogueConteneur : 0px rendu\r\n             *     #ColonneDroite : ABSENT\r\n             *     #via-col-ColonneGauche : ABSENT\r\n             *   La sonde a tire a +3000 ms, avant que le popup ne soit monte \u2014 et\r\n             *   probablement dans l IFRAME PRECHARGEE (pb1656), ou rien ne s assemble\r\n             *   jamais. Les tailles relevees ne sont donc pas celles que l utilisateur\r\n             *   voit, et la comparaison entre appareils n aurait rien voulu dire.\r\n             *   C est exactement la lecon pb1871, que j applique partout ailleurs dans\r\n             *   ce fichier et que j ai oubliee ici : on attend la CONDITION.\r\n             *   Condition retenue : le catalogue pose par pb1905, ou le popup de\r\n             *   colonne present. Plafond dur, et surtout SORTIE EXPLICITE : un releve\r\n             *   sans objet doit se dire tel, pas se deguiser en mesure.\r\n             * ================================================================ *\/\r\n            (function _autoEchelle1934() {\r\n                if (window._viaPb1934Off === true) { return; }\r\n                if (window._viaArme1934 === true) { return; }\r\n                window._viaArme1934 = true;\r\n                var _n34b = 0;\r\n                var _t34b = setInterval(function () {\r\n                    _n34b++;\r\n                    if (_n34b > 60) {\r\n                        clearInterval(_t34b);\r\n                        var _cf34 = document.getElementById('TarifsCatalogueConteneur');\r\n                        console.log('[pb1934c] jamais de g\u00e9om\u00e9trie rendue dans ce document'\r\n                            + ' (catalogue pos\u00e9=' + (window._viaCataloguePaysPose1905 === true)\r\n                            + ' | clientWidth=' + document.documentElement.clientWidth\r\n                            + ' | catalogue=' + (_cf34\r\n                                ? Math.round(_cf34.getBoundingClientRect().width) + 'px' : 'ABSENT')\r\n                            + ') -> relev\u00e9 sans objet ici : iframe masqu\u00e9e ou pr\u00e9charg\u00e9e.'\r\n                            + ' window._viaSondeEchelle1934() reste appelable \u00e0 la main.');\r\n                        return;\r\n                    }\r\n                    \/* ================================================================\r\n                     * pb1934c : \u00ab MONTE \u00bb NE SUFFIT PAS, IL FAUT \u00ab RENDU \u00bb.\r\n                     *   Deuxieme releve, meme piege d un cran plus loin :\r\n                     *     contexte : catalogue pos\u00e9=true\r\n                     *     outer \/ inner width : 430 \/ 0\r\n                     *     documentElement.clientWidth : 0\r\n                     *     #TarifsCatalogueConteneur : 1px rendu | #ColonneDroite : 1px\r\n                     *   Le catalogue etait bien pose \u2014 ma condition etait remplie \u2014 mais\r\n                     *   l iframe n avait PAS ENCORE DE LAYOUT : une iframe masquee, ou\r\n                     *   dont un ancetre l est, rapporte innerWidth 0, clientWidth 0, et\r\n                     *   ses elements mesurent 1 px. C est le piege documente de ce projet,\r\n                     *   \u00ab innerWidth = 0 dans l iframe mobile \u00bb, rencontre ici sous sa\r\n                     *   forme la plus complete.\r\n                     *   Un etat LOGIQUE ne prouve pas un etat RENDU. On exige donc les\r\n                     *   deux : le catalogue pose ET une geometrie reelle \u2014 clientWidth du\r\n                     *   document non nul et catalogue plus large que 50 px. En dessous,\r\n                     *   la mesure ne decrit rien de ce que l utilisateur voit.\r\n                     *   Meme famille que pb1785 : mesurer ce qui SORT, pas ce qu on injecte.\r\n                     * ================================================================ *\/\r\n                    var _pret34 = (window._viaCataloguePaysPose1905 === true);\r\n                    if (!_pret34) {\r\n                        _pret34 = !!document.getElementById('via-col-ColonneGauche');\r\n                    }\r\n                    if (_pret34) {\r\n                        if (!(document.documentElement.clientWidth > 0)) { _pret34 = false; }\r\n                    }\r\n                    if (_pret34) {\r\n                        var _cat34c = document.getElementById('TarifsCatalogueConteneur');\r\n                        var _w34c = _cat34c ? _cat34c.getBoundingClientRect().width : 0;\r\n                        if (!(_w34c > 50)) { _pret34 = false; }\r\n                    }\r\n                    if (!_pret34) { return; }\r\n                    clearInterval(_t34b);\r\n                    setTimeout(function () {\r\n                        try { window._viaSondeEchelle1934(); }\r\n                        catch (_eA34) { console.warn('[pb1934b] ' + _eA34.message); }\r\n                    }, 800);\r\n                }, 500);\r\n            })();\r\n\r\n            \/\/ pb634 : les enrichissements pb612->633 sont concus pour la REGIE.\r\n            \/\/   Sur les sites pays, ce template tourne dans l'iframe du popup VLP\r\n            \/\/   ou plusieurs dependances (viaRenderPays613\/615, conteneurs Elementor\r\n            \/\/   specifiques regie) n'existent pas. Une exception ici bloquait toute\r\n            \/\/   l'init et cassait le popup. On isole donc ces appels : chacun est\r\n            \/\/   protege.\r\n            \/\/ ================================================================\r\n            \/\/ pb1902 : LA BONNE QUESTION EST \u00ab SUIS-JE LA REGIE ? \u00bb, PAS \u00ab SUIS-JE\r\n            \/\/   EN IFRAME ? \u00bb.\r\n            \/\/   pb634 refusait les enrichissements sur le seul critere\r\n            \/\/   window.self !== window.top. Ce test ne distingue pas deux situations\r\n            \/\/   opposees :\r\n            \/\/     - une PAGE PAYS chargee dans une iframe VLP \u2014 les dependances regie\r\n            \/\/       n'existent effectivement pas, il faut sortir ;\r\n            \/\/     - la REGIE ELLE-MEME chargee en iframe depuis un site pays\r\n            \/\/       (pb1642 : yearbook-media.com#mode=popup&layout=plein), ou toutes\r\n            \/\/       les dependances sont la, puisque c'est la regie.\r\n            \/\/   Depuis pb1642 le popup d'achat des sites pays EST ce second cas :\r\n            \/\/   l'achat express y etait donc integralement inerte, alors que le\r\n            \/\/   fichier se charge bien ([GRILLE ECHO] visible en console).\r\n            \/\/   Le discriminant n'est pas a inventer : c'est celui du laissez-passer\r\n            \/\/   pb1641, lu sur NOTRE PROPRE URL \u2014 mode=popup (\u00ab je viens d'un site\r\n            \/\/   pays \u00bb) ou layout=plein (\u00ab je dispose de tout l'ecran \u00bb). Une page\r\n            \/\/   pays en iframe VLP ne porte ni l'un ni l'autre : elle continue de\r\n            \/\/   sortir, comme avant.\r\n            \/\/   pb1642 met ses parametres dans le HASH, pas dans la query : on lit\r\n            \/\/   les deux, comme le fait deja la garde de yearbook-media.js l.4185.\r\n            \/\/   Chaque init journalise desormais son ISSUE, pas seulement son echec :\r\n            \/\/   savoir laquelle des six aboutit dans ce contexte est precisement la\r\n            \/\/   mesure qui manquait.\r\n            \/\/   Revert : window._viaPb1902Off = true (retour au seul test iframe).\r\n            \/\/ ================================================================\r\n            let _enIframe634 = false;\r\n            try { _enIframe634 = (window.self !== window.top); } catch (e) { _enIframe634 = true; }\r\n            \/\/ pb1910 : ce bloc etait le quatrieme a poser la meme question. Il passe\r\n            \/\/   par le helper commun ; _viaPb1902Off reste accepte, il vise la meme\r\n            \/\/   bascule que _viaPb1910Off et les deux sont lus ici.\r\n            var _regie1902 = (window._viaPb1902Off === true)\r\n                ? !_enIframe634\r\n                : window._viaContexteRegie1910('enrichissements pb634');\r\n            if (_regie1902) {\r\n                const _initSafe634 = (nom, fn) => {\r\n                    try { fn(); }\r\n                    catch (err) {\r\n                        console.warn('[pb634] init ' + nom + ' ignoree:', err.message);\r\n                    }\r\n                };\r\n                const _g = window.VIA_GrilleTarifaire;\r\n                _initSafe634('rendreListePays613',      () => _g.rendreListePays613());\r\n                _initSafe634('brancherSelectionTarif612', () => _g.brancherSelectionTarif612());\r\n                _initSafe634('initAccordeons632',        () => _g.initAccordeons632());\r\n                _initSafe634('centrerChampPays619',      () => _g.centrerChampPays619());\r\n                _initSafe634('brancherContinuerResa628', () => _g.brancherContinuerResa628());\r\n                _initSafe634('majEtapes631',             () => _g.majEtapes631());\r\n                console.log('[pb634] enrichissements regie appliques');\r\n            } else {\r\n                console.log('[pb634] page pays en iframe -> enrichissements regie non appliques');\r\n            }\r\n        }\r\n    }, 100);\r\n}\r\n\r\n\/\/ Ex\u00e9cuter imm\u00e9diatement si DOM d\u00e9j\u00e0 pr\u00eat, sinon attendre\r\nif (document.readyState === 'loading') {\r\n    document.addEventListener('DOMContentLoaded', initGrilleModules);\r\n} else {\r\n    initGrilleModules();\r\n}\r\n\r\n})(); \/\/ Fin de l'auto-ex\u00e9cution\r\n\r\n}); \r\n});\r\n<\/script>\r\n\r\n<style>\r\n.FormHideButton .elementor-button {\r\n    display: none !important;\r\n        transform: scale(0.8);\r\n    transform-origin: top center;\r\n}\r\n\r\n\/* pb685 : popup Tarifs - une valeur SAISIE s'affiche en #3F3F3F ; le placeholder\r\n   reste rouge. La pseudo-classe :placeholder-shown ne matche que si le champ est\r\n   VIDE (donc placeholder visible) : on cible son inverse pour n'atteindre que les\r\n   champs renseignes. Aucun JS n'impose de couleur inline a ces 3 inputs (verifie),\r\n   une regle de feuille suffit donc.\r\n   Prerequis : les 3 champs portent un attribut placeholder. Sans placeholder,\r\n   :placeholder-shown ne matche jamais et la regle s'appliquerait aussi a vide. *\/\r\n#form-field-Nationalite_Societe_Tarifs:not(:placeholder-shown),\r\n#form-field-PopupTarifsDebutCampagne:not(:placeholder-shown),\r\n#form-field-PopupTarifsFinCampagne:not(:placeholder-shown) {\r\n    color: #36c24a !important;\r\n}\r\n\r\n\/* pb686 : couleur du PLACEHOLDER = couleur du titre de l'etape correspondante,\r\n   qui varie (gris #808080 inactif \/ rouge #fb5e2a actif, cf majEtapes631).\r\n   ::placeholder n'est pas adressable en style inline : on la pilote par une\r\n   variable CSS posee sur l'input par majEtapes631. Repli sur le rouge actif si\r\n   la variable n'est pas encore renseignee (premier rendu).\r\n   Le doublon -webkit- couvre les Safari\/iOS anciens qui ignorent ::placeholder. *\/\r\n#form-field-Nationalite_Societe_Tarifs::placeholder,\r\n#form-field-PopupTarifsDebutCampagne::placeholder,\r\n#form-field-PopupTarifsFinCampagne::placeholder {\r\n    color: var(--via686-ph, #fb5e2a) !important;\r\n    opacity: 1 !important;\r\n}\r\n#form-field-Nationalite_Societe_Tarifs::-webkit-input-placeholder,\r\n#form-field-PopupTarifsDebutCampagne::-webkit-input-placeholder,\r\n#form-field-PopupTarifsFinCampagne::-webkit-input-placeholder {\r\n    color: var(--via686-ph, #fb5e2a) !important;\r\n    opacity: 1 !important;\r\n}\r\n<\/style>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <!-- Pop-up 4 -->\r\n    <div id=\"popup4\" class=\"popup-container\">\r\n        <div class=\"handle\">\r\n            Conditions G\u00e9n\u00e9rales de Vente\r\n            <div class=\"handle-icon-container\">\r\n                <div class=\"handle-icon\" onclick=\"closePopup('popup4')\"><img decoding=\"async\" src=\"https:\/\/via-agency.media\/wp-content\/uploads\/2024\/07\/Croix-retour-HP-fond-transparent.webp\" class=\"handle-icon\"><\/div>\r\n            <\/div>\r\n        <\/div>\r\n        <div class=\"popup-content\">\r\n            \t\t<div data-elementor-type=\"page\" data-elementor-id=\"210731\" class=\"elementor elementor-210731\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1585357f e-con-full e-flex e-con e-parent\" data-id=\"1585357f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1becf802 e-con-full e-flex e-con e-child\" data-id=\"1becf802\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-a55fa3d e-con-full elementor-hidden-desktop e-flex e-con e-child\" data-id=\"a55fa3d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d727924 RedactionnelsCloseButton elementor-widget elementor-widget-image\" data-id=\"d727924\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"#\">\n\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Croix-retour-HP-fond-blanc-qvbkx47v2z3t147hgkk8f1cj4fvm32efrhdzz4ckuy.jpg\" title=\"\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5353818a elementor-widget elementor-widget-text-editor\" data-id=\"5353818a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><style>.elementor-340126 .elementor-element.elementor-element-6b676e3{--display:flex;--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-607b2be{--display:flex;}.elementor-340126 .elementor-element.elementor-element-8075754{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-widget-text-editor{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );color:var( --e-global-color-text );}.elementor-widget-text-editor.elementor-drop-cap-view-stacked .elementor-drop-cap{background-color:var( --e-global-color-primary );}.elementor-widget-text-editor.elementor-drop-cap-view-framed .elementor-drop-cap, .elementor-widget-text-editor.elementor-drop-cap-view-default .elementor-drop-cap{color:var( --e-global-color-primary );border-color:var( --e-global-color-primary );}.elementor-340126 .elementor-element.elementor-element-1066fd0{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-cbec13b{--display:flex;}.elementor-340126 .elementor-element.elementor-element-1c4da91{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-9a350a9{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-e83cb97{--display:flex;}.elementor-340126 .elementor-element.elementor-element-d077826{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-4625b0f{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-234ac91{--display:flex;}.elementor-340126 .elementor-element.elementor-element-aa383e4{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-14a9bb8{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-ee5e789{--display:flex;}.elementor-340126 .elementor-element.elementor-element-abf7c94{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-e280ef4{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-6a66782{--display:flex;}.elementor-340126 .elementor-element.elementor-element-517fcb4{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-5ba390c{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-433e675{--display:flex;}.elementor-340126 .elementor-element.elementor-element-57e56f4{--display:flex;--flex-direction:column;--container-widget-width:100%;--container-widget-height:initial;--container-widget-flex-grow:0;--container-widget-align-self:initial;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-434400a{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-5b83d2b{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:10px;font-weight:600;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-5b83d2b > .elementor-widget-container{margin:-14px 0px 0px 0px;}.elementor-340126 .elementor-element.elementor-element-bf06426{--display:flex;--flex-direction:column;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:initial;--container-widget-flex-grow:0;--container-widget-align-self:initial;--flex-wrap-mobile:wrap;--align-items:flex-start;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-10px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-bf06426:not(.elementor-motion-effects-element-type-background), .elementor-340126 .elementor-element.elementor-element-bf06426 > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#FFFFFF;}.elementor-340126 .elementor-element.elementor-element-bf06426.e-con{--align-self:center;}.elementor-widget-image .widget-image-caption{color:var( --e-global-color-text );font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-340126 .elementor-element.elementor-element-c9d2ab7{font-family:\"Roboto\", Sans-serif;font-size:7.5px;font-weight:600;color:#213864;}.elementor-340126 .elementor-element.elementor-element-c9d2ab7 > .elementor-widget-container{margin:10px 0px -10px 0px;}.elementor-340126 .elementor-element.elementor-element-92e4e7e{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-92e4e7e > .elementor-widget-container{margin:20px 0px 0px 0px;}.elementor-340126 .elementor-element.elementor-element-107cd8e{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:10px;font-weight:600;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-107cd8e > .elementor-widget-container{margin:-14px 0px 0px 0px;}.elementor-340126 .elementor-element.elementor-element-9e331c2{--display:flex;--flex-direction:column;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:initial;--container-widget-flex-grow:0;--container-widget-align-self:initial;--flex-wrap-mobile:wrap;--align-items:flex-start;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-10px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-9e331c2:not(.elementor-motion-effects-element-type-background), .elementor-340126 .elementor-element.elementor-element-9e331c2 > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#FFFFFF;}.elementor-340126 .elementor-element.elementor-element-9e331c2.e-con{--align-self:center;}.elementor-340126 .elementor-element.elementor-element-4f74c43{font-family:\"Roboto\", Sans-serif;font-size:7.5px;font-weight:600;color:#213864;}.elementor-340126 .elementor-element.elementor-element-4f74c43 > .elementor-widget-container{margin:10px 0px -10px 0px;}.elementor-340126 .elementor-element.elementor-element-2352ad4{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-2352ad4 > .elementor-widget-container{margin:15px 0px 0px 0px;}.elementor-340126 .elementor-element.elementor-element-3ddbdf9{--display:flex;}.elementor-340126 .elementor-element.elementor-element-62605a4{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-42d9123{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-3b5a5b5{--display:flex;}.elementor-340126 .elementor-element.elementor-element-38d1215{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-6036f40{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-5f48a74{--display:flex;}.elementor-340126 .elementor-element.elementor-element-472c12d{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-6e6378e{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-b5a7f29{--display:flex;}.elementor-340126 .elementor-element.elementor-element-1b3ef16{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-64c23b9{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-c36c44a{--display:flex;}.elementor-340126 .elementor-element.elementor-element-016f268{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-a11e24c{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-c569cfe{--display:flex;}.elementor-340126 .elementor-element.elementor-element-59441dc{--display:flex;--flex-direction:row;--container-widget-width:initial;--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-51f0c59{text-align:justify;font-family:\"Roboto\", Sans-serif;font-size:11px;font-weight:400;line-height:1.1em;color:#3D3D3D;}.elementor-340126 .elementor-element.elementor-element-8a6f578{--n-accordion-title-icon-order:-1;--n-accordion-title-font-size:12px;--n-accordion-item-title-space-between:5px;--n-accordion-item-title-distance-from-content:0px;--n-accordion-border-radius:0px 0px 0px 0px;--n-accordion-title-normal-color:#225DA9;--n-accordion-title-hover-color:#225DA9;--n-accordion-title-active-color:#225DA9;--n-accordion-icon-size:15px;width:100%;max-width:100%;}.elementor-340126 .elementor-element.elementor-element-8a6f578 > .elementor-widget-container > .e-n-accordion > .e-n-accordion-item > .e-n-accordion-item-title{border-style:none;}.elementor-340126 .elementor-element.elementor-element-8a6f578 {--n-accordion-padding:0px 0px 0px 0px;}:where( .elementor-340126 .elementor-element.elementor-element-8a6f578 > .elementor-widget-container > .e-n-accordion > .e-n-accordion-item > .e-n-accordion-item-title > .e-n-accordion-item-title-header ) > .e-n-accordion-item-title-text{font-weight:600;}:where( .elementor-340126 .elementor-element.elementor-element-8a6f578 > .elementor-widget-container > .e-n-accordion > .e-n-accordion-item ) > .e-con{border-style:none;--border-radius:0px 0px 0px 0px;--padding-top:0px;--padding-right:0px;--padding-bottom:0px;--padding-left:0px;}@media(max-width:1001px){.elementor-340126 .elementor-element.elementor-element-c9d2ab7 > .elementor-widget-container{margin:5px 0px -5px 0px;}.elementor-340126 .elementor-element.elementor-element-4f74c43 > .elementor-widget-container{margin:5px 0px -5px 0px;}}@media(min-width:1001px){.elementor-340126 .elementor-element.elementor-element-8075754{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-1c4da91{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-d077826{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-aa383e4{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-abf7c94{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-517fcb4{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-57e56f4{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-bf06426{--width:100%;}.elementor-340126 .elementor-element.elementor-element-9e331c2{--width:100%;}.elementor-340126 .elementor-element.elementor-element-62605a4{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-38d1215{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-472c12d{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-1b3ef16{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-016f268{--content-width:100%;}.elementor-340126 .elementor-element.elementor-element-59441dc{--content-width:100%;}}@media(max-width:1000px){.elementor-340126 .elementor-element.elementor-element-1066fd0{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-9a350a9{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-4625b0f{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-14a9bb8{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-e280ef4{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-5ba390c{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-434400a{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-5b83d2b{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-bf06426{--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-c9d2ab7 > .elementor-widget-container{margin:5px 0px 0px 0px;}.elementor-340126 .elementor-element.elementor-element-92e4e7e{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-107cd8e{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-9e331c2{--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-340126 .elementor-element.elementor-element-4f74c43 > .elementor-widget-container{margin:5px 0px 0px 0px;}.elementor-340126 .elementor-element.elementor-element-2352ad4{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-42d9123{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-6036f40{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-6e6378e{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-64c23b9{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-a11e24c{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-51f0c59{font-size:10px;}.elementor-340126 .elementor-element.elementor-element-8a6f578{--n-accordion-title-font-size:10px;}.elementor-340126 .elementor-element.elementor-element-8a6f578 > .elementor-widget-container{margin:-50px 0px 0px 0px;padding:0px 0px 0px 0px;}}\/* Start custom CSS for nested-accordion, class: .elementor-element-8a6f578 *\/\/* Change closed icon (currently fa-plus) *\/\r\n.elementor-340126 .elementor-element.elementor-element-8a6f578 .e-n-accordion-item-title-icon .e-closed i {\r\n    font-family: \"Font Awesome 5 Free\" !important;\r\n}\r\n\r\n.elementor-340126 .elementor-element.elementor-element-8a6f578 .e-n-accordion-item-title-icon .e-closed i:before {\r\n    content: \"\\f078\" !important; \/* Chevron down *\/\r\n}\r\n\r\n\/* Change opened icon (currently fa-minus) *\/\r\n.elementor-340126 .elementor-element.elementor-element-8a6f578 .e-n-accordion-item-title-icon .e-opened i:before {\r\n    content: \"\\f077\" !important; \/* Chevron up *\/\r\n}\/* End custom CSS *\/<\/style>\t\t<div data-elementor-type=\"loop-item\" data-elementor-id=\"340126\" class=\"elementor elementor-340126 elementor-bc-flex-widget e-loop-item e-loop-item-218790 post-218790 page type-page status-publish has-post-thumbnail\" data-elementor-post-type=\"elementor_library\" data-custom-edit-handle=\"1\">\n\t\t\t<div class=\"elementor-element elementor-element-6b676e3 e-flex e-con-boxed e-con e-parent\" data-id=\"6b676e3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8a6f578 elementor-widget__width-inherit elementor-widget elementor-widget-n-accordion\" data-id=\"8a6f578\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;default_state&quot;:&quot;all_collapsed&quot;,&quot;n_accordion_animation_duration&quot;:{&quot;unit&quot;:&quot;ms&quot;,&quot;size&quot;:300,&quot;sizes&quot;:[]},&quot;max_items_expended&quot;:&quot;one&quot;}\" data-widget_type=\"nested-accordion.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"e-n-accordion\" aria-label=\"Accordion. Open links with Enter or Space, close with Escape, and navigate with Arrow Keys\">\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1450\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"1\" tabindex=\"0\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1450\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 1. Cadre des CGV <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1450\" class=\"elementor-element elementor-element-607b2be e-con-full e-flex e-con e-child\" data-id=\"607b2be\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1450\" class=\"elementor-element elementor-element-8075754 e-flex e-con-boxed e-con e-child\" data-id=\"8075754\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1066fd0 elementor-widget elementor-widget-text-editor\" data-id=\"1066fd0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong>1.1. Cadre g\u00e9n\u00e9ral des CGV<\/strong>. Les pr\u00e9sentes conditions g\u00e9n\u00e9rales de vente (CGV) constituent, conform\u00e9ment, \u00e0 l\u2019article L. 441-1 du code du commerce en droit Fran\u00e7ais, le socle unique de la relation commerciale entre les parties. Elles ont pour objet de d\u00e9finir les conditions dans lesquelles Via Agency nomm\u00e9 parfois \u00ab\u00a0Via Agency Media\u00a0\u00bb (marque d\u00e9pos\u00e9e) ou encore \u201cLe Prestataire\u201d fournit aux Clients professionnels et institutionnels parfois nomm\u00e9s \u201cLe Client\u00a0\u00bb ou \u00ab\u00a0Les Clients\u201d les services suivants :<br \/>\u2013 Vente d\u2019espaces publicitaires sur des emplacements d\u00e9di\u00e9s via des sites web et\/ou par impression sur tous supports, dont entre autre papier et num\u00e9rique.<br \/>La commercialisation des espaces publicitaires est r\u00e9alis\u00e9e par tous moyens tels que les sites web, \u00a0Email, SMS, t\u00e9l\u00e9phone, visioconf\u00e9rence, en pr\u00e9sentiel et par tout autre moyen.<br \/>\u2013 Conseil en communication, afin d\u2019accompagner et d\u2019assister les clients \u00e0 la mise en \u0153uvre de la conception et \u00e0 la r\u00e9alisation de supports publicitaires et\/ou \u00e0 la conception, l\u2019assistance, la mise en \u0153uvre et \/ou au suivi des campagnes publicitaires.<br \/>\u2013 mise en \u0153uvre de r\u00e9dactionnels, (articles, communiqu\u00e9s, interviews, parrainages, etc.).<br \/>\u2013 mise en \u0153uvre de visuels, (graphisme, vid\u00e9o, etc.).<br \/>Les sites web mis en \u0153uvre par Via Agency et d\u00e9crits ci-apr\u00e8s permettent entre autres de commercialiser des espaces publicitaires\u00a0: via-agency.media, yearbook-media.com, afrique.yearbook-media.com, cameroun.yearbook-media.com, congo.yearbook-media.com, gabon.yearbook-media.com, madagascar.yearbook-media.com, rdc.yearbook-media.com, togo.yearbook-media.com, cette liste n\u2019est pas limitative.<br \/>Les services et activit\u00e9s de conseil en communication, de cr\u00e9ation de contenus r\u00e9dactionnels, de visuels, les qualifications des prestations, les d\u00e9lais de r\u00e9alisation, les services rendus et les modalit\u00e9s paiements font l\u2019objet d\u2019\u00e9changes entre d\u2019une part le Prestataire (ses repr\u00e9sentants, ses sous-traitants ou ses mandataires) et d\u2019autre part les clients sous forme d\u2019Emails, sms, r\u00e9unions t\u00e9l\u00e9phoniques, visio conf\u00e9rences, r\u00e9union en pr\u00e9sentiel, etc., et sont d\u00e9crits dans les contrats liants les parties et\/ou dans les bons de commande, enfin par des factures envoy\u00e9es par le Prestataire apr\u00e8s le ou les paiements des prestations\u00a0de Services.<br \/><strong>1.2. Etendue des CGV.\u00a0<\/strong>Les pr\u00e9sentes Conditions G\u00e9n\u00e9rales de Vente\u00a0s\u2019appliquent, sans restriction ni r\u00e9serve, \u00e0 tous les Services rendus par le Prestataire aupr\u00e8s des Clients de m\u00eame cat\u00e9gorie, quelles que soient les clauses pouvant figurer sur les documents du Client, et notamment ses conditions g\u00e9n\u00e9rales\u00a0d\u2019achat.\u00a0<br \/>Les CGV sont accessibles sur le pr\u00e9sent site et sur les autres sites du Prestataire et sont communicables \u00e0 tout Client qui en fait la demande. Toute commande de Services implique, de la part du Client, l\u2019acceptation des pr\u00e9sentes Conditions G\u00e9n\u00e9rales de Vente. Les renseignements figurant sur les sites web du Prestataire ainsi que les propositions commerciales propos\u00e9s par voie \u00e9lectronique (email, messagerie, visioconf\u00e9rence, etc.), par t\u00e9l\u00e9phone, sur support print, ou en rendez-vous commerciaux sont donn\u00e9es pour une dur\u00e9e d\u00e9termin\u00e9e et sont r\u00e9visables par le Prestataire. Le Prestataire est en droit d\u2019y apporter \u00e0 tout moment, toutes modifications qui s\u2019inscrivent dans le cadre l\u00e9gal et r\u00e9glementaire. Les contrats et\/ou les bons de commande fixe les modalit\u00e9s d&rsquo;ex\u00e9cution des prestations et les prix.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1451\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"2\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1451\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 2. Prestations, bon de commande &amp; facture <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1451\" class=\"elementor-element elementor-element-cbec13b e-con-full e-flex e-con e-child\" data-id=\"cbec13b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1451\" class=\"elementor-element elementor-element-1c4da91 e-flex e-con-boxed e-con e-child\" data-id=\"1c4da91\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9a350a9 elementor-widget elementor-widget-text-editor\" data-id=\"9a350a9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong>2.1. Les prestations.<\/strong> Les prestations de vente d\u2018espaces publicitaires, d\u2019activit\u00e9 de conseil en communication, de cr\u00e9ation de r\u00e9dactionnels et de visuels, sont consid\u00e9r\u00e9s comme parfaites qu\u2019apr\u00e8s \u00e9tablissement et la signature d\u2019un contrat et\/ou l\u2019\u00e9tablissement d\u2019un bon de commande accept\u00e9 par le client et \/ou par le r\u00e8glement de tout ou partie de la prestation, l\u2019un ou plusieurs de ces \u00e9l\u00e9ments vaut acceptation par le Client de la prestation propos\u00e9e.<br \/>Le Prestataire dispose de moyens \u00e9lectroniques pour \u00e9tablir des bons de commande en fonction des choix des clients (y compris d\u2019acceptation et de confirmation des commandes). Les clients peuvent acheter des espaces publicitaires sur les sites du Prestataire dans les meilleures conditions possibles de commodit\u00e9 et de rapidit\u00e9.<br \/>Pour les commandes pass\u00e9es par les clients sur les sites internet du prestataire, les commandes sont consid\u00e9r\u00e9es comme d\u00e9finitives lorsqu\u2019un client valide sa ou ses commandes. Le Client a la possibilit\u00e9 de v\u00e9rifier le d\u00e9tail de sa commande, son prix total et de corriger d\u2019\u00e9ventuelles erreurs avant de confirmer son acceptation (article 1127-2 du code civil fran\u00e7ais). Cette validation implique l\u2019acceptation de l\u2019int\u00e9gralit\u00e9 des pr\u00e9sentes Conditions g\u00e9n\u00e9rales de vente et constitue une preuve du contrat de vente.<br \/><strong>2.2. Bons de commande et factures. <\/strong>Apr\u00e8s commandes par les Clients, Via Agency leur adresse les bons de commande par email, aussi les adresses mail doivent \u00eatre obligatoirement et parfaitement renseign\u00e9es par les Clients, en cas d&rsquo;erreur dans d&rsquo;adresse mail, Via Agency d\u00e9cline toute responsabilit\u00e9 et le bon de commande n&rsquo;a pas de validit\u00e9. Les bons de commande doivent \u00eatre r\u00e9gl\u00e9s par les Clients sous 15 jours, au del\u00e0 de ce terme Via Agency se r\u00e9serve le droit d&rsquo;annuler les bons de commande sans que les Clients ne puissent demander une quelconque indemnisation ou compensation.<br \/>Aucun escompte ne sera pratiqu\u00e9 par le Prestataire pour paiement avant la date figurant sur la facture ou dans un d\u00e9lai inf\u00e9rieur \u00e0 celui mentionn\u00e9 aux pr\u00e9sentes Conditions g\u00e9n\u00e9rales de vente.<br \/>Via Agency adresse aux Clients les factures par email, les adresses mail doivent \u00eatre obligatoirement et parfaitement renseign\u00e9es par les Clients, en cas d&rsquo;erreur dans d&rsquo;adresse mail, Via Agency d\u00e9cline toute responsabilit\u00e9. Les factures sont \u00e9mises par Via Agency apr\u00e8s paiements par le Client. Dans le cas de paiement en plusieurs \u00e9ch\u00e9ance, une facture est \u00e9mise par \u00e9ch\u00e9ance r\u00e9gl\u00e9e, puis apr\u00e8s le paiement de la derni\u00e8re \u00e9ch\u00e9ance, une facture r\u00e9capitulative est transmise par mail au Client.<br \/>Par ailleurs les bons de commande et les factures peuvent \u00eatre t\u00e9l\u00e9charg\u00e9s \u00e0 partir des comptes Clients si les comptes ont \u00e9t\u00e9 cr\u00e9es par les Clients avant la date de cr\u00e9ation et d&rsquo;\u00e9mission des bons de commande et des factures par Via Agency.<br \/>Les donn\u00e9es enregistr\u00e9es dans le syst\u00e8me informatique du Prestataire constituent la preuve de l\u2019ensemble des informations fournies par le Client et des transactions commerciales (bons de commande et factures) conclues avec le Client.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1452\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"3\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1452\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 3. Publication et cadre l\u00e9gal <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1452\" class=\"elementor-element elementor-element-e83cb97 e-con-full e-flex e-con e-child\" data-id=\"e83cb97\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1452\" class=\"elementor-element elementor-element-d077826 e-flex e-con-boxed e-con e-child\" data-id=\"d077826\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4625b0f elementor-widget elementor-widget-text-editor\" data-id=\"4625b0f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong>3.1. Cadre g\u00e9n\u00e9ral<\/strong>. L&rsquo;ensemble des annonces et les \u00e9l\u00e9ments qui composent les annonces (entre autres images, vid\u00e9os,\u00a0 textes, sons, etc.) doivent respecter la l\u00e9gislation fran\u00e7aise.<br \/><strong>3.2. Publication et non publication d&rsquo;annonces<\/strong>. La direction et\/ou la r\u00e9daction de Via Agency se r\u00e9serve le droit de ne pas publier des annonces qui ne respectent pas la l\u00e9gislation en vigueur et\/ou les sp\u00e9cifications techniques \u00e9tablies par Via Agency et\/ou qui seraient pr\u00e9judiciables aux pays faisant l&rsquo;objet d&rsquo;un Yearbook Rapport \u00c9conomique et\/ou qui seraient pr\u00e9judiciables aux annonceurs et\/ou qui seraient pr\u00e9judiciables \u00e0 la soci\u00e9t\u00e9 Via Agency.<br \/><strong>3.3. Annonces et propri\u00e9t\u00e9 intellectuelle<\/strong>. En acceptant les Conditions G\u00e9n\u00e9rales de Vente, le Client s\u2019engage \u00e0 disposer de l\u2019int\u00e9gralit\u00e9 des droits de propri\u00e9t\u00e9 intellectuelle (dont droits \u00e0 l\u2019image et droits d&rsquo;auteurs) sur les \u00e9l\u00e9ments n\u00e9cessaires \u00e0 l\u2019ex\u00e9cution des prestations, \u00e0 les transmettre au Prestataire et \u00e0 les garantir pendant toute la dur\u00e9e de l\u2019ex\u00e9cution des prestations \u00e0 laquelle s\u2019ajoute un d\u00e9lais de 6 mois suppl\u00e9mentaire afin de r\u00e9aliser le traitement administratif et technique li\u00e9 \u00e0 la suppression des \u00e9l\u00e9ments.\u00a0 <br \/>D\u00e8s lors, la responsabilit\u00e9 de la soci\u00e9t\u00e9 Via Agency ne pourra en aucun cas \u00eatre recherch\u00e9e du fait de la reproduction et de la diffusion de l\u2019annonce, cela sur tout support appartenant \u00e0 Via Agency et ce pendant toute la dur\u00e9e de sa reproduction et de sa diffusion plus six mois.<br \/><strong>3.4. Cr\u00e9ations de Via Agency et propri\u00e9t\u00e9 intellectuelle. <\/strong>Via Agency est propri\u00e9taire des droits de propri\u00e9t\u00e9 intellectuelle des cr\u00e9ations et r\u00e9alisations des \u00e9tudes, dessins, mod\u00e8les, prototypes, etc., r\u00e9alis\u00e9s (m\u00eame \u00e0 la demande du Client) en vue de la Fourniture des Services au Client. Le Client s\u2019interdit donc toute reproduction ou exploitation desdites \u00e9tudes, dessins, mod\u00e8les et prototypes, etc., sans l\u2019autorisation expresse, \u00e9crite et pr\u00e9alable du Prestataire qui peut la conditionner \u00e0 une contrepartie financi\u00e8re en suppl\u00e9ment du paiement de la prestation de publication d\u2019annonce.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1453\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"4\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1453\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 4. Espaces publicitaires <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1453\" class=\"elementor-element elementor-element-234ac91 e-con-full e-flex e-con e-child\" data-id=\"234ac91\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1453\" class=\"elementor-element elementor-element-aa383e4 e-flex e-con-boxed e-con e-child\" data-id=\"aa383e4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-14a9bb8 elementor-widget elementor-widget-text-editor\" data-id=\"14a9bb8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong>4.1. Espaces publicitaires.<\/strong> A partir du site de r\u00e9gie publicitaire yearbook-media.com, du site Via Agency Media (acc\u00e8s par l\u2019intitul\u00e9 \u00ab Achat d\u2019espaces publicitaires \u00bb) et par les diff\u00e9rents sites pays (acc\u00e8s par une pastille de couleur dor\u00e9e) les annonceurs ont acc\u00e8s aux fonctionnalit\u00e9s d\u2019achats d\u2019espaces publicitaires (repr\u00e9sent\u00e9s par des aplats bleus clairs).<br \/><strong>4.2. Types d&rsquo;espaces publicitaires. <\/strong>Sur l\u2019ensemble des pages des sites web propos\u00e9s, Il existe deux types d\u2019espaces publicitaires, des espaces publicitaires fixes et par page web un ou plusieurs espaces publicitaires pop up, (voir la description des caract\u00e9ristiques des pop-ups au point 5.4.).<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1454\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"5\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1454\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 5. Cr\u00e9ation et\/ou transmission d&rsquo;annonces <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1454\" class=\"elementor-element elementor-element-ee5e789 e-con-full e-flex e-con e-child\" data-id=\"ee5e789\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1454\" class=\"elementor-element elementor-element-abf7c94 e-flex e-con-boxed e-con e-child\" data-id=\"abf7c94\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e280ef4 elementor-widget elementor-widget-text-editor\" data-id=\"e280ef4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong>5.1. Cr\u00e9ation d\u2019annonces. <\/strong>Via Agency propose la possibilit\u00e9 de cr\u00e9ation d\u2019annonce \u00e0 partir des sites pays et de la r\u00e9gie yearbook-media.com. Les annonces doivent \u00eatre gliss\u00e9es d\u00e9pos\u00e9es ou t\u00e9l\u00e9charg\u00e9es dans les espaces publicitaires d\u00e9di\u00e9s. La cr\u00e9ation d&rsquo;annonc\u00e9es sur les sites n&rsquo;engage aucunement la responsabilit\u00e9s de Via Agency.<br \/><strong>5.2.<\/strong> <strong>Transmission<\/strong> <strong>des annonces. <\/strong>Les annonces cr\u00e9es et\/ou transmises \u00e0 Via Agency, sous format de visuels et\/ou de r\u00e9dactionnels doivent \u00eatre conformes \u00e0 la l\u00e9gislation en vigueur et correspondre aux sp\u00e9cifications d\u00e9crites ci-apr\u00e8s pour \u00eatre publi\u00e9es sous r\u00e9serve de la validation par Via Agency sur les sites de Via Agency. La publication par Via Agency vaut acceptation, dans le cas contraire un email pourrait \u00e9ventuellement \u00eatre envoy\u00e9 \u00e0 l&rsquo;annonceur par Via Agency, dans tous les cas si sous deux semaines l&rsquo;annonce n&rsquo;est pas publi\u00e9e cela \u00e9quivaut \u00e0 un refus de publication de Via Agency li\u00e9 au non respect de crit\u00e8res techniques et\/ou juridiques, dans ce cas de figure aucun remboursement total ou partiel ne pourra \u00eatre demand\u00e9 par un tiers (prospect, annonceur, client public ou priv\u00e9 et\/ou repr\u00e9sentant d&rsquo;un tiers, etc.).<br \/><strong>5.3. Sp\u00e9cifications et formats des annonces<br \/><\/strong><strong>Vid\u00e9o<\/strong>. 16\/9, dimensions proportionnelles ou autres dimensions, vid\u00e9os aux formats .mp4 .mov .webm. Dur\u00e9e maximale 30 sec. Taille maximale 2 Mo<br \/><strong>Banni\u00e8res<\/strong>. 970x250px ou 300x250px (ou dimensions proportionnelles). Banni\u00e8res fixes au format .jpeg .png, taille maximale 150 Ko. Banni\u00e8res anim\u00e9s au format .gif, taille maximale 150 Ko<br \/><strong>Communiqu\u00e9s<\/strong>. Documents comprenant des visuels et des textes. Communiqu\u00e9s aux formats .docx .doc .pdf. Taille maximale 400 Ko<br \/><strong>Interviews<\/strong>. Documents comprenant des visuels et des textes. Interviews aux formats .docx .doc .pdf. Taille maximale 400 Ko<br \/><strong>Parrainages<\/strong>. Le texte de parrainage comprend le nom de la soci\u00e9t\u00e9 et\/ou la marque et\/ou le logo. Le texte comporte un maximum de 4 lignes pour un total de 120 caract\u00e8res dont l&rsquo;expression du parrainage. Le style de police, la taille de caract\u00e8res, les dimensions de logo, les ajustements des diff\u00e9rents \u00e9l\u00e9ments et l&#8217;emplacement d\u00e9finitif sont d\u00e9finis et \u00e9tablis par Via Agency<br \/><strong>5.4.<\/strong> <strong>Les Sp\u00e9cifications des pop up<\/strong>. \u00a0Les sp\u00e9cifications sont les suivantes :<br \/>. Affichage du pop-up \u00e0 l&rsquo;ouverture de la page<br \/>. Possibilit\u00e9 de d\u00e9placer manuellement le pop-up dans la page<br \/>. Le pop-up suit le mouvement de la page web et est toujours visible, il ne peut \u00eatre d\u00e9plac\u00e9 ni masqu\u00e9 hors de la zone visible<br \/>. Le pop-up ne peut \u00eatre referm\u00e9 qu&rsquo;apr\u00e8s 4 secondes en cliquant sur une croix positionn\u00e9e en haut \u00e0 droite de l&rsquo;annonce<br \/>. Les annonces publi\u00e9es dans le pop-up peuvent \u00eatre au format banni\u00e8re, vid\u00e9o, communiqu\u00e9, interview ou parrainage dont les caract\u00e9ristiques sont d\u00e9taill\u00e9es au point 5.3.<br \/>Les sp\u00e9cifications peuvent \u00e9voluer dans le temps selon les d\u00e9cisions de Via Agency.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1455\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"6\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1455\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 6. Ex\u00e9cution de la prestation <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1455\" class=\"elementor-element elementor-element-6a66782 e-con-full e-flex e-con e-child\" data-id=\"6a66782\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1455\" class=\"elementor-element elementor-element-517fcb4 e-flex e-con-boxed e-con e-child\" data-id=\"517fcb4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5ba390c elementor-widget elementor-widget-text-editor\" data-id=\"5ba390c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong>6.1. D\u00e9lais d&rsquo;ex\u00e9cution<\/strong>. L&rsquo;ex\u00e9cution de la prestation est r\u00e9alis\u00e9e \u00e0 partir d&rsquo;un d\u00e9lai de 21 jours. Le d\u00e9lai tient compte\u00a0de la r\u00e9ception par le Prestataire de l\u2019ensemble des \u00e9l\u00e9ments n\u00e9cessaires \u00e0 l\u2019ex\u00e9cution des prestations (les \u00e9l\u00e9ments techniques et administratifs fournis doivent parfaitement correspondre aux caract\u00e9ristiques demand\u00e9es par le Prestataire) et de la r\u00e9ception du paiement de la premi\u00e8re \u00e9ch\u00e9ance de la commande pour les paiements par carte bancaire ou par virement. Le d\u00e9lai de 21 jours ouvr\u00e9s est port\u00e9 \u00e0 30 jours ouvr\u00e9s pour les commandes pass\u00e9es durant les mois de juillet, ao\u00fbt et d\u00e9cembre.<br \/>Ce d\u00e9lai ne constitue pas un d\u00e9lai de rigueur et le Prestataire ne pourra pas voir sa responsabilit\u00e9 engag\u00e9e \u00e0 l\u2019\u00e9gard du Client en cas de retard dans la Fourniture des Services n\u2019exc\u00e9dant pas 30 jours ouvr\u00e9s et 60\u00a0 jours ouvr\u00e9s si les \u00e9l\u00e9ments techniques sont ind\u00e9pendants de\u00a0 Via Agency.<br \/><strong>6.2. Conformit\u00e9 des annonces<\/strong>. Dans le cas de la vente d\u2019espaces publicitaires, un d\u00e9lai d\u2019ex\u00e9cution de la prestation permet notamment au Prestataire de v\u00e9rifier si les textes et visuels transmis par le client sont conformes au cadre juridique en vigueur et aux sp\u00e9cifications techniques (voir point 5.3). Cela permet aussi de v\u00e9rifier si le bar\u00e8me tarifaire s\u00e9lectionn\u00e9 est conforme \u00e0 l&rsquo;annonce transmise. En cas de non-conformit\u00e9, le client peut \u00e9ventuellement \u00eatre inform\u00e9 par email par Via Agency. La non conformit\u00e9 met fin de facto \u00e0 l&rsquo;ex\u00e9cution de la prestation par Via Agency et aucun remboursement total ou partiel ne pourra \u00eatre demand\u00e9 par un tiers (prospect, annonceur, client public ou priv\u00e9 et\/ou repr\u00e9sentant d&rsquo;un tiers, etc.). Le respect de la mise en conformit\u00e9 est de la responsabilit\u00e9 totale et enti\u00e8re du client. Le client accepte express\u00e9ment que le Prestataire puisse modifier les formats, textes et visuels afin de correspondre au cadre juridique en vigueur et aux sp\u00e9cifications techniques. Le Prestataire selon sa seule d\u00e9cision pourra proposer au Client une prestation de mise en conformit\u00e9 qui fera l&rsquo;objet d&rsquo;un devis sp\u00e9cifique. En cas de non conformit\u00e9, la prestation sera annul\u00e9e sur d\u00e9cision unique du Prestataire. Aucun remboursement total ou partiel ne pourra \u00eatre demand\u00e9 par un tiers (prospect, annonceur, client public ou priv\u00e9 et\/ou repr\u00e9sentant d&rsquo;un tiers, etc.) et le Prestataire ne pourra pas voir sa responsabilit\u00e9 engag\u00e9e.<br \/>En acceptant les conditions g\u00e9n\u00e9rales de ventes pr\u00e9sentes, le client s\u2019engage \u00e0 accepter les d\u00e9cisions du Prestataire et d\u00e9gage le prestataire de toute poursuites judiciaires, quelque en soit la juridiction.<br \/><strong>6.3. D\u00e9roulement de la prestation<\/strong>. Les \u00e9l\u00e9ments n\u00e9cessaires \u00e0 l\u2019ex\u00e9cution des prestations de vente d\u2019espaces publicitaires comprennent la s\u00e9lection d\u2019une page du site web permettant d\u2019associer l\u2019annonce \u00e0 une page, l\u2019envoi par le Client d\u2019\u00e9l\u00e9ments techniques conformes aux sp\u00e9cifications d\u00e9crites dans l&rsquo;interface d\u2019achat, le choix d\u2019un format d\u2019annonce, le choix des dates de d\u00e9but et de fin de campagne, et la s\u00e9lection de la nationalit\u00e9 de la soci\u00e9t\u00e9 de l\u2019annonceur. A la demande du client, le Prestataire pourra proposer une prestation de conseil en communication et\/ou de mise en \u0153uvre de r\u00e9dactionnels ou de visuels qui fera l&rsquo;objet d&rsquo;un devis sp\u00e9cifique. Pendant le process d&rsquo;achat le client a la possibilit\u00e9 de choisir l&rsquo;envoi diff\u00e9r\u00e9 de son annonce. Dans ce cas, il pourra transmettre son annonce jusqu&rsquo;\u00e0 8 jours apr\u00e8s paiement via le lien pr\u00e9sent dans le mail d&rsquo;envoi du bon de commande.<br \/>Le client s\u00e9lectionne les dates de d\u00e9but et de fin de ses campagnes ce qui permet de calculer la dur\u00e9e de chaque campagne. Le premier jour de campagne est d\u00e9di\u00e9 \u00e0 la mise en place de la campagne, ce premier jour n&rsquo;est pas comptabilis\u00e9 dans le calcul de la dur\u00e9e. Ainsi par exemple une campagne dont la date de d\u00e9but est J et la date de fin est J+10, a une dur\u00e9e de 10 jours pleins soit de J+1 \u00e0 J+10 inclus.<br \/>Le(s) site(s) internet du Prestataire disposent d\u2019une fonctionnalit\u00e9 de traduction automatique en langue anglaise op\u00e9r\u00e9e par Google Translate. Le Client peut passer commande en utilisant cette fonctionnalit\u00e9 de traduction en anglais. Toutefois, le Client est inform\u00e9 que seul le texte en fran\u00e7ais fera foi en cas de litige.<br \/>Le Client est \u00e9galement inform\u00e9 que le(s) site(s) internet du Prestataire \u00e9voluent : entre autres des intitul\u00e9s, des d\u00e9nominations peuvent \u00eatre modifi\u00e9s, des articles peuvent \u00eatre actualis\u00e9s, etc. Dans tous les cas, le Prestataire met tout en \u0153uvre, avec une obligation de moyens, afin de conserver le niveau des prestations de Services fournies au Client. Le prestataire n\u2019a pas d\u2019obligation de r\u00e9sultat, en cas de non d\u00e9livrance du service, le client se voit proposer un report \u00e0 une autre date de la prestation et\/ou \u00e0 une prestation de substitution, ou enfin un remboursement partiel de la prestation (au prorata temporis).<br \/>Les services propos\u00e9s par le Prestataire d\u00e9pendent du fonctionnement de r\u00e9seaux et services tiers, notamment : infrastructures internet, services d&rsquo;h\u00e9bergement tel que Hostinger ou tout autre h\u00e9bergeur, fournisseur de services de messagerie \u00e9lectronique tel que SMTP2GO ou tout autre fournisseur de service de messagerie \u00e9lectronique, et autres fournisseurs de services. Aussi, la responsabilit\u00e9 du Prestataire ne saurait \u00eatre engag\u00e9e en cas d\u2019indisponibilit\u00e9, de d\u00e9faillance ou de dysfonctionnement imputable \u00e0 ces r\u00e9seaux, h\u00e9bergeurs ou fournisseurs de services. Le Prestataire est tenu d\u2019une obligation de moyens et non de r\u00e9sultat.<br \/>Dans le cas de demande de renseignement ou de d\u00e9faut d\u2019ex\u00e9cution, le client s\u2019adresse au prestataire sur l\u2019adresse mail suivante : contact@via-agency.media. Le Client renseigne parfaitement ses r\u00e9f\u00e9rences, ses coordonn\u00e9es et d\u00e9crit parfaitement le ou les probl\u00e8mes rencontr\u00e9s. Dans le cas contraire, Via Agency peut ne pas faire r\u00e9ponse.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1456\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"7\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1456\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 7. Tarification <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1456\" class=\"elementor-element elementor-element-433e675 e-con-full e-flex e-con e-child\" data-id=\"433e675\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1456\" class=\"elementor-element elementor-element-57e56f4 e-flex e-con-boxed e-con e-child\" data-id=\"57e56f4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-434400a elementor-widget elementor-widget-text-editor\" data-id=\"434400a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Les tarifs et les bar\u00e8mes des prix en vigueur sont disponibles\u00a0dans les espaces d\u2019achat d\u2019espaces publicitaires des sites web du Prestataire. Les tarifs sont fix\u00e9s librement par le Prestataire et \u00e9voluent r\u00e9guli\u00e8rement.<br \/><strong>7.1. Les bar\u00e8mes tarifaires<\/strong>.\u00a0 Afin de favoriser l\u2019accompagnement des pays et la capacit\u00e9 des entreprises \u00e0 communiquer sur les sites du Prestataire, les bar\u00e8mes tarifaires sont adapt\u00e9s aux diff\u00e9rents pays d\u2019implantation des soci\u00e9t\u00e9s selon des crit\u00e8res \u00e9num\u00e9r\u00e9s ci-apr\u00e8s : PIB des pays, PIB\/habitants, Taux de change par rapport \u00e0 l\u2019Euro et au Dollar, nombres de tr\u00e8s grandes entreprises et de soci\u00e9t\u00e9s multinationales du pays. Les sources retenues pour \u00e9tablir la classification des pays et les tarifications sont entre autres l\u2019ONU, La Banque Mondiale, Le FMI, (d&rsquo;autres r\u00e9f\u00e9rences peuvent \u00eatre utilis\u00e9es). Les crit\u00e8res \u00e9num\u00e9r\u00e9s permettent \u00e0 Via Agency d&rsquo;\u00e9tablir deux groupes de pays : le groupe A et le groupe B. Si un pays n&rsquo;est pas attribu\u00e9 \u00e0 un des 2 groupes merci de nous contacter via <a href=\"mailto:contact@via-agency.media\">contact@via-agency.media\u00a0<\/a><br \/>Le groupe A de pays a la grille tarifaire avec des prix \u00a0tr\u00e8s cibl\u00e9s et concurrentiels sur le march\u00e9 et se compose des pays suivants :<br \/>Afrique du Sud, Alg\u00e9rie, Allemagne, Andorre, Arabie saoudite, Argentine, Australie, Autriche, Bahamas, Belgique, Br\u00e9sil, Bulgarie, Canada, Chili, Chine, Colombie, Cor\u00e9e du Sud, Chypre, \u00c9gypte, \u00c9mirats arabes unis (EAU), Espagne, Estonie, \u00c9tats-Unis d&rsquo;Am\u00e9rique (USA), Finlande, France, Gr\u00e8ce, Hong Kong, Hongrie, \u00celes Ca\u00efmans, \u00celes Marshall, Inde, Indon\u00e9sie, Irak, Irlande, Islande, Italie, Isra\u00ebl, Japon, Kazakhstan, Kowe\u00eft, Lettonie, Liechtenstein, Lituanie, Luxembourg, Malaisie, Maroc, Mexique, Monaco, Mont\u00e9n\u00e9gro, Nigeria, Norv\u00e8ge, Nouvelle-Z\u00e9lande, Pays-Bas, P\u00e9rou, Philippines, Pologne, Porto Rico, Portugal, Qatar, R\u00e9publique tch\u00e8que, Roumanie, Royaume-Uni, Russie, Singapour, Slovaquie, Slov\u00e9nie, Su\u00e8de, Suisse, Tha\u00eflande, Taiwan, Tunisie, Vietnam.<\/p><p style=\"text-align: center;\"><strong>Pays du groupe A &#8211; Tarifs de 1er jour de campagne<\/strong><\/p>\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-5b83d2b elementor-widget elementor-widget-text-editor\" data-id=\"5b83d2b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Tarif d\u00e9gressif de 0.5% \u00e0 partir du 8e jour de campagne<br \/>Dur\u00e9e minimale de campagne de 7 jours<br \/>Dur\u00e9e maximale de campagne de 200 jours<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1456\" class=\"elementor-element elementor-element-bf06426 e-con-full e-flex e-con e-child\" data-id=\"bf06426\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e9d54d7 elementor-widget elementor-widget-image\" data-id=\"e9d54d7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/via-agency.media\/wp-content\/uploads\/2024\/05\/Tarif-GA-210726-V2.jpg\" title=\"\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-c9d2ab7 elementor-widget elementor-widget-text-editor\" data-id=\"c9d2ab7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Home P. : Home page<br \/>Autres P. : Autres Pages (th\u00e8mes, secteurs et articles)<br \/>hdp : position d&rsquo;une annonce en haut de page sur l&rsquo;un des deux 1er rangs d&rsquo;espaces publicitaires<br \/>cdp : position d&rsquo;une annonce en corps de page \u00e0 partir du 3e rang d&rsquo;espaces publicitaires<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-92e4e7e elementor-widget elementor-widget-text-editor\" data-id=\"92e4e7e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Le groupe B de pays a une grille tarifaire avec des prix r\u00e9duits et se compose des pays suivants :<br \/>Afghanistan,\u00a0 Albanie, Angola, Antigua-et-Barbuda, Arm\u00e9nie, Aruba, Azerba\u00efdjan, Bahre\u00efn, Bangladesh, Barbade, Belize, B\u00e9nin, Bermudes, Bhoutan, Bi\u00e9lorussie, Birmanie, Bolivie, Bosnie-Herz\u00e9govine, Botswana, Brunei, Burkina Faso, Burundi, Cambodge, Cameroun, Cap-Vert, Comores, Costa Rica, C\u00f4te d&rsquo;Ivoire, Croatie, Cura\u00e7ao, Djibouti, Dominique, \u00c9quateur, \u00c9rythr\u00e9e, Eswatini, \u00c9thiopie, Fidji, Gabon, Gambie, G\u00e9orgie, Ghana, Grenade, Guatemala, Guin\u00e9e, Guin\u00e9e \u00e9quatoriale, Guin\u00e9e-Bissau, Guyana, Ha\u00efti, Honduras, Jama\u00efque, Jordanie, Kenya, Kirghizistan, Kiribati, Kosovo, Laos, Lesotho, Liban, Libye, Macao, Mac\u00e9doine du Nord, Madagascar, Malawi, Maldives, Mali, Malte, Maurice, Mauritanie, Micron\u00e9sie, Moldavie, Mongolie, Mozambique, Myanmar, Namibie, Nauru, N\u00e9pal, Nicaragua, Niger, Oman, Ouganda, Ouzb\u00e9kistan, Pakistan, Palaos, Panama, Papouasie-Nouvelle-Guin\u00e9e, Paraguay, R\u00e9publique centrafricaine, R\u00e9publique d\u00e9mocratique du Congo (RDC), R\u00e9publique dominicaine, R\u00e9publique du Congo, Rwanda, Saint-Christophe-et-Ni\u00e9v\u00e8s, Sainte-Lucie, Saint-Marin, Saint-Martin (Pays-Bas), Saint-Vincent-et-les-Grenadines, Salomon, Salvador, Samoa, Sao Tom\u00e9-et-Principe, S\u00e9n\u00e9gal, Serbie, Seychelles, Sierra Leone, Soudan, Soudan du Sud, Sri Lanka, Suriname, Tadjikistan, Tanzanie, Tchad, Timor oriental, Togo, Tonga, Trinit\u00e9-et-Tobago, Turkm\u00e9nistan, Tuvalu, Uganda, Ukraine , Uruguay, Vanuatu, Venezuela, Y\u00e9men, Zambie, Zimbabwe.<\/p><p style=\"text-align: center;\"><strong>Pays du groupe B &#8211; Tarifs de 1er jour de campagne<\/strong><\/p>\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-107cd8e elementor-widget elementor-widget-text-editor\" data-id=\"107cd8e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Tarif d\u00e9gressif de 0.5% \u00e0 partir du 8e jour de campagne<br \/>Dur\u00e9e minimale de campagne de 7 jours<br \/>Dur\u00e9e maximale de campagne de 200 jours<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1456\" class=\"elementor-element elementor-element-9e331c2 e-con-full e-flex e-con e-child\" data-id=\"9e331c2\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5cb5c22 elementor-widget elementor-widget-image\" data-id=\"5cb5c22\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/via-agency.media\/wp-content\/uploads\/2024\/05\/Tarif-GB-210726-V2.jpg\" title=\"\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\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-4f74c43 elementor-widget elementor-widget-text-editor\" data-id=\"4f74c43\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Home P. : Home page<br \/>Autres P. : Autres Pages (th\u00e8mes, secteurs et articles)<br \/>hdp : position d&rsquo;une annonce en haut de page sur l&rsquo;un des deux 1er rangs d&rsquo;espaces publicitaires<br \/>cdp : position d&rsquo;une annonce en corps de page \u00e0 partir du 3e rang d&rsquo;espaces publicitaires<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2352ad4 elementor-widget elementor-widget-text-editor\" data-id=\"2352ad4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"border: none; mso-padding-alt: 31.0pt 31.0pt 31.0pt 31.0pt; mso-border-shadow: yes;\"><b><span style=\"color: black;\">7.2. D\u00e9gressivit\u00e9 du tarif journalier.<span style=\"mso-spacerun: yes;\">\u00a0 <\/span><\/span><\/b><span style=\"color: black;\">Le tarif journalier est d\u00e9gressif \u00e0 partir du 8e jour des campagnes. A partir du 8e jour d&rsquo;une campagne, le tarif du jour suppl\u00e9mentaire est \u00e9gal au tarif du jour pr\u00e9c\u00e9dent sur lequel un pourcentage de d\u00e9gressivit\u00e9 de 0.5% est appliqu\u00e9. Le tarif total de la campagne est arrondi \u00e0 l&rsquo;euro sup\u00e9rieur.<br \/><\/span><span style=\"color: #000000;\"><strong>7.3. Dur\u00e9e des campagnes et \u00e9volutions tarifaires. <\/strong>La dur\u00e9e minimale d&rsquo;une campagne est de 7 jours. <\/span><span style=\"color: #000000;\">La dur\u00e9e maximale d&rsquo;une campagne est de 200 jours.<\/span><br style=\"color: #000000;\" \/><span style=\"color: black;\">Via Agency peut \u00e0 tout moment changer et\/ou arr\u00eater la m\u00e9thode de classification des pays, changer les m\u00e9thodes de calcul des grilles tarifaires, et\/ou changer le pourcentage de d\u00e9gressivit\u00e9.<br \/>Les crit\u00e8res, les tarifs, la cr\u00e9ation de groupes de pays et\/ou la place d\u2019un pays dans un groupe peuvent \u00e9voluer \u00e0 tout moment par d\u00e9cision du Prestataire. Les pays et groupes de pays sont donn\u00e9s \u00e0 titre indicatifs et peuvent \u00e9voluer \u00e0 tout moment.<br \/><span style=\"color: #000000;\"><strong>7.4. Tarifs sp\u00e9cifiques. <\/strong><\/span><\/span><span style=\"color: black; font-size: inherit;\">Via Agency peut \u00e0 tout moment choisir de proposer des tarifs sp\u00e9cifiques qui peuvent d\u00e9roger aux grilles g\u00e9n\u00e9rales pr\u00e9sent\u00e9es. Il peut s\u2019agir entre autre de tarifs promotionnels, de campagnes sp\u00e9cifiques, d\u2019approches commerciales cibl\u00e9es.<\/span><span style=\"color: black;\"><br \/><\/span><span style=\"color: black;\"><span style=\"color: #000000;\"><strong>7.5. Prestations de Services. <\/strong><\/span>Les prestations de Services sont fournies aux tarifs du Prestataire en vigueur au jour de la passation de la commande, selon le bon de commande pr\u00e9alablement \u00e9tabli par le Prestataire et accept\u00e9 par le Client, comme indiqu\u00e9 \u00e0 l\u2019article 2 \u00ab\u00a0Prestations, bon de commande &amp; facture\u00a0\u00bb ci-dessus. Les tarifs s\u2019entendent nets, HT et sont libell\u00e9s en euros, devise de r\u00e9f\u00e9rence.<\/span><\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1457\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"8\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1457\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 8. Taux de change <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1457\" class=\"elementor-element elementor-element-3ddbdf9 e-con-full e-flex e-con e-child\" data-id=\"3ddbdf9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1457\" class=\"elementor-element elementor-element-62605a4 e-flex e-con-boxed e-con e-child\" data-id=\"62605a4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-42d9123 elementor-widget elementor-widget-text-editor\" data-id=\"42d9123\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Selon chaque pays d\u2019origine et\/ou d\u2019implantation du client, ce dernier peut selon les l\u00e9gislations en vigueur avoir la possibilit\u00e9 de payer par carte bancaire. Le client peut choisir de r\u00e9gler dans une autre devise que l\u2019Euro parmi les devises suivantes : USD, GBP, CHF, XAF, XOF, CDF, MGA. Dans ce cas, le tarif en euros est converti dans la devise de son choix sur la base du taux de change du jour actualis\u00e9 aupr\u00e8s du fournisseur que l\u2019openexchangerates.org chaque jour \u00e0 16h15 (heure de Paris, soit UTC + 1 en heure d\u2019hiver et UTC + 2 en heure d\u2019\u00e9t\u00e9). Le tarif converti en devise figure sur le bon de commande et les factures. En cas de litige les tarifs de r\u00e9f\u00e9rence sont ceux libell\u00e9s en euros. En cas de non convertibilit\u00e9 et\/ou de d\u00e9pr\u00e9ciation d\u2019une devises par rapport \u00e0 l\u2019Euro, le Prestataire se r\u00e9serve le droit d\u2019annuler les commandes dont la conversion en Euro n\u2019a pas \u00e9t\u00e9 ex\u00e9cut\u00e9e pour cause de non convertibilit\u00e9 et\/ou pour toutes raisons, entre autres technique, bancaire, financi\u00e8re administrative ; ou , \u00e0 un taux de change trop faible ou d\u00e9favorable \u00e0 Via Agency. Le prestataire seul se r\u00e9serve le droit de d\u00e9cider si un taux de change est trop faible, d\u00e9favorable et\/ou non convertible pour son activit\u00e9.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1458\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"9\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1458\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 9. Modalit\u00e9 de paiement <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1458\" class=\"elementor-element elementor-element-3b5a5b5 e-con-full e-flex e-con e-child\" data-id=\"3b5a5b5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1458\" class=\"elementor-element elementor-element-38d1215 e-flex e-con-boxed e-con e-child\" data-id=\"38d1215\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6036f40 elementor-widget elementor-widget-text-editor\" data-id=\"6036f40\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong>9.1. Paiement par virement.<\/strong> Le paiement par virement permet de r\u00e9gler les prestations de Services en plusieurs \u00e9ch\u00e9ances hebdomadaires sans frais. Chaque \u00e9ch\u00e9ance dispose d&rsquo;un d\u00e9lai de paiement de 7 jours. La premi\u00e8re \u00e9ch\u00e9ance est \u00e0 r\u00e9gler dans les 7 jours suivant la passation de la commande. Les \u00e9ch\u00e9ances suivantes sont \u00e0 r\u00e9gler dans les 7 jours suivant l&rsquo;\u00e9ch\u00e9ance pr\u00e9c\u00e9dente. Les dates exactes de chaque p\u00e9riode de paiement sont pr\u00e9cis\u00e9es sur le bon de commande remis au Client. Le nombre maximal d&rsquo;\u00e9ch\u00e9ances est d\u00e9fini de mani\u00e8re \u00e0 ce que la derni\u00e8re \u00e9ch\u00e9ance intervienne au moins une semaine avant la date de fin de campagne la plus tardive et ne peut d\u00e9passer 3 \u00e9ch\u00e9ances hebdomadaires. A r\u00e9ception, les virements sont rapproch\u00e9s de la commande et valid\u00e9s par le Prestataire. Ces op\u00e9rations peuvent s\u2019\u00e9tendre sur une dur\u00e9e comprise entre 3 heures et 2 jours, au terme de laquelle la facture est adress\u00e9e au Client.<br \/><strong>9.2. Paiement par carte bancaire.<\/strong> Le paiement par carte bancaire permet de r\u00e9gler les prestations de Services en plusieurs \u00e9ch\u00e9ances hebdomadaires sans frais \u00e0 compter de la date de passation de la commande comme pr\u00e9cis\u00e9 sur le bon de commande remis au Client.\u00a0Le paiement par carte bancaire doit intervenir dans les 2 heures apr\u00e8s avoir pass\u00e9 commande. Le paiement par carte bancaire est op\u00e9r\u00e9 par Stripe.com.\u00a0 Le nombre maximal d&rsquo;\u00e9ch\u00e9ances est d\u00e9fini de mani\u00e8re \u00e0 ce que la derni\u00e8re \u00e9ch\u00e9ance intervienne au moins une semaine avant la date de fin de campagne la plus tardive et ne peut d\u00e9passer 8 \u00e9ch\u00e9ances hebdomadaires. Apr\u00e8s le paiement de chaque \u00e9ch\u00e9ance, une facture est adress\u00e9e au Client. Puis une facture r\u00e9capitulative est adress\u00e9e apr\u00e8s le dernier paiement.<br \/><strong>9.3. Non-respect des conditions de paiement. <\/strong>Dans le cas d&rsquo;un paiement par carte bancaire ou par virement en plusieurs \u00e9ch\u00e9ances, si le paiement des \u00e9ch\u00e9ances est interrompu, le Prestataire se r\u00e9serve le droit de suspendre les prestations des Services command\u00e9es par le Client et de suspendre l\u2019ex\u00e9cution de ses obligations.<br \/>Si les sommes dues sont vers\u00e9es apr\u00e8s la date indiqu\u00e9e sur la facture, le Client sera redevable d\u2019une indemnit\u00e9 forfaitaire de 40 euros au titre des frais de recouvrement.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-1459\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"10\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-1459\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 10. Garanties &amp; Droit de r\u00e9tractation <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1459\" class=\"elementor-element elementor-element-5f48a74 e-con-full e-flex e-con e-child\" data-id=\"5f48a74\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-1459\" class=\"elementor-element elementor-element-472c12d e-flex e-con-boxed e-con e-child\" data-id=\"472c12d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6e6378e elementor-widget elementor-widget-text-editor\" data-id=\"6e6378e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Le Prestataire garantit, conform\u00e9ment aux dispositions l\u00e9gales, le Client, contre tout d\u00e9faut de conformit\u00e9 des Services et tout vice cach\u00e9, provenant d\u2019un d\u00e9faut de conception ou de Fourniture desdits services \u00e0 l\u2019exclusion de toute n\u00e9gligence ou faute du Client.<br \/>La responsabilit\u00e9 du Prestataire ne peut \u00eatre engag\u00e9e qu\u2019en cas de faute ou de n\u00e9gligence prouv\u00e9e et est limit\u00e9e aux pr\u00e9judices directs \u00e0 l\u2019exclusion de tout pr\u00e9judice indirect, de quelque nature que ce soit.<br \/>Afin de faire valoir ses droits, le Client devra, sous peine de d\u00e9ch\u00e9ance de toute action s\u2019y rapportant, informer le Prestataire, par \u00e9crit, de l\u2019existence des vices dans un d\u00e9lai maximum de\u00a030 jours calendaires\u00a0\u00e0 compter de leur d\u00e9couverte.<br \/>Le Prestataire rectifiera ou fera rectifier, \u00e0 ses frais exclusifs, selon les modalit\u00e9s ad\u00e9quates et agr\u00e9\u00e9es par le Client, dans le cadre des pr\u00e9sentes conditions g\u00e9n\u00e9rales de ventes,\u00a0 les Services jug\u00e9s d\u00e9fectueux.<br \/>En tout \u00e9tat de cause, au cas o\u00f9 la responsabilit\u00e9 du Prestataire serait retenue, la garantie du Prestataire serait limit\u00e9e au montant HT pay\u00e9 par le Client pour la Fourniture des Services.<br \/>Le Client n\u2019est pas concern\u00e9 par le droit de r\u00e9tractation sauf si le nombre de salari\u00e9s du Client est inf\u00e9rieur \u00e0 6\u00a0et si l\u2019objet du contrat n\u2019entre pas dans le champ de l\u2019activit\u00e9 principale du Client.\u00a0Dans le cas o\u00f9 les deux conditions sont r\u00e9unies, le d\u00e9lai de r\u00e9tractation est fix\u00e9 \u00e0\u00a014 jours. Il court \u00e0 compter de l\u2019\u00e9tablissement du bon de commande\u00a0et de son acceptation.<br \/>Le Client souhaitant se r\u00e9tracter doit en informer le Prestataire par \u00e9crit. Si le client a parfaitement renseign\u00e9 les donn\u00e9es administratives (en particulier, nom du responsable de l\u2019achat, informations bancaires \u00e0 jour, adresse exacte, mail de contact), le Prestataire dispose d\u2019un d\u00e9lai de\u00a014 jours pour proc\u00e9der au remboursement\u00a0de la totalit\u00e9 des sommes vers\u00e9es.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-14510\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"11\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-14510\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 11. Donn\u00e9es personnelles <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-14510\" class=\"elementor-element elementor-element-b5a7f29 e-con-full e-flex e-con e-child\" data-id=\"b5a7f29\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-14510\" class=\"elementor-element elementor-element-1b3ef16 e-flex e-con-boxed e-con e-child\" data-id=\"1b3ef16\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-64c23b9 elementor-widget elementor-widget-text-editor\" data-id=\"64c23b9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Les donn\u00e9es personnelles recueillies aupr\u00e8s des Clients font l\u2019objet d\u2019un traitement informatique r\u00e9alis\u00e9 par le Prestataire. Elles sont enregistr\u00e9es dans sa base de donn\u00e9es Clients et sont indispensables au traitement de sa commande. Ces informations et donn\u00e9es personnelles sont \u00e9galement conserv\u00e9es \u00e0 des fins de s\u00e9curit\u00e9, afin de respecter les obligations l\u00e9gales et r\u00e9glementaires. Elles seront conserv\u00e9es aussi longtemps que n\u00e9cessaire pour l\u2019ex\u00e9cution des commandes et des garanties \u00e9ventuellement applicables.<br \/>Le responsable du traitement des donn\u00e9es est le Prestataire. L\u2019acc\u00e8s aux donn\u00e9es personnelles sera strictement limit\u00e9 aux employ\u00e9s du responsable de traitement, habilit\u00e9s \u00e0 les traiter en raison de leurs fonctions. Les informations recueillies pourront \u00e9ventuellement \u00eatre communiqu\u00e9es \u00e0 des tiers li\u00e9s \u00e0 l\u2019entreprise par contrat pour l\u2019ex\u00e9cution de t\u00e2ches sous-trait\u00e9es, sans que l\u2019autorisation du Client soit n\u00e9cessaire.<br \/>Dans le cadre de l\u2019ex\u00e9cution de leurs prestations, les tiers n\u2019ont qu\u2019un acc\u00e8s limit\u00e9 aux donn\u00e9es et ont l\u2019obligation de les utiliser en conformit\u00e9 avec les dispositions de la l\u00e9gislation applicable en mati\u00e8re de protection des donn\u00e9es personnelles. En dehors des cas \u00e9nonc\u00e9s ci-dessus, le Prestataire s\u2019interdit de vendre, louer, c\u00e9der ou donner acc\u00e8s \u00e0 des tiers aux donn\u00e9es sans consentement pr\u00e9alable du Client, \u00e0 moins d\u2019y \u00eatre contraint en raison d\u2019un motif l\u00e9gitime.<br \/>Si les donn\u00e9es sont amen\u00e9es \u00e0 \u00eatre transf\u00e9r\u00e9es en dehors de l\u2019UE, le Client en sera inform\u00e9 et les garanties prises afin de s\u00e9curiser les donn\u00e9es (par exemple, pour les \u00c9tats-Unis conform\u00e9ment \u00e0 la d\u00e9cision d\u2019ad\u00e9quation de la Commission europ\u00e9enne du 10\u00a0juillet 2023 constatant que les \u00c9tats-Unis assurent un niveau de protection \u00e9quivalent \u00e0 celui de l\u2019UE, adoption de clauses types de protection valid\u00e9es par la CNIL, adoption d\u2019un code de conduite, obtention d\u2019une certification CNIL,\u00a0etc.) lui seront pr\u00e9cis\u00e9es.<br \/>Conform\u00e9ment \u00e0 la r\u00e9glementation applicable, l\u2019Acheteur dispose d\u2019un droit d\u2019acc\u00e8s, de rectification, d\u2019effacement, et de portabilit\u00e9 des donn\u00e9es le concernant, ainsi que du droit de s\u2019opposer au traitement pour motif l\u00e9gitime, droits qu\u2019il peut exercer en s\u2019adressant au responsable de traitement \u00e0 l\u2019email suivante : contact@via-agency.media. En cas de r\u00e9clamation, le Client peut adresser une r\u00e9clamation aupr\u00e8s de la Commission Nationale de l\u2019Informatique et des Libert\u00e9s.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-14511\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"12\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-14511\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 12. R\u00e9solution &amp; Droit applicable <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-14511\" class=\"elementor-element elementor-element-c36c44a e-con-full e-flex e-con e-child\" data-id=\"c36c44a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-14511\" class=\"elementor-element elementor-element-016f268 e-flex e-con-boxed e-con e-child\" data-id=\"016f268\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a11e24c elementor-widget elementor-widget-text-editor\" data-id=\"a11e24c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>La r\u00e9solution de plein droit pour force majeure, ne pourra, nonobstant la clause R\u00e9solution pour manquement d\u2019une partie \u00e0 ses obligations figurant ci-apr\u00e8s, avoir lieu que dix (10) jours apr\u00e8s la r\u00e9ception d\u2019une mise en demeure notifi\u00e9e par lettre recommand\u00e9e avec demande d\u2019avis de r\u00e9ception ou tout acte extrajudiciaire.<br \/>Les pr\u00e9sentes Conditions g\u00e9n\u00e9rales et les op\u00e9rations qui en d\u00e9coulent sont r\u00e9gies exclusivement par le droit fran\u00e7ais. Elles sont r\u00e9dig\u00e9es en langue fran\u00e7aise. Dans le cas o\u00f9 elles seraient traduites en une ou plusieurs langues, seul le texte fran\u00e7ais ferait foi en cas de litige. Le fait que le cas \u00e9ch\u00e9ant, les \u00e9changes habituels entre le prestataire et le client aient lieu totalement ou partiellement dans une langue diff\u00e9rente de la langue fran\u00e7aise, ne peut en aucun cas \u00eatre consid\u00e9r\u00e9 comme une renonciation \u00e0 l\u2019application des pr\u00e9sentes conditions g\u00e9n\u00e9rales de vente ou de l\u2019une quelconque de ses stipulations.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-14512\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"13\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-14512\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> 13. Acceptation <\/div><\/span>\n\t\t\t\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-14512\" class=\"elementor-element elementor-element-c569cfe e-con-full e-flex e-con e-child\" data-id=\"c569cfe\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-14512\" class=\"elementor-element elementor-element-59441dc e-flex e-con-boxed e-con e-child\" data-id=\"59441dc\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-51f0c59 elementor-widget elementor-widget-text-editor\" data-id=\"51f0c59\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Les pr\u00e9sentes Conditions g\u00e9n\u00e9rales de vente sont express\u00e9ment agr\u00e9\u00e9es et accept\u00e9s par le Client, qui d\u00e9clare et reconna\u00eet en avoir une parfaite connaissance, et renonce, de ce fait, \u00e0 se pr\u00e9valoir de tout document contradictoire et, notamment, ses propres conditions g\u00e9n\u00e9rales d\u2019achat, qui seront inopposables au Prestataire, m\u00eame s\u2019il en a eu connaissance.<\/p>\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\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t<\/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-dd695ad elementor-widget elementor-widget-html\" data-id=\"dd695ad\" data-element_type=\"widget\" data-e-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\njQuery(document).ready(function($) {\r\n    \r\n    $(document).on('click', '.e-n-accordion .e-n-accordion-item-title', function(e) {\r\n        var $toggler = $(this);\r\n        var isCurrentlyClosed = $toggler.attr('aria-expanded') === 'false';\r\n        \r\n        if (isCurrentlyClosed) {\r\n            setTimeout(function() {\r\n                var container, scrollTarget;\r\n                \r\n                if (window.outerWidth > 1000) {\r\n                    container = $('#Content4Items');\r\n                    scrollTarget = $toggler.offset().top - container.offset().top + container.scrollTop();\r\n                } else {\r\n                    container = $('#ConteneurRedactionel');\r\n                    scrollTarget = $toggler.offset().top - container.offset().top + container.scrollTop() - 10;\r\n                }\r\n                \r\n                container.animate({ scrollTop: scrollTarget }, 250);\r\n            }, 400);\r\n        }\r\n    });\r\n    \r\n    \/\/ Observer qui d\u00e9tecte quand l'accord\u00e9on n'est plus visible et le referme\r\n    const accordionContainer = document.querySelector('.e-n-accordion');\r\n    \r\n    if (accordionContainer) {\r\n        const observer = new IntersectionObserver(function(entries) {\r\n            entries.forEach(function(entry) {\r\n                if (!entry.isIntersecting) {\r\n                    \/\/ Fermer tous les <details> ouverts\r\n                    accordionContainer.querySelectorAll('details.e-n-accordion-item[open]').forEach(function(detail) {\r\n                        detail.removeAttribute('open');\r\n                    });\r\n                }\r\n            });\r\n        }, { threshold: 0 });\r\n    \r\n        observer.observe(accordionContainer);\r\n    }\r\n        \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<div class=\"elementor-element elementor-element-150c381 elementor-widget elementor-widget-html\" data-id=\"150c381\" data-element_type=\"widget\" data-e-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(function () {\r\n    if (window.location.search.indexOf('vlpml=1') !== -1) {\r\n        document.documentElement.classList.add('via-ml-embed');\r\n    }\r\n})();\r\n<\/script>\r\n<style>\r\n\/* Couleur : posee sur TOUS les niveaux + surcharge de la variable Elementor. *\/\r\n.via-ml-embed {\r\n    --n-accordion-title-normal-color: #213864;\r\n    --n-accordion-title-hover-color:  #213864;\r\n    --n-accordion-title-active-color: #213864;\r\n}\r\n.via-ml-embed .e-n-accordion-item-title,\r\n.via-ml-embed .e-n-accordion-item-title-header,\r\n.via-ml-embed .e-n-accordion-item-title-text { color: #213864 !important; }\r\n\r\n\/* Taille : UN SEUL niveau -- et le BON : .e-n-accordion-item-title-TEXT,\r\n   celui qu'Elementor style directement. *\/\r\n.via-ml-embed .e-n-accordion-item-title-text { font-size: calc(1em - 3px) !important; }\r\n\r\n.via-ml-embed .elementor-widget-text-editor p,\r\n.via-ml-embed .elementor-widget-text-editor li { font-size: calc(1em + 2px) !important; }\r\n<\/style>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9df4ebe elementor-widget elementor-widget-html\" data-id=\"9df4ebe\" data-element_type=\"widget\" data-e-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\/* ============================================================================================\r\n   pb587 \u2014 PINCH-ZOOM pour les pages VIA-AGENCY affich\u00e9es dans un VLP (Mentions l\u00e9gales & CGV,\r\n   Via Agency, YBRE\u2026).\r\n\r\n   POURQUOI CE FICHIER\r\n   Le zoom maison (pb96) se joue en DEUX morceaux :\r\n     - un EMETTEUR, qui vit DANS l'iframe : il capte le pinch, bloque le zoom natif, et relaie\r\n       l'\u00e9chelle au parent par postMessage ;\r\n     - un RECEPTEUR (pb96r, Entete_VLP.txt), qui vit dans le PARENT : il applique un\r\n       transform:scale au popup.\r\n   Le r\u00e9cepteur est d\u00e9j\u00e0 en place sur les sites pays. L'\u00e9metteur, lui, est dans Entete_Layout.txt\r\n   \u2014 qui n'est PAS d\u00e9ploy\u00e9 sur via-agency.media (ce n'est pas un site pays). R\u00e9sultat : aucun code\r\n   \u00e0 nous ne tournait dans cette iframe, le navigateur gardait la main sur le pinch, et la PAGE\r\n   S'ACTUALISAIT au zoom sur mobile.\r\n   Ce snippet est l'\u00e9metteur, rendu AUTONOME. Aucune d\u00e9pendance : ni jQuery, ni Entete*.\r\n\r\n   OU LE POSER\r\n   Sur via-agency.media, sur les pages charg\u00e9es dans un VLP :\r\n     \/mentions-legales-disclaimers-textes-2 , \/conditions-generales-de-vente-textes , etc.\r\n   (ou dans l'ent\u00eate du site : il ne s'active QUE dans une iframe, donc il est inerte ailleurs.)\r\n\r\n   PROTOCOLE \u2014 identique \u00e0 l'\u00e9metteur d'origine, sinon le r\u00e9cepteur ne comprendrait rien :\r\n     postMessage { type: 'vlp-pinch-origin', x, y }      -> transform-origin du popup\r\n     postMessage { type: 'vlp-pinch-zoom',   scale }      -> \u00e9chelle du popup (born\u00e9e 0.5 \u2013 4.0)\r\n   Double-tap = retour \u00e0 1.0.\r\n\r\n   REVERT : supprimer ce bloc. Le zoom natif reprend la main (et le bug de rechargement avec).\r\n   ============================================================================================ *\/\r\n(function _viaPinchZoomStandalone587() {\r\n\r\n    \/* Ne s'active QUE dans une iframe : hors VLP, la page garde son zoom natif normal. *\/\r\n    function _inIframe587() {\r\n        try { return window.parent !== window; } catch (_eIf) { return false; }\r\n    }\r\n\r\n    function _init587() {\r\n        if (_inIframe587() ? false : true) { return; }\r\n        if (window._pb587Installed === true) { return; }\r\n        if (document.body ? false : true) { setTimeout(_init587, 50); return; }\r\n\r\n        \/* D\u00e9sactive le pinch-zoom NATIF : c'est lui qui provoquait le rechargement de la page. *\/\r\n        document.body.style.setProperty('touch-action', 'pan-x pan-y', 'important');\r\n\r\n        var _s = 1.0, _base = 1.0, _dist0 = 0, _on = false, _tap = 0;\r\n        var _raf = false, _pending = 1.0;\r\n\r\n        \/* Envoi throttl\u00e9 par rAF : un seul postMessage par frame, quel que soit le d\u00e9bit des\r\n           touchmove (un pinch en g\u00e9n\u00e8re des dizaines par seconde). *\/\r\n        function _send587(_v) {\r\n            _v = (_v < 0.5) ? 0.5 : ((_v > 4.0) ? 4.0 : _v);   \/* bornes identiques a pb96 *\/\r\n            _s = _v;\r\n            _pending = _v;\r\n            if (_raf ? false : true) {\r\n                _raf = true;\r\n                requestAnimationFrame(function() {\r\n                    _raf = false;\r\n                    try { window.parent.postMessage({ type: 'vlp-pinch-zoom', scale: _pending }, '*'); } catch (_eP) {}\r\n                });\r\n            }\r\n        }\r\n\r\n        function _dist587(_e) {\r\n            var _dx = _e.touches[0].clientX - _e.touches[1].clientX;\r\n            var _dy = _e.touches[0].clientY - _e.touches[1].clientY;\r\n            return Math.sqrt((_dx * _dx) + (_dy * _dy));\r\n        }\r\n\r\n        document.addEventListener('touchstart', function(_e) {\r\n            if (_e.touches.length === 2) {\r\n                _on = true;\r\n                _base = _s;\r\n                _dist0 = _dist587(_e);\r\n                \/* Centre du pinch (m\u00e9diane des 2 doigts) -> le parent en fait le transform-origin,\r\n                   pour que le zoom parte du point pinc\u00e9 et non du haut du popup. *\/\r\n                try {\r\n                    window.parent.postMessage({\r\n                        type: 'vlp-pinch-origin',\r\n                        x: (_e.touches[0].clientX + _e.touches[1].clientX) \/ 2,\r\n                        y: (_e.touches[0].clientY + _e.touches[1].clientY) \/ 2\r\n                    }, '*');\r\n                } catch (_eO) {}\r\n            }\r\n            if (_e.touches.length === 1) {\r\n                var _now = Date.now();\r\n                if ((_now - _tap) < 300) { _send587(1.0); }   \/* double-tap = reset *\/\r\n                _tap = _now;\r\n            }\r\n        }, { passive: false });\r\n\r\n        document.addEventListener('touchmove', function(_e) {\r\n            if (_on ? false : true) { return; }\r\n            if (_e.touches.length !== 2) { return; }\r\n            if (_dist0 === 0) { return; }\r\n            _e.preventDefault();                              \/* bloque le zoom natif *\/\r\n            _send587(_base * (_dist587(_e) \/ _dist0));\r\n        }, { passive: false });\r\n\r\n        document.addEventListener('touchend', function(_e) {\r\n            if (_e.touches.length < 2) { _on = false; }\r\n        }, { passive: true });\r\n\r\n        \/* iOS bascule le pinch en GESTURE events apr\u00e8s un court touchmove : touch-action et\r\n           preventDefault sur touchmove ne suffisent PAS, le natif reprend la main. On capte donc\r\n           aussi les gesture events WebKit. (Android ne les \u00e9met pas -> le touchmove ci-dessus suffit.) *\/\r\n        var _gBase = 1.0;\r\n        document.addEventListener('gesturestart', function(_g) {\r\n            _g.preventDefault(); _gBase = _s;\r\n        }, { passive: false });\r\n        document.addEventListener('gesturechange', function(_g) {\r\n            _g.preventDefault(); _send587(_gBase * _g.scale);\r\n        }, { passive: false });\r\n        document.addEventListener('gestureend', function(_g) {\r\n            _g.preventDefault();\r\n        }, { passive: false });\r\n\r\n        window._pb587Installed = true;\r\n        console.log('[pb587] emetteur pinch autonome installe (via-agency en iframe) -> relais vlp-pinch-zoom vers le parent');\r\n    }\r\n\r\n    if (document.readyState !== 'loading') { _init587(); }\r\n    else { document.addEventListener('DOMContentLoaded', _init587); }\r\n})();\r\n<\/script>\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<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\r\n        <\/div>\r\n    <\/div>\r\n\r\n\r\n    <script>\r\n        \/\/ Variables globales pour le drag & drop\r\n        let activePopups = new Set();\r\n        let dragData = {};\r\n\r\n        \/\/ Fonction pour basculer l'affichage d'un pop-up\r\n        function togglePopup(popupId) {\r\n            const popup = document.getElementById(popupId);\r\n            \r\n            if (popup.classList.contains('active')) {\r\n                closePopup(popupId);\r\n            } else {\r\n                openPopup(popupId);\r\n            }\r\n        }\r\n\r\n        \/\/ Fonction pour ouvrir un pop-up\r\n        \/\/ Variable globale pour tracker le listener\r\n        function getIframeDepth() {\r\n    let depth = 0;\r\n    let win = window;\r\n    try {\r\n        while (win !== win.top) {\r\n            depth++;\r\n            win = win.parent;\r\n        }\r\n    } catch (e) {\r\n        return 2; \/\/ Cross-origin = consid\u00e9r\u00e9 comme iframe double\r\n    }\r\n    return depth;\r\n}\r\nlet scrollHandler = null;\r\n\r\n\/\/ ====================================================================\r\n\/\/ pb627 : hauteur du popup TARIFS (#popup3) = 115 % de celle du popup\r\n\/\/   colonne de reference (.via-col-popup, cree par yearbook-media.js).\r\n\/\/   Ce dernier se dimensionne en Math.min(hauteurNaturelle + 28,\r\n\/\/   window.innerHeight - 24) : sa hauteur suit donc la fenetre. On reprend\r\n\/\/   la meme formule en repli quand aucun popup colonne n'est ouvert.\r\n\/\/   Desktop uniquement ; un redimensionnement manuel (pb611) desactive\r\n\/\/   l'ajustement automatique pour ce popup.\r\n\/\/ ====================================================================\r\nfunction hauteurReference627() {\r\n    const ref = document.querySelector('.via-col-popup');\r\n    if (ref && ref.offsetHeight > 50) {\r\n        return ref.offsetHeight;\r\n    }\r\n    return Math.max(200, window.innerHeight - 24);   \/\/ meme plafond que la reference\r\n}\r\n\r\nfunction appliquerHauteurTarif627() {\r\n    const isMobile = window.matchMedia(\"(max-width: 1000px)\").matches;\r\n    if (isMobile) { return; }\r\n    const popup = document.getElementById('popup3');\r\n    if (!popup) { return; }\r\n    if (popup._viaResizeManuel627) { return; }   \/\/ l'utilisateur a redimensionne : on respecte\r\n    \/\/ pb668 : en etat reduit (header seul), ne PAS reimposer la hauteur pleine.\r\n    \/\/   Sans cette garde, le resize de la fenetre re-deplierait le popup.\r\n    if (popup.classList.contains('popup-reduced653')) { return; }\r\n\r\n    const ref = hauteurReference627();\r\n    const voulue = Math.round(ref * 1.15);\r\n    \/\/ plafond viewport : au-dela le popup sortirait de l'ecran\r\n    const max = window.innerHeight - 20;\r\n    const finale = Math.min(voulue, max);\r\n    popup.style.setProperty('height', finale + 'px', 'important');\r\n    console.log('[pb627] hauteur popup3:', finale + 'px', '(ref ' + ref + ' x1.15 =', voulue + (voulue > max ? ', plafonne)' : ')'));\r\n}\r\n\r\n\/\/ suivre le redimensionnement de la fenetre (debounce)\r\nlet _tResize627 = null;\r\nwindow.addEventListener('resize', () => {\r\n    clearTimeout(_tResize627);\r\n    _tResize627 = setTimeout(() => {\r\n        const popup = document.getElementById('popup3');\r\n        if (popup && popup.classList.contains('active')) {\r\n            appliquerHauteurTarif627();\r\n        }\r\n    }, 150);\r\n});\r\n\r\n\/\/ pb639 : si le popup Express checking (popup3) est ouvert via le lien\r\n\/\/   TitrePopUpDoc3, le header .handle affiche le TEXTE de ce lien.\r\ndocument.addEventListener('click', function (e) {\r\n    var lien = e.target.closest ? e.target.closest('#TitrePopUpDoc3') : null;\r\n    if (!lien) { return; }\r\n    var txt = (lien.textContent || '').replace(\/\\s+\/g, ' ').trim();\r\n    if (txt) { window._viaHandleTitre639 = txt; }\r\n}, true);\r\n\r\nfunction openPopup(popupId) {\r\n    const popup = document.getElementById(popupId);\r\n    const btn = document.getElementById('btn' + popupId.slice(-1));\r\n    const isMobile = window.matchMedia(\"(max-width: 1000px)\").matches;\r\n    \r\n    if (isMobile) {\r\n        const iframeDepth = getIframeDepth();\r\n        \r\n        if (iframeDepth >= 2) {\r\n            \/\/ Iframe double : position absolute + suivre le scroll\r\n            popup.style.setProperty('position', 'absolute', 'important');\r\n            \r\n            \/\/ Fonction pour repositionner\r\n            const repositionPopup = () => {\r\n                const scrollTop = window.scrollY || window.pageYOffset || 0;\r\n                const newTop = scrollTop + 450;\r\n                popup.style.setProperty('top', newTop + 'px', 'important');\r\n            };\r\n            \r\n            \/\/ Positionner imm\u00e9diatement\r\n            repositionPopup();\r\n            \r\n            \/\/ Suivre le scroll\r\n            if (scrollHandler) {\r\n                window.removeEventListener('scroll', scrollHandler);\r\n            }\r\n            scrollHandler = repositionPopup;\r\n            window.addEventListener('scroll', scrollHandler, { passive: true });\r\n            \r\n        } else {\r\n            \/\/ Direct ou iframe simple : fixed fonctionne\r\n            popup.style.setProperty('position', 'fixed', 'important');\r\n            popup.style.setProperty('top', '50px', 'important');\r\n        }\r\n        \r\n        popup.style.setProperty('left', '10px', 'important');\r\n        \r\n        \/\/ Reset transform\r\n        popup.style.setProperty('transform', 'translate(0px, 0px)', 'important');\r\n        if (dragData[popupId]) {\r\n            dragData[popupId].currentX = 0;\r\n            dragData[popupId].currentY = 0;\r\n            dragData[popupId].xOffset = 0;\r\n            dragData[popupId].yOffset = 0;\r\n            dragData[popupId].initialX = 0;\r\n            dragData[popupId].initialY = 0;\r\n        }\r\n    }\r\n    \r\n    popup.classList.add('active');\r\n    if (btn) btn.classList.add('active');\r\n    activePopups.add(popupId);\r\n\r\n    \/\/ pb639 : titre du handle selon la SOURCE d'ouverture (lien TitrePopUpDoc3\r\n    \/\/   ou sandwich \"Express checking\"). Chaque source pose window._viaHandleTitre639\r\n    \/\/   juste avant d'ouvrir ; a defaut, titre generique.\r\n    if (popupId === 'popup3') {\r\n        var _titreH = document.getElementById('handle-title-popup3');\r\n        if (_titreH) {\r\n            _titreH.textContent = window._viaHandleTitre639 || 'Tarifs des espaces publicitaires';\r\n        }\r\n        \/\/ consommer le titre : la prochaine ouverture devra reposer sa source\r\n        window._viaHandleTitre639 = null;\r\n    }\r\n\r\n    \/\/ pb624 : CENTRER le popup Tarifs (#popup3) dans l'ecran a l'ouverture.\r\n    \/\/   Mesure APRES l'ajout de .active (avant, display:none -> dimensions nulles).\r\n    \/\/   offsetWidth\/Height : entiers, insensibles au transform du drag.\r\n    \/\/   Le transform est remis a zero juste avant, sinon le centrage se cumulerait\r\n    \/\/   avec un deplacement precedent.\r\n    if (popupId === 'popup3' && !isMobile) {\r\n        appliquerHauteurTarif627();   \/\/ pb627 : hauteur avant le centrage\r\n        popup.style.setProperty('transform', 'translate(0px, 0px)', 'important');\r\n        if (dragData[popupId]) {\r\n            dragData[popupId].currentX = 0;\r\n            dragData[popupId].currentY = 0;\r\n            dragData[popupId].xOffset = 0;\r\n            dragData[popupId].yOffset = 0;\r\n            dragData[popupId].initialX = 0;\r\n            dragData[popupId].initialY = 0;\r\n        }\r\n        requestAnimationFrame(() => {\r\n            const w = popup.offsetWidth;\r\n            const h = popup.offsetHeight;\r\n            const left = Math.max(10, Math.round((window.innerWidth - w) \/ 2));\r\n            const top = Math.max(10, Math.round((window.innerHeight - h) \/ 2));\r\n            popup.style.setProperty('position', 'fixed', 'important');\r\n            popup.style.setProperty('left', left + 'px', 'important');\r\n            popup.style.setProperty('top', top + 'px', 'important');\r\n            console.log('[pb624] popup3 centre:', left + 'x' + top, '(' + w + 'x' + h + ')');\r\n        });\r\n    }\r\n    \r\n    \/\/ pb641 : mobile \u2014 popup Express checking (popup3) ouvert 5px plus haut et\r\n    \/\/   10px plus grand. Applique apres .active (dimensions connues).\r\n    if (isMobile && popupId === 'popup3') {\r\n        requestAnimationFrame(() => {\r\n            var _cs = getComputedStyle(popup);\r\n            var _top = parseInt(_cs.top, 10);\r\n            if (isNaN(_top)) { _top = popup.offsetTop; }\r\n            var _h = parseInt(_cs.height, 10) || popup.offsetHeight;\r\n            popup.style.setProperty('top', (_top - 5) + 'px', 'important');\r\n            popup.style.setProperty('height', (_h + 10) + 'px', 'important');\r\n            console.log('[pb641] popup3 mobile: top', _top, '->', _top - 5, '| height', _h, '->', _h + 10);\r\n        });\r\n    }\r\n\r\n    \/\/ \u2705 v4.9ds+ Pb 11 : Scrollbar custom toujours visible sur mobile\r\n    if (isMobile) {\r\n        const pc = popup.querySelector('.popup-content');\r\n        if (pc && !pc._viaSbTrack) {\r\n            pc.style.position = 'relative';\r\n            const track = document.createElement('div');\r\n            track.style.cssText = 'position:absolute;right:2px;top:0;bottom:0;width:4px;background:rgba(0,0,0,0.07);border-radius:2px;pointer-events:none;z-index:10;';\r\n            const thumb = document.createElement('div');\r\n            thumb.style.cssText = 'position:absolute;right:0;width:4px;background:rgba(0,0,0,0.32);border-radius:2px;pointer-events:none;min-height:24px;';\r\n            track.appendChild(thumb);\r\n            pc.appendChild(track);\r\n            pc._viaSbTrack = track;\r\n            const update = () => {\r\n                const bh = pc.clientHeight, sh = pc.scrollHeight;\r\n                if (sh <= bh) { track.style.display = 'none'; return; }\r\n                track.style.display = 'block';\r\n                const thumbH = Math.max(24, Math.round(bh * bh \/ sh));\r\n                const thumbTop = Math.round((pc.scrollTop \/ (sh - bh)) * (bh - thumbH));\r\n                thumb.style.height = thumbH + 'px';\r\n                thumb.style.top   = thumbTop + 'px';\r\n            };\r\n            pc.addEventListener('scroll', update, { passive: true });\r\n            new ResizeObserver(update).observe(pc);\r\n            setTimeout(update, 300);\r\n        }\r\n    }\r\n\r\n    focusPopup(popupId);\r\n}\r\n\r\nfunction closePopup(popupId) {\r\n    const popup = document.getElementById(popupId);\r\n    const btn = document.getElementById('btn' + popupId.slice(-1));\r\n    \r\n    \/\/ Envoyer un message \u00e0 l'iframe pour fermer les accord\u00e9ons des CGV\r\n    const iframe = popup.querySelector('iframe');\r\n    if (iframe && iframe.contentWindow) {\r\n        iframe.contentWindow.postMessage({ action: 'closeAllAccordions' }, 'https:\/\/via-agency.media');\r\n    }\r\n    \r\n    popup.classList.remove('active', 'focused');\r\n    if (btn) btn.classList.remove('active');\r\n    activePopups.delete(popupId);\r\n    \r\n    window.closeAllRedactionnels();\r\n    \r\n    if (activePopups.size === 0 && scrollHandler) {\r\n        window.removeEventListener('scroll', scrollHandler);\r\n        scrollHandler = null;\r\n    }\r\n}\r\n\r\n        \/\/ pb653 : toggle reduction du popup Express checking (popup3).\r\n        \/\/   Reduit = header seul (contenu masque via .popup-reduced653).\r\n        \/\/   pb654 memorise la largeur INITIALE avant toute reduction.\r\n        function reducePopup3653() {\r\n            var p3 = document.getElementById(\"popup3\");\r\n            if (!p3) { return; }\r\n            console.log(\"[pb653] reducePopup3653 appele | reduit actuellement:\", p3.classList.contains(\"popup-reduced653\"));\r\n            if (p3.classList.contains(\"popup-reduced653\")) {\r\n                p3.classList.remove(\"popup-reduced653\");\r\n                \/\/ pb668 : restaurer la hauteur inline d'origine (memorisee a la reduction).\r\n                if (window._p3HautInline668 !== undefined) {\r\n                    if (window._p3HautInline668) {\r\n                        p3.style.setProperty('height', window._p3HautInline668, 'important');\r\n                    } else {\r\n                        p3.style.removeProperty('height');\r\n                    }\r\n                    window._p3HautInline668 = undefined;\r\n                }\r\n                p3.style.removeProperty('min-height');\r\n                p3.style.removeProperty('max-height');\r\n                console.log(\"[pb653] popup3 re-agrandi\");\r\n                return;\r\n            }\r\n            if (typeof window._popup3LargeurInit654 !== \"number\") {\r\n                window._popup3LargeurInit654 = p3.getBoundingClientRect().width;\r\n            }\r\n            p3.classList.add(\"popup-reduced653\");\r\n            \/\/ pb668 : la classe CSS (#popup3.popup-container.popup-reduced653) ne peut\r\n            \/\/   PAS gagner sur desktop : appliquerHauteurTarif627 pose la hauteur en\r\n            \/\/   INLINE !important (ex. 754px), et un inline important bat toute regle\r\n            \/\/   de feuille de style, meme !important. La reduction n'avait donc aucun\r\n            \/\/   effet (elle ne marchait qu'en mobile, ou la regle concurrente est en\r\n            \/\/   feuille). On ecrit donc la hauteur reduite en inline important aussi,\r\n            \/\/   apres avoir memorise la valeur a restaurer.\r\n            window._p3HautInline668 = p3.style.getPropertyValue('height');\r\n            p3.style.setProperty('height', '45px', 'important');\r\n            p3.style.setProperty('min-height', '45px', 'important');\r\n            p3.style.setProperty('max-height', '45px', 'important');\r\n            console.log(\"[pb653] popup3 reduit | largeur init =\", window._popup3LargeurInit654, \"| hauteur inline memorisee =\", window._p3HautInline668 || '(aucune)');\r\n        }\r\n        window.reducePopup3653 = reducePopup3653;\r\n\r\n        \/\/ pb655 (1) : le picto est dans le .handle draggable -> sur mobile le drag\r\n        \/\/   (touchstart) avale le clic. On branche des listeners dedies qui stoppent\r\n        \/\/   la propagation vers le drag et declenchent la reduction.\r\n        (function _brancherPictoReduire655() {\r\n            function _bind() {\r\n                var pic = document.querySelector('#popup3 .handle-reduce-container');\r\n                if (!pic) { return false; }\r\n                if (pic._pb655Bound) { return true; }\r\n                pic._pb655Bound = true;\r\n                ['click', 'touchstart', 'pointerdown'].forEach(function (ev) {\r\n                    pic.addEventListener(ev, function (e) {\r\n                        e.stopPropagation();\r\n                        if (ev === 'click') { reducePopup3653(); }\r\n                    }, true);\r\n                });\r\n                \/\/ le touch declenche la reduction (le click peut ne pas suivre apres stopPropagation)\r\n                pic.addEventListener('touchend', function (e) {\r\n                    e.stopPropagation();\r\n                    e.preventDefault();\r\n                    reducePopup3653();\r\n                }, true);\r\n                console.log('[pb655] picto Reduire popup3 branche');\r\n                return true;\r\n            }\r\n            if (!_bind()) {\r\n                var _n = 0, _iv = setInterval(function () {\r\n                    if (_bind() ? true : (++_n > 40)) { clearInterval(_iv); }\r\n                }, 250);\r\n            }\r\n        })();\r\n\r\n        \/\/ pb710 : MEME probleme que pb655 ci-dessus \u2014 le lien \"Reinitialiser\" vit dans\r\n        \/\/   le .handle DRAGGABLE : sur mobile, le touchstart du deplacement avale le\r\n        \/\/   tap et le click de synthese n'arrive jamais (ou seulement si le doigt ne\r\n        \/\/   bouge pas d'un pixel). D'ou un lien \"tres difficile a cliquer\".\r\n        \/\/   Solution identique : listeners dedies sur l'element, en capture, qui\r\n        \/\/   stoppent la propagation vers le drag ; touchend declenche l'action.\r\n        \/\/   L'action elle-meme vit dans JS_Grille_tarifaire (window.viaReinitialiserPopup710),\r\n        \/\/   qui porte la confirmation et une garde de re-entrance touchend\/click.\r\n        (function _brancherLienReset710() {\r\n            function _bind710() {\r\n                var lien = document.querySelector('#popup3 .handle-reset-710');\r\n                if (!lien) { return false; }\r\n                if (lien._pb710Bound) { return true; }\r\n                lien._pb710Bound = true;\r\n                var _go710 = function () {\r\n                    if (typeof window.viaReinitialiserPopup710 === 'function') {\r\n                        window.viaReinitialiserPopup710();\r\n                    } else {\r\n                        console.warn('[pb710] viaReinitialiserPopup710 absente (JS_Grille_tarifaire pas a jour ?)');\r\n                    }\r\n                };\r\n                ['click', 'touchstart', 'pointerdown'].forEach(function (ev) {\r\n                    lien.addEventListener(ev, function (e) {\r\n                        e.stopPropagation();\r\n                        if (ev === 'click') { _go710(); }\r\n                    }, true);\r\n                });\r\n                lien.addEventListener('touchend', function (e) {\r\n                    e.stopPropagation();\r\n                    e.preventDefault();\r\n                    _go710();\r\n                }, true);\r\n                console.log('[pb710] lien Reinitialiser popup3 branche (tactile)');\r\n                return true;\r\n            }\r\n            if (!_bind710()) {\r\n                var _n710 = 0, _iv710 = setInterval(function () {\r\n                    if (_bind710() ? true : (++_n710 > 40)) { clearInterval(_iv710); }\r\n                }, 250);\r\n            }\r\n        })();\r\n\r\n        \/\/ Fonction pour fermer tous les pop-ups\r\n        function closeAllPopups() {\r\n            activePopups.forEach(popupId => {\r\n                closePopup(popupId);\r\n            });\r\n            activePopups.clear();\r\n        }\r\n\r\n        \/\/ pb665 : z-index de focus DYNAMIQUE. Le 10000 fixe ne suffit plus depuis\r\n        \/\/   pb663\/pb664 : les via-link-popup (VLP, ColonneGauche\/Droite) ecrivent\r\n        \/\/   desormais max+2 en !important et depassaient ce plafond (mesure :\r\n        \/\/   popup3 10000 vs via-col-ColonneGauche 10005). Echelle partagee.\r\n        function _zFocus665() {\r\n            var _z665 = 10000;\r\n            if (typeof window._viaMaxZPopups663 === 'function') {\r\n                var _m665 = window._viaMaxZPopups663();\r\n                if (_m665 + 2 > _z665) { _z665 = _m665 + 2; }\r\n            }\r\n            return _z665;\r\n        }\r\n\r\n        \/\/ Fonction pour mettre un pop-up au premier plan\r\n        function focusPopup(popupId) {\r\n            \/\/ Retirer le focus de tous les popups (desktop + mobile).\r\n            \/\/ Inline !important : garantit d'etre au-dessus des via-link-popup pb135\r\n            \/\/ dont le z-index est egalement inline (sans !important).\r\n            document.querySelectorAll('.popup-container').forEach(p => {\r\n                p.classList.remove('focused');\r\n                p.style.setProperty('z-index', '9999', 'important');\r\n            });\r\n            \r\n            \/\/ Mettre au premier plan le popup cible\r\n            const focusedPopup = document.getElementById(popupId);\r\n            focusedPopup.classList.add('focused');\r\n            focusedPopup.style.setProperty('z-index', String(_zFocus665()), 'important');\r\n        }\r\n\r\n        \/\/ Initialiser le drag & drop pour un pop-up\r\n        function initializeDragAndDrop(popupId) {\r\n            const popup = document.getElementById(popupId);\r\n            const handle = popup.querySelector('.handle');\r\n            \r\n            \/\/ V\u00e9rifier si on est sur mobile\r\n            const isMobile = window.matchMedia(\"(max-width: 1000px)\").matches;\r\n            \r\n            dragData[popupId] = {\r\n                isDragging: false,\r\n                currentX: 0, \/\/ Start at 0 for transform\r\n                currentY: 0, \/\/ Start at 0 for transform\r\n                initialX: 0,\r\n                initialY: 0,\r\n                xOffset: 0,  \/\/ No initial offset for transform\r\n                yOffset: 0   \/\/ No initial offset for transform\r\n            };\r\n\r\n            \/\/ Configuration CSS pour mobile et desktop\r\n            popup.style.userSelect = 'none';\r\n            \r\n            if (isMobile) {\r\n                \/\/ Forcer les styles mobiles via JavaScript pour s'assurer qu'ils sont appliqu\u00e9s\r\n                popup.style.position = 'absolute';\r\n                popup.style.width = '410px';\r\n                popup.style.height = '595px';\r\n                \r\n                \/\/ Mobile-specific optimizations\r\n                handle.style.touchAction = 'none';\r\n                handle.style.cursor = 'grab';\r\n                popup.style.transition = 'box-shadow 0.2s ease';\r\n            } else {\r\n                \/\/ Desktop setup - keep position: fixed from CSS\r\n                popup.style.touchAction = 'none';\r\n            }\r\n\r\n            \/\/ Events pour le drag (mobile et desktop)\r\n            handle.addEventListener('mousedown', (e) => dragStart(e, popupId));\r\n            handle.addEventListener('touchstart', (e) => dragStart(e, popupId));\r\n            \r\n            \/\/ Clic pour mettre au premier plan\r\n            popup.addEventListener('mousedown', () => focusPopup(popupId));\r\n            \r\n            \/\/ Handle orientation changes on mobile\r\n            if (isMobile) {\r\n                window.addEventListener('orientationchange', () => handleOrientationChange(popupId));\r\n                window.addEventListener('resize', () => handleOrientationChange(popupId));\r\n            }\r\n        }\r\n\r\n        \/\/ ================================================================\r\n        \/\/ pb611 : REDIMENSIONNEMENT DES POPUPS REDACTIONNELS\r\n        \/\/   Standard viaPop290 (yearbook-media.js) : 8 poignees invisibles\r\n        \/\/   (4 bords + 4 coins) + 4 equerres bleues en repere visuel.\r\n        \/\/   Pointer Events -> souris et doigt avec le meme code.\r\n        \/\/   Le drag reste sur `.handle`, le resize sur les poignees : pas de\r\n        \/\/   conflit. `.popup-content` est en height:calc(100% - 40px) : il suit.\r\n        \/\/ ================================================================\r\n        const RESIZE_MIN_W = 300;   \/\/ largeur CSS minimale (px)\r\n        const RESIZE_MIN_H = 200;   \/\/ hauteur CSS minimale (px)\r\n\r\n        function initializeResize(popupId) {\r\n            const popup = document.getElementById(popupId);\r\n            if (!popup) return;\r\n            if (popup.querySelector('.popup-rh')) return;   \/\/ deja pose\r\n\r\n            \/\/ equerres bleues (visuel seul) puis poignees (saisie)\r\n            ['tl', 'tr', 'bl', 'br'].forEach(function(c) {\r\n                const sq = document.createElement('div');\r\n                sq.className = 'popup-sq ' + c;\r\n                popup.appendChild(sq);\r\n            });\r\n            ['n', 's', 'w', 'e', 'nw', 'ne', 'sw', 'se'].forEach(function(d) {\r\n                const rh = document.createElement('div');\r\n                rh.className = 'popup-rh';\r\n                rh.setAttribute('data-d', d);\r\n                rh.title = 'Redimensionner \u2014 double-clic : taille par d\u00e9faut';\r\n                popup.appendChild(rh);\r\n                brancherPoignee(rh, d);\r\n            });\r\n\r\n            let startX = 0, startY = 0, startW = 0, startH = 0;\r\n            let startLeft = 0, startTop = 0, dir = '', resizing = false;\r\n\r\n            \/\/ Taille \"CSS\" courante : la valeur a ecrire dans style.width\/height\r\n            \/\/ pour que la taille RENDUE ne bouge pas. Depend de box-sizing\r\n            \/\/ (Elementor impose border-box, la feuille locale ne le declare pas)\r\n            \/\/ -> on mesure au lieu de supposer.\r\n            function metriques() {\r\n                const cs = getComputedStyle(popup);\r\n                const borderBox = cs.boxSizing === 'border-box';\r\n                const extraX = parseFloat(cs.paddingLeft) + parseFloat(cs.paddingRight)\r\n                             + parseFloat(cs.borderLeftWidth) + parseFloat(cs.borderRightWidth);\r\n                const extraY = parseFloat(cs.paddingTop) + parseFloat(cs.paddingBottom)\r\n                             + parseFloat(cs.borderTopWidth) + parseFloat(cs.borderBottomWidth);\r\n                \/\/ offsetWidth\/Height : entiers, insensibles au transform du drag\r\n                \/\/ (getBoundingClientRect est peu fiable sur iOS avec transform)\r\n                let w = popup.offsetWidth;\r\n                let h = popup.offsetHeight;\r\n                if (!borderBox) { w -= extraX; h -= extraY; }\r\n                return { w: Math.round(w), h: Math.round(h), extraX: extraX, extraY: extraY };\r\n            }\r\n\r\n            function appliquer(w, h) {\r\n                \/\/ !important obligatoire : la media query mobile force\r\n                \/\/ width\/height en !important, et Elementor peut surcharger.\r\n                popup.style.setProperty('width', Math.round(w) + 'px', 'important');\r\n                popup.style.setProperty('height', Math.round(h) + 'px', 'important');\r\n            }\r\n\r\n            function brancherPoignee(rh, d) {\r\n                rh.addEventListener('pointerdown', function(e) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    focusPopup(popupId);\r\n\r\n                    const m = metriques();\r\n                    const r = popup.getBoundingClientRect();\r\n                    startW = m.w; startH = m.h;\r\n                    startX = e.clientX; startY = e.clientY;\r\n                    startLeft = parseFloat(getComputedStyle(popup).left) || 0;\r\n                    startTop = parseFloat(getComputedStyle(popup).top) || 0;\r\n                    dir = d;\r\n                    resizing = true;\r\n\r\n                    \/\/ taille d'origine memorisee au 1er resize -> reset double-clic\r\n                    if (!popup._viaTailleDefaut611) {\r\n                        popup._viaTailleDefaut611 = { w: m.w, h: m.h };\r\n                    }\r\n                    popup._viaResizeManuel627 = true;   \/\/ pb627 : ne plus imposer la hauteur auto\r\n\r\n                    popup.classList.add('resizing');\r\n                    try { rh.setPointerCapture(e.pointerId); } catch (err) {}\r\n                });\r\n\r\n                rh.addEventListener('pointermove', function(e) {\r\n                    if (!resizing) return;\r\n                    e.preventDefault();\r\n\r\n                    const m = metriques();\r\n                    \/\/ position RENDUE (transform du drag inclus) pour brider au viewport\r\n                    const r = popup.getBoundingClientRect();\r\n                    const dx = e.clientX - startX;\r\n                    const dy = e.clientY - startY;\r\n\r\n                    let w = startW, h = startH;\r\n                    let newLeft = startLeft, newTop = startTop;\r\n\r\n                    if (dir.indexOf('e') !== -1) {\r\n                        const maxW = Math.max(RESIZE_MIN_W, window.innerWidth - r.left - 8 - m.extraX);\r\n                        w = Math.min(Math.max(startW + dx, RESIZE_MIN_W), maxW);\r\n                    }\r\n                    if (dir.indexOf('s') !== -1) {\r\n                        const maxH = Math.max(RESIZE_MIN_H, window.innerHeight - r.top - 8 - m.extraY);\r\n                        h = Math.min(Math.max(startH + dy, RESIZE_MIN_H), maxH);\r\n                    }\r\n                    \/\/ bords ouest \/ nord : la taille grandit vers la gauche \/ le haut,\r\n                    \/\/ il faut donc deplacer l'origine du meme montant.\r\n                    if (dir.indexOf('w') !== -1) {\r\n                        w = Math.max(startW - dx, RESIZE_MIN_W);\r\n                        newLeft = startLeft + (startW - w);\r\n                    }\r\n                    if (dir.indexOf('n') !== -1) {\r\n                        h = Math.max(startH - dy, RESIZE_MIN_H);\r\n                        newTop = startTop + (startH - h);\r\n                    }\r\n\r\n                    appliquer(w, h);\r\n                    if (dir.indexOf('w') !== -1) {\r\n                        popup.style.setProperty('left', Math.round(newLeft) + 'px', 'important');\r\n                    }\r\n                    if (dir.indexOf('n') !== -1) {\r\n                        popup.style.setProperty('top', Math.round(newTop) + 'px', 'important');\r\n                    }\r\n                });\r\n\r\n                function finResize(e) {\r\n                    if (!resizing) return;\r\n                    resizing = false;\r\n                    popup.classList.remove('resizing');\r\n                    try { rh.releasePointerCapture(e.pointerId); } catch (err) {}\r\n                }\r\n                rh.addEventListener('pointerup', finResize);\r\n                rh.addEventListener('pointercancel', finResize);\r\n\r\n                \/\/ double-clic : retour a la taille par defaut\r\n                rh.addEventListener('dblclick', function(e) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    const def = popup._viaTailleDefaut611;\r\n                    if (def) { appliquer(def.w, def.h); }\r\n                });\r\n            }\r\n        }\r\n\r\n        \/\/ \u00c9v\u00e9nements globaux pour le drag\r\n        document.addEventListener('mousemove', drag);\r\n        document.addEventListener('mouseup', dragEnd);\r\n        document.addEventListener('touchmove', drag);\r\n        document.addEventListener('touchend', dragEnd);\r\n\r\n        function dragStart(e, popupId) {\r\n            \/\/ V\u00e9rifier si on clique sur la croix de fermeture\r\n            if (e.target.closest('.handle-icon') || e.target.classList.contains('handle-icon')) {\r\n                e.stopPropagation();\r\n                return; \/\/ Ne pas d\u00e9marrer le drag si on clique sur la croix\r\n            }\r\n            \r\n            e.preventDefault(); \/\/ Prevent default touch behavior\r\n            \r\n            const data = dragData[popupId];\r\n            const isMobile = window.matchMedia(\"(max-width: 1000px)\").matches;\r\n            \r\n            if (e.type === \"touchstart\") {\r\n                data.initialX = e.touches[0].clientX - data.xOffset;\r\n                data.initialY = e.touches[0].clientY - data.yOffset;\r\n            } else {\r\n                data.initialX = e.clientX - data.xOffset;\r\n                data.initialY = e.clientY - data.yOffset;\r\n            }\r\n            \r\n            if (e.target.closest('.handle')) {\r\n                data.isDragging = true;\r\n                data.activePopupId = popupId;\r\n                focusPopup(popupId);\r\n                \r\n                \/\/ Visual feedback for mobile\r\n                if (isMobile) {\r\n                    const popup = document.getElementById(popupId);\r\n                    const handle = popup.querySelector('.handle');\r\n                    \r\n                    popup.style.boxShadow = '0 8px 25px rgba(0,0,0,0.3)';\r\n                    \/\/ pb665 : meme echelle dynamique que focusPopup (ecriture !important\r\n                    \/\/   sinon le plain 10000 effacait le flag important pose au focus).\r\n                    popup.style.setProperty('z-index', String(_zFocus665()), 'important');\r\n                    handle.style.cursor = 'grabbing';\r\n                }\r\n            }\r\n        }\r\n        \r\n        function drag(e) {\r\n            \/\/ Trouver quel popup est en cours de drag\r\n            const activePopupId = Object.keys(dragData).find(id => dragData[id].isDragging);\r\n            if (!activePopupId) return;\r\n            \r\n            const data = dragData[activePopupId];\r\n            const popup = document.getElementById(activePopupId);\r\n            const isMobile = window.matchMedia(\"(max-width: 1000px)\").matches;\r\n            \r\n            e.preventDefault();\r\n            \r\n            if (e.type === \"touchmove\") {\r\n                data.currentX = e.touches[0].clientX - data.initialX;\r\n                data.currentY = e.touches[0].clientY - data.initialY;\r\n            } else {\r\n                data.currentX = e.clientX - data.initialX;\r\n                data.currentY = e.clientY - data.initialY;\r\n            }\r\n            \r\n            \/\/ R\u00e9cup\u00e9rer les dimensions n\u00e9cessaires\r\n            const containerWidth = popup.offsetWidth;\r\n            const containerHeight = popup.offsetHeight;\r\n            const viewportWidth = window.innerWidth;\r\n            const viewportHeight = window.innerHeight;\r\n            const handleHeight = popup.querySelector('.handle').offsetHeight;\r\n            \r\n            \/\/ Calculer la position r\u00e9elle du popup (position CSS + transform)\r\n            const computedStyle = window.getComputedStyle(popup);\r\n            const rect = popup.getBoundingClientRect();\r\n            \r\n            \/\/ Position initiale CSS du popup\r\n            let initialLeft = parseInt(computedStyle.left) || 0;\r\n            let initialTop = parseInt(computedStyle.top) || 0;\r\n            \r\n            \/\/ Position finale apr\u00e8s transformation\r\n            const finalX = initialLeft + data.currentX;\r\n            const finalY = initialTop + data.currentY;\r\n            \r\n            \/\/ Contraintes de d\u00e9placement\r\n            \/\/ Pour le haut : garder le header \u00e0 au moins 10px du bord sup\u00e9rieur\r\n            const minY = 10 - initialTop;\r\n            \r\n            \/\/ Pour le bas : garder au moins 10px du header visible en bas\r\n            const maxY = viewportHeight - initialTop - handleHeight - 10;\r\n            \r\n            \/\/ Pour la gauche : garder au moins 15px du header visible\r\n            const minX = -initialLeft - containerWidth + 15;\r\n            \r\n            \/\/ Pour la droite : garder au moins 15px du header visible\r\n            const maxX = viewportWidth - initialLeft - 15;\r\n            \r\n            \/\/ Appliquer les limites\r\n            data.currentX = Math.max(minX, Math.min(maxX, data.currentX));\r\n            data.currentY = Math.max(minY, Math.min(maxY, data.currentY));\r\n            \r\n            data.xOffset = data.currentX;\r\n            data.yOffset = data.currentY;\r\n            \r\n            popup.style.transform = `translate(${data.currentX}px, ${data.currentY}px)`;\r\n        }\r\n\r\n        function dragEnd() {\r\n            Object.keys(dragData).forEach(popupId => {\r\n                const data = dragData[popupId];\r\n                if (data.isDragging) {\r\n                    data.initialX = data.currentX;\r\n                    data.initialY = data.currentY;\r\n                    data.isDragging = false;\r\n                    \r\n                    \/\/ Reset visual feedback for mobile\r\n                    const isMobile = window.matchMedia(\"(max-width: 1000px)\").matches;\r\n                    if (isMobile) {\r\n                        const popup = document.getElementById(popupId);\r\n                        const handle = popup.querySelector('.handle');\r\n                        \r\n                        popup.style.boxShadow = '';\r\n                        \/\/ Ne pas remettre le z-index \u00e0 vide, garder le focus\r\n                        handle.style.cursor = 'grab';\r\n                    }\r\n                }\r\n            });\r\n        }\r\n        \r\n        \/\/ Handle orientation changes on mobilefunction handleOrientationChange(popupId) {\r\n        setTimeout(function() {\r\n            const isMobile = window.matchMedia(\"(max-width: 1000px)\").matches;\r\n            if (!isMobile) return;\r\n            \r\n            const popup = document.getElementById(popupId);\r\n            const data = dragData[popupId];\r\n            \r\n            \/\/ R\u00e9cup\u00e9rer les dimensions n\u00e9cessaires\r\n            const containerWidth = popup.offsetWidth;\r\n            const containerHeight = popup.offsetHeight;\r\n            const viewportWidth = window.innerWidth;\r\n            const viewportHeight = window.innerHeight;\r\n            const handleHeight = popup.querySelector('.handle').offsetHeight;\r\n            \r\n            \/\/ Position initiale CSS du popup\r\n            const computedStyle = window.getComputedStyle(popup);\r\n            let initialLeft = parseInt(computedStyle.left) || 0;\r\n            let initialTop = parseInt(computedStyle.top) || 0;\r\n            \r\n            \/\/ Contraintes de d\u00e9placement\r\n            const minY = 10 - initialTop;\r\n            const maxY = viewportHeight - initialTop - handleHeight - 10;\r\n            const minX = -initialLeft - containerWidth + 15;\r\n            const maxX = viewportWidth - initialLeft - 15;\r\n            \r\n            \/\/ V\u00e9rifier et ajuster si n\u00e9cessaire\r\n            if (data.currentX < minX || data.currentX > maxX || \r\n                data.currentY < minY || data.currentY > maxY) {\r\n                \r\n                data.currentX = Math.max(minX, Math.min(maxX, data.currentX));\r\n                data.currentY = Math.max(minY, Math.min(maxY, data.currentY));\r\n                \r\n                data.xOffset = data.currentX;\r\n                data.yOffset = data.currentY;\r\n                data.initialX = data.currentX;\r\n                data.initialY = data.currentY;\r\n                \r\n                popup.style.transform = `translate(${data.currentX}px, ${data.currentY}px)`;\r\n            }\r\n        }, 100);\r\n    \r\n\r\n        \/\/ Initialisation au chargement de la page\r\n        document.addEventListener('DOMContentLoaded', function() {\r\n            \/\/ Initialiser le drag & drop pour tous les popups\r\n            const popups = ['popup1', 'popup2', 'popup3', 'popup4'];\r\n            \/\/ D\u00e9placer chaque popup vers document.body pour \u00e9chapper au contexte\r\n            \/\/ d'empilement de l'anc\u00eatre Elementor (position:fixed serait trapp\u00e9 sinon).\r\n            \/\/ Apr\u00e8s le d\u00e9placement les popups sont dans le root stacking context,\r\n            \/\/ leur z-index inline !important (10000) bat l'inline pb135 (9501+, sans !important).\r\n            popups.forEach(popupId => {\r\n                const _pEsc = document.getElementById(popupId);\r\n                if (_pEsc) { document.body.appendChild(_pEsc); }\r\n            });\r\n            popups.forEach(popupId => {\r\n                initializeDragAndDrop(popupId);\r\n                initializeResize(popupId);   \/\/ pb611\r\n                \r\n                \/\/ Ajouter des \u00e9v\u00e9nements sp\u00e9cifiques pour les croix de fermeture sur mobile\r\n                const popup = document.getElementById(popupId);\r\n                const closeIcon = popup.querySelector('.handle-icon');\r\n                \r\n                if (closeIcon) {\r\n                    \/\/ \u00c9v\u00e9nements tactiles pour la croix\r\n                    closeIcon.addEventListener('touchstart', function(e) {\r\n                        e.stopPropagation();\r\n                        e.preventDefault();\r\n                    });\r\n                    \r\n                    closeIcon.addEventListener('touchend', function(e) {\r\n                        e.stopPropagation();\r\n                        e.preventDefault();\r\n                        closePopup(popupId);\r\n                    });\r\n                    \r\n                    \/\/ \u00c9v\u00e9nement click classique pour desktop\r\n                    closeIcon.addEventListener('click', function(e) {\r\n                        e.stopPropagation();\r\n                        e.preventDefault();\r\n                        closePopup(popupId);\r\n                    });\r\n                }\r\n            });\r\n            \r\n            \/\/ Forcer les styles mobiles si n\u00e9cessaire (sans dupliquer les positions)\r\n            const isMobile = window.matchMedia(\"(max-width: 1000px)\").matches;\r\n            if (isMobile) {\r\n                popups.forEach(popupId => {\r\n                    const popup = document.getElementById(popupId);\r\n                    popup.style.position = 'absolute';\r\n                    popup.style.width = '410px';\r\n                    popup.style.height = '595px';\r\n                });\r\n            }\r\n            \r\n        });\r\n    <\/script>\r\n<\/body>\r\n<\/html>\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\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-127df141 e-con-full FondBlancOrdi e-flex e-con e-child\" data-id=\"127df141\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-3964fe48 e-con-full CarrouselHP e-flex e-con e-child\" data-id=\"3964fe48\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-e079951 e-con-full e-flex e-con e-child\" data-id=\"e079951\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-29fb8b44 e-con-full e-flex e-con e-child\" data-id=\"29fb8b44\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1460424f elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"1460424f\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MessageAttenteTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4b81dae9 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-parent\" data-id=\"4b81dae9\" data-element_type=\"container\" data-e-type=\"container\" id=\"ServicesYB\">\n\t\t<div class=\"elementor-element elementor-element-33ce09be e-con-full e-flex e-con e-child\" data-id=\"33ce09be\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4fc5d5a7 e-con-full e-flex e-con e-child\" data-id=\"4fc5d5a7\" data-element_type=\"container\" data-e-type=\"container\" id=\"PaysSecteursContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-907613b elementor-widget__width-inherit elementor-widget-tablet__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"907613b\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ProcessEtapesElementorTemplate\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"278591\" class=\"elementor elementor-278591\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1547ddad e-con-full TobedisplayedLater e-flex e-con e-parent\" data-id=\"1547ddad\" data-element_type=\"container\" data-e-type=\"container\" id=\"ServicesYB\">\n\t\t<div class=\"elementor-element elementor-element-40ccfe03 e-con-full e-flex e-con e-child\" data-id=\"40ccfe03\" data-element_type=\"container\" data-e-type=\"container\" id=\"3Colonnes\">\n\t\t<div class=\"elementor-element elementor-element-d46015c e-con-full e-flex e-con e-child\" data-id=\"d46015c\" data-element_type=\"container\" data-e-type=\"container\" id=\"ColonneGauche\">\n\t\t<div class=\"elementor-element elementor-element-1ea9d99 e-con-full e-flex e-con e-child\" data-id=\"1ea9d99\" data-element_type=\"container\" data-e-type=\"container\" id=\"ProcessAnnonceurEtape\">\n\t\t<div class=\"elementor-element elementor-element-c023d6b e-con-full e-flex e-con e-child\" data-id=\"c023d6b\" data-element_type=\"container\" data-e-type=\"container\" id=\"ProcessAnnonceurTitreContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5222427 ProcessAnnonceurtitre elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"5222427\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ProcessAnnonceurIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-6ca5481 ProcessAnnonceurtitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"6ca5481\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ProcessAnnonceurIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-e028548 ProcessAnnonceurtitre elementor-widget elementor-widget-text-editor\" data-id=\"e028548\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ProcessAnnonceurtitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #999999;\">Renseigner le pays de la soci\u00e9t\u00e9 de l\u2019annonceur<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-540c104 e-con-full ProcessAnnonceurConteneurClass e-flex e-con e-child\" data-id=\"540c104\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-32cd634c e-con-full e-flex e-con e-child\" data-id=\"32cd634c\" data-element_type=\"container\" data-e-type=\"container\" id=\"NationaliteConteneur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-600bd240 elementor-button-align-center elementor-widget__width-initial elementor-widget-mobile__width-initial CfCSSPersonnalise elementor-widget elementor-widget-form\" data-id=\"600bd240\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"NationaliteAnnonceurForm\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_Nationalite_Societe\" aria-label=\"Formulaire_Nationalite_Societe\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"600bd240\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-Nationalite_Societe elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-Nationalite_Societe\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tNationalit\u00e9 soci\u00e9t\u00e9\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[Nationalite_Societe]\" id=\"form-field-Nationalite_Societe\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Indiquer ici le pays\">\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-xs\" type=\"submit\" id=\"Button_Nationalit\u00e9_Annonceur\">\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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2fd36428 e-con-full e-flex e-con e-child\" data-id=\"2fd36428\" data-element_type=\"container\" data-e-type=\"container\" id=\"PaysSecteursChildContainer\">\n\t\t<div class=\"elementor-element elementor-element-9b83c67 e-con-full e-flex e-con e-child\" data-id=\"9b83c67\" data-element_type=\"container\" data-e-type=\"container\" id=\"Titre2Ordinateur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7a76b64 AssocierPaysTitre elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"7a76b64\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"AssocierPaysTitreIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-1aadd77 AssocierPaysTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"1aadd77\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"AssocierPaysTitreIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-a9367bd AssocierPaysTitre elementor-widget elementor-widget-text-editor\" data-id=\"a9367bd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #958848;\">Associer votre communication \u00e0 des pays<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-40d98ad e-con-full e-flex e-con e-child\" data-id=\"40d98ad\" data-element_type=\"container\" data-e-type=\"container\" id=\"AssocierPaysMessageContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0be1738 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"0be1738\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"AssocierPaysMessageTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Communication associ\u00e9e au site Yearbook<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3c6f641 e-con-full AssocierPaysClass elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"3c6f641\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-a32ca82 e-con-full e-flex e-con e-child\" data-id=\"a32ca82\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-78c2a2b2 elementor-widget__width-initial elementor-widget-mobile__width-initial SousTitre  elementor-widget elementor-widget-text-editor\" data-id=\"78c2a2b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Choisir un site Yearbook Rapport Economique<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-375e6dd5 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"375e6dd5\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgPaysStep2\">\n\t\t\t\t<div class=\"elementor-element elementor-element-27e059ff elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"27e059ff\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MsgPaysStep2Text\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Merci de s\u00e9lectionner un continent ou un pays<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-39264e60 e-con-full TobedisplayedLater  e-flex e-con e-child\" data-id=\"39264e60\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-68195ea2 e-con-full TobedisplayedLater e-flex e-con e-child\" data-id=\"68195ea2\" data-element_type=\"container\" data-e-type=\"container\" id=\"ListeSitesConteneurScroll\">\n\t\t<div class=\"elementor-element elementor-element-608059b e-con-full SiteIdAfrique HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"608059b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1f9e5a04 VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"1f9e5a04\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAfrique\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-3b711163 elementor-widget elementor-widget-text-editor\" data-id=\"3b711163\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFran\u00e7ais\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4bdc831d e-con-full SiteIdCameroun HPContinentPays  SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"4bdc831d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-942d8b2 VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"942d8b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCameroun\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-2b3f7be7 elementor-widget elementor-widget-text-editor\" data-id=\"2b3f7be7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFran\u00e7ais\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7bc1dae0 e-con-full SiteIdCongo HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"7bc1dae0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-222221ab VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"222221ab\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCongo\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-16154852 elementor-widget elementor-widget-text-editor\" data-id=\"16154852\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFran\u00e7ais\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2985261d e-con-full SiteIdGabon HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"2985261d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-44ac2ae4 VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"44ac2ae4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tGabon\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-3625f939 elementor-widget elementor-widget-text-editor\" data-id=\"3625f939\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFran\u00e7ais\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-205a2954 e-con-full SiteIdMadagascar HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"205a2954\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-febdf19 VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"febdf19\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMadagascar\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-337276ad elementor-widget elementor-widget-text-editor\" data-id=\"337276ad\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFran\u00e7ais\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-41383213 e-con-full SiteIdRDC HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"41383213\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7cf8857e VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"7cf8857e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tRDC\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-695d28b elementor-widget elementor-widget-text-editor\" data-id=\"695d28b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFran\u00e7ais\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3fd2a1ed e-con-full SiteIdTogo HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"3fd2a1ed\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5fc15f1d VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"5fc15f1d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tTogo\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-75035df2 elementor-widget elementor-widget-text-editor\" data-id=\"75035df2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFran\u00e7ais\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4c9d6594 e-con-full HPContinentPays SiteIdDjibouti e-flex e-con e-child\" data-id=\"4c9d6594\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4f5a6621 VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"4f5a6621\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tDjibouti\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-64fad3e2 elementor-widget elementor-widget-text-editor\" data-id=\"64fad3e2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEn cr\u00e9ation\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-56a03130 e-con-full HPContinentPays SiteIdIvoire  e-flex e-con e-child\" data-id=\"56a03130\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2a48d687 VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"2a48d687\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tC\u00f4te d&rsquo;Ivoire\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-11e879ac elementor-widget elementor-widget-text-editor\" data-id=\"11e879ac\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEn cr\u00e9ation\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3f7c2176 e-con-full HPContinentPays e-flex e-con e-child\" data-id=\"3f7c2176\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-49da38ac elementor-widget elementor-widget-text-editor\" data-id=\"49da38ac\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAsie\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-348ac171 elementor-widget elementor-widget-text-editor\" data-id=\"348ac171\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>en cr\u00e9ation<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-aa63fee e-con-full SiteIdAfrica HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"aa63fee\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4ddf82f VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"4ddf82f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAfrica\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-27dbd7a8 elementor-widget elementor-widget-text-editor\" data-id=\"27dbd7a8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEnglish\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-62ac0538 e-con-full SiteIdCameroon HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"62ac0538\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b39e5e8 VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"b39e5e8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCameroon\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-4d417b7d elementor-widget elementor-widget-text-editor\" data-id=\"4d417b7d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEnglish\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4e70fada e-con-full SiteIdCongo-en HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"4e70fada\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-18395c80 VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"18395c80\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCongo\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-63346247 elementor-widget elementor-widget-text-editor\" data-id=\"63346247\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEnglish\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5a373b5e e-con-full SiteIdGabon-en HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"5a373b5e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7cc2930d VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"7cc2930d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tGabon\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-df99d7d elementor-widget elementor-widget-text-editor\" data-id=\"df99d7d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEnglish\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-38a3415f e-con-full SiteIdMadagascar-en HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"38a3415f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1fdd2d4b VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"1fdd2d4b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMadagascar\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-24cc5567 elementor-widget elementor-widget-text-editor\" data-id=\"24cc5567\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEnglish\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1c5e8de9 e-con-full SiteIdDRC HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"1c5e8de9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-666ce5c3 VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"666ce5c3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tDRC\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-49363f81 elementor-widget elementor-widget-text-editor\" data-id=\"49363f81\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEnglish\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2ce4d382 e-con-full SiteIdTogo-en HPContinentPays SiteContinentPaysTitre e-flex e-con e-child\" data-id=\"2ce4d382\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7a4d277f VosCampagnesPaysTexteClass elementor-widget elementor-widget-text-editor\" data-id=\"7a4d277f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tTogo\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-3394fc76 elementor-widget elementor-widget-text-editor\" data-id=\"3394fc76\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEnglish\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3a35d896 e-con-full HPContinentPays e-flex e-con e-child\" data-id=\"3a35d896\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5c9960a elementor-widget elementor-widget-text-editor\" data-id=\"5c9960a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAmeriques\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-18c7fc1c elementor-widget elementor-widget-text-editor\" data-id=\"18c7fc1c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>en cr\u00e9ation<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-64505b62 e-con-full HPContinentPays e-flex e-con e-child\" data-id=\"64505b62\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-436dc56e elementor-widget elementor-widget-text-editor\" data-id=\"436dc56e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEurope\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-3143046d elementor-widget elementor-widget-text-editor\" data-id=\"3143046d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>en cr\u00e9ation<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3dc6ca17 e-con-full HPContinentPays e-flex e-con e-child\" data-id=\"3dc6ca17\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4fb255e elementor-widget elementor-widget-text-editor\" data-id=\"4fb255e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tOc\u00e9anie\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-10afa050 elementor-widget elementor-widget-text-editor\" data-id=\"10afa050\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>en cr\u00e9ation<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9b30c6e e-con-full e-flex e-con e-child\" data-id=\"9b30c6e\" data-element_type=\"container\" data-e-type=\"container\" id=\"SecteurContainer\">\n\t\t<div class=\"elementor-element elementor-element-16f8e04 e-con-full e-flex e-con e-child\" data-id=\"16f8e04\" data-element_type=\"container\" data-e-type=\"container\" id=\"Titre3Secteurs\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4479461 AssocierSecteurTitre elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"4479461\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"AssocierSecteurTitreIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-470715c AssocierSecteurTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"470715c\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"AssocierSecteurTitreIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-78e53e1 AssocierSecteurTitre elementor-widget elementor-widget-text-editor\" data-id=\"78e53e1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #999999;\">S\u00e9lectionner les pages secteurs, th\u00e8mes ou articles<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c92783f e-con-full e-flex e-con e-child\" data-id=\"c92783f\" data-element_type=\"container\" data-e-type=\"container\" id=\"SecteursMessageContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-49ce339 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"49ce339\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"SecteursMessageTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>La page web a \u00e9t\u00e9 s\u00e9lectionn\u00e9e<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-0cb2ab3 e-con-full AssocierSecteurClass e-flex e-con e-child\" data-id=\"0cb2ab3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-b3d4ae9 e-con-full e-flex e-con e-child\" data-id=\"b3d4ae9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-74dbddf e-con-full e-flex e-con e-child\" data-id=\"74dbddf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7b4d65d elementor-widget__width-initial elementor-widget-mobile__width-initial SousTitre elementor-widget elementor-widget-text-editor\" data-id=\"7b4d65d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Publier vos annonces dans les pages web d\u00e9di\u00e9es \u00e0 votre secteur d&rsquo;activit\u00e9<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-243624db e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"243624db\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgSecteurStep3\">\n\t\t\t\t<div class=\"elementor-element elementor-element-35ed2fa2 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"35ed2fa2\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MsgSecteurStep3Text\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMerci de s\u00e9lectionner une page secteur, th\u00e8me ou article\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2c9e9c8c e-con-full e-flex e-con e-child\" data-id=\"2c9e9c8c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-645bd03b e-con-full TobedisplayedLater e-flex e-con e-child\" data-id=\"645bd03b\" data-element_type=\"container\" data-e-type=\"container\" id=\"ListeSecteurs\">\n\t\t<div class=\"elementor-element elementor-element-6f6e1d77 e-con-full HPType SecteurIdHomepage e-flex e-con e-child\" data-id=\"6f6e1d77\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2f9cb5f0 TitresHPetArticles notranslate elementor-widget elementor-widget-text-editor\" data-id=\"2f9cb5f0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tHomepage\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-29a397d8 e-con-full ArtType e-flex e-con e-child\" data-id=\"29a397d8\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-47de23f9 e-con-full CartoucheArticles SecteurIdArticle e-flex e-con e-child\" data-id=\"47de23f9\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-480a658c TitresHPetArticles notranslate elementor-widget elementor-widget-text-editor\" data-id=\"480a658c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tArticles\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5058afb8 e-con-full PTType SecteurIdAerien e-flex e-con e-child\" data-id=\"5058afb8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-29d3872a TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"29d3872a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tA\u00e9rien\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6b775081 e-con-full PTType SecteurIdAgro-industries e-flex e-con e-child\" data-id=\"6b775081\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-73dcc365 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"73dcc365\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAgro-industries\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b973341 e-con-full PTType SecteurIdAssurances e-flex e-con e-child\" data-id=\"b973341\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5763f76 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"5763f76\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAssurances\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1ddce106 e-con-full PTType SecteurIdBanque e-flex e-con e-child\" data-id=\"1ddce106\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5a1a8780 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"5a1a8780\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tBanque\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-33ffac42 e-con-full PTType SecteurIdBTP e-flex e-con e-child\" data-id=\"33ffac42\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-50c306c8 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"50c306c8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tBTP\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1f7ce0a6 e-con-full PTType SecteurIdCroissance e-flex e-con e-child\" data-id=\"1f7ce0a6\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-63c34d8a TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"63c34d8a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCroissance &amp;<br>\nFaits stylis\u00e9s\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1eb1d9c5 e-con-full PTType SecteurIdCulture e-flex e-con e-child\" data-id=\"1eb1d9c5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7c4e331d TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"7c4e331d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCulture\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-193c7d52 e-con-full PTType SecteurIdEau e-flex e-con e-child\" data-id=\"193c7d52\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b6fbac0 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"b6fbac0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEau\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-54167d6e e-con-full PTType SecteurIdElectricite e-flex e-con e-child\" data-id=\"54167d6e\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-309ab985 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"309ab985\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tElectricit\u00e9\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4c082352 e-con-full PTType SecteurIdElevage e-flex e-con e-child\" data-id=\"4c082352\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3d75852a TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"3d75852a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tElevage\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-57e7148 e-con-full PTType SecteurIdEnseignement e-flex e-con e-child\" data-id=\"57e7148\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-148440a3 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"148440a3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tEnseignement\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1b92f38b e-con-full PTType SecteurIdForet e-flex e-con e-child\" data-id=\"1b92f38b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-20678bd1 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"20678bd1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tFor\u00eat\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-574894f8 e-con-full PTType SecteurIdHydrocarbures e-flex e-con e-child\" data-id=\"574894f8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4dd8897d TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"4dd8897d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tHydrocarbures\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7233c43f e-con-full PTType SecteurIdInternational e-flex e-con e-child\" data-id=\"7233c43f\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-125a2eb9 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"125a2eb9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tInternational\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6ccd4b1a e-con-full PTType SecteurIdInvestissement e-flex e-con e-child\" data-id=\"6ccd4b1a\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5ceba2ef TitresHPetArticles  elementor-widget elementor-widget-text-editor\" data-id=\"5ceba2ef\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tInvestissement\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5e695266 e-con-full PTType SecteurIdMines e-flex e-con e-child\" data-id=\"5e695266\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fd8e50f TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"fd8e50f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMines\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-791670c9 e-con-full PTType SecteurIdNumerique e-flex e-con e-child\" data-id=\"791670c9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-71670a24 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"71670a24\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tNum\u00e9rique\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2edddeb3 e-con-full PTType SecteurIdPeche e-flex e-con e-child\" data-id=\"2edddeb3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-30c86318 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"30c86318\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tP\u00eache\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-30716e3e e-con-full PTType SecteurIdSante e-flex e-con e-child\" data-id=\"30716e3e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-443ced03 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"443ced03\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tSant\u00e9\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4bb3b69a e-con-full PTType SecteurIdTelecom e-flex e-con e-child\" data-id=\"4bb3b69a\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-746d9f7b TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"746d9f7b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tTelecom\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-51e3e665 e-con-full PTType SecteurIdTourisme e-flex e-con e-child\" data-id=\"51e3e665\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-47483394 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"47483394\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tTourisme\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-720d28da e-con-full PTType SecteurIdTransport e-flex e-con e-child\" data-id=\"720d28da\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-174ef21e TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"174ef21e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tTransport\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-47c8daa5 e-con-full FuturType e-flex e-con e-child\" data-id=\"47c8daa5\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-439e7b61 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"439e7b61\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tJuridique, fiscal<br>\n&amp; r\u00e9glementaire\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-23c50d90 elementor-widget elementor-widget-text-editor\" data-id=\"23c50d90\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\ten cr\u00e9ation\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-40b6ea84 e-con-full FuturType e-flex e-con e-child\" data-id=\"40b6ea84\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-119a9950 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"119a9950\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tComptabilit\u00e9<br>\ngestion &amp; audit\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-67bc8ea8 elementor-widget elementor-widget-text-editor\" data-id=\"67bc8ea8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\ten cr\u00e9ation\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-bad1c5e e-con-full FuturType e-flex e-con e-child\" data-id=\"bad1c5e\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-793f7313 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"793f7313\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tDistribution\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-93e3d2e elementor-widget elementor-widget-text-editor\" data-id=\"93e3d2e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>en cr\u00e9ation<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-0e87585 e-con-full FuturType elementor-hidden-desktop e-flex e-con e-child\" data-id=\"0e87585\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8750826 TitresHPetArticles elementor-widget elementor-widget-text-editor\" data-id=\"8750826\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tConseil\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-a7e6556 elementor-widget elementor-widget-text-editor\" data-id=\"a7e6556\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>en cr\u00e9ation<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9d8ea75 e-con-full SelectArticles elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"9d8ea75\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-345c3fdd e-con-full e-flex e-con e-child\" data-id=\"345c3fdd\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1fe1bcab elementor-widget elementor-widget-text-editor\" data-id=\"1fe1bcab\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>\t\t<header data-elementor-type=\"header\" data-elementor-id=\"82921\" class=\"elementor elementor-82921\" data-elementor-post-type=\"elementor_library\">\n\t\t\t<div class=\"elementor-element elementor-element-6ce7fe08 e-con-full e-flex e-con e-parent\" data-id=\"6ce7fe08\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-99b83be e-con-full e-flex e-con e-child\" data-id=\"99b83be\" data-element_type=\"container\" data-e-type=\"container\" id=\"AccesArticlesMenuConteneur\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-fa40633 e-con-full elementor-hidden-desktop elementor-hidden-tablet ListePaysMenu e-flex e-con e-child\" data-id=\"fa40633\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5138cf4 e-con-full e-flex e-con e-child\" data-id=\"5138cf4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-064f8f4 e-con-full e-flex e-con e-child\" data-id=\"064f8f4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8b51f7b   elementor-widget elementor-widget-text-editor\" data-id=\"8b51f7b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tArticles\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-e1ed82d e-con-full e-flex e-con e-child\" data-id=\"e1ed82d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-fd64912 e-con-full e-flex e-con e-child\" data-id=\"fd64912\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ab67c16 e-con-full e-flex e-con e-child\" data-id=\"ab67c16\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-717f544   elementor-widget elementor-widget-text-editor\" data-id=\"717f544\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tS\u00e9lectionner un pays\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-45676d3 e-con-full e-flex e-con e-child\" data-id=\"45676d3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-edb7efb SelectPaysCroix elementor-widget elementor-widget-image\" data-id=\"edb7efb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"#\">\n\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Croix-retour-HP-fond-blanc-r3ccahl57w5zg2nwtflgf1f4ita65898woed2vu76s.jpg\" title=\"Croix-retour-HP-fond-blanc.jpg\" alt=\"Croix-retour-HP-fond-blanc.jpg\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-0507966 e-con-full e-flex e-con e-child\" data-id=\"0507966\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-b3b46f9 e-con-full e-flex e-con e-child\" data-id=\"b3b46f9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-61fe900 elementor-widget-mobile__width-initial zoom paysCameroun elementor-widget elementor-widget-text-editor\" data-id=\"61fe900\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PaysMenu1\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Cameroun<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1a45498 e-con-full e-flex e-con e-child\" data-id=\"1a45498\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5329ce4 elementor-widget-mobile__width-initial zoom paysCongo elementor-widget elementor-widget-text-editor\" data-id=\"5329ce4\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PaysMenu2\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Congo<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b184038 e-con-full e-flex e-con e-child\" data-id=\"b184038\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6fecc5b elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"6fecc5b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\">C\u00f4te d&rsquo;Ivoire<\/span><\/p>\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-c7e81f1 elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"c7e81f1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\">en cr\u00e9ation<\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2ff626f e-con-full e-flex e-con e-child\" data-id=\"2ff626f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3bd135d elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"3bd135d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225da9;\">Djibouti<\/span><\/p>\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-055cb22 elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"055cb22\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\">en cr\u00e9ation<\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-98b7335 e-con-full e-flex e-con e-child\" data-id=\"98b7335\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-a722305 e-con-full e-flex e-con e-child\" data-id=\"a722305\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4bec8ee elementor-widget-mobile__width-inherit zoom paysGabon elementor-widget elementor-widget-text-editor\" data-id=\"4bec8ee\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PaysMenu3\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">Gabon<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f9cb002 e-con-full e-flex e-con e-child\" data-id=\"f9cb002\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-daf456d elementor-widget-mobile__width-initial zoom paysMadagascar elementor-widget elementor-widget-text-editor\" data-id=\"daf456d\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PaysMenu4\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">Madagascar<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5f0090f e-con-full e-flex e-con e-child\" data-id=\"5f0090f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9577b99 elementor-widget-mobile__width-initial zoom paysRDC elementor-widget elementor-widget-text-editor\" data-id=\"9577b99\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PaysMenu5\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">RDC<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-fc9244a e-con-full e-flex e-con e-child\" data-id=\"fc9244a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f9d4292 elementor-widget-mobile__width-initial zoom paysTogo elementor-widget elementor-widget-text-editor\" data-id=\"f9d4292\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PaysMenu6\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">Togo<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-94a1c64 e-con-full ListeThemeMenu e-flex e-con e-child\" data-id=\"94a1c64\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-53ded08 e-con-full e-flex e-con e-child\" data-id=\"53ded08\" data-element_type=\"container\" data-e-type=\"container\" id=\"TitreThemeMenu\">\n\t\t<div class=\"elementor-element elementor-element-8c5fcf5 e-con-full e-flex e-con e-child\" data-id=\"8c5fcf5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3c1191c   elementor-widget elementor-widget-text-editor\" data-id=\"3c1191c\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"AssocierAThemeMenu\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tArticles\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d75dff7 e-con-full e-flex e-con e-child\" data-id=\"d75dff7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-7ca9490 e-con-full e-flex e-con e-child\" data-id=\"7ca9490\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9fb5886 e-con-full e-flex e-con e-child\" data-id=\"9fb5886\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-24e45d8   elementor-widget elementor-widget-text-editor\" data-id=\"24e45d8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tS\u00e9lectionner un th\u00e8me ou un secteur\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c96354e e-con-full e-flex e-con e-child\" data-id=\"c96354e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d0f3827 SelectSecteurCroix elementor-widget elementor-widget-image\" data-id=\"d0f3827\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"#\">\n\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Croix-retour-HP-fond-blanc-r3ccahl57w5zg2nwtflgf1f4ita65898woed2vu76s.jpg\" title=\"Croix-retour-HP-fond-blanc.jpg\" alt=\"Croix-retour-HP-fond-blanc.jpg\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c836ac1 e-con-full e-flex e-con e-child\" data-id=\"c836ac1\" data-element_type=\"container\" data-e-type=\"container\" id=\"ThemeMenuAllConteneur\">\n\t\t<div class=\"elementor-element elementor-element-be8ae40 e-con-full e-flex e-con e-child\" data-id=\"be8ae40\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-aa905fc e-con-full e-flex e-con e-child\" data-id=\"aa905fc\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1ee6804 elementor-widget-mobile__width-inherit ActiviteSectorielle themeAerien elementor-widget elementor-widget-text-editor\" data-id=\"1ee6804\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu1\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">A\u00e9rien<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-18d73d0 e-con-full e-flex e-con e-child\" data-id=\"18d73d0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8713f77 elementor-widget-mobile__width-inherit ActiviteSectorielle themeBTP elementor-widget elementor-widget-text-editor\" data-id=\"8713f77\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu5\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">BTP<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ce8d32f e-con-full e-flex e-con e-child\" data-id=\"ce8d32f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ea6eb27 elementor-widget-mobile__width-inherit ActiviteSectorielle themeElectricite elementor-widget elementor-widget-text-editor\" data-id=\"ea6eb27\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu9\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Electricit\u00e9<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f2e269a e-con-full e-flex e-con e-child\" data-id=\"f2e269a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d983618 elementor-widget-mobile__width-inherit ActiviteSectorielle themeHydrocarbures elementor-widget elementor-widget-text-editor\" data-id=\"d983618\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu13\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Hydrocarbures<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5a5f96e e-con-full e-flex e-con e-child\" data-id=\"5a5f96e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-01531f0 elementor-widget-mobile__width-inherit ActiviteSectorielle themeNumerique elementor-widget elementor-widget-text-editor\" data-id=\"01531f0\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu17\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Num\u00e9rique<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-dce67d0 e-con-full e-flex e-con e-child\" data-id=\"dce67d0\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e7cd1d5 elementor-widget-mobile__width-inherit ActiviteSectorielle themeTourisme elementor-widget elementor-widget-text-editor\" data-id=\"e7cd1d5\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu21\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">Tourisme<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-e76ac22 e-con-full e-flex e-con e-child\" data-id=\"e76ac22\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5a7b8b6 e-con-full e-flex e-con e-child\" data-id=\"5a7b8b6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-78de278 elementor-widget-mobile__width-inherit ActiviteSectorielle themeAgro-industries elementor-widget elementor-widget-text-editor\" data-id=\"78de278\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu2\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">Agro-industries<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c93ac5d e-con-full e-flex e-con e-child\" data-id=\"c93ac5d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-27184d2 elementor-widget-mobile__width-inherit ActiviteSectorielle themeCroissance elementor-widget elementor-widget-text-editor\" data-id=\"27184d2\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu6\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">Croissance\n<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6412c11 e-con-full e-flex e-con e-child\" data-id=\"6412c11\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9a7d55b elementor-widget-mobile__width-inherit ActiviteSectorielle themeElevage elementor-widget elementor-widget-text-editor\" data-id=\"9a7d55b\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu10\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">Elevage<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f28eaa1 e-con-full e-flex e-con e-child\" data-id=\"f28eaa1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2fbe5c8 elementor-widget-mobile__width-inherit ActiviteSectorielle themeInternational elementor-widget elementor-widget-text-editor\" data-id=\"2fbe5c8\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu14\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">International<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ef88c46 e-con-full e-flex e-con e-child\" data-id=\"ef88c46\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0dde199 elementor-widget-mobile__width-inherit ActiviteSectorielle themePeche elementor-widget elementor-widget-text-editor\" data-id=\"0dde199\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu18\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">P\u00eache\n<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3a965bd e-con-full e-flex e-con e-child\" data-id=\"3a965bd\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a4cd0c1 elementor-widget-mobile__width-inherit ActiviteSectorielle themeTransport elementor-widget elementor-widget-text-editor\" data-id=\"a4cd0c1\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu22\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><a href=\"#\"><span style=\"color: #225da9;\">Transport<\/span><\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c7558f8 e-con-full e-flex e-con e-child\" data-id=\"c7558f8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-745bff9 e-con-full e-flex e-con e-child\" data-id=\"745bff9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fd50e49 elementor-widget-mobile__width-inherit ActiviteSectorielle themeAssurances elementor-widget elementor-widget-text-editor\" data-id=\"fd50e49\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu3\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">Assurances<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-062a171 e-con-full e-flex e-con e-child\" data-id=\"062a171\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8c1b86e elementor-widget-mobile__width-inherit ActiviteSectorielle themeCulture elementor-widget elementor-widget-text-editor\" data-id=\"8c1b86e\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu7\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">Culture<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d73596b e-con-full e-flex e-con e-child\" data-id=\"d73596b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5869780 elementor-widget-mobile__width-initial ActiviteSectorielle themeEnseignement elementor-widget elementor-widget-text-editor\" data-id=\"5869780\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu11\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225DA9;\"><a style=\"color: #225DA9;\" href=\"#\">Enseignement<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d4b3c0b e-con-full e-flex e-con e-child\" data-id=\"d4b3c0b\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f29d90f elementor-widget-mobile__width-inherit ActiviteSectorielle themeInvestir elementor-widget elementor-widget-text-editor\" data-id=\"f29d90f\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu15\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><a href=\"#\"><span style=\"color: #225da9;\">Investissement<\/span><\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c308425 e-con-full e-flex e-con e-child\" data-id=\"c308425\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2e89c7f elementor-widget-mobile__width-inherit ActiviteSectorielle themeSante elementor-widget elementor-widget-text-editor\" data-id=\"2e89c7f\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu19\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><a href=\"#\"><span style=\"color: #225DA9;\">Sant\u00e9<\/span><\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-0257990 e-con-full e-flex e-con e-child\" data-id=\"0257990\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-abd658a elementor-widget-mobile__width-inherit ActiviteSectorielle themeDivers elementor-widget elementor-widget-text-editor\" data-id=\"abd658a\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu23\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><a href=\"#\"><span style=\"color: #225da9;\"><\/span><\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f5d3ca5 e-con-full e-flex e-con e-child\" data-id=\"f5d3ca5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-9b5bcb4 e-con-full e-flex e-con e-child\" data-id=\"9b5bcb4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-33ee04b elementor-widget-mobile__width-inherit ActiviteSectorielle themeBanque elementor-widget elementor-widget-text-editor\" data-id=\"33ee04b\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu4\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Banque<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-40ced3d e-con-full e-flex e-con e-child\" data-id=\"40ced3d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-297934b elementor-widget-mobile__width-inherit ActiviteSectorielle themeEau elementor-widget elementor-widget-text-editor\" data-id=\"297934b\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu8\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Eau<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-54dc4a7 e-con-full e-flex e-con e-child\" data-id=\"54dc4a7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2877c8a elementor-widget-mobile__width-initial ActiviteSectorielle themeForet elementor-widget elementor-widget-text-editor\" data-id=\"2877c8a\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu12\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">For\u00eat<\/a><\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d1c2775 e-con-full e-flex e-con e-child\" data-id=\"d1c2775\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4403c97 elementor-widget-mobile__width-inherit ActiviteSectorielle themeMines elementor-widget elementor-widget-text-editor\" data-id=\"4403c97\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu16\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><a href=\"#\"><span style=\"color: #225da9;\">Mines<\/span><\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ba82785 e-con-full e-flex e-con e-child\" data-id=\"ba82785\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5e0dd54 elementor-widget-mobile__width-inherit ActiviteSectorielle themeTelecom elementor-widget elementor-widget-text-editor\" data-id=\"5e0dd54\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ThemeMenu20\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><a href=\"#\"><span style=\"color: #225da9;\">Telecom<\/span><\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2b23619 e-con-full e-flex e-con e-child\" data-id=\"2b23619\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d9e5175 elementor-widget-mobile__width-inherit ActiviteSectorielle elementor-widget elementor-widget-text-editor\" data-id=\"d9e5175\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\"><a href=\"#\"><span style=\"color: #225da9;\"><\/span><\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-92eb31c e-con-full ListeArticles elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"92eb31c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-088f206 e-con-full e-flex e-con e-child\" data-id=\"088f206\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d3ab2eb   elementor-widget elementor-widget-text-editor\" data-id=\"d3ab2eb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tArticles\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-592264a e-con-full e-flex e-con e-child\" data-id=\"592264a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-262d119 e-con-full e-flex e-con e-child\" data-id=\"262d119\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-289938a e-con-full e-flex e-con e-child\" data-id=\"289938a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e28b49d   elementor-widget elementor-widget-text-editor\" data-id=\"e28b49d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tChoisir un article\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7e33796 e-con-full e-flex e-con e-child\" data-id=\"7e33796\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4ceba7a ChoixArticlesCroix elementor-widget elementor-widget-image\" data-id=\"4ceba7a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"#\">\n\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Croix-retour-HP-fond-blanc-r3ccahl57w5zg2nwtflgf1f4ita65898woed2vu76s.jpg\" title=\"Croix-retour-HP-fond-blanc.jpg\" alt=\"Croix-retour-HP-fond-blanc.jpg\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-fb414d7 e-con-full ListeArticles elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"fb414d7\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-176af2a elementor-widget-mobile__width-initial CatchLinksArticles elementor-widget elementor-widget-text-editor\" data-id=\"176af2a\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ListedesArticlesMenu\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tArticles\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/header>\n\t\t<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6c13ec3 e-con-full e-flex e-con e-child\" data-id=\"6c13ec3\" data-element_type=\"container\" data-e-type=\"container\" id=\"ProcessDatesDeviseEtape\">\n\t\t<div class=\"elementor-element elementor-element-195f666 e-con-full e-flex e-con e-child\" data-id=\"195f666\" data-element_type=\"container\" data-e-type=\"container\" id=\"ProcessDatesDeviseTitreContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-97e2d0a ProcessDatesDevisetitre elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"97e2d0a\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ProcessDatesDeviseIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-8c858aa ProcessDatesDevisetitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"8c858aa\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ProcessDatesDeviseIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-cd85e10 ProcessDatesDevisetitre elementor-widget elementor-widget-text-editor\" data-id=\"cd85e10\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ProcessDatesDevisetitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\">Choisir les dates, la dur\u00e9e et la devise de la campagne\t\t\t\t\t\t\t<\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-93c31cf e-con-full ProcessDatesDeviseConteneurClass e-flex e-con e-child\" data-id=\"93c31cf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-dc8eb7d elementor-widget elementor-widget-text-editor\" data-id=\"dc8eb7d\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"DureeMinimaleTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Dur\u00e9e minimale de campagne 7 jours<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b3cbba4 e-con-full e-flex e-con e-child\" data-id=\"b3cbba4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-6652ec1d e-con-full e-flex e-con e-child\" data-id=\"6652ec1d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-33402c   elementor-widget elementor-widget-text-editor\" data-id=\"33402c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"color: #4b689b;\">D\u00e9but<\/span><\/p>\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-4a6560df elementor-button-align-center elementor-widget__width-initial elementor-widget elementor-widget-form\" data-id=\"4a6560df\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"DateDebutForm\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_D\u00e9but_Campagne\" aria-label=\"Formulaire_D\u00e9but_Campagne\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"4a6560df\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-DebutCampagne elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-DebutCampagne\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tD\u00e9but campagne\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[DebutCampagne]\" id=\"form-field-DebutCampagne\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"jj\/mm\/aaaa\">\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-156f096 e-con-full e-flex e-con e-child\" data-id=\"156f096\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-27ebd170   elementor-widget elementor-widget-text-editor\" data-id=\"27ebd170\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"color: #4b689b;\">Fin<\/span><\/p>\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-31bc18f3 elementor-button-align-center elementor-widget__width-initial elementor-widget elementor-widget-form\" data-id=\"31bc18f3\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"DateFinForm\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_Fin_Campagne\" aria-label=\"Formulaire_Fin_Campagne\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"31bc18f3\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-FinCampagne elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-FinCampagne\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tFin campagne\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[FinCampagne]\" id=\"form-field-FinCampagne\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"jj\/mm\/aaaa\">\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-63cc3665 e-con-full e-flex e-con e-child\" data-id=\"63cc3665\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2cef0394   elementor-widget elementor-widget-text-editor\" data-id=\"2cef0394\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"color: #4b689b;\">Nb de jours<\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-382c80be e-con-full e-flex e-con e-child\" data-id=\"382c80be\" data-element_type=\"container\" data-e-type=\"container\" id=\"NbJoursField\">\n\t\t<div class=\"elementor-element elementor-element-f1d7812 e-con-full e-flex e-con e-child\" data-id=\"f1d7812\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-601790ec CampagneNbJours elementor-widget elementor-widget-text-editor\" data-id=\"601790ec\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #225da9;\">&#8211;<\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-35403e50 e-con-full e-flex e-con e-child\" data-id=\"35403e50\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5d867346 elementor-button-align-end FormSelectDevises elementor-widget__width-initial elementor-widget elementor-widget-form\" data-id=\"5d867346\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"FormSelectDevisesId\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&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=\"FormSelectDevises\" aria-label=\"FormSelectDevises\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"5d867346\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-select elementor-field-group elementor-column elementor-field-group-selected_currency_visuels elementor-col-100\">\n\t\t\t\t\t\t\t<div class=\"elementor-field elementor-select-wrapper remove-before \">\n\t\t\t<div class=\"select-caret-down-wrapper\">\n\t\t\t\t<i aria-hidden=\"true\" class=\"eicon-caret-down\"><\/i>\t\t\t<\/div>\n\t\t\t<select name=\"form_fields[selected_currency_visuels]\" id=\"form-field-selected_currency_visuels\" class=\"elementor-field-textual elementor-size-xs\">\n\t\t\t\t\t\t\t\t\t<option value=\"EUR\">EUR<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"USD\">USD<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"GBP\">GBP<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"CHF\">CHF<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"XAF\">XAF<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"XOF\">XOF<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"CDF\">CDF<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"MGA\">MGA<\/option>\n\t\t\t\t\t\t\t<\/select>\n\t\t<\/div>\n\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6cf4acc0 e-con-full e-flex e-con e-child\" data-id=\"6cf4acc0\" data-element_type=\"container\" data-e-type=\"container\" id=\"FormatContainer\">\n\t\t<div class=\"elementor-element elementor-element-f9e2199 e-con-full e-flex e-con e-child\" data-id=\"f9e2199\" data-element_type=\"container\" data-e-type=\"container\" id=\"FormatTitre\">\n\t\t\t\t<div class=\"elementor-element elementor-element-37e0631 ChoixFormatTitre elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"37e0631\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ChoixFormatTitreIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-e04b31b ChoixFormatTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"e04b31b\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ChoixFormatTitreIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-1633af5 ChoixFormatTitre elementor-widget elementor-widget-text-editor\" data-id=\"1633af5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #999999;\">Choisir, changer ou cr\u00e9er des formats d&rsquo;annonce \u00e0 publier<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4734be7 e-con-full e-flex e-con e-child\" data-id=\"4734be7\" data-element_type=\"container\" data-e-type=\"container\" id=\"FormatMessageContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-71646ef elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"71646ef\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"FormatMessageTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Le format choisi est yyy<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c532182 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"c532182\" data-element_type=\"container\" data-e-type=\"container\" id=\"FormatMessagePreselectionContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d06acc6 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"d06acc6\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"FormatMessagePreselectionTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVous pouvez choisir le format d&rsquo;annonce ici ou dans l&rsquo;espace publicitaire\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3c3011a e-con-full ChoixFormatClass e-flex e-con e-child\" data-id=\"3c3011a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-527bfa0 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"527bfa0\" data-element_type=\"container\" data-e-type=\"container\" id=\"ChoixFormatClassMessageCorail\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4751e8fe elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"4751e8fe\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ChoixFormatClassMessageCorailText\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMerci de choisir un format\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-10bba494 e-con-full e-flex e-con e-child\" data-id=\"10bba494\" data-element_type=\"container\" data-e-type=\"container\" id=\"FormatSubContainer\">\n\t\t<div class=\"elementor-element elementor-element-3e2bf65b e-con-full FormatSubSubContainerClass elementor-hidden-tablet e-flex e-con e-child\" data-id=\"3e2bf65b\" data-element_type=\"container\" data-e-type=\"container\" id=\"ListeFormats\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<a class=\"elementor-element elementor-element-c9b77e2 e-con-full CreationFormat e-flex e-con e-child\" data-id=\"c9b77e2\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-51655de elementor-widget elementor-widget-text-editor\" data-id=\"51655de\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCr\u00e9ation<br>d&rsquo;un format<br>d&rsquo;annonce\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t<a class=\"elementor-element elementor-element-49af8a90 e-con-full FormatClassique FormatSelectParrainage e-flex e-con e-child\" data-id=\"49af8a90\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1f075e59 elementor-widget elementor-widget-text-editor\" data-id=\"1f075e59\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tParrainage\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t<a class=\"elementor-element elementor-element-1a7d594 e-con-full FormatClassique FormatSelectInterview e-flex e-con e-child\" data-id=\"1a7d594\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e722513 elementor-widget elementor-widget-text-editor\" data-id=\"e722513\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tInterview\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t<a class=\"elementor-element elementor-element-086ac2e e-con-full CreationFormat e-flex e-con e-child\" data-id=\"086ac2e\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-44cb4a9 elementor-widget elementor-widget-text-editor\" data-id=\"44cb4a9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCr\u00e9ation<br>d&rsquo;un format<br>d&rsquo;annonce\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t<a class=\"elementor-element elementor-element-2dc606fd e-con-full FormatClassique FormatSelectBanni\u00e8re e-flex e-con e-child\" data-id=\"2dc606fd\" data-element_type=\"container\" data-e-type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2e2aa9d0 elementor-widget elementor-widget-text-editor\" data-id=\"2e2aa9d0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tBanni\u00e8re\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t<a class=\"elementor-element elementor-element-b0cce79 e-con-full e-flex e-con e-child\" data-id=\"b0cce79\" data-element_type=\"container\" data-e-type=\"container\" id=\"ContainerVideo\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<a class=\"elementor-element elementor-element-23bfe385 e-con-full FormatClassique FormatSelectVid\u00e9o e-flex e-con e-child\" data-id=\"23bfe385\" data-element_type=\"container\" data-e-type=\"container\" id=\"Step1VideoContainer\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-31aa5c24 VideoSample elementor-widget elementor-widget-video\" data-id=\"31aa5c24\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;video_type&quot;:&quot;hosted&quot;,&quot;autoplay&quot;:&quot;yes&quot;,&quot;play_on_mobile&quot;:&quot;yes&quot;,&quot;mute&quot;:&quot;yes&quot;,&quot;loop&quot;:&quot;yes&quot;}\" data-widget_type=\"video.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"e-hosted-video elementor-wrapper elementor-open-inline\">\n\t\t\t\t\t<video class=\"elementor-video\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/05\/Video-Congo-small-size.mp4\" autoplay=\"\" loop=\"\" muted=\"muted\" playsinline=\"\" controlsList=\"nodownload\"><\/video>\n\t\t\t\t<\/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-451ea836 elementor-widget elementor-widget-text-editor\" data-id=\"451ea836\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVid\u00e9o\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/a>\n\t\t<a class=\"elementor-element elementor-element-0fafd9c e-con-full CreationFormat e-flex e-con e-child\" data-id=\"0fafd9c\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1a7f14f elementor-widget elementor-widget-text-editor\" data-id=\"1a7f14f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCr\u00e9ation<br>d&rsquo;un format<br>d&rsquo;annonce\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t<a class=\"elementor-element elementor-element-5b8f69ed e-con-full FormatPopup e-flex e-con e-child\" data-id=\"5b8f69ed\" data-element_type=\"container\" data-e-type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-63d096f4 elementor-widget elementor-widget-text-editor\" data-id=\"63d096f4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPop-up\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t<a class=\"elementor-element elementor-element-78e911b2 e-con-full FormatClassique FormatSelectCommuniqu\u00e9 e-flex e-con e-child\" data-id=\"78e911b2\" data-element_type=\"container\" data-e-type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-38269f13 elementor-widget elementor-widget-text-editor\" data-id=\"38269f13\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCommuniqu\u00e9\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-17bcbb5 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"17bcbb5\" data-element_type=\"container\" data-e-type=\"container\" id=\"ColonneCentre\">\n\t\t<div class=\"elementor-element elementor-element-4c012ae e-con-full e-flex e-con e-child\" data-id=\"4c012ae\" data-element_type=\"container\" data-e-type=\"container\" id=\"PageWebConteneur\">\n\t\t<div class=\"elementor-element elementor-element-ddf1721 e-con-full e-flex e-con e-child\" data-id=\"ddf1721\" data-element_type=\"container\" data-e-type=\"container\" id=\"PageWebTitreContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-dd8b8a0 PageWebTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"dd8b8a0\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PageWebTitreIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-ea92ae1 PageWebTitre elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"ea92ae1\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PageWebTitreIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-f54f684 PageWebTitre elementor-widget elementor-widget-text-editor\" data-id=\"f54f684\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #999999;\">R\u00e9server les espaces publicitaires de votre choix<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-db85d77 e-con-full elementor-hidden-desktop e-flex e-con e-child\" data-id=\"db85d77\" data-element_type=\"container\" data-e-type=\"container\" id=\"MobileMsgReserverMSgDefaut\">\n\t\t<div class=\"elementor-element elementor-element-5e86d66 e-con-full e-flex e-con e-child\" data-id=\"5e86d66\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-541f998 elementor-widget elementor-widget-text-editor\" data-id=\"541f998\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tL&rsquo;espace publicitaire s&rsquo;ouvre apr\u00e8s s\u00e9lection d&rsquo;un site pays,<br>un th\u00e8me ou un secteur et un format d&rsquo;annonce\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-cd557a1 e-con-full e-flex e-con e-child\" data-id=\"cd557a1\" data-element_type=\"container\" data-e-type=\"container\" id=\"PageWebMessageContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7ff3a5c1 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"7ff3a5c1\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PageWebMessageTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Un ou plusieurs espaces publicitaires ont \u00e9t\u00e9 r\u00e9serv\u00e9s<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-416b46aa e-con-full PageWebTemplate PageWebSousTitre e-flex e-con e-child\" data-id=\"416b46aa\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-11121b43 elementor-widget__width-initial elementor-widget-mobile__width-initial SousTitre elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"11121b43\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Dans l&rsquo;espace publicitaire, ins\u00e9rer une annonce ou choisir l&rsquo;envoi diff\u00e9r\u00e9<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4a8a7ceb e-con-full e-flex e-con e-child\" data-id=\"4a8a7ceb\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4df4d07d e-con-full PageWebTemplate e-flex e-con e-child\" data-id=\"4df4d07d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4ec80e8 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"4ec80e8\" data-element_type=\"container\" data-e-type=\"container\" id=\"ColonneDroite\">\n\t\t<div class=\"elementor-element elementor-element-2f3b9e0 e-con-full e-flex e-con e-child\" data-id=\"2f3b9e0\" data-element_type=\"container\" data-e-type=\"container\" id=\"PageWebMobileEtape\">\n\t\t<div class=\"elementor-element elementor-element-aadb3d4 e-con-full e-flex e-con e-child\" data-id=\"aadb3d4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-7c4a2a1 e-con-full e-flex e-con e-child\" data-id=\"7c4a2a1\" data-element_type=\"container\" data-e-type=\"container\" id=\"PageWebMobileTitreContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3590371 PageWebMobiletitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"3590371\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PageWebMobileIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-09ebf54 PageWebMobiletitre elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"09ebf54\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PageWebMobileIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-eaf315c PageWebMobiletitre elementor-widget elementor-widget-text-editor\" data-id=\"eaf315c\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PageWebMobiletitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #999999;\">Choisir les espaces publicitaires dans la page web<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-07be7d8 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"07be7d8\" data-element_type=\"container\" data-e-type=\"container\" id=\"PageWebMobileMessageContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-06c2c3b elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"06c2c3b\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PageWebMobileMessageTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Une ou plusieurs r\u00e9servations sont valid\u00e9es<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c9fc55f e-con-full PageWebMobileConteneurClass e-flex e-con e-child\" data-id=\"c9fc55f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5d1f090 e-con-full e-flex e-con e-child\" data-id=\"5d1f090\" data-element_type=\"container\" data-e-type=\"container\" id=\"EtapeRecapitulatif\">\n\t\t<div class=\"elementor-element elementor-element-cf5c38a e-con-full e-flex e-con e-child\" data-id=\"cf5c38a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-8130801 e-con-full e-flex e-con e-child\" data-id=\"8130801\" data-element_type=\"container\" data-e-type=\"container\" id=\"RecapitulatifVosCommandestitreContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6bafb88 RecapitulatifVosCommandestitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"6bafb88\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"RecapitulatifVosCommandesIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-e583f1d RecapitulatifVosCommandestitre elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"e583f1d\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"RecapitulatifVosCommandesIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-e4d466a RecapitulatifVosCommandestitre elementor-widget elementor-widget-text-editor\" data-id=\"e4d466a\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"RecapitulatifVosCommandestitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #fb5e2a;\">Vos r\u00e9servations<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-19efc8c6 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"19efc8c6\" data-element_type=\"container\" data-e-type=\"container\" id=\"RecapitulatifMessageContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-276135e9 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"276135e9\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"RecapitulatifMessageTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Une ou plusieurs r\u00e9servations sont valid\u00e9es<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-43e4db19 e-con-full VosCampagnesConteneurClass e-flex e-con e-child\" data-id=\"43e4db19\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1da1a816 e-con-full e-flex e-con e-child\" data-id=\"1da1a816\" data-element_type=\"container\" data-e-type=\"container\" id=\"VosCampagnesConteneur\">\n\t\t<div class=\"elementor-element elementor-element-1c5ddd0a e-con-full SiteContinentPaysTitre CampagneTemplateClass CampagnePaysClass e-flex e-con e-child\" data-id=\"1c5ddd0a\" data-element_type=\"container\" data-e-type=\"container\" id=\"CampagneTemplate\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-59d66f2e e-con-full CampagnePageClass e-flex e-con e-child\" data-id=\"59d66f2e\" data-element_type=\"container\" data-e-type=\"container\" id=\"CampagnePage\">\n\t\t<div class=\"elementor-element elementor-element-59647d28 e-con-full e-flex e-con e-child\" data-id=\"59647d28\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-252adae4 e-con-full CampagnePageRefClass CommandeElements e-flex e-con e-child\" data-id=\"252adae4\" data-element_type=\"container\" data-e-type=\"container\" id=\"CampagnePageRef\">\n\t\t<div class=\"elementor-element elementor-element-63ca01c7 e-con-full 1rdtPartCommandeContainer e-flex e-con e-child\" data-id=\"63ca01c7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-2f82cc64 e-con-full e-flex e-con e-child\" data-id=\"2f82cc64\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3217be67 CampagnePaysSocieteClass CampagnePaysSocieteContainer elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"3217be67\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Pays<\/p>\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-48f4a4d9 SiteContinentPaysTitre  CampagnePaysClass elementor-widget elementor-widget-text-editor\" data-id=\"48f4a4d9\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"CampagnePaysTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t&nbsp;\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-414fefb9 CampagnePageTextClass elementor-widget elementor-widget-text-editor\" data-id=\"414fefb9\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"CampagnePageText\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>NoPage<\/p>\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-47b9b3f1 ArticleTitre CommandeDetails elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"47b9b3f1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Article Titre<\/p>\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-26dfbe4e CampagnePositionClass elementor-widget elementor-widget-text-editor\" data-id=\"26dfbe4e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t&nbsp;\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-219157bb CampagneFormatClass elementor-widget elementor-widget-text-editor\" data-id=\"219157bb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Format<\/p>\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-42a74cc3 TarifClosedClass elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"42a74cc3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Tarif closed<\/p>\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-61965d75 CampagneAnnonceDeposeClass CommandeDetails elementor-widget elementor-widget-text-editor\" data-id=\"61965d75\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAnnonce ins\u00e9r\u00e9e\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-67956c39 CampagneNoClass elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"67956c39\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Commande r\u00e9f\u00e9rence<\/p>\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-278daab8 CampagneReferenceClass elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"278daab8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t&nbsp;\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1f84f597 e-con-full CampagnePaysSocieteContainer CampagneDatesContainer CommandeDetails elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"1f84f597\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5d4d097 e-con-full e-flex e-con e-child\" data-id=\"5d4d097\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-52e833f2 CampagneDatesClass elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"52e833f2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Dates<\/p>\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-15e9513a CampagneTarifClass elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget__width-auto elementor-widget elementor-widget-text-editor\" data-id=\"15e9513a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t&nbsp;\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7248b672 e-con-full e-flex e-con e-child\" data-id=\"7248b672\" data-element_type=\"container\" data-e-type=\"container\" id=\"TarifCommercialtobedisplayedConteneur\">\n\t\t<div class=\"elementor-element elementor-element-d25d4b3 e-con-full e-flex e-con e-child\" data-id=\"d25d4b3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2f44d966 elementor-button-align-center elementor-widget__width-initial elementor-widget-mobile__width-initial elementor-widget elementor-widget-form\" data-id=\"2f44d966\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"TarifCommercialForm\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_TarifCommercial\" aria-label=\"Formulaire_TarifCommercial\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"2f44d966\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-TarifCommercial elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<input size=\"1\" type=\"text\" name=\"form_fields[TarifCommercial]\" id=\"form-field-TarifCommercial\" class=\"elementor-field elementor-size-xs  elementor-field-textual\">\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-xs\" type=\"submit\" id=\"Button_TarifCommercial\">\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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-39c13862 CampagneEnvoiUlterieurClass CommandeDetails elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"39c13862\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAnnonce \u00e0 transmettre jusqu\u2019\u00e0 8 jours apr\u00e8s paiement,<br>\nun lien vous sera adress\u00e9 par contact@via-agency.media\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6f2269e9 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"6f2269e9\" data-element_type=\"container\" data-e-type=\"container\" id=\"SyntheseConteneur\">\n\t\t<div class=\"elementor-element elementor-element-52818512 e-con-full e-flex e-con e-child\" data-id=\"52818512\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-2a9a9aca e-con-full FinaliserBouton e-flex e-con e-child\" data-id=\"2a9a9aca\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3c51f774  PasserCommandeBouton elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"3c51f774\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Finaliser la ou les r\u00e9servations(s)<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<a class=\"elementor-element elementor-element-faeb44b e-con-full e-flex e-con e-child\" data-id=\"faeb44b\" data-element_type=\"container\" data-e-type=\"container\" id=\"AutreCommandeBouton\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t<div class=\"elementor-element elementor-element-adc4340 e-con-full e-flex e-con e-child\" data-id=\"adc4340\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f98d680 elementor-widget elementor-widget-text-editor\" data-id=\"f98d680\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAjouter une r\u00e9servation\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-77c8a2b e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"77c8a2b\" data-element_type=\"container\" data-e-type=\"container\" id=\"DatesDureeTarifContainerOLD\">\n\t\t<div class=\"elementor-element elementor-element-acc60eb e-con-full e-flex e-con e-child\" data-id=\"acc60eb\" data-element_type=\"container\" data-e-type=\"container\" id=\"Etape1ContainerOLD\">\n\t\t<div class=\"elementor-element elementor-element-6cd7a75f e-con-full DatesDureeCampagneClassOLD e-flex e-con e-child\" data-id=\"6cd7a75f\" data-element_type=\"container\" data-e-type=\"container\" id=\"ProcessAchatInsideOLD\">\n\t\t<div class=\"elementor-element elementor-element-14b19e13 e-con-full elementor-hidden-tablet elementor-hidden-desktop elementor-hidden-mobile e-flex e-con e-child\" data-id=\"14b19e13\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgSelectEspace\">\n\t\t\t\t<div class=\"elementor-element elementor-element-609898ca elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"609898ca\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Merci de s\u00e9lectionner un espace publicitaire en d\u00e9posant une annonce ou en choisissant l&rsquo;envoi diff\u00e9r\u00e9<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-12176660 e-con-full elementor-hidden-tablet Etape1TEST e-flex e-con e-child\" data-id=\"12176660\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-13a4f499 e-con-full e-flex e-con e-child\" data-id=\"13a4f499\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-25393a11 elementor-widget elementor-widget-text-editor\" data-id=\"25393a11\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"Etape1TarifHTText\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Tarif H.T.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ad7b195 e-con-full e-flex e-con e-child\" data-id=\"ad7b195\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1f9164e4 e-con-full e-flex e-con e-child\" data-id=\"1f9164e4\" data-element_type=\"container\" data-e-type=\"container\" id=\"TariftobedisplayedConteneur\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-55c2583e elementor-widget elementor-widget-text-editor\" data-id=\"55c2583e\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"Tariftobedisplayed\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"color: #225da9;\">&#8211;<\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-742ecee0 e-con-full Etape1TEST e-flex e-con e-child\" data-id=\"742ecee0\" data-element_type=\"container\" data-e-type=\"container\" id=\"Etape1BoutonValider\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-550c365f   elementor-widget elementor-widget-text-editor\" data-id=\"550c365f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Valider la r\u00e9servation<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-8fec31a e-con-full e-flex e-con e-child\" data-id=\"8fec31a\" data-element_type=\"container\" data-e-type=\"container\" id=\"EtapeReferences\">\n\t\t<div class=\"elementor-element elementor-element-f78275c e-con-full e-flex e-con e-child\" data-id=\"f78275c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-d8527be e-con-full e-flex e-con e-child\" data-id=\"d8527be\" data-element_type=\"container\" data-e-type=\"container\" id=\"ReferenceTitreContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ff6c3ec ReferencesTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"ff6c3ec\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ReferencesTitreIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-2bb7abf elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile ReferencesTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"2bb7abf\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ReferencesTitreIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-b7ec951 ReferencesTitre elementor-widget elementor-widget-text-editor\" data-id=\"b7ec951\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ReferencesTitreText\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #999999;\">Merci d&rsquo;indiquer ou modifier vos r\u00e9f\u00e9rences<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-726215cc e-con-full e-flex e-con e-child\" data-id=\"726215cc\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgCompleterFormulaireOKConteneur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6e2ce497 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"6e2ce497\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MsgCompleterFormulaireOK\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Les r\u00e9f\u00e9rences sont indiqu\u00e9es<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6e213dfb e-con-full LisereBleu ReferencesConteneur e-flex e-con e-child\" data-id=\"6e213dfb\" data-element_type=\"container\" data-e-type=\"container\" id=\"ReferencesContentConteneur\">\n\t\t<div class=\"elementor-element elementor-element-26689451 e-con-full ReferencesConteneur elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"26689451\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-499402b9 elementor-button-align-center elementor-widget__width-inherit  FormHideButton elementor-widget elementor-widget-form\" data-id=\"499402b9\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"RechercherFicheClient\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"RechercherFicheClient\" aria-label=\"RechercherFicheClient\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"499402b9\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-RechercherFicheClient elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-RechercherFicheClient\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tRechercher une fiche client\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[RechercherFicheClient]\" id=\"form-field-RechercherFicheClient\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Rechercher une fiche client\">\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-xs\" type=\"submit\" id=\"Button_RechercherFicheClient\">\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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-71c6fa16 e-con-full e-flex e-con e-child\" data-id=\"71c6fa16\" data-element_type=\"container\" data-e-type=\"container\" id=\"ReferencesFormulaires\">\n\t\t<div class=\"elementor-element elementor-element-4f688359 e-con-full ReferencesConteneurOLD elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"4f688359\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-22ce7339 elementor-widget elementor-widget-image\" data-id=\"22ce7339\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"EffacerReferences\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"#\">\n\t\t\t\t\t\t\t<img decoding=\"async\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/Croix-retour-HP-qvbkx71dnh7nzy3e03s44imwwlhpq5pmrvcgey8eca.png\" title=\"Croix retour HP\" alt=\"Croix retour HP\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5e84c09e elementor-button-align-center elementor-widget__width-inherit ReferencesConteneur  ReferencesConteneurScale elementor-widget-mobile__width-inherit elementor-widget elementor-widget-form\" data-id=\"5e84c09e\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ReferencesConteneurId\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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\" id=\"Formulaire_Annonceur_donnees_notconnected2\" name=\"Formulaire_Annonceur_donnees2\" aria-label=\"Formulaire_Annonceur_donnees2\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"5e84c09e\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-annonceur_nom_societe elementor-col-100 elementor-field-required\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_nom_societe\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tNom de l&rsquo;institution ou de la soci\u00e9t\u00e9 *\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[annonceur_nom_societe]\" id=\"form-field-annonceur_nom_societe\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Nom de l&#039;institution ou de la soci\u00e9t\u00e9 *\" required=\"required\">\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-type-text elementor-field-group elementor-column elementor-field-group-annonceur_nom_contact elementor-col-30 elementor-sm-66\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_nom_contact\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tNom et pr\u00e9nom *\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[annonceur_nom_contact]\" id=\"form-field-annonceur_nom_contact\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Nom et pr\u00e9nom *\">\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-type-text elementor-field-group elementor-column elementor-field-group-annonceur_direction_service elementor-col-20 elementor-sm-33\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_direction_service\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tFonction\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[annonceur_direction_service]\" id=\"form-field-annonceur_direction_service\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Fonction\">\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-type-email elementor-field-group elementor-column elementor-field-group-annonceur_email_contact elementor-col-25 elementor-sm-50 elementor-field-required\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_email_contact\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tEmail *\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=\"email\" name=\"form_fields[annonceur_email_contact]\" id=\"form-field-annonceur_email_contact\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Email *\" required=\"required\">\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-type-text elementor-field-group elementor-column elementor-field-group-annonceur_telephone_contact elementor-col-25 elementor-sm-50\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_telephone_contact\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tTel.\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[annonceur_telephone_contact]\" id=\"form-field-annonceur_telephone_contact\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Tel.\">\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-type-text elementor-field-group elementor-column elementor-field-group-annonceur_adresse_ligne1 elementor-col-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_adresse_ligne1\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tAdresse de l&rsquo;institution ou de la soci\u00e9t\u00e9 *\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[annonceur_adresse_ligne1]\" id=\"form-field-annonceur_adresse_ligne1\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Adresse de l&#039;institution ou de la soci\u00e9t\u00e9 *\">\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-type-text elementor-field-group elementor-column elementor-field-group-annonceur_code_postal elementor-col-33 elementor-sm-33\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_code_postal\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tCode postal *\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[annonceur_code_postal]\" id=\"form-field-annonceur_code_postal\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Code postal *\">\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-type-text elementor-field-group elementor-column elementor-field-group-annonceur_ville elementor-col-33 elementor-sm-33\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_ville\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tVille *\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[annonceur_ville]\" id=\"form-field-annonceur_ville\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Ville *\">\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-type-text elementor-field-group elementor-column elementor-field-group-annonceur_pays elementor-col-33 elementor-sm-33 elementor-field-required\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_pays\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tPays *\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[annonceur_pays]\" id=\"form-field-annonceur_pays\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Pays *\" required=\"required\">\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-type-text elementor-field-group elementor-column elementor-field-group-annonceur_numero_immatriculation elementor-col-33 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_numero_immatriculation\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tN\u00b0 d&rsquo;immatriculation \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[annonceur_numero_immatriculation]\" id=\"form-field-annonceur_numero_immatriculation\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"N\u00b0 d&#039;immatriculation\">\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-type-text elementor-field-group elementor-column elementor-field-group-annonceur_numero_tva elementor-col-33 elementor-sm-50\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-annonceur_numero_tva\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tNum\u00e9ro de TVA\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[annonceur_numero_tva]\" id=\"form-field-annonceur_numero_tva\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Num\u00e9ro de TVA\">\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-type-text elementor-field-group elementor-column elementor-field-group-field_RegimeTVA elementor-col-33 elementor-sm-50\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-field_RegimeTVA\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tR\u00e9gime de TVA\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[field_RegimeTVA]\" id=\"form-field-field_RegimeTVA\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"R\u00e9gime de TVA\">\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-xs\" type=\"submit\" id=\"ButtonValidDataAnnonceur2\">\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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-57d8a72a e-con-full ReferencesConteneur ReferencesConteneurScale e-flex e-con e-child\" data-id=\"57d8a72a\" data-element_type=\"container\" data-e-type=\"container\" id=\"ChampsObligatoiresNEW\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6d0d608c elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"6d0d608c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"color: #213864;\">* champ obligatoire<\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-21683a93 elementor-button-align-center elementor-widget__width-inherit ReferencesConteneur  ReferencesConteneurScale elementor-widget elementor-widget-form\" data-id=\"21683a93\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ChoixDataFacturationForm\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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\" id=\"Formulaire_Annonceur_donnees_notconnected2\" name=\"Formulaire_Annonceur_donnees3\" aria-label=\"Formulaire_Annonceur_donnees3\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"21683a93\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-checkbox elementor-field-group elementor-column elementor-field-group-DataFacturation elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-DataFacturation\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tSi vos informations de facturation sont diff\u00e9rentes, \u000bmerci de cocher la case afin de les renseigner\t\t\t\t\t\t\t<\/label>\n\t\t\t\t\t\t<div class=\"elementor-field-subgroup  \"><span class=\"elementor-field-option\"><input type=\"checkbox\" value=\"Yes\" id=\"form-field-DataFacturation-0\" name=\"form_fields[DataFacturation]\"> <label for=\"form-field-DataFacturation-0\">Si vos informations de facturation sont diff\u00e9rentes, merci de cocher la case afin de les renseigner<\/label><\/span><\/div>\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-xs\" type=\"submit\" id=\"ButtonValidDataAnnonceur3\">\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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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 class=\"elementor-element elementor-element-17541d4f elementor-button-align-center elementor-widget__width-inherit ReferencesConteneurScale elementor-widget elementor-widget-form\" data-id=\"17541d4f\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"DataFacturationForm\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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\" id=\"Formulaire_Annonceur_donnees_notconnected2\" name=\"Formulaire_Annonceur_donnees4\" aria-label=\"Formulaire_Annonceur_donnees4\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"17541d4f\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-facturation_contact elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-facturation_contact\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tContact de facturation (nom pr\u00e9nom et\/ou service)\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[facturation_contact]\" id=\"form-field-facturation_contact\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Contact de facturation (nom pr\u00e9nom et\/ou service)\">\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-type-text elementor-field-group elementor-column elementor-field-group-facturation_adresse elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-facturation_adresse\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tAdresse de facturation\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[facturation_adresse]\" id=\"form-field-facturation_adresse\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Adresse de facturation\">\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-type-text elementor-field-group elementor-column elementor-field-group-facturation_code_postal elementor-col-33 elementor-sm-33\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-facturation_code_postal\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tCode postal (facturation)\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[facturation_code_postal]\" id=\"form-field-facturation_code_postal\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Code postal (facturation)\">\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-type-text elementor-field-group elementor-column elementor-field-group-facturation_ville elementor-col-33 elementor-sm-33\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-facturation_ville\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tVille (facturation)\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[facturation_ville]\" id=\"form-field-facturation_ville\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Ville (facturation)\">\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-type-text elementor-field-group elementor-column elementor-field-group-facturation_pays elementor-col-33 elementor-sm-33\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-facturation_pays\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tPays (facturation)\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[facturation_pays]\" id=\"form-field-facturation_pays\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Pays (facturation)\">\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-type-text elementor-field-group elementor-column elementor-field-group-facturation_email elementor-col-50 elementor-sm-50\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-facturation_email\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tEmail de facturation\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[facturation_email]\" id=\"form-field-facturation_email\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Email de facturation\">\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-type-text elementor-field-group elementor-column elementor-field-group-facturation_telephone elementor-col-50 elementor-sm-50\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-facturation_telephone\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tTel. mobile et\/ou fixe\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[facturation_telephone]\" id=\"form-field-facturation_telephone\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Tel. mobile et\/ou fixe\">\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-xs\" type=\"submit\" id=\"ButtonValidDataAnnonceur2\">\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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-6086a613 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"6086a613\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgCompleterFormulaireCoordonneesConteneur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2d6ed5c6 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"2d6ed5c6\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MsgCompleterFormulaireCoordonnees\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Msg Saisie coordonn\u00e9es<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-568df68 e-con-full e-flex e-con e-child\" data-id=\"568df68\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-3b8c114b e-con-full ReferencesConteneur e-flex e-con e-child\" data-id=\"3b8c114b\" data-element_type=\"container\" data-e-type=\"container\" id=\"ValiderReferencesBouton\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2655e5b5   elementor-widget elementor-widget-text-editor\" data-id=\"2655e5b5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Valider<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-15fc38f e-con-full e-flex e-con e-child\" data-id=\"15fc38f\" data-element_type=\"container\" data-e-type=\"container\" id=\"EtapeModedePaiement\">\n\t\t<div class=\"elementor-element elementor-element-54f6a4c e-con-full e-flex e-con e-child\" data-id=\"54f6a4c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-dd77993 e-con-full e-flex e-con e-child\" data-id=\"dd77993\" data-element_type=\"container\" data-e-type=\"container\" id=\"ModePaiementTitreContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0772baf ChoisirPaiementTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"0772baf\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ChoisirPaiementTitreIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-a13856f elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile ChoisirPaiementTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"a13856f\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ChoisirPaiementTitreIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-0737f52 ChoisirPaiementTitre elementor-widget elementor-widget-text-editor\" data-id=\"0737f52\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ChoisirPaiementTitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #999999;\">Choix des modes de paiement<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7b5a64eb e-con-full e-flex e-con e-child\" data-id=\"7b5a64eb\" data-element_type=\"container\" data-e-type=\"container\" id=\"DeviseModedePaiementMsgConteneur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-548b11ec elementor-widget__width-inherit elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"548b11ec\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"DeviseModedePaiementMsg\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMerci de finaliser la commande\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-340186f1 e-con-full LisereBleu ChoisirPaiementClass e-flex e-con e-child\" data-id=\"340186f1\" data-element_type=\"container\" data-e-type=\"container\" id=\"ModePaiementLisereBleu\">\n\t\t<div class=\"elementor-element elementor-element-54fd976d e-con-full ChoisirPaiementClass e-flex e-con e-child\" data-id=\"54fd976d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-6e1e9997 e-flex e-con-boxed e-con e-child\" data-id=\"6e1e9997\" data-element_type=\"container\" data-e-type=\"container\" id=\"MontantAPayerId\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c1ea51a elementor-widget elementor-widget-text-editor\" data-id=\"c1ea51a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tMontant \u00e0 r\u00e8gler\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-2cee9111 elementor-widget elementor-widget-text-editor\" data-id=\"2cee9111\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MontantARegler\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>&#8211;<\/p>\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\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-bd901bb e-con-full ChoisirPaiementClass e-flex e-con e-child\" data-id=\"bd901bb\" data-element_type=\"container\" data-e-type=\"container\" id=\"PayableParMsgConteneur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2076bd1 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"2076bd1\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"PayableParMsg\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Payable soit par virement en Y \u00e9ch\u00e9ance de xxx \u20ac, soit par CB en X \u00e9ch\u00e9ances de www \u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1db482cd e-con-full ChoisirPaiementClass e-flex e-con e-child\" data-id=\"1db482cd\" data-element_type=\"container\" data-e-type=\"container\" id=\"ChoisirPaiement\">\n\t\t<div class=\"elementor-element elementor-element-1800893e e-con-full e-flex e-con e-child\" data-id=\"1800893e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-6c6f4088 e-con-full e-flex e-con e-child\" data-id=\"6c6f4088\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-26922d01 e-con-full e-flex e-con e-child\" data-id=\"26922d01\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-35146153 e-con-full e-flex e-con e-child\" data-id=\"35146153\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-19a2c73a   elementor-widget elementor-widget-text-editor\" data-id=\"19a2c73a\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"CarteBancaireTitre\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCarte Bancaire\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3393ff99 e-con-full EcheancierCB e-flex e-con e-child\" data-id=\"3393ff99\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-40b43413 e-con-full Echeancesactivecontener e-flex e-con e-child\" data-id=\"40b43413\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-73f6803b e-con-full e-flex e-con e-child\" data-id=\"73f6803b\" data-element_type=\"container\" data-e-type=\"container\" id=\"EcheanceActiveWithInput\">\n\t\t<div class=\"elementor-element elementor-element-67d1db80 e-con-full e-flex e-con e-child\" data-id=\"67d1db80\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-2a4910bc e-con-full e-flex e-con e-child\" data-id=\"2a4910bc\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-269467d7 elementor-widget elementor-widget-text-editor\" data-id=\"269467d7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ech\u00e9ances<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-64d14576 e-con-full e-flex e-con e-child\" data-id=\"64d14576\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7efde04 elementor-button-align-end elementor-widget elementor-widget-form\" data-id=\"7efde04\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"SaisieEcheance\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&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=\"Nouveau formulaire\" aria-label=\"Nouveau formulaire\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"7efde04\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-select elementor-field-group elementor-column elementor-field-group-nb_echeancesCB elementor-col-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-nb_echeancesCB\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tEch\u00e9ances\t\t\t\t\t\t\t<\/label>\n\t\t\t\t\t\t\t\t<div class=\"elementor-field elementor-select-wrapper remove-before \">\n\t\t\t<div class=\"select-caret-down-wrapper\">\n\t\t\t\t<i aria-hidden=\"true\" class=\"eicon-caret-down\"><\/i>\t\t\t<\/div>\n\t\t\t<select name=\"form_fields[nb_echeancesCB]\" id=\"form-field-nb_echeancesCB\" class=\"elementor-field-textual elementor-size-xs\">\n\t\t\t\t\t\t\t\t\t<option value=\"1\" selected=\"selected\">1<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"2\">2<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"3\">3<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"4\">4<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"5\">5<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"6\">6<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"7\">7<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"8\">8<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"9\">9<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"10\">10<\/option>\n\t\t\t\t\t\t\t<\/select>\n\t\t<\/div>\n\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<\/div>\n\t\t<div class=\"elementor-element elementor-element-6cf3709d e-con-full e-flex e-con e-child\" data-id=\"6cf3709d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-16bf14bc elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"16bf14bc\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MontantHebdomadaireSansFraisText\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">hebdomadaire(s)<br>sans frais<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7c752827 e-con-full EcheancierContener elementor-hidden-tablet e-flex e-con e-child\" data-id=\"7c752827\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-11a33c6f Echeanciertexte elementor-widget elementor-widget-text-editor\" data-id=\"11a33c6f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">&#8211;<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-379401f1 e-con-full e-flex e-con e-child\" data-id=\"379401f1\" data-element_type=\"container\" data-e-type=\"container\" id=\"PaiementparCBBouton\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7dd0bb4d   elementor-widget elementor-widget-text-editor\" data-id=\"7dd0bb4d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Choisir<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4f0f5c0d e-con-full e-flex e-con e-child\" data-id=\"4f0f5c0d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-36dd2f55 e-con-full e-flex e-con e-child\" data-id=\"36dd2f55\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2ed90daa   elementor-widget elementor-widget-text-editor\" data-id=\"2ed90daa\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"VirementTitre\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVirement\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7df0ef49 e-con-full EcheancierVir e-flex e-con e-child\" data-id=\"7df0ef49\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-55a831f1 e-con-full Echeancesactivecontener e-flex e-con e-child\" data-id=\"55a831f1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1484e258 e-con-full e-flex e-con e-child\" data-id=\"1484e258\" data-element_type=\"container\" data-e-type=\"container\" id=\"EcheanceActiveWithInputVir\">\n\t\t<div class=\"elementor-element elementor-element-4ddff702 e-con-full e-flex e-con e-child\" data-id=\"4ddff702\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-ec7b6f8 e-con-full e-flex e-con e-child\" data-id=\"ec7b6f8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1574d523 elementor-widget elementor-widget-text-editor\" data-id=\"1574d523\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ech\u00e9ances<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6c3110d7 e-con-full e-flex e-con e-child\" data-id=\"6c3110d7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-18a18e28 elementor-button-align-end elementor-widget elementor-widget-form\" data-id=\"18a18e28\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"SaisieEcheance\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&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=\"Nouveau formulaire\" aria-label=\"Nouveau formulaire\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"18a18e28\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-select elementor-field-group elementor-column elementor-field-group-nb_echeancesVir elementor-col-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-nb_echeancesVir\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tEch\u00e9ances\t\t\t\t\t\t\t<\/label>\n\t\t\t\t\t\t\t\t<div class=\"elementor-field elementor-select-wrapper remove-before \">\n\t\t\t<div class=\"select-caret-down-wrapper\">\n\t\t\t\t<i aria-hidden=\"true\" class=\"eicon-caret-down\"><\/i>\t\t\t<\/div>\n\t\t\t<select name=\"form_fields[nb_echeancesVir]\" id=\"form-field-nb_echeancesVir\" class=\"elementor-field-textual elementor-size-xs\">\n\t\t\t\t\t\t\t\t\t<option value=\"1\" selected=\"selected\">1<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"2\">2<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"3\">3<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"4\">4<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"5\">5<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"6\">6<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"7\">7<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"8\">8<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"9\">9<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"10\">10<\/option>\n\t\t\t\t\t\t\t<\/select>\n\t\t<\/div>\n\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<\/div>\n\t\t<div class=\"elementor-element elementor-element-26fe5ce8 e-con-full e-flex e-con e-child\" data-id=\"26fe5ce8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4236a7ec elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"4236a7ec\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MontantHebdomadaireSansFraisTextVir\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">hebdomadaire(s)<br>sans frais<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3aba6142 e-con-full EcheancierContenerVir elementor-hidden-tablet e-flex e-con e-child\" data-id=\"3aba6142\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7e725703 EcheanciertexteVir elementor-widget elementor-widget-text-editor\" data-id=\"7e725703\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p style=\"text-align: center;\">&#8211;<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1bb5d25e e-con-full e-flex e-con e-child\" data-id=\"1bb5d25e\" data-element_type=\"container\" data-e-type=\"container\" id=\"PaiementparVirBouton\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5d932e3a   elementor-widget elementor-widget-text-editor\" data-id=\"5d932e3a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Choisir<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1b252b16 e-con-full ChoisirDeviseConteneur e-flex e-con e-child\" data-id=\"1b252b16\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5b910fed elementor-button-align-end FormSelectDevises elementor-widget__width-initial elementor-widget elementor-widget-form\" data-id=\"5b910fed\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"FormDevise2\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&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=\"FormSelectDevises2\" aria-label=\"FormSelectDevises2\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"5b910fed\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-select elementor-field-group elementor-column elementor-field-group-selected_currency_2 elementor-col-100\">\n\t\t\t\t\t\t\t<div class=\"elementor-field elementor-select-wrapper remove-before \">\n\t\t\t<div class=\"select-caret-down-wrapper\">\n\t\t\t\t<i aria-hidden=\"true\" class=\"eicon-caret-down\"><\/i>\t\t\t<\/div>\n\t\t\t<select name=\"form_fields[selected_currency_2]\" id=\"form-field-selected_currency_2\" class=\"elementor-field-textual elementor-size-xs\">\n\t\t\t\t\t\t\t\t\t<option value=\"EUR\">Devise<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"EUR\">EUR<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"USD\">USD<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"GBP\">GBP<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"CHF\">CHF<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"XAF\">XAF<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"XOF\">XOF<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"CDF\">CDF<\/option>\n\t\t\t\t\t\t\t\t\t<option value=\"MGA\">MGA<\/option>\n\t\t\t\t\t\t\t<\/select>\n\t\t<\/div>\n\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-169bc90 e-con-full e-flex e-con e-child\" data-id=\"169bc90\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-6dac89ba e-con-full ChoisirPaiementClass e-flex e-con e-child\" data-id=\"6dac89ba\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-440fed7c elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"440fed7c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Le nombre d&rsquo;\u00e9ch\u00e9ances est li\u00e9 \u00e0 la derni\u00e8re \u00e9ch\u00e9ance de paiement fix\u00e9e \u00e0 7 jours avant la fin d&rsquo;une campagne<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f9d0c61 e-con-full e-flex e-con e-child\" data-id=\"f9d0c61\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgAlerteModedePaiementConteneur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5ca8d170 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"5ca8d170\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MsgAlerteModedePaiementTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Le bon de commande est adress\u00e9 au client par email<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-25fd4bd e-con-full e-flex e-con e-child\" data-id=\"25fd4bd\" data-element_type=\"container\" data-e-type=\"container\" id=\"EtapeValidations\">\n\t\t<div class=\"elementor-element elementor-element-aa1d9e8 e-con-full e-flex e-con e-child\" data-id=\"aa1d9e8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-18df48e e-con-full e-flex e-con e-child\" data-id=\"18df48e\" data-element_type=\"container\" data-e-type=\"container\" id=\"ValidationTitreContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1fe6545 ValidationsTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"1fe6545\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ValidationsTitreIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-7e698e9 ValidationsTitre elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"7e698e9\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ValidationsTitreIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-2182b27 ValidationsTitre elementor-widget elementor-widget-text-editor\" data-id=\"2182b27\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ValidationsTitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #999999;\">Validations et CGV<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4a6acc7d e-con-full e-flex e-con e-child\" data-id=\"4a6acc7d\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgCommandeValidee\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5bf67699 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"5bf67699\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>La ou les commande(s) sont confirm\u00e9e(s)<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7693f85b e-con-full LisereBleu e-flex e-con e-child\" data-id=\"7693f85b\" data-element_type=\"container\" data-e-type=\"container\" id=\"ValidationsConteneur\">\n\t\t<div class=\"elementor-element elementor-element-5f5cb0e3 e-con-full e-flex e-con e-child\" data-id=\"5f5cb0e3\" data-element_type=\"container\" data-e-type=\"container\" id=\"ValidationsSubConteneur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6e49b5e8 elementor-button-align-center elementor-widget__width-inherit ValidationBoiteACocher elementor-widget-mobile__width-initial elementor-widget elementor-widget-form\" data-id=\"6e49b5e8\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ValidationCommandeCheck\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_Validation_Commande\" aria-label=\"Formulaire_Validation_Commande\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"6e49b5e8\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-checkbox elementor-field-group elementor-column elementor-field-group-Validation_Commande elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-Validation_Commande\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tValidation Commande\t\t\t\t\t\t\t<\/label>\n\t\t\t\t\t\t<div class=\"elementor-field-subgroup  \"><span class=\"elementor-field-option\"><input type=\"checkbox\" value=\"Accepter les \u00e9l\u00e9ments de(s) r\u00e9servation(s) et transmettre la ou les annonces\" id=\"form-field-Validation_Commande-0\" name=\"form_fields[Validation_Commande]\"> <label for=\"form-field-Validation_Commande-0\">Accepter les \u00e9l\u00e9ments de(s) r\u00e9servation(s) et transmettre la ou les annonces<\/label><\/span><\/div>\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-58d08955 e-con-full e-flex e-con e-child\" data-id=\"58d08955\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgElementsCommande\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8d5508d elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"8d5508d\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MsgElementsCommandeText\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tAfin de passer commande, merci d&rsquo;accepter les \u00e9l\u00e9ments command\u00e9s\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1ef29d84 elementor-button-align-center elementor-widget__width-inherit ValidationBoiteACocher elementor-widget elementor-widget-form\" data-id=\"1ef29d84\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ValidationCGVCheck\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_Acceptation_CGV\" aria-label=\"Formulaire_Acceptation_CGV\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"1ef29d84\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-checkbox elementor-field-group elementor-column elementor-field-group-Acceptation_CGV elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-Acceptation_CGV\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tAcceptation CGV\t\t\t\t\t\t\t<\/label>\n\t\t\t\t\t\t<div class=\"elementor-field-subgroup  \"><span class=\"elementor-field-option\"><input type=\"checkbox\" value=\"Conditions G\u00e9n\u00e9rales de Vente lues et accept\u00e9es\" id=\"form-field-Acceptation_CGV-0\" name=\"form_fields[Acceptation_CGV]\"> <label for=\"form-field-Acceptation_CGV-0\">Conditions G\u00e9n\u00e9rales de Vente lues et accept\u00e9es<\/label><\/span><\/div>\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-5483939 e-con-full e-flex e-con e-child\" data-id=\"5483939\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5a5af3c4 UrlCGV elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"5a5af3c4\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"VoirCGV\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #7c89a4;\"><a style=\"color: #7c89a4;\" href=\"#\">(voir CGV)<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2329e56b e-con-full PasserCommandeClass e-flex e-con e-child\" data-id=\"2329e56b\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgCGV\">\n\t\t\t\t<div class=\"elementor-element elementor-element-69d8325c elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"69d8325c\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MsgCGVText\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVeuillez accepter les Conditions G\u00e9n\u00e9rales de Vente\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2f41fdd7 elementor-button-align-center elementor-widget__width-inherit ValidationBoiteACocher elementor-widget elementor-widget-form\" data-id=\"2f41fdd7\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"AcceptationCommandeCheck\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_Acceptation_Commande\" aria-label=\"Formulaire_Acceptation_Commande\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"2f41fdd7\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-checkbox elementor-field-group elementor-column elementor-field-group-Acceptation_Commande elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-Acceptation_Commande\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tAcceptation Commande\t\t\t\t\t\t\t<\/label>\n\t\t\t\t\t\t<div class=\"elementor-field-subgroup  \"><span class=\"elementor-field-option\"><input type=\"checkbox\" value=\"J&#039;accepte de passer commande et de payer\" id=\"form-field-Acceptation_Commande-0\" name=\"form_fields[Acceptation_Commande]\"> <label for=\"form-field-Acceptation_Commande-0\">J&rsquo;accepte de passer commande et de payer<\/label><\/span><\/div>\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-xs\" 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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-1dd57b36 e-con-full PasserCommandeClass e-flex e-con e-child\" data-id=\"1dd57b36\" data-element_type=\"container\" data-e-type=\"container\" id=\"MsgAcceptationCommandeConteneur\">\n\t\t\t\t<div class=\"elementor-element elementor-element-447f429d elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"447f429d\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MsgAcceptationCommandeText\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Merci d&rsquo;accepter de passer commande et de payer<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5808f1f8 e-con-full ValidationsCGVBouton e-flex e-con e-child\" data-id=\"5808f1f8\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-28ea8edc   elementor-widget elementor-widget-text-editor\" data-id=\"28ea8edc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Valider<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-89c7adb e-con-full e-flex e-con e-child\" data-id=\"89c7adb\" data-element_type=\"container\" data-e-type=\"container\" id=\"EtapePaiement\">\n\t\t<div class=\"elementor-element elementor-element-eb40f12 e-con-full e-flex e-con e-child\" data-id=\"eb40f12\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-910e338 e-con-full e-flex e-con e-child\" data-id=\"910e338\" data-element_type=\"container\" data-e-type=\"container\" id=\"PaiementTitreContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a13fc30 ProcederPaiementTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"a13fc30\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ProcederPaiementTitreIconeUp\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-up\"><\/i>\t\t\t<\/a>\n\t\t<\/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-3a87fe2 elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile ProcederPaiementTitre elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"3a87fe2\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ProcederPaiementTitreIconeDown\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-down\"><\/i>\t\t\t<\/a>\n\t\t<\/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-d9e8fe8 ProcederPaiementTitre elementor-widget elementor-widget-text-editor\" data-id=\"d9e8fe8\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ProcederPaiementTitreTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<a href=\"#\"><span style=\"color: #999999;\">Bon de commande, paiement et facture<\/span><\/a>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7836db77 e-con-full e-flex e-con e-child\" data-id=\"7836db77\" data-element_type=\"container\" data-e-type=\"container\" id=\"ProcederPaiementContenu\">\n\t\t<div class=\"elementor-element elementor-element-4059e13a e-con-full LisereBleu elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"4059e13a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-25949722 e-con-full Bondecommande e-flex e-con e-child\" data-id=\"25949722\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t<div class=\"elementor-element elementor-element-122ebc32 e-con-full e-flex e-con e-child\" data-id=\"122ebc32\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6a98b3ed elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"6a98b3ed\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-right\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b81fe35 e-con-full e-flex e-con e-child\" data-id=\"b81fe35\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-92d044a elementor-widget__width-inherit elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"92d044a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tBon de commande\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-5a3babd8 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"5a3babd8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tdisponible ici et adress\u00e9 sur le mail renseign\u00e9\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5a9915c e-con-full e-flex e-con e-child\" data-id=\"5a9915c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2a54548e e-con-full LisereBleu elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"2a54548e\" data-element_type=\"container\" data-e-type=\"container\" id=\"Paiement2eLisereBleu\">\n\t\t<div class=\"elementor-element elementor-element-2c30321b e-con-full e-flex e-con e-child\" data-id=\"2c30321b\" data-element_type=\"container\" data-e-type=\"container\" id=\"ProcederPaiementConteneur\">\n\t\t<div class=\"elementor-element elementor-element-3f04e8a e-con-full EcheancierCB e-flex e-con e-child\" data-id=\"3f04e8a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-748fe0f7 e-con-full Echeancesactivecontener e-flex e-con e-child\" data-id=\"748fe0f7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-21ddc92d e-con-full e-flex e-con e-child\" data-id=\"21ddc92d\" data-element_type=\"container\" data-e-type=\"container\" id=\"EcheanceActiveTextNoInputConteneur\">\n\t\t<div class=\"elementor-element elementor-element-50c32544 e-con-full e-flex e-con e-child\" data-id=\"50c32544\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ac753b6 elementor-widget__width-initial elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"ac753b6\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"EcheanceActiveTextNoInput\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>paiement de -\u20ac<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4b101e55 elementor-widget__width-initial elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"4b101e55\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MailsFactureTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Mails facture<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-16f67d4e e-con-full e-flex e-con e-child\" data-id=\"16f67d4e\" data-element_type=\"container\" data-e-type=\"container\" id=\"ValiditeBdcPaiementContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3d5238d2 elementor-widget__width-inherit elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"3d5238d2\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"ValiditeBdcPaiement\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Le bon de commande, le tarif et le paiement sont valables<br \/>durant 6 heures jusqu&rsquo;\u00e0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7cf8819d e-con-full e-flex e-con e-child\" data-id=\"7cf8819d\" data-element_type=\"container\" data-e-type=\"container\" id=\"FormulaireCB\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5f734fd0 elementor-widget-mobile__width-inherit  Bondecommande elementor-widget elementor-widget-text-editor\" data-id=\"5f734fd0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPaiement par carte bancaire\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-27a96001 e-con-full e-flex e-con e-child\" data-id=\"27a96001\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1ee59bfe e-con-full e-flex e-con e-child\" data-id=\"1ee59bfe\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-48618ead elementor-widget elementor-widget-text-editor\" data-id=\"48618ead\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPowered by \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1d0a4ca5 e-con-full e-flex e-con e-child\" data-id=\"1d0a4ca5\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2f66b3c6 elementor-widget elementor-widget-image\" data-id=\"2f66b3c6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"468\" height=\"223\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/Stripe_wordmark_-_slate.png\" class=\"attachment-full size-full wp-image-160669\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/Stripe_wordmark_-_slate.png 468w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/Stripe_wordmark_-_slate-300x143.png 300w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/Stripe_wordmark_-_slate-18x9.png 18w\" sizes=\"(max-width: 468px) 100vw, 468px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-15879106 e-con-full e-flex e-con e-child\" data-id=\"15879106\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-2bee9eee e-con-full e-flex e-con e-child\" data-id=\"2bee9eee\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5147012 elementor-widget elementor-widget-image\" data-id=\"5147012\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"128\" height=\"80\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/22.png\" class=\"attachment-large size-large wp-image-160670\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/22.png 128w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/22-18x12.png 18w\" sizes=\"(max-width: 128px) 100vw, 128px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-513f7c22 e-con-full e-flex e-con e-child\" data-id=\"513f7c22\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4a02a401 elementor-widget elementor-widget-image\" data-id=\"4a02a401\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"128\" height=\"80\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/2.png\" class=\"attachment-full size-full wp-image-160671\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/2.png 128w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/2-18x12.png 18w\" sizes=\"(max-width: 128px) 100vw, 128px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-764d2282 e-con-full e-flex e-con e-child\" data-id=\"764d2282\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-11655557 elementor-widget elementor-widget-image\" data-id=\"11655557\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"128\" height=\"80\" src=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/1.png\" class=\"attachment-full size-full wp-image-160672\" alt=\"\" srcset=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/1.png 128w, https:\/\/yearbook-media.com\/wp-content\/uploads\/2025\/04\/1-18x12.png 18w\" sizes=\"(max-width: 128px) 100vw, 128px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5c296acc e-con-full e-flex e-con e-child\" data-id=\"5c296acc\" data-element_type=\"container\" data-e-type=\"container\" id=\"CBPayerSommeContainer\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3e6a8f64   elementor-widget elementor-widget-text-editor\" data-id=\"3e6a8f64\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"Payerlasommede\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPayer la somme de\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-52194cfc   elementor-widget elementor-widget-text-editor\" data-id=\"52194cfc\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"FormCBMontant\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t&nbsp;\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-24fd12f8 e-con-full e-flex e-con e-child\" data-id=\"24fd12f8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-22d35b1d elementor-widget-mobile__width-inherit   elementor-widget elementor-widget-text-editor\" data-id=\"22d35b1d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Titulaire de la carte<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-55d2643e e-con-full e-flex e-con e-child\" data-id=\"55d2643e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-2de80ac4 e-con-full e-flex e-con e-child\" data-id=\"2de80ac4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-54bc7ce7 elementor-button-align-center elementor-widget__width-initial elementor-widget-mobile__width-initial elementor-widget elementor-widget-form\" data-id=\"54bc7ce7\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"CBNomTitulaireCarte\" data-settings=\"{&quot;step_next_label&quot;:&quot;Suivant&quot;,&quot;step_previous_label&quot;:&quot;Pr\\u00e9c\\u00e9dent&quot;,&quot;step_type&quot;:&quot;none&quot;,&quot;step_icon_shape&quot;:&quot;none&quot;,&quot;button_width&quot;:&quot;100&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=\"Formulaire_nom_email_titulaire_carte\" aria-label=\"Formulaire_nom_email_titulaire_carte\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"278591\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"54bc7ce7\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n\n\t\t\t\t\t\t\t<input type=\"hidden\" name=\"queried_id\" value=\"218790\"\/>\n\t\t\t\n\t\t\t<div class=\"elementor-form-fields-wrapper elementor-labels-\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-field-type-text elementor-field-group elementor-column elementor-field-group-nom_titulaire_carte elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-nom_titulaire_carte\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tNom du titulaire de la carte\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[nom_titulaire_carte]\" id=\"form-field-nom_titulaire_carte\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"First &amp; last name\">\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-xs\" type=\"submit\" id=\"Buttonnom_titulaire_carte\">\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\t\t<span class=\"elementor-button-text\"> <\/span>\n\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<div class=\"elementor-element elementor-element-2624c140 e-con-full e-flex e-con e-child\" data-id=\"2624c140\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-71b41a83 elementor-widget elementor-widget-html\" data-id=\"71b41a83\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<form action=\"\/process-payment\" method=\"post\" id=\"stripe-payment-form\">    \r\n    <div class=\"form-row\">\r\n    <div class=\"flex-container\">\r\n      <div id=\"brand-icon-container\"><img decoding=\"async\" id=\"brand-icon\" src=\"\"><\/div>\r\n      <div id=\"card-number-element\"><\/div>\r\n    <\/div>\r\n    <div class=\"flex-container\">\r\n      <div id=\"card-expiry-element\"><\/div>\r\n      <div id=\"card-cvc-element\"><\/div>\r\n      <div id=\"postal-code-element\"><\/div>\r\n    <\/div>\r\n    <\/div>\r\n<\/form>\r\n\r\n<script src=\"https:\/\/js.stripe.com\/v3\/\"><\/script>\r\n\r\n<style>\r\n.flex-container {\r\n  display: flex;\r\n  justify-content: space-between;\r\n  margin-top: 5px;\r\n  margin-bottom: 5px;\r\n}\r\n\r\n#brand-icon-container {\r\n  width: 55px;\r\n  height: 35px;\r\n}\r\n\r\n#brand-icon,\r\n#card-number-element,\r\n#card-expiry-element,\r\n#card-cvc-element,\r\n#postal-code-element {\r\n  margin-top: 5px;\r\n  margin-bottom: 5px;\r\n}\r\n\r\n#brand-icon,\r\n#card-number-element {\r\n  flex: 1;\r\n  width: 45%; \/* Adjust this value as needed *\/\r\n}\r\n\r\n#card-expiry-element,\r\n#card-cvc-element,\r\n#postal-code-element {\r\n  flex: 1;\r\n  width: 45%; \/* Adjust this value as needed *\/\r\n}\r\n<\/style>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2fc269bf e-con-full e-flex e-con e-child\" data-id=\"2fc269bf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-2cb536 e-con-full e-flex e-con e-child\" data-id=\"2cb536\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-79b24814 elementor-widget elementor-widget-text-editor\" data-id=\"79b24814\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tZip if required\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-59380997 e-con-full e-flex e-con e-child\" data-id=\"59380997\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-548943a1 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"548943a1\" data-element_type=\"widget\" data-e-type=\"widget\" id=\"MsgErreurTitulaireCarte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Paiement disponible apr\u00e8s transmission de l&rsquo;annonce<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-53926c62 e-flex e-con-boxed e-con e-child\" data-id=\"53926c62\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-11f256b5 e-con-full e-flex e-con e-child\" data-id=\"11f256b5\" data-element_type=\"container\" data-e-type=\"container\" id=\"ButtonValiderCB\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2cc1d3b2   elementor-widget elementor-widget-text-editor\" data-id=\"2cc1d3b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #225da9;\"><a style=\"color: #225da9;\" href=\"#\">Payer<\/a><\/span>\t\t\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\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-8f69c47 elementor-hidden-desktop elementor-hidden-mobile e-flex e-con-boxed e-con e-child\" data-id=\"8f69c47\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-484885c9 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"484885c9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6f84a5eb elementor-widget elementor-widget-html\" data-id=\"6f84a5eb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<html lang=\"fr\">\r\n\r\n<input type=\"hidden\" id=\"espacepub_id\">\r\n<input type=\"hidden\" id=\"format\">\r\n<input type=\"hidden\" id=\"position\">\r\n<input type=\"hidden\" id=\"emplacement_page_web\">\r\n\r\n<\/html>\r\n<script>\r\n\/**\r\n * VIA Agency - Formulaire Elementor (Version 3.6 - AssocierPaysMessage)\r\n * @version 3.6 - F\u00e9vrier 2026\r\n * - v3.4 : anti-doublon commandes, r\u00e9initialisation formulaire\r\n * - \u2705 v3.5 : Couleur vert flash #E8F0FE pour .date-selected et .country-selected\r\n * - \u2705 v3.6 : R\u00e9activation #AssocierPaysMessageContainer quand accord\u00e9on pays ferm\u00e9 manuellement\r\n *\/\r\n\r\n(function() {\r\n    'use strict';\r\n\r\n    \/\/ pb465 : reduire de 5px l'espace sous le message \"Communication associee au site X\" quand l'etape\r\n    \/\/   Pays est FERMEE (mobile + desktop). DIAGNOSTIC : Elementor (ou kit.js) REIMPOSE en boucle le\r\n    \/\/   margin-bottom:32px inline du #AssocierPaysMessageContainer -> toute modif de notre part declenche\r\n    \/\/   une re-pose -> guerre infinie (435 oscillations 32<->27 observees). On ABANDONNE donc ce combat.\r\n    \/\/   SOLUTION : reduire le margin-bottom du PARENT #PaysSecteursChildContainer (qu'Elementor ne touche\r\n    \/\/   PAS en inline) de 5px relatif a sa valeur reelle. Effet visuel identique (l'espace total sous le\r\n    \/\/   message = margin-bottom du message, a l'interieur du parent, + margin-bottom du parent). Pose UNE\r\n    \/\/   SEULE FOIS (verrou data-via-pb465 anti-recursion), pas d'observer -> aucune boucle possible.\r\n    var _pb465Active = false;\r\n    var _PB465_REDUCE = 5;\r\n    var _PB465_PARENT = 'PaysSecteursChildContainer';\r\n    function _viaPb465ApplyOnce() {\r\n        if (!_pb465Active) { return; }\r\n        var _p = document.getElementById(_PB465_PARENT);\r\n        if (!_p) { return; }\r\n        if (_p.getAttribute('data-via-pb465') === '1') { return; } \/\/ deja applique -> ne pas re-soustraire\r\n        var _cur = parseFloat(window.getComputedStyle(_p).marginBottom);\r\n        if (isNaN(_cur)) { _cur = 0; }\r\n        _p.style.setProperty('margin-bottom', (_cur - _PB465_REDUCE) + 'px', 'important');\r\n        _p.setAttribute('data-via-pb465', '1');\r\n    }\r\n    function _viaPb465Apply() {\r\n        _pb465Active = true;\r\n        _viaPb465ApplyOnce();\r\n        \/\/ retries pour le timing (rendu differe) ; le verrou empeche toute re-soustraction\r\n        [50, 200, 500, 1000, 2000].forEach(function(_d465) { setTimeout(_viaPb465ApplyOnce, _d465); });\r\n    }\r\n    \/\/ pb465 : etape OUVERTE -> rendre la main (retirer notre margin + le verrou).\r\n    function _viaPb465Release() {\r\n        _pb465Active = false;\r\n        var _p = document.getElementById(_PB465_PARENT);\r\n        if (_p) {\r\n            _p.style.removeProperty('margin-bottom');\r\n            _p.removeAttribute('data-via-pb465');\r\n        }\r\n    }\r\n\r\n    \/\/ \u2705 v2.6 : Proxy tarif \u2014 intercepte calculerTarifAPI avant que VIA_App ne soit pr\u00eat\r\n    \/\/ S'ex\u00e9cute de fa\u00e7on synchrone d\u00e8s le chargement du script\r\n    function _proxyCalculerTarif(format, position, duree, paysCible) {\r\n        var apiData = { format: format, position: position, duree: duree, pays_cible: paysCible, nb_echeances: 1 };\r\n        return fetch(window.location.origin + '\/wp-json\/yearbook\/v1\/calculer-tarif', {\r\n            method: 'POST',\r\n            headers: { 'Content-Type': 'application\/json' },\r\n            body: JSON.stringify(apiData)\r\n        }).then(function(r) { return r.json(); }).then(function(data) {\r\n            if (data.success) {\r\n                return { success: true, tarif_ht: parseFloat(data.data.tarif_ht), tarif_ttc: parseFloat(data.data.tarif_ttc) };\r\n            }\r\n            return { success: false, message: data.message };\r\n        }).catch(function(e) {\r\n            return { success: false, message: 'Erreur proxy: ' + e.message };\r\n        });\r\n    }\r\n    \/\/ \u2705 v2.7 : Exposer le proxy globalement pour que Panier_manager puisse l'utiliser (\u00e9vite CORS via-agency.media)\r\n    window._viaProxyCalculerTarif = _proxyCalculerTarif;\r\n\r\n    \/\/ Remplacer d\u00e8s que VIA_App est d\u00e9fini (polling l\u00e9ger)\r\n    var _proxyInterval = setInterval(function() {\r\n        if (window.VIA_App && typeof window.VIA_App.calculerTarifAPI === 'function') {\r\n            window.VIA_App.calculerTarifAPI = _proxyCalculerTarif;\r\n            console.log('\ud83d\udd01 [proxy] calculerTarifAPI substitu\u00e9e');\r\n            clearInterval(_proxyInterval);\r\n        }\r\n    }, 50);\r\n\r\n    \r\n    \/\/ \u2705 Fonction helper pour \u00e9viter l'encodage WordPress de &&\r\n    const AND = (a, b) => !(!a || !b);\r\n\r\n    \/\/ pb1261 : ECHO DE VERSION. Ce fichier n'en avait pas \u2014 impossible de\r\n    \/\/   distinguer \u00ab snippet non deploye \/ cache LiteSpeed \u00bb de \u00ab deploye mais\r\n    \/\/   branche non atteinte \u00bb, alors que c'est la premiere verification du\r\n    \/\/   protocole. Meme role que _viaPanierVer et _viaEnteteVer ailleurs.\r\n    window._viaFormulaireVer = 'FRM-pb2354';\r\n    console.log('[FORMULAIRE ECHO] ' + window._viaFormulaireVer + ' SERVI');\r\n    console.log('\ud83c\udfa8 Initialisation formulaire Elementor VIA Agency v3.6 (AssocierPaysMessage)');\r\n\r\n    const MAIN_JS_URL = 'https:\/\/via-agency.media\/wp-content\/plugins\/via-agency\/assets\/js\/main.js';    \r\n    const COUNTRIES_JS_URL = 'https:\/\/via-agency.media\/wp-content\/plugins\/via-agency\/assets\/js\/countries-config.js?v=2.0';\r\n    const JQUERY_UI_URL = 'https:\/\/code.jquery.com\/ui\/1.12.1\/jquery-ui.min.js';\r\n\r\n    function loadScript(url, id) {\r\n        return new Promise((resolve, reject) => {\r\n            if (document.getElementById(id)) {\r\n                console.log(`\u2705 Script d\u00e9j\u00e0 charg\u00e9: ${id}`);\r\n                resolve();\r\n                return;\r\n            }\r\n\r\n            console.log(`\ud83d\udd04 Chargement de ${id} depuis ${url}`);\r\n            \r\n            const script = document.createElement('script');\r\n            script.id = id;\r\n            script.src = url;\r\n            script.onload = () => {\r\n                console.log(`\u2705 ${id} charg\u00e9 avec succ\u00e8s`);\r\n                resolve();\r\n            };\r\n            script.onerror = () => {\r\n                console.error(`\u274c \u00c9chec du chargement de ${id} depuis ${url}`);\r\n                reject(new Error(`Impossible de charger ${id}`));\r\n            };\r\n\r\n            document.head.appendChild(script);\r\n        });\r\n    }\r\n\r\n    async function initFormulaire() {\r\n        try {\r\n            if (typeof jQuery === 'undefined') {\r\n                console.error('\u274c jQuery non charg\u00e9');\r\n                alert('ERREUR: jQuery doit \u00eatre charg\u00e9 avant ce script.');\r\n                return;\r\n            }\r\n            console.log('\u2705 jQuery disponible');\r\n\r\n            \/\/ \u2705 v2.6 : chargement parall\u00e8le (1-2s gagn\u00e9s vs s\u00e9quentiel)\r\n            console.log('\ud83d\udd04 Chargement parall\u00e8le main.js + countries-config.js...');\r\n            await Promise.all([\r\n                loadScript(MAIN_JS_URL, 'via-main-js'),\r\n                loadScript(COUNTRIES_JS_URL, 'via-countries-config-js')\r\n            ]);\r\n\r\n            let attempts = 0;\r\n            while (AND(typeof window.VIA_App === 'undefined', attempts < 30)) { \/\/ \u2705 v2.6 : 10s \u2192 3s\r\n                await new Promise(resolve => setTimeout(resolve, 100));\r\n                attempts++;\r\n            }\r\n\r\n            if (typeof window.VIA_App === 'undefined') {\r\n                throw new Error('VIA_App non disponible apr\u00e8s 3 secondes');\r\n            }\r\n\r\n            console.log('\u2705 main.js charg\u00e9, VIA_App disponible');\r\n\r\n            \/\/ \u2705 v2.6 : Override calculerTarifAPI pour passer par le proxy local (\u00e9vite CORS)\r\n            window.VIA_App.calculerTarifAPI = async function(format, position, duree, paysCible) {\r\n                console.log('\ud83d\udd01 [proxy] calculerTarifAPI via proxy local:', { format, position, duree, paysCible });\r\n                const apiData = { format: format, position: position, duree: duree, pays_cible: paysCible, nb_echeances: 1 };\r\n                try {\r\n                    const response = await fetch(window.location.origin + '\/wp-json\/yearbook\/v1\/calculer-tarif', {\r\n                        method: 'POST',\r\n                        headers: { 'Content-Type': 'application\/json' },\r\n                        body: JSON.stringify(apiData)\r\n                    });\r\n                    const data = await response.json();\r\n                    if (data.success) {\r\n                        return { success: true, tarif_ht: parseFloat(data.data.tarif_ht), tarif_ttc: parseFloat(data.data.tarif_ttc) };\r\n                    } else {\r\n                        return { success: false, message: data.message };\r\n                    }\r\n                } catch (error) {\r\n                    console.error('\u274c [proxy] Erreur:', error);\r\n                    return { success: false, message: 'Erreur de connexion au proxy' };\r\n                }\r\n            };\r\n            console.log('\ud83d\udd01 calculerTarifAPI remplac\u00e9e par version proxy');\r\n\r\n            \/\/ v2.9 : overrider checkTauxInDB -> appel same-origin (yearbook-media.com\/wp-admin\/admin-ajax.php)\r\n            \/\/ Le proxy via_taux_de_change_proxy est deja deploye sur yearbook-media.com\r\n            window.VIA_App.checkTauxInDB = async function() {\r\n                var _r = await fetch(window.location.origin + '\/wp-admin\/admin-ajax.php', {\r\n                    method: 'POST',\r\n                    credentials: 'same-origin',\r\n                    headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n                    body: 'action=via_taux_de_change_proxy'\r\n                });\r\n                var _data = await _r.json();\r\n                if (_data && _data.success && _data.taux) {\r\n                    this.saveTauxToSessionStorage(_data.taux);\r\n                    console.log('\ud83d\udd01 checkTauxInDB proxy same-origin OK:', Object.keys(_data.taux).join(', '));\r\n                    return 'OK';\r\n                }\r\n                return 'KO';\r\n            };\r\n\r\n            attempts = 0;\r\n            while (AND(!window.VIA_App.tauxDeChange.EUR, attempts < 20)) { \/\/ \u2705 v2.6 : 5s \u2192 2s\r\n                await new Promise(resolve => setTimeout(resolve, 100));\r\n                attempts++;\r\n            }\r\n\r\n            if (!window.VIA_App.tauxDeChange.EUR) {\r\n                console.warn('\u26a0\ufe0f Taux de change non charg\u00e9s apr\u00e8s 2 secondes');\r\n            } else {\r\n                console.log('\u2705 Taux de change disponibles');\r\n            }\r\n\r\n            jQuery(function($) {\r\n                \/\/ \u2705 v1.7 : Initialiser AssocierPays imm\u00e9diatement (pas besoin des taux de change)\r\n                $('.AssocierPaysTitre').off('click').on('click', function(event) {\r\n                    event.preventDefault();\r\n                    if ($('.AssocierPaysClass').is(':hidden')) {\r\n                        $('.AssocierPaysClass').show();\r\n                        $('.AssocierPaysClass .SousTitre').show();\r\n                        $('#AssocierPaysTitreIconeUp').show();\r\n                        $('#AssocierPaysTitreIconeDown').hide();\r\n                        \/\/ \u2705 v1.9 : Masquer le message quand l'accord\u00e9on est ouvert\r\n                        $('#AssocierPaysMessageContainer').hide();\r\n                        _viaPb465Release(); \/\/ pb465 : etape ouverte -> rendre la main a Elementor (32px)\r\n                    } else {\r\n                        \/\/ \u2705 v1.16.0 : Masquer SousTitre imm\u00e9diatement\r\n                        $('.AssocierPaysClass .SousTitre').hide();\r\n                        $('.AssocierPaysClass').hide();\r\n                        $('#AssocierPaysTitreIconeUp').hide();\r\n                        $('#AssocierPaysTitreIconeDown').show();\r\n                        \/\/ \u2705 v1.9 : Afficher le message si un pays est s\u00e9lectionn\u00e9\r\n                        \/\/ \u2705 v2.0.1 : R\u00e9activ\u00e9\r\n                        const continentPaysTitre = sessionStorage.getItem('ContinentPaysTitre');\r\n                        if (continentPaysTitre) {\r\n                            const siteName = sessionStorage.getItem('ContinentPaysTitreDisplayed') || continentPaysTitre.split(\/[\\s]+\/)[0];\r\n                            \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction EN\r\n                            var _isEN_AP1 = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                            var _msgAP1 = _isEN_AP1\r\n                                ? 'Communication linked to the ' + siteName + ' site'\r\n                                : 'Communication associ\u00e9e au site ' + siteName;\r\n                            $('#AssocierPaysMessageTexte').text(_msgAP1);\r\n                            $('#AssocierPaysMessageContainer').show();\r\n                            _viaPb465Apply(); \/\/ pb465 : etape fermee + message affiche -> margin-bottom 27px\r\n                        }\r\n                    }\r\n                });\r\n                console.log('\u2705 Gestion AssocierPays initialis\u00e9e (imm\u00e9diat)');\r\n                \r\n                \/\/ \u2705 v1.7 : Initialiser AssocierSecteur imm\u00e9diatement (pas besoin des taux de change)\r\n                $('.AssocierSecteurTitre').off('click').on('click', function(event) {\r\n                    event.preventDefault();\r\n                    if ($('.AssocierSecteurClass').is(':hidden')) {\r\n                        $('.AssocierSecteurClass').show();\r\n                        $('.AssocierSecteurClass .SousTitre').show();\r\n                        $('#AssocierSecteurTitreIconeUp').show();\r\n                        $('#AssocierSecteurTitreIconeDown').hide();\r\n                        \/\/ \u2705 v1.9 : Masquer le message quand l'accord\u00e9on est ouvert\r\n                        $('#SecteursMessageContainer').hide();\r\n                    } else {\r\n                        \/\/ \u2705 v1.16.0 : Masquer SousTitre imm\u00e9diatement\r\n                        $('.AssocierSecteurClass .SousTitre').hide();\r\n                        $('.AssocierSecteurClass').hide();\r\n                        $('#AssocierSecteurTitreIconeUp').hide();\r\n                        $('#AssocierSecteurTitreIconeDown').show();\r\n                        \/\/ \u2705 v1.9 : Afficher le message si un secteur\/article est s\u00e9lectionn\u00e9\r\n                        const selectedPageType = sessionStorage.getItem('SelectedPageType');\r\n                        const selectedPageSecteurDisplayed = sessionStorage.getItem('SelectedPageSecteurDisplayed');\r\n                        if (selectedPageType && selectedPageSecteurDisplayed) {\r\n                            let messageText;\r\n                            \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction EN\r\n                            var _isEN_AS = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                            if (selectedPageType === 'ArtType') {\r\n                                messageText = _isEN_AS\r\n                                    ? \"The \" + selectedPageSecteurDisplayed + \" article has been selected\"\r\n                                    : \"L'article \" + selectedPageSecteurDisplayed + \" a \u00e9t\u00e9 s\u00e9lectionn\u00e9\";\r\n                            } else if (selectedPageType === 'HPType') {\r\n                                messageText = _isEN_AS\r\n                                    ? \"The Homepage has been selected\"\r\n                                    : \"La Homepage a \u00e9t\u00e9 s\u00e9lectionn\u00e9e\";\r\n                            } else {\r\n                                messageText = _isEN_AS\r\n                                    ? \"The \" + selectedPageSecteurDisplayed + \" page has been selected\"\r\n                                    : \"La page \" + selectedPageSecteurDisplayed + \" a \u00e9t\u00e9 s\u00e9lectionn\u00e9e\";\r\n                            }\r\n                            $('#SecteursMessageTexte').text(messageText);\r\n                            $('#SecteursMessageContainer').show();\r\n                        }\r\n                    }\r\n                });\r\n                console.log('\u2705 Gestion AssocierSecteur initialis\u00e9e (imm\u00e9diat)');\r\n                \r\n                \/\/ \u2705 v1.7 : Initialiser ChoixFormat imm\u00e9diatement (pas besoin des taux de change)\r\n                $('.ChoixFormatTitre').off('click').on('click', function(event) {\r\n                    event.preventDefault();\r\n                    if ($('.ChoixFormatClass').is(':hidden')) {\r\n                        $('.ChoixFormatClass').show();\r\n                        $('.ChoixFormatClass .SousTitre').show();\r\n                        \/\/ \u2705 pb507 : a l'OUVERTURE manuelle, reposer le TEXTE VERT du format\r\n                        \/\/   selectionne (le SousTitre etait montre mais son texte n'etait pas\r\n                        \/\/   repose -> il disparaissait a chaque reouverture) ET recentrer le\r\n                        \/\/   format \u2014 exactement comme pays\/secteurs. centerOnSelected delegue\r\n                        \/\/   au moteur pb504 (jumeau set 1, course des 2 cotes).\r\n                        var _fsFmtOpen507 = sessionStorage.getItem('FormatSelect');\r\n                        var _pcFmtOpen507 = sessionStorage.getItem('PopUpChoice');\r\n                        if (_fsFmtOpen507) {\r\n                            var _lblFmtOpen507 = (_pcFmtOpen507 === 'Yes') ? 'Pop-up' : _fsFmtOpen507;\r\n                            var _isENfmtOpen507 = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                            var _txtFmtOpen507 = _isENfmtOpen507\r\n                                ? ('The ' + _lblFmtOpen507 + ' format has been selected')\r\n                                : ('Le format ' + _lblFmtOpen507 + ' a \u00e9t\u00e9 s\u00e9lectionn\u00e9');\r\n                            $('.ChoixFormatClass .SousTitre').find('p').text(_txtFmtOpen507).css({ 'color': '#56BE50' });\r\n                            if (window.HorizontalScroll && typeof window.HorizontalScroll.centerOnSelected === 'function') {\r\n                                setTimeout(function() { window.HorizontalScroll.centerOnSelected('ListeFormats'); }, 150);\r\n                            }\r\n                        }\r\n                        $('#ChoixFormatTitreIconeUp').show();\r\n                        $('#ChoixFormatTitreIconeDown').hide();\r\n                        \/\/ \u2705 v1.9 : Masquer le message quand l'accord\u00e9on est ouvert\r\n                        $('#FormatMessageContainer').hide();\r\n                        \/\/ \u2705 v1.14 : Masquer le message de pr\u00e9s\u00e9lection\r\n                        $('#FormatMessagePreselectionContainer').hide();\r\n                    } else {\r\n                        \/\/ \u2705 v1.16.0 : Masquer SousTitre imm\u00e9diatement\r\n                        $('.ChoixFormatClass .SousTitre').hide();\r\n                        $('.ChoixFormatClass').hide();\r\n                        $('#ChoixFormatTitreIconeUp').hide();\r\n                        $('#ChoixFormatTitreIconeDown').show();\r\n                        \/\/ \u2705 v1.9 : Afficher le message si un format est s\u00e9lectionn\u00e9\r\n                        const popUpChoice = sessionStorage.getItem('PopUpChoice');\r\n                        const formatSelect = sessionStorage.getItem('FormatSelect');\r\n                        if (popUpChoice !== null && formatSelect !== null) {\r\n                            const formatText = popUpChoice === 'Yes' ? 'Pop-up' : formatSelect;\r\n                            if (formatText) {\r\n                                \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction EN\r\n                                var _isEN_FT = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                                var _msgFT = _isEN_FT\r\n                                    ? 'The chosen format is ' + formatText\r\n                                    : 'Le format choisi est ' + formatText;\r\n                                $('#FormatMessageTexte').text(_msgFT);\r\n                                $('#FormatMessageContainer').show();\r\n                            }\r\n                        } else if (new URLSearchParams(window.location.search).has('site')) {\r\n                            \/\/ \u2705 v1.14 : R\u00e9afficher le message preselector uniquement en mode preselector\r\n                            $('#FormatMessagePreselectionContainer').show();\r\n                        }\r\n                    }\r\n                });\r\n                console.log('\u2705 Gestion ChoixFormat initialis\u00e9e (imm\u00e9diat)');\r\n\r\n                \/\/ ============================================================\r\n                \/\/ pb892 : nouvelle \u00e9tape MOBILE UNIQUEMENT \"PageWebMobile\", entre\r\n                \/\/   ChoixFormat et le r\u00e9capitulatif. Toggle manuel identique aux 3\r\n                \/\/   bandeaux ci-dessus, mais d\u00e9l\u00e8gue l'ouverture\/fermeture aux\r\n                \/\/   fonctions writer-unique window.openPageWebMobile()\/\r\n                \/\/   closePageWebMobile() (yearbook-media.js) plut\u00f4t que de dupliquer\r\n                \/\/   la logique show\/hide ici.\r\n                \/\/   Revert : window._viaPb892Off = true.\r\n                \/\/ ============================================================\r\n                if (window.outerWidth < 1000) {\r\n                    $('.PageWebMobiletitre').off('click').on('click', function(event) {\r\n                        event.preventDefault();\r\n                        if (window._viaPb892Off === true) { return; }\r\n                        if ($('.PageWebMobileConteneurClass').is(':hidden')) {\r\n                            if (typeof window.openPageWebMobile === 'function') { window.openPageWebMobile(); }\r\n                        } else {\r\n                            if (typeof window.closePageWebMobile === 'function') { window.closePageWebMobile(); }\r\n                        }\r\n                    });\r\n                    console.log('\u2705 Gestion PageWebMobile initialis\u00e9e (imm\u00e9diat, mobile)');\r\n                }\r\n                \r\n                \/\/ \u2705 v1.7 : Initialiser DatesDureeCampagne imm\u00e9diatement\r\n                $('.DatesDureeCampagneTitre').off('click').on('click', function(event) {\r\n                    event.preventDefault();\r\n\r\n                    \/\/ \u2705 v2.0.9 : Logique bandeau ChoixDates (mobile + desktop)\r\n                    var $msg = $('#MobileMsgChoixDatesMSgDefaut');\r\n                    var msgVisible = $msg.hasClass('via-msg-visible');\r\n\r\n                    if (msgVisible) {\r\n                        \/\/ Toggle : fermer le message si d\u00e9j\u00e0 visible\r\n                        $msg.removeClass('via-msg-visible');\r\n                        return;\r\n                    }\r\n\r\n                    \/\/ Espace pub s\u00e9lectionn\u00e9 = au moins un item avec emplacementPageWeb dans le panier\r\n                    var espaceSelectionne = !!(window.VIA_Panier && window.VIA_Panier.state.items.some(function(item) {\r\n                        return item.emplacementPageWeb || item.lienEspacePub || item.cheminFichierAnnonce ||\r\n                               (item.donneesIframe && item.donneesIframe.Commande_Emplacement_Page_Web);\r\n                    }));\r\n\r\n                    if (!espaceSelectionne) {\r\n                        \/\/ Pas d'espace pub : afficher le message, masquer le formulaire, stopper\r\n                        $msg.addClass('via-msg-visible');\r\n                        $('.DatesDureeCampagneClass').hide();\r\n                        $('#DatesDureeCampagneIconeUp').hide();\r\n                        $('#DatesDureeCampagneIconeDown').show();\r\n                        return;\r\n                    }\r\n                    \/\/ Espace pub s\u00e9lectionn\u00e9 : masquer le message, laisser le toggle s'ex\u00e9cuter\r\n                    $msg.removeClass('via-msg-visible');\r\n\r\n                    if ($('.DatesDureeCampagneClass').is(':hidden')) {\r\n                        $('.DatesDureeCampagneClass').show();\r\n                        $('#DatesDureeCampagneIconeUp').show();\r\n                        $('#DatesDureeCampagneIconeDown').hide();\r\n                        $('#Etape1MessageContainer').hide();\r\n                        \/\/ v4.9ds : \u00e0 la r\u00e9ouverture manuelle de l'\u00e9tape Dates,\r\n                        \/\/   replacer DatesDureeTarifContainer APR\u00c8S EtapeRecapitulatif\r\n                        \/\/   (= position d'origine du DOM) + activer titre Dates en couleur active.\r\n                        if (window.VIA_Panier ? typeof window.VIA_Panier._viaActiverEtapeDates === 'function' : false) {\r\n                            try { window.VIA_Panier._viaActiverEtapeDates(); } catch(_eAct) {}\r\n                        }\r\n                    } else {\r\n                        $('.DatesDureeCampagneClass').hide();\r\n                        $('#DatesDureeCampagneIconeUp').hide();\r\n                        $('#DatesDureeCampagneIconeDown').show();\r\n                        if (window.VIA_Panier && window.VIA_Panier.state.items.some(item => item.tarifHT && item.tarifHT > 0)) {\r\n                            $('#Etape1MessageContainer').show();\r\n                        }\r\n                    }\r\n                });\r\n                console.log('\u2705 Gestion DatesDureeCampagne initialis\u00e9e (imm\u00e9diat)');\r\n                \r\n                initFormulaireElementor($);\r\n            });\r\n\r\n        } catch (error) {\r\n            console.error('\u274c Erreur lors de l\\'initialisation:', error);\r\n            alert('ERREUR: Impossible de charger main.js depuis via-agency.media. V\u00e9rifiez la connexion r\u00e9seau et les permissions CORS.');\r\n        }\r\n    }\r\n\r\n\r\n    function initFormulaireElementor($) {\r\n        console.log('\ud83c\udfa8 Configuration du formulaire Elementor...');\r\n\r\n        const CONFIG = {\r\n            FIELDS: {\r\n                dateDebut: 'form-field-DebutCampagne',\r\n                dateFin: 'form-field-FinCampagne',\r\n                dureeContainer: '.CampagneNbJours',\r\n                pays: 'form-field-Nationalite_Societe',\r\n                devise: 'form-field-selected_currency_visuels',\r\n                tarifDisplay: '#Tariftobedisplayed',\r\n                espacepubId: 'espacepub_id',\r\n                format: 'format',\r\n                position: 'position',\r\n                emplacementPageWeb: 'emplacement_page_web'\r\n            }\r\n        };\r\n        \r\n        const API_CLIENTS = {\r\n            url: 'https:\/\/via-agency.media\/wp-content\/plugins\/via-agency\/includes\/api\/clients-api.php'\r\n        };\r\n\r\n        const STATE = {\r\n            isJQueryUILoaded: false,\r\n            selectedCountry: null,\r\n            startDate: null,\r\n            endDate: null,\r\n            espacePubSelected: false,\r\n            format: null,\r\n            position: null,\r\n            isCommercial: false,\r\n            tarifCommercialSaisi: null,\r\n            deviseTarifCommercial: 'EUR',\r\n            isUpdatingPays: false,\r\n            lienEspacePub: null,\r\n            cheminFichierAnnonce: null\r\n        };\r\n        \r\n        \/\/ \u2705 v3.4 : Anti-doublon global\r\n        const ANTI_DOUBLON = {\r\n            derniersTraitements: {},\r\n            DELAI_MS: 2000\r\n        };\r\n\r\n        function isCommercialConnected() {\r\n            return sessionStorage.getItem('CommercialConnected') === 'Yes';\r\n        }\r\n\r\n        function gererAffichageCommerciaux() {\r\n            const isCommercial = isCommercialConnected();\r\n            STATE.isCommercial = isCommercial;\r\n            \r\n            const $containerNormal = $('#TariftobedisplayedConteneur');\r\n            \/\/ pb2126 : toutes les instances (ids dupliques par clonage des cartes).\r\n            const $containerCommercial = $('[id=\"TarifCommercialtobedisplayedConteneur\"]');\r\n            const $containerReferences = $('.ReferencesConteneur');\r\n            const $rechercheClient = $('#RechercherFicheClient');\r\n            const $etapeValidations = $('#EtapeValidations');\r\n            const $etapePaiement = $('#EtapePaiement');\r\n            \r\n            if (isCommercial) {\r\n                console.log('\ud83d\udc54 Utilisateur commercial d\u00e9tect\u00e9');\r\n                $containerNormal.hide();\r\n                \/\/ \u2705 Masquer les \u00e9tapes Validations et Paiement pour les commerciaux\r\n                $etapeValidations.hide();\r\n                $etapePaiement.hide();\r\n                console.log('\ud83d\udc54 \u00c9tapes Validations et Paiement masqu\u00e9es pour commercial');\r\n                \/\/ \u2705 setProperty important apr\u00e8s d\u00e9lai (Panier_manager peut re-cacher apr\u00e8s init)\r\n                \/\/ D\u00e9lai 1500ms + logs diagnostic\r\n                setTimeout(function() {\r\n                    console.log('\ud83d\udc54 [commercial setTimeout] CommercialConnected:', sessionStorage.getItem('CommercialConnected'));\r\n                    console.log('\ud83d\udc54 [commercial setTimeout] $containerCommercial length:', $containerCommercial.length);\r\n                    console.log('\ud83d\udc54 [commercial setTimeout] $rechercheClient length:', $rechercheClient.length);\r\n                    \/\/ pb2123 : le champ de saisie du montant N'EST PLUS affiche a\r\n                    \/\/   l'init (demande JF) \u2014 il n'apparait que lorsque le tarif de\r\n                    \/\/   la resa active s'affiche (afficherTarif, branche\r\n                    \/\/   commerciale). Panier_manage l.12286 le masque deja au\r\n                    \/\/   demarrage ; on ne le re-affiche plus ici.\r\n                    \/\/   Revert : window._viaPb2123Off = true (affichage a l'init).\r\n                    if (window._viaPb2123Off === true) {\r\n                        $containerCommercial.each(function() {\r\n                            this.style.setProperty('display','block','important');\r\n                            console.log('\ud83d\udc54 TarifCommercialtobedisplayedConteneur display apr\u00e8s setProperty:', this.style.display);\r\n                        });\r\n                    } else {\r\n                        $containerCommercial.hide();\r\n                        console.log('[pb2123] champ tarif commercial masque a l\\'init \u2014 attente du tarif');\r\n                    }\r\n                    \/\/ \u2705 Ne pas auto-ouvrir ReferencesConteneur (accord\u00e9on) \u2014 seulement s'assurer que RechercherFicheClient est visible \u00e0 l'int\u00e9rieur\r\n                    $rechercheClient.each(function() {\r\n                        this.style.setProperty('display','block','important');\r\n                        console.log('\ud83d\udc54 RechercherFicheClient display apr\u00e8s setProperty:', this.style.display);\r\n                    });\r\n                    console.log('\ud83d\udc54 \u00c9l\u00e9ments commerciaux affich\u00e9s (post-init)');\r\n                }, 1500);\r\n            } else {\r\n                console.log('\ud83d\udc64 Utilisateur standard');\r\n                $containerCommercial.hide();\r\n                $containerNormal.show();\r\n                $containerReferences.hide();\r\n                $rechercheClient.hide();\r\n                \/\/ \u2705 Afficher les \u00e9tapes pour les utilisateurs standard\r\n                $etapeValidations.show();\r\n                $etapePaiement.show();\r\n            }\r\n        }\r\n        \r\n        function remplirFormulaireClient(clientData) {\r\n            console.log('\ud83d\udcdd Remplissage formulaire client:', clientData);\r\n            \r\n            sessionStorage.setItem('ClientIdActif', clientData.annonceur_id);\r\n            \r\n            $('#form-field-annonceur_nom_societe').val(clientData.nom_societe || '');\r\n            \r\n            const nomComplet = [clientData.annonceur_prenom, clientData.annonceur_nom]\r\n                .filter(Boolean)\r\n                .join(' ');\r\n            $('#form-field-annonceur_nom_contact').val(nomComplet);\r\n            \r\n            $('#form-field-annonceur_direction_service').val(clientData.direction_service || '');\r\n            $('#form-field-annonceur_numero_immatriculation').val(clientData.numero_immatriculation || '');\r\n            $('#form-field-annonceur_numero_tva').val(clientData.numero_tva || '');\r\n            $('#form-field-annonceur_adresse_ligne1').val(clientData.adresse_ligne1 || '');\r\n            $('#form-field-annonceur_code_postal').val(clientData.code_postal || '');\r\n            $('#form-field-annonceur_ville').val(clientData.ville || '');\r\n            $('#form-field-annonceur_pays').val(clientData.pays || '');\r\n            $('#form-field-annonceur_email_contact').val(clientData.annonceur_email || '');\r\n            $('#form-field-annonceur_telephone_contact').val(clientData.telephone || clientData.mobile || '');\r\n            $('#form-field-facturation_contact').val(clientData.facturation_contact || '');\r\n            $('#form-field-facturation_adresse').val(clientData.facturation_adresse || '');\r\n            $('#form-field-facturation_code_postal').val(clientData.facturation_code_postal || '');\r\n            $('#form-field-facturation_ville').val(clientData.facturation_ville || '');\r\n            $('#form-field-facturation_pays').val(clientData.facturation_pays || '');\r\n            $('#form-field-facturation_email').val(clientData.facturation_email || '');\r\n            $('#form-field-facturation_telephone').val(clientData.facturation_telephone || '');\r\n            \r\n            console.log('\u2705 Formulaire client rempli');\r\n        }\r\n\r\n        function extraireChiffres(texte) {\r\n            if (!texte) return '';\r\n            return texte.toString().replace(\/[^\\d]\/g, '');\r\n        }\r\n        \r\n        function validerTarifCommercial(montantSaisi, devise) {\r\n            const limiteRemise = parseFloat(sessionStorage.getItem('limiteremise')) || 0;\r\n            \r\n            \/\/ ================================================================\r\n            \/\/ pb2125 : SONDE \u2014 le controle de remise max \u00ab ne fonctionne pas \u00bb\r\n            \/\/   (constat JF). Trois sorties rendaient valide:true en silence\r\n            \/\/   (regle 5.2) : limiteremise absente\/<=0, pas d'itemActif,\r\n            \/\/   tarifHT_initial absent. Chaque sortie nomme desormais TOUS ses\r\n            \/\/   discriminants. limiteremise arrive par postMessage\r\n            \/\/   VIA_REFERENCES_DATA (yearbook-media storeData) \u2014 stockee\r\n            \/\/   seulement si non vide : suspect n\u00b01.\r\n            \/\/   Sonde neutre, a retirer apres verdict.\r\n            \/\/ ================================================================\r\n            if (limiteRemise <= 0) {\r\n                console.warn('[pb2125] controle remise INACTIF | limiteremise brut=\"'\r\n                    + (sessionStorage.getItem('limiteremise') || '(absent)')\r\n                    + '\" parse=' + limiteRemise\r\n                    + ' | CommercialConnected=' + (sessionStorage.getItem('CommercialConnected') || '(absent)')\r\n                    + ' | montantSaisi=' + montantSaisi + ' ' + devise);\r\n                return { valide: true, minimum: 0, message: '' };\r\n            }\r\n            \r\n            if (!window.VIA_Panier || !window.VIA_Panier.state.itemActif) {\r\n                console.warn('[pb2125] controle remise SAUTE | VIA_Panier='\r\n                    + (window.VIA_Panier ? 'present' : 'ABSENT')\r\n                    + ' | itemActif=' + (window.VIA_Panier ? (window.VIA_Panier.state.itemActif || '(vide)') : '-')\r\n                    + ' | limiteremise=' + limiteRemise);\r\n                return { valide: true, minimum: 0, message: '' };\r\n            }\r\n            \r\n            const item = window.VIA_Panier.state.items.find(i => i.id === window.VIA_Panier.state.itemActif);\r\n            \r\n            if (!item || !item.tarifHT_initial) {\r\n                console.warn('[pb2125] controle remise SAUTE | item='\r\n                    + (item ? item.id : 'INTROUVABLE')\r\n                    + ' | tarifHT_initial=' + (item ? item.tarifHT_initial : '-')\r\n                    + ' | tarifHT=' + (item ? item.tarifHT : '-')\r\n                    + ' | limiteremise=' + limiteRemise);\r\n                return { valide: true, minimum: 0, message: '' };\r\n            }\r\n            console.log('[pb2125] controle remise ACTIF | limiteremise=' + limiteRemise\r\n                + '% | tarifHT_initial=' + item.tarifHT_initial + ' EUR | saisi='\r\n                + montantSaisi + ' ' + devise);\r\n            \r\n            const pourcentageMinimum = (100 - limiteRemise) \/ 100;\r\n            const tarifMinimumEUR = item.tarifHT_initial * pourcentageMinimum;\r\n            \r\n            let montantSaisiEUR = montantSaisi;\r\n            if (AND(devise !== 'EUR', verifierTauxDeChange())) {\r\n                montantSaisiEUR = window.VIA_App.convertirDevise(montantSaisi, devise, 'EUR');\r\n            }\r\n            \r\n            let tarifMinimumDevise = tarifMinimumEUR;\r\n            if (AND(devise !== 'EUR', verifierTauxDeChange())) {\r\n                tarifMinimumDevise = window.VIA_App.convertirDevise(tarifMinimumEUR, 'EUR', devise);\r\n            }\r\n            \r\n            const tarifMinimumArrondi = Math.ceil(tarifMinimumDevise);\r\n            \r\n            if (montantSaisiEUR < tarifMinimumEUR) {\r\n                const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                const message = lang === 'EN'\r\n                    ? `Minimum price: ${tarifMinimumArrondi} ${devise} (max discount: ${limiteRemise}%)`\r\n                    : `Tarif minimum : ${tarifMinimumArrondi} ${devise} (remise max : ${limiteRemise}%)`;\r\n                \r\n                return {\r\n                    valide: false,\r\n                    minimum: tarifMinimumArrondi,\r\n                    message: message\r\n                };\r\n            }\r\n            \r\n            return { valide: true, minimum: tarifMinimumArrondi, message: '' };\r\n        }\r\n\r\n        \/\/ ================================================================\r\n        \/\/ pb2122 : DEVISE a droite de la zone de saisie commerciale.\r\n        \/\/   Span absolute dans le field-group (CSS ci-dessus) : l'input reste\r\n        \/\/   centre. Affichee SEULEMENT quand un montant est present (reponse\r\n        \/\/   JF). Suit STATE.deviseTarifCommercial \u2014 deja convertie par le\r\n        \/\/   change devise existant. Appelee aux QUATRE points ou la valeur de\r\n        \/\/   l'input change : saisie (input), change devise, pre-remplissage\r\n        \/\/   afficherTarif, et mettreAJourTarifCommercialDansCommande (les\r\n        \/\/   .val() programmatiques ne declenchent pas 'input').\r\n        \/\/   Revert : window._viaPb2122Off = true (span retire).\r\n        \/\/ ================================================================\r\n        function _majDeviseTarifCommercial2122() {\r\n            try {\r\n                \/\/ pb2126 : TOUTES les instances (ids dupliques par clonage des\r\n                \/\/   cartes) \u2014 span par input, en CLASSE et non en id.\r\n                var _inps2122 = document.querySelectorAll('input[name=\"form_fields[TarifCommercial]\"]');\r\n                if (_inps2122.length === 0) { return; }\r\n                _inps2122.forEach(function (_inp2122) {\r\n                    var _sp2122 = _inp2122.parentElement\r\n                        ? _inp2122.parentElement.querySelector('.via-devise-tarifcom-2122') : null;\r\n                    if (window._viaPb2122Off === true) {\r\n                        if (_sp2122) { _sp2122.remove(); }\r\n                        return;\r\n                    }\r\n                    var _v2122 = (_inp2122.value || '').toString().trim();\r\n                    var _plein2122 = _v2122 ? (_v2122 !== '-') : false;\r\n                    if (!_plein2122) {\r\n                        if (_sp2122) { _sp2122.style.display = 'none'; }\r\n                        return;\r\n                    }\r\n                    if (!_sp2122) {\r\n                        _sp2122 = document.createElement('span');\r\n                        _sp2122.className = 'via-devise-tarifcom-2122';\r\n                        _inp2122.parentElement.appendChild(_sp2122);\r\n                    }\r\n                    _sp2122.textContent = STATE.deviseTarifCommercial || 'EUR';\r\n                    _sp2122.style.display = '';\r\n                });\r\n            } catch (_e2122) { console.warn('[pb2122]', _e2122.message); }\r\n        }\r\n\r\n        function initTarifCommercial() {\r\n            const $tarifCommercialInput = $('#form-field-TarifCommercial');\r\n            \r\n            if ($tarifCommercialInput.length === 0) {\r\n                console.warn('\u26a0\ufe0f Champ tarif commercial introuvable');\r\n                return;\r\n            }\r\n            \r\n            STATE.deviseTarifCommercial = $('#' + CONFIG.FIELDS.devise).val() || 'EUR';\r\n            \r\n            \/\/ ================================================================\r\n            \/\/ pb2126 : BINDING DELEGUE \u2014 le champ vit DANS la carte de resa\r\n            \/\/   (log JF : input#form-field-TarifCommercial dans\r\n            \/\/   #CampagneTemplate_...). Les cartes sont CLONEES : l'id est\r\n            \/\/   duplique, $('#id') ne lie que la PREMIERE occurrence (souvent\r\n            \/\/   le template) \u2014 la saisie dans une carte reelle ne declenchait\r\n            \/\/   RIEN : ni controle remise, ni MAJ carte\/total. C'est la cause\r\n            \/\/   commune des trois constats JF.\r\n            \/\/   Remede : delegation document sur le NAME (precedent :\r\n            \/\/   yearbook-media l.22205 reset par ce meme selecteur). Le handler\r\n            \/\/   travaille sur $(this) \u2014 l'instance reellement saisie. Si la\r\n            \/\/   saisie vient d'une carte qui n'est PAS l'item actif, elle est\r\n            \/\/   ignoree et journalisee (la MAJ ne vise que l'itemActif).\r\n            \/\/   Revert : window._viaPb2126Off = true (binding direct d'origine).\r\n            \/\/ ================================================================\r\n            var _cible2126 = (window._viaPb2126Off === true)\r\n                ? $tarifCommercialInput : $(document);\r\n            var _selDelegue2126 = (window._viaPb2126Off === true)\r\n                ? null : 'input[name=\"form_fields[TarifCommercial]\"]';\r\n            _cible2126.on('input', _selDelegue2126, function() {\r\n                const $inp2126 = $(this);\r\n                if (window._viaPb2126Off !== true) {\r\n                    var _carte2126 = $inp2126.closest('[id^=\"CampagneTemplate_\"]');\r\n                    var _idCarte2126 = _carte2126.length ? _carte2126.attr('id') : '(hors carte)';\r\n                    var _actif2126 = window.VIA_Panier ? window.VIA_Panier.state.itemActif : null;\r\n                    if (_carte2126.length ? (_actif2126 ? _idCarte2126 !== _actif2126 : true) : false) {\r\n                        console.warn('[pb2126] saisie IGNOREE : carte ' + _idCarte2126\r\n                            + ' n\\'est pas l\\'item actif (' + (_actif2126 || 'aucun') + ')');\r\n                        return;\r\n                    }\r\n                    console.log('[pb2126] saisie sur ' + _idCarte2126 + ' | actif=' + (_actif2126 || 'aucun'));\r\n                }\r\n                const valeurBrute = $inp2126.val();\r\n                const chiffresSeuls = extraireChiffres(valeurBrute);\r\n                \r\n                if (valeurBrute !== chiffresSeuls) {\r\n                    $inp2126.val(chiffresSeuls);\r\n                }\r\n                \r\n                $('[id=\"tarif-commercial-erreur\"]').remove();\r\n                $inp2126.css('border-color', '');\r\n                \r\n                if (chiffresSeuls) {\r\n                    const montant = parseFloat(chiffresSeuls);\r\n                    \r\n                    const validation = validerTarifCommercial(montant, STATE.deviseTarifCommercial);\r\n                    \r\n                    if (!validation.valide) {\r\n                        $inp2126.css('border-color', '#ef4444');\r\n                        \r\n                        if ($('[id=\"tarif-commercial-erreur\"]').length === 0) {\r\n                            $inp2126.after(\r\n                                \/* pb2129 : message CENTRE (desktop + mobile, demande JF) \u2014\r\n                                   display:block + width:100% + text-align:center, il passe\r\n                                   sous le champ et se centre dessus. nowrap conserve. *\/\r\n                                `<span id=\"tarif-commercial-erreur\" style=\"color: #ef4444; font-size: 9px; white-space: nowrap; display: block; width: 100%; text-align: center;\">${validation.message}<\/span>`\r\n                            );\r\n                        }\r\n                        \r\n                        console.warn('\u26a0\ufe0f Tarif commercial invalide:', validation.message);\r\n                        STATE.tarifCommercialSaisi = null;\r\n                        _majDeviseTarifCommercial2122();   \/\/ pb2122 : montant present, devise affichee\r\n                        return;\r\n                    }\r\n                    \r\n                    $inp2126.css('border-color', '#37D900');\r\n                    STATE.tarifCommercialSaisi = montant;\r\n                    console.log('\ud83d\udcb0 [initTarifCommercial] montant saisi:', montant, '| devise:', STATE.deviseTarifCommercial);\r\n                    console.log('\ud83d\udcb0 [initTarifCommercial] itemActif:', window.VIA_Panier ? window.VIA_Panier.state.itemActif : 'VIA_Panier non dispo');\r\n                    console.log('\ud83d\udcb0 [initTarifCommercial] items count:', window.VIA_Panier ? window.VIA_Panier.state.items.length : 'N\/A');\r\n                    mettreAJourTarifCommercialDansCommande(STATE.tarifCommercialSaisi, STATE.deviseTarifCommercial);\r\n                    \r\n                    console.log('\ud83d\udcb0 Tarif commercial saisi:', STATE.tarifCommercialSaisi, STATE.deviseTarifCommercial);\r\n                } else {\r\n                    STATE.tarifCommercialSaisi = null;\r\n                }\r\n                _majDeviseTarifCommercial2122();   \/\/ pb2122\r\n            });\r\n            \r\n            const $deviseSelect = $('#' + CONFIG.FIELDS.devise);\r\n            if ($deviseSelect.length > 0) {\r\n                $deviseSelect.on('change', function() {\r\n                    const nouvelleDevise = $(this).val();\r\n                    const ancienneDevise = STATE.deviseTarifCommercial;\r\n                    \r\n                    if (AND(STATE.tarifCommercialSaisi, AND(STATE.tarifCommercialSaisi > 0, ancienneDevise !== nouvelleDevise))) {\r\n                        console.log(`\ud83d\udcb1 Conversion tarif commercial: ${STATE.tarifCommercialSaisi} ${ancienneDevise} \u2192 ${nouvelleDevise}`);\r\n                        \r\n                        if (verifierTauxDeChange()) {\r\n                            try {\r\n                                const montantConverti = window.VIA_App.convertirDevise(\r\n                                    STATE.tarifCommercialSaisi,\r\n                                    ancienneDevise,\r\n                                    nouvelleDevise\r\n                                );\r\n                                \r\n                                const montantArrondi = Math.round(montantConverti);\r\n                                \r\n                                \/\/ pb2126 : toutes les instances (ids dupliques par clonage).\r\n                                $('input[name=\"form_fields[TarifCommercial]\"]').val(montantArrondi);\r\n                                STATE.tarifCommercialSaisi = montantArrondi;\r\n                                STATE.deviseTarifCommercial = nouvelleDevise;\r\n                                \r\n                                mettreAJourTarifCommercialDansCommande(montantArrondi, nouvelleDevise);\r\n                                \r\n                                console.log(`\u2705 Tarif converti: ${montantArrondi} ${nouvelleDevise}`);\r\n                                \r\n                                _majDeviseTarifCommercial2122();   \/\/ pb2122\r\n                                $('input[name=\"form_fields[TarifCommercial]\"]').addClass('country-selected').css('background-color', '#E8F0FE');\r\n                                setTimeout(() => {\r\n                                    $('input[name=\"form_fields[TarifCommercial]\"]').removeClass('country-selected').css('background-color', '');\r\n                                }, 600);\r\n                                \r\n                            } catch (error) {\r\n                                console.error('\u274c Erreur conversion tarif commercial:', error);\r\n                                alert('Erreur lors de la conversion du tarif. Veuillez ressaisir le montant.');\r\n                            }\r\n                        } else {\r\n                            console.warn('\u26a0\ufe0f Taux non disponibles, conversion impossible');\r\n                            $deviseSelect.val(ancienneDevise);\r\n                        }\r\n                    } else {\r\n                        STATE.deviseTarifCommercial = nouvelleDevise;\r\n                        console.log('\ud83d\udcb1 Devise mise \u00e0 jour pour prochaine saisie:', nouvelleDevise);\r\n                        _majDeviseTarifCommercial2122();   \/\/ pb2122\r\n                    }\r\n                });\r\n            }\r\n            \r\n            const $formCommercial = $('#TarifCommercialForm form');\r\n            if ($formCommercial.length > 0) {\r\n                $formCommercial.on('submit', function(e) {\r\n                    e.preventDefault();\r\n                    console.log('\u2705 Tarif commercial valid\u00e9');\r\n                    return false;\r\n                });\r\n            }\r\n            \r\n            console.log('\u2705 Champ tarif commercial initialis\u00e9');\r\n        }\r\n        \r\n        function mettreAJourTarifCommercialDansCommande(montant, devise) {\r\n            if (!window.VIA_Panier || !window.VIA_Panier.state.itemActif) {\r\n                console.warn('\u26a0\ufe0f Pas de commande active');\r\n                return;\r\n            }\r\n            \r\n            const item = window.VIA_Panier.state.items.find(i => i.id === window.VIA_Panier.state.itemActif);\r\n            if (!item) {\r\n                console.warn('\u26a0\ufe0f Item non trouv\u00e9');\r\n                return;\r\n            }\r\n            \r\n            if (typeof item.tarifHT_initial === 'undefined' || item.tarifHT_initial === null) {\r\n                item.tarifHT_initial = item.tarifHT || 0;\r\n            }\r\n            \r\n            let tarifCommercialEUR = montant;\r\n            if (AND(devise !== 'EUR', verifierTauxDeChange())) {\r\n                tarifCommercialEUR = window.VIA_App.convertirDevise(montant, devise, 'EUR');\r\n            }\r\n            \r\n            let tarifInitialDevise = item.tarifHT_initial;\r\n            let tarifCommercialDevise = montant;\r\n            \r\n            if (AND(devise !== 'EUR', verifierTauxDeChange())) {\r\n                tarifInitialDevise = window.VIA_App.convertirDevise(item.tarifHT_initial, 'EUR', devise);\r\n            }\r\n            \r\n            const montantRemiseDevise = Math.max(0, tarifInitialDevise - tarifCommercialDevise);\r\n            const tauxCommission = parseFloat(sessionStorage.getItem('CommercialTauxCommission')) || 0;\r\n            const montantCommissionDevise = (tarifCommercialDevise * tauxCommission) \/ 100;\r\n            \r\n            window.VIA_Panier.mettreAJourItem(window.VIA_Panier.state.itemActif, {\r\n                tarifHT: tarifCommercialEUR,\r\n                tarifHT_initial: item.tarifHT_initial,\r\n                tarifTTC: tarifCommercialEUR * 1.20,\r\n                devise: devise,\r\n                statut: 'valide',\r\n                tarifCommercial: true,\r\n                montantRemise: montantRemiseDevise,\r\n                tauxCommission: tauxCommission,\r\n                montantCommission: montantCommissionDevise,\r\n                deviseRemiseCommission: devise\r\n            });\r\n            \r\n            const $item = $(`#${window.VIA_Panier.state.itemActif}`);\r\n            if (AND($item.length, window.VIA_App)) {\r\n                const tarifFormate = window.VIA_App.formaterMontant(tarifCommercialDevise, devise, 2);\r\n                const remiseFormate = window.VIA_App.formaterMontant(montantRemiseDevise, devise, 2);\r\n                \r\n                \/\/ pb2121 : resa active d'un commercial -> libelle seul, remise\r\n                \/\/   <small> conservee (reponse JF). Helper defini dans\r\n                \/\/   Panier_manage ; garde typeof (ordre de chargement).\r\n                var _txtTC2121 = `Tarif H.T. ${tarifFormate} <small>(remise: ${remiseFormate})<\/small>`;\r\n                if (typeof window._viaLibelleTarif2121 === 'function') {\r\n                    _txtTC2121 = window._viaLibelleTarif2121(window.VIA_Panier.state.itemActif, _txtTC2121);\r\n                }\r\n                $item.find('.CampagneTarifClass')\r\n                    .html(_txtTC2121)\r\n                    .show();\r\n            }\r\n            \r\n            window.VIA_Panier.calculerTotalPanier();\r\n            \r\n            \/\/ V\u00e9rifier que tarifHT est bien pos\u00e9 sur l'item apr\u00e8s mettreAJourItem\r\n            const _itemApres = window.VIA_Panier.state.items.find(i => i.id === window.VIA_Panier.state.itemActif);\r\n            console.log('\u2705 [tarifCommercial] Tarif mis \u00e0 jour | itemActif:', window.VIA_Panier.state.itemActif);\r\n            console.log('\u2705 [tarifCommercial] tarifHT sur item APR\u00c8S MAJ:', _itemApres ? _itemApres.tarifHT : 'item non trouv\u00e9');\r\n            console.log('\u2705 [tarifCommercial] statut item:', _itemApres ? _itemApres.statut : 'N\/A');\r\n            console.log('\u2705 Tarif commercial mis \u00e0 jour:', {\r\n                tarifInitial_EUR: item.tarifHT_initial,\r\n                tarifCommercial_EUR: tarifCommercialEUR,\r\n                remise: montantRemiseDevise,\r\n                tauxCommission: tauxCommission,\r\n                devise: devise\r\n            });\r\n        } \r\n\r\n        function checkEspacePubData() {\r\n            var format = STATE.format;\r\n            var position = STATE.position;\r\n            \r\n            \/\/ \u2705 v2.5 : Fallback \u2014 restaurer format\/position depuis l'item actif du panier\r\n            if ((!format || !position) && window.VIA_Panier && window.VIA_Panier.state) {\r\n                var _itemActif = window.VIA_Panier.state.items && window.VIA_Panier.state.items.find(function(i) {\r\n                    return i.id === window.VIA_Panier.state.itemActif;\r\n                });\r\n                if (!_itemActif) { _itemActif = window.VIA_Panier.state.items && window.VIA_Panier.state.items[0]; }\r\n                if (_itemActif) {\r\n                    if (!format && _itemActif.format) { format = _itemActif.format; STATE.format = format; }\r\n                    if (!position && _itemActif.position) { position = _itemActif.position; STATE.position = position; }\r\n                    if (_itemActif.emplacementPageWeb) { STATE.emplacementPageWeb = _itemActif.emplacementPageWeb; }\r\n                    \/\/ \u2705 pb213 : espace R\u00c9SERV\u00c9 (envoi diff\u00e9r\u00e9) \u2192 l'item a emplacementPageWeb\r\n                    \/\/   mais position peut \u00eatre null sur l'objet item \u2192 tarif jamais calcul\u00e9.\r\n                    \/\/   On r\u00e9cup\u00e8re la position depuis le sessionStorage (PositionDataVosCampagnes\r\n                    \/\/   {index}) ou depuis donneesIframe, sinon le calcul reste bloqu\u00e9 \u00e0 tort.\r\n                    if (!position) {\r\n                        if (_itemActif.emplacementPageWeb) {\r\n                            var _idx213 = _itemActif.sessionStorageIndex;\r\n                            var _idxOk213 = (_idx213 !== undefined) ? (_idx213 !== null) : false;\r\n                            var _posSS213 = _idxOk213\r\n                                ? sessionStorage.getItem('PositionDataVosCampagnes' + _idx213)\r\n                                : null;\r\n                            if (_posSS213) {\r\n                                position = _posSS213; STATE.position = position;\r\n                                console.log('\u2705 [pb213] position restaur\u00e9e depuis sessionStorage:', position);\r\n                            } else {\r\n                                var _diPos213 = (_itemActif.donneesIframe)\r\n                                    ? _itemActif.donneesIframe.PositionDataVosCampagnes\r\n                                    : null;\r\n                                if (_diPos213) {\r\n                                    position = _diPos213; STATE.position = position;\r\n                                    console.log('\u2705 [pb213] position restaur\u00e9e depuis donneesIframe:', position);\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                    console.log('\u2705 [checkEspacePubData] fallback panier \u2014 format:', format, '| position:', position);\r\n                }\r\n            }\r\n            \r\n            if (AND(format, position)) {\r\n                STATE.espacePubSelected = true;\r\n                console.log('\u2705 Donn\u00e9es espace pub d\u00e9tect\u00e9es:', { format, position });\r\n                return true;\r\n            }\r\n            \r\n            return false;\r\n        }\r\n\r\n        async function loadJQueryUI() {\r\n            if (AND(typeof $.fn.datepicker === 'function', typeof $.fn.autocomplete === 'function')) {\r\n                console.log('\u2705 jQuery UI d\u00e9j\u00e0 charg\u00e9');\r\n                STATE.isJQueryUILoaded = true;\r\n                return;\r\n            }\r\n\r\n            await loadScript(JQUERY_UI_URL, 'jquery-ui');\r\n            STATE.isJQueryUILoaded = true;\r\n        }\r\n\r\n        function injectStyles() {\r\n            if (document.getElementById('via-elementor-styles')) {\r\n                return;\r\n            }\r\n\r\n            const styles = `\r\n                #ui-datepicker-div,\r\n                .ui-datepicker {\r\n                    transform: scale(0.7) !important;\r\n                    transform-origin: top left !important;\r\n                }\r\n\r\n                \/* pb1261 : LE :has() EST RETIRE \u2014 un seul writer pour cette marge.\r\n                   La condition \u00ab position visible \u00bb rendait cette regle inoperante sur\r\n                   une carte PARTIELLE, ou remplirItemPartiel masque la position : la\r\n                   marge Elementor d'origine, plus grande, reprenait la main et l'ecart\r\n                   au-dessus des dates sautait aux yeux. pb1260 compensait cote JS, ce\r\n                   qui faisait DEUX sources pour la meme propriete \u2014 exactement ce que\r\n                   ce projet a appris a ne pas faire.\r\n                   La marge ne depend pas de la position : elle separe le bloc dates de\r\n                   ce qui le precede, quel qu'il soit. Sans condition, elle vaut dans\r\n                   les deux etats, et le passage de partielle a complete ne change plus\r\n                   rien a cet endroit.\r\n                   En mode reduit la question ne se pose pas : .CampagneDatesContainer y\r\n                   est masque (regle data-via-reduit=\"true\" de Panier_manager.txt).\r\n                   Revert : remettre le :has(...) devant .CampagneDatesContainer, ici et\r\n                   dans la media query ci-dessous. *\/\r\n                .CampagnePageRefClass .CampagneDatesContainer {\r\n                    margin-top: 5px !important;\r\n                }\r\n                \r\n                @media (max-width: 1015px) {\r\n                    body.datepicker-open::before {\r\n                        content: '';\r\n                        position: fixed;\r\n                        top: 0;\r\n                        left: 0;\r\n                        right: 0;\r\n                        bottom: 0;\r\n                        background: rgba(0, 0, 0, 0.5);\r\n                        z-index: 9998;\r\n                    }\r\n                    \r\n                    #ui-datepicker-div {\r\n                        box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3) !important;\r\n                    }\r\n                    \r\n                    \/* pb1261 : idem, sans le :has(). *\/\r\n                    .CampagnePageRefClass .CampagneDatesContainer {\r\n                        margin-top: 7px !important; \/* \u2705 v2.4.5 : +15px mobile (-8\u21927) *\/\r\n                    }\r\n                }\r\n        \r\n                #ui-datepicker-div {\r\n                    margin-left: 0 !important;\r\n                }\r\n                \/* ============================================================\r\n                   pb2143 : LE CURSEUR SUIT LE DRAG, PAS LE THEME.\r\n                   Constat JF : dans l'achat express, le drag fonctionne mais le\r\n                   curseur \u00ab move \u00bb n'apparait pas au survol du bandeau. Cause :\r\n                   pb2142 avait scope la regle sur .via-datepicker, alors que le\r\n                   moteur JS, lui, cible .ui-datepicker-header SANS scope \u2014 et\r\n                   l'express n'applique pas cette classe (il pose\r\n                   campaign-datepicker, et seulement sur le champ de fin :\r\n                   JS_Grille_tarifaire l.553). Le style disait donc moins que le\r\n                   comportement.\r\n                   La regle porte desormais sur #ui-datepicker-div, l'element\r\n                   UNIQUE que jQuery UI partage entre tous les champs de tous les\r\n                   process : meme perimetre pour le curseur et pour le drag.\r\n                   ============================================================ *\/\r\n                #ui-datepicker-div .ui-datepicker-header {\r\n                    cursor: move !important;\r\n                    touch-action: none !important;\r\n                }\r\n                #ui-datepicker-div .ui-datepicker-prev,\r\n                #ui-datepicker-div .ui-datepicker-next {\r\n                    cursor: pointer !important;\r\n                    touch-action: auto !important;\r\n                }\r\n                .via-datepicker {\r\n                    z-index: 10000 !important;\r\n                    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;\r\n                    border: 1px solid #ddd !important;\r\n                    border-radius: 8px !important;\r\n                    overflow: hidden !important;\r\n                    font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-header {\r\n                    background: #007cba !important;\r\n                    color: white !important;\r\n                    border: none !important;\r\n                    padding: 12px 10px !important;\r\n                    border-radius: 0 !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-title {\r\n                    color: white !important;\r\n                    text-align: center !important;\r\n                    font-weight: 600 !important;\r\n                    font-size: 15px !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-prev,\r\n                .via-datepicker .ui-datepicker-next {\r\n                    cursor: pointer !important;\r\n                    position: absolute !important;\r\n                    top: 50% !important;\r\n                    transform: translateY(-50%) !important;\r\n                    width: 32px !important;\r\n                    height: 32px !important;\r\n                    border-radius: 4px !important;\r\n                    transition: background-color 0.2s ease !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-prev:hover,\r\n                .via-datepicker .ui-datepicker-next:hover {\r\n                    background-color: rgba(255, 255, 255, 0.2) !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-prev {\r\n                    left: 8px !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-next {\r\n                    right: 8px !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-prev span,\r\n                .via-datepicker .ui-datepicker-next span {\r\n                    display: block !important;\r\n                    width: 0 !important;\r\n                    height: 0 !important;\r\n                    border-style: solid !important;\r\n                    background: none !important;\r\n                    \/* pb715 : centrage EXPLICITE du triangle dans l'ancre 32x32.\r\n                       jQuery UI centre son icone par des margin negatifs calibres sur\r\n                       16px ; avec un triangle agrandi de 80% ces marges decalent le\r\n                       dessin. On neutralise les marges et on centre par transform. *\/\r\n                    position: absolute !important;\r\n                    left: 50% !important;\r\n                    top: 50% !important;\r\n                    margin: 0 !important;\r\n                    transform: translate(-50%, -50%) !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-prev span {\r\n                    \/* pb715 : +80% (6 -> 10.8 ; 8 -> 14.4) *\/\r\n                    border-width: 10.8px 14.4px 10.8px 0 !important;\r\n                    border-color: transparent white transparent transparent !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-next span {\r\n                    \/* pb715 : +80% (6 -> 10.8 ; 8 -> 14.4) *\/\r\n                    border-width: 10.8px 0 10.8px 14.4px !important;\r\n                    border-color: transparent transparent transparent white !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-calendar th {\r\n                    padding: 8px 0 !important;\r\n                    text-align: center !important;\r\n                    font-size: 12px !important;\r\n                    font-weight: 600 !important;\r\n                    color: #666 !important;\r\n                }\r\n                .via-datepicker .ui-state-default {\r\n                    text-align: center !important;\r\n                    padding: 8px !important;\r\n                    border: 1px solid transparent !important;\r\n                    background: white !important;\r\n                    transition: all 0.2s ease !important;\r\n                    display: block !important;\r\n                    text-decoration: none !important;\r\n                    color: #333 !important;\r\n                }\r\n                .via-datepicker .ui-state-hover,\r\n                .via-datepicker .ui-state-focus {\r\n                    background: #f0f0f0 !important;\r\n                    border-color: #007cba !important;\r\n                }\r\n                .via-datepicker .ui-state-active,\r\n                .via-datepicker .ui-state-highlight {\r\n                    background: #007cba !important;\r\n                    color: white !important;\r\n                    border-color: #007cba !important;\r\n                    font-weight: 600 !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-today .ui-state-default {\r\n                    background: #fff3cd !important;\r\n                    border-color: #ffc107 !important;\r\n                    font-weight: 600 !important;\r\n                }\r\n                .via-datepicker .ui-datepicker-unselectable .ui-state-default {\r\n                    color: #ccc !important;\r\n                    cursor: default !important;\r\n                }\r\n                .date-selected {\r\n                    background-color: #E8F0FE !important;\r\n                    transition: background-color 0.3s ease !important;\r\n                }\r\n                .date-selected[readonly],\r\n                input.date-selected,\r\n                input[readonly].date-selected,\r\n                #form-field-DebutCampagne.date-selected,\r\n                #form-field-FinCampagne.date-selected {\r\n                    background-color: #E8F0FE !important;\r\n                }\r\n                .ui-autocomplete {\r\n                    \/* pb2133 : PLANCHER 1e8 (etait 9999). Constat JF : la liste\r\n                       clients passe encore sous #via-col-ColonneDroite et le <ul>\r\n                       releve ne porte PAS le z-index inline de pb2131 \u2014 le\r\n                       handler open: n'a pas ecrit (version servie ou handler muet,\r\n                       verdict au log). Le plancher feuille couvre ce cas : 1e8 bat\r\n                       les deux bases connues (popups 1e7, process 2e7) et toute\r\n                       cascade realiste de bring-to-front (+1 par clic), tout en\r\n                       restant sous la capture drag (2 147 483 600) et le ghost.\r\n                       Les writers dynamiques pb791\/pb2131 restent au-dessus si un\r\n                       popup depasse un jour ce plancher (menu transient : passer\r\n                       devant la miniature 12e6 est acceptable, il se ferme au\r\n                       blur). *\/\r\n                    z-index: 100000000 !important;\r\n                    max-height: 300px;\r\n                    overflow-y: auto;\r\n                    overflow-x: hidden;\r\n                    background: white;\r\n                    border: 1px solid #ccc;\r\n                    border-radius: 4px;\r\n                    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\r\n                    font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\r\n                }\r\n                .ui-menu .ui-menu-item {\r\n                    padding: 10px 14px;\r\n                    border-bottom: 1px solid #f0f0f0;\r\n                    cursor: pointer;\r\n                    font-size: 14px;\r\n                    transition: background-color 0.15s ease;\r\n                }\r\n                .ui-menu .ui-menu-item:last-child {\r\n                    border-bottom: none;\r\n                }\r\n                .ui-menu .ui-menu-item:hover {\r\n                    background-color: #f8f9fa;\r\n                }\r\n                .ui-menu .ui-menu-item.ui-state-active,\r\n                .ui-menu .ui-menu-item.ui-state-focus {\r\n                    background-color: #007cba !important;\r\n                    color: white !important;\r\n                }\r\n                .country-selected {\r\n                    background-color: #E8F0FE !important;\r\n                    transition: background-color 0.3s ease;\r\n                }\r\n                #form-field-DebutCampagne,\r\n                #form-field-FinCampagne,\r\n                #form-field-Nationalite_Societe {\r\n                    text-align: center !important;\r\n                }\r\n                #form-field-DebutCampagne:focus,\r\n                #form-field-FinCampagne:focus,\r\n                #form-field-Nationalite_Societe:focus {\r\n                    outline: 2px solid #007cba !important;\r\n                    outline-offset: 2px !important;\r\n                }\r\n                #espace-notification {\r\n                    animation: slideDown 0.3s ease;\r\n                }\r\n                @keyframes slideDown {\r\n                    from {\r\n                        opacity: 0;\r\n                        transform: translateY(-10px);\r\n                    }\r\n                    to {\r\n                        opacity: 1;\r\n                        transform: translateY(0);\r\n                    }\r\n                }\r\n                \r\n                #form-field-selected_currency_visuels:disabled {\r\n                    background-color: #f5f5f5 !important;\r\n                    cursor: not-allowed !important;\r\n                    opacity: 0.6;\r\n                }\r\n                \r\n                .devise-loading {\r\n                    position: relative;\r\n                }\r\n                \r\n                .devise-loading::after {\r\n                    content: '\u23f3';\r\n                    position: absolute;\r\n                    right: 30px;\r\n                    top: 50%;\r\n                    transform: translateY(-50%);\r\n                    animation: pulse 1s infinite;\r\n                }\r\n                \r\n                @keyframes pulse {\r\n                    0%, 100% { opacity: 1; }\r\n                    50% { opacity: 0.5; }\r\n                }\r\n                \r\n                #CampagneTemplate {\r\n                    display: none !important;\r\n                    visibility: hidden !important;\r\n                }\r\n                #CampagneTemplate,\r\n                .template-masque {\r\n                    display: none !important;\r\n                    visibility: hidden !important;\r\n                    position: absolute !important;\r\n                    left: -9999px !important;\r\n                    opacity: 0 !important;\r\n                    pointer-events: none !important;\r\n                }\r\n                \r\n                #form-field-TarifCommercial.tarif-invalide {\r\n                    border-color: #ef4444 !important;\r\n                    background-color: #fef2f2 !important;\r\n                }\r\n                \r\n                \/* pb2122 : montant CENTRE dans la zone de saisie commerciale, et\r\n                   devise a DROITE en absolute \u2014 l'input garde sa largeur et son\r\n                   centrage, rien ne bouge dans le flux (demande JF). *\/\r\n                #form-field-TarifCommercial {\r\n                    text-align: center !important;\r\n                }\r\n                .elementor-field-group-TarifCommercial {\r\n                    position: relative !important;\r\n                }\r\n                .via-devise-tarifcom-2122 {\r\n                    position: absolute;\r\n                    right: 10px;\r\n                    top: 50%;\r\n                    transform: translateY(-50%);\r\n                    color: #4B689B;\r\n                    font-size: 12px;\r\n                    font-weight: 600;\r\n                    pointer-events: none;\r\n                }\r\n                #form-field-TarifCommercial.tarif-valide {\r\n                    border-color: #37D900 !important;\r\n                }\r\n                \r\n                #tarif-commercial-erreur {\r\n                    animation: shake 0.3s ease-in-out;\r\n                }\r\n                \r\n                @keyframes shake {\r\n                    0%, 100% { transform: translateX(0); }\r\n                    25% { transform: translateX(-5px); }\r\n                    75% { transform: translateX(5px); }\r\n                }\r\n            `;\r\n\r\n            const styleElement = document.createElement('style');\r\n            styleElement.id = 'via-elementor-styles';\r\n            styleElement.textContent = styles;\r\n            document.head.appendChild(styleElement);\r\n\r\n            console.log('\u2705 Styles inject\u00e9s');\r\n        }\r\n\r\n        function setupDatePickers() {\r\n            const $dateDebut = $('#' + CONFIG.FIELDS.dateDebut);\r\n            const $dateFin = $('#' + CONFIG.FIELDS.dateFin);\r\n        \r\n            if ($dateDebut.length === 0 || $dateFin.length === 0) {\r\n                console.warn('\u26a0\ufe0f Champs de date introuvables');\r\n                return;\r\n            }\r\n            \r\n            const isMobile = \/iPhone|iPad|iPod|Android\/i.test(navigator.userAgent);\r\n            \r\n            \/\/ ================================================================\r\n            \/\/ pb2142 : CALENDRIERS DEPLACABLES (desktop + mobile, demande JF).\r\n            \/\/   #ui-datepicker-div est UNIQUE et partage par les deux champs :\r\n            \/\/   un seul moteur suffit, pose une fois (latch _viaDragCal2142).\r\n            \/\/   POURQUOI PAS $.fn.draggable (precedent Entete pb245) : le div\r\n            \/\/   porte transform: scale(0.7) (feuille ci-dessus). jQuery UI\r\n            \/\/   calcule ses deltas en coordonnees NON transformees \u2014 le\r\n            \/\/   calendrier glisserait sous le curseur d'un facteur 0,7. On\r\n            \/\/   ecrit donc top\/left nous-memes a partir du delta ecran, comme\r\n            \/\/   le drag maison des VLP (pb480b : screenX\/Y, repere fixe,\r\n            \/\/   insensible au scroll et au zoom).\r\n            \/\/   POIGNEE : tout le bandeau .ui-datepicker-header, SAUF les\r\n            \/\/   fleches Prev\/Next (elles doivent rester cliquables \u2014 meme gate\r\n            \/\/   que pb532b sur les pictos VLP).\r\n            \/\/   MOBILE : memes gestes en touch (jQuery UI draggable ne gere pas\r\n            \/\/   le tactile, aucun touch-punch dans le corpus).\r\n            \/\/   PERSISTANCE : aucune (reponse JF) \u2014 le calendrier se replace\r\n            \/\/   normalement a chaque ouverture, donc on ne memorise rien et on\r\n            \/\/   ne touche pas a beforeShow.\r\n            \/\/   CLAMP : regle pb245 \u2014 20 % au moins dans le viewport, jamais\r\n            \/\/   au-dessus du haut.\r\n            \/\/   Delegation au document : le div est cree\/detruit par le widget.\r\n            \/\/   Revert : window._viaPb2142Off = true.\r\n            \/\/ ================================================================\r\n            \/\/ ================================================================\r\n            \/\/ pb2199 : LE CONTENU DESCEND EN BAS QUAND LE CLAVIER OUVRE.\r\n            \/\/   (Recepteur pb2188\/pb2190\/pb2193 + geste pb2199, retabli : mon\r\n            \/\/   retrait de la sonde pb2145 l avait emporte avec elle \u2014 les deux\r\n            \/\/   blocs se suivaient, et j ai supprime par bornes. C est le risque\r\n            \/\/   inscrit au carnet, reproduit ici.)\r\n            \/\/   Le parent (Entete.txt) envoie la bande reellement visible, deja\r\n            \/\/   convertie dans le repere de l iframe (pb2190). L iframe, elle,\r\n            \/\/   descend son contenu en fin de defilement : le formulaire\r\n            \/\/   References etant le dernier bloc, il se place dans la zone qui\r\n            \/\/   reste visible, quel que soit le decalage applique par iOS.\r\n            \/\/   Aucune mesure transposee d un repere a l autre \u2014 c est ce qui a\r\n            \/\/   fait echouer pb2186, pb2190 et pb2198.\r\n            \/\/   Rafales filtrees (pb2193) : iOS emet plusieurs vv-resize pendant\r\n            \/\/   l animation du clavier, seul le DERNIER etat est traite.\r\n            \/\/   Le defilement d avant clavier est rendu a la fermeture.\r\n            \/\/   Revert : window._viaPb2199Off = true (aucun scroll) ;\r\n            \/\/            window._viaPb2193Ms   = 250 (delai de la rafale).\r\n            \/\/ ================================================================\r\n            if (!window._viaRecepteurBande2188) {\r\n                window._viaRecepteurBande2188 = true;\r\n                window._viaTraiterBande2188 = function (_d2188) {\r\n                    try {\r\n                        if (!_d2188.clavier) {\r\n                            if (window._viaTranslate2201) {   \/\/ pb2201 : translation retiree\r\n                                document.body.style.removeProperty('transform');\r\n                                document.body.style.removeProperty('transition');\r\n                                console.log('[pb2201] clavier ferme -> translation retiree (' + window._viaTranslate2201 + 'px)');\r\n                                window._viaTranslate2201 = 0;\r\n                            }\r\n                            if (window._viaPad2254) {   \/* pb2254 : le defilement pretait, on le rend *\/\r\n                                document.body.style.removeProperty('padding-bottom');\r\n                                window.scrollTo(0, 0);\r\n                                console.log('[pb2254] clavier ferme -> padding retire ('\r\n                                    + window._viaPad2254 + 'px), defilement rendu a 0');\r\n                                window._viaPad2254 = 0;\r\n                            }\r\n                            \/* pb2215 : le bloc \u00ab defilement rendu \u00bb qui suivait etait\r\n                               MORT \u2014 _viaScrollAvant2188 n est ecrit nulle part dans\r\n                               le corpus, son ecrivain ayant disparu avec la sonde\r\n                               pb2145 (suppression par bornes, lecon 10 du carnet).\r\n                               Il ne pouvait donc jamais s executer ; retire. *\/\r\n                            return;\r\n                        }\r\n                        var _a2199 = document.activeElement;\r\n                        if (_a2199 ? (_a2199.tagName !== 'INPUT') : true) {\r\n                            console.log('[pb2199] bande recue, aucun champ focalise | actif='\r\n                                + (_a2199 ? _a2199.tagName : 'aucun'));\r\n                            return;\r\n                        }\r\n                        if (window._viaPb2199Off === true) {\r\n                            console.log('[pb2199] desactive (_viaPb2199Off) -> aucun scroll');\r\n                            return;\r\n                        }\r\n                        \/* ================================================\r\n                         * pb2201 : RIEN NE DEFILE -> ON TRANSLATE LE CONTENU.\r\n                         *   Log pb2200, sans appel : \u00ab elementor-widget-container\r\n                         *   0\/6 | ReferencesConteneurId 0\/5 | ybm-in-iframe 6\/6 |\r\n                         *   window 6 \u00bb. Aucun ancetre ne deborde de plus de 6 px :\r\n                         *   le document de l iframe tient dans sa fenetre, il n y\r\n                         *   a AUCUN defilement possible, a aucun niveau. Un\r\n                         *   \u00ab scroll vers le bas \u00bb ne peut donc rien faire \u2014 les\r\n                         *   trois tentatives (pb2188, pb2199, pb2200) visaient un\r\n                         *   mecanisme qui n existe pas ici.\r\n                         *   Ce qui reste possible : DEPLACER le contenu. On\r\n                         *   translate le body de l iframe vers le haut, juste\r\n                         *   assez pour amener le champ focalise en haut de la\r\n                         *   bande visible recue du parent (repere iframe, pb2190),\r\n                         *   avec une marge. Le layout n est pas touche, aucune\r\n                         *   mesure ne derive : la translation est absolue,\r\n                         *   recalculee a chaque bande, et retiree a la fermeture\r\n                         *   du clavier.\r\n                         *   Revert : window._viaPb2201Off = true.\r\n                         * ================================================ *\/\r\n                        \/* ================================================\r\n                         * pb2215 : ON MESURE DANS LE REPERE NATUREL.\r\n                         *   pb2201 lisait la position du champ AVEC la\r\n                         *   translation en cours, puis la recomposait\r\n                         *   (_r.top + _dejaT). Deux failles :\r\n                         *     - la transition de 150ms fait que _r.top est une\r\n                         *       valeur INTERMEDIAIRE d animation, pas la valeur\r\n                         *       posee : la recomposition est alors fausse ;\r\n                         *     - c est precisement \u00ab relire une propriete que la\r\n                         *       passe precedente a ecrite \u00bb, que le carnet\r\n                         *       proscrit pour cause de derive cumulative.\r\n                         *   On retire donc la translation AVANT de mesurer : le\r\n                         *   rect obtenu EST le repere naturel, sans arithmetique.\r\n                         *   La transition disparait aussi \u2014 elle n apportait rien\r\n                         *   et rendait toute mesure ambigue.\r\n                         * ================================================ *\/\r\n                        \/* ================================================\r\n                         * pb2216 : LE HAUT DE LA BANDE PEUT ETRE NEGATIF, ET\r\n                         *          LA CIBLE N EST PAS LE HAUT DE LA BANDE.\r\n                         *   Log JF : \u00ab bande=-82..302 (top iframe=82) \u00bb puis\r\n                         *   TRANSLATE de -404px pour un champ a 338. La bande\r\n                         *   commence a -82 dans le repere de l iframe parce que\r\n                         *   les 82 premiers pixels de l ecran montrent le PARENT,\r\n                         *   pas l iframe. Viser ce -82 revenait a demander que le\r\n                         *   champ se place 82px AU-DESSUS du bord haut de\r\n                         *   l iframe : d ou \u00ab le formulaire est trop haut \u00bb.\r\n                         *   Deux corrections :\r\n                         *     - le point le plus haut visible du CONTENU de\r\n                         *       l iframe est max(0, offsetTop), jamais negatif ;\r\n                         *     - la cible n est plus \u00ab colle en haut avec 16px \u00bb\r\n                         *       mais 150px sous ce point (demande JF), reglable\r\n                         *       a chaud par window._viaMarge2216.\r\n                         *   Effet secondaire utile : le resultat ne depend plus\r\n                         *   de la bande recue (-82..302 ou -37..344 donnaient\r\n                         *   404 puis 441 puis 396 pour le MEME champ). Le\r\n                         *   placement devient idempotent.\r\n                         * ================================================ *\/\r\n                        var _bandeBrut2216 = _d2188.offsetTop;\r\n                        var _bandeHaut2201 = _bandeBrut2216;\r\n                        if (_bandeHaut2201 < 0) { _bandeHaut2201 = 0; }\r\n                        var _marge2201 = (typeof window._viaMarge2216 === 'number') ? window._viaMarge2216 : 150;\r\n                        var _body2201 = document.body;\r\n                        var _dejaT2201 = (typeof window._viaTranslate2201 === 'number') ? window._viaTranslate2201 : 0;\r\n                        _body2201.style.removeProperty('transition');\r\n                        _body2201.style.removeProperty('transform');\r\n                        var _champNat2201 = _a2199.getBoundingClientRect().top;   \/\/ repere naturel\r\n                        \/* ================================================\r\n                         * pb2254 : RECREER LE DEFILEMENT AU LIEU DE LE SIMULER.\r\n                         *   La regie fonctionne sans aucun appareillage parce que\r\n                         *   son document DEFILE : iOS y fait son geste natif. Ici,\r\n                         *   pb2200 a etabli qu aucun ancetre ne deborde de plus de\r\n                         *   6px \u2014 il n existe rien a scroller, et pb2201 simulait\r\n                         *   le defilement par un translateY sur le body (transform\r\n                         *   qui casse les fixed descendants et a impose la mesure\r\n                         *   au repere naturel de pb2215).\r\n                         *   On rend au document sa capacite a defiler : un\r\n                         *   padding-bottom de la hauteur masquee par le clavier\r\n                         *   (+ marge) cree le debordement, puis un VRAI scrollBy\r\n                         *   place le champ. Idempotent par construction :\r\n                         *   getBoundingClientRect integre deja le defilement\r\n                         *   courant, le delta est exact a chaque passe, aucune\r\n                         *   relecture d une valeur ecrite par la passe precedente.\r\n                         *   Le padding est retire et le defilement rendu a 0 a la\r\n                         *   fermeture du clavier (branche !clavier ci-dessus).\r\n                         *   scrollY est journalise avant\/apres : si iOS ajoute son\r\n                         *   propre defilement une fois le document scrollable, on\r\n                         *   le verra en un tour.\r\n                         *   Revert : window._viaPb2254Off = true -> chaine\r\n                         *   translateY pb2201 d origine, conservee verbatim.\r\n                         * ================================================ *\/\r\n                        if (window._viaPb2254Off === true) {\r\n                        var _dy2201 = Math.round(_champNat2201 - _bandeHaut2201 - _marge2201);\r\n                        if (_dy2201 < 0) { _dy2201 = 0; }\r\n                        if (window._viaPb2201Off === true) { _dy2201 = 0; }\r\n                        if (_dy2201 > 0) {\r\n                            _body2201.style.setProperty('transform', 'translateY(-' + _dy2201 + 'px)', 'important');\r\n                            window._viaTranslate2201 = _dy2201;\r\n                        } else {\r\n                            window._viaTranslate2201 = 0;\r\n                        }\r\n                        } else {\r\n                            window._viaTranslate2201 = 0;   \/\/ aucun transform dans cette voie\r\n                            var _basVisible2254 = _d2188.offsetTop + _d2188.hauteur;\r\n                            \/* pb2258 : la lecture vive pb2257 (visualViewport dans le\r\n                               document racine) est RETIREE, avec tout l appareillage\r\n                               regie de pb2256\/pb2257. Releve JF : corrections=12 (le\r\n                               plafond) a chaque garde, cible 278 -> scrollY final 556,\r\n                               \u00ab la page tremble terriblement \u00bb. Cause structurelle :\r\n                               pendant le panotage, iOS maintient pageTop constant \u2014\r\n                               chaque scrollBy(err) augmente scrollY, iOS diminue\r\n                               offsetTop d autant, et l erreur ressort INCHANGEE.\r\n                               L axe n est pas asservissable. Lecon 3 du carnet : on\r\n                               retire au lieu d empiler \u2014 la regie revient au geste\r\n                               natif d iOS, son comportement de reference. En iframe\r\n                               (sites pays), cette fonction ne recoit que la bande du\r\n                               parent : rien ne change au chemin valide. *\/\r\n                            var _cache2254 = Math.round(window.innerHeight - _basVisible2254);\r\n                            if (_cache2254 < 0) { _cache2254 = 0; }\r\n                            var _pad2254 = _cache2254 + _marge2201;\r\n                            _body2201.style.setProperty('padding-bottom', _pad2254 + 'px', 'important');\r\n                            window._viaPad2254 = _pad2254;\r\n                            var _syAv2254 = Math.round(window.scrollY || 0);\r\n                            var _delta2254 = Math.round(_champNat2201 - _bandeHaut2201 - _marge2201);\r\n                            if (window._viaPb2201Off !== true) {\r\n                                if (_delta2254 !== 0) { window.scrollBy(0, _delta2254); }\r\n                            }\r\n                            var _syAp2254 = Math.round(window.scrollY || 0);\r\n                            \/* ================================================\r\n                             * pb2255 : iOS SCROLLE AUSSI \u2014 ON PIN LA CIBLE.\r\n                             *   Releve JF (17:43) : nous posons 207, iOS relit 147\r\n                             *   220ms plus tard ; a chaque focus, [pb1895] trouve un\r\n                             *   scrollY different du notre. Le document etant devenu\r\n                             *   scrollable (pb2254), iOS refait son geste natif a\r\n                             *   chaque focus, a une position qui varie selon le champ\r\n                             *   tape. Deux mouvements par tape : instable.\r\n                             *   On ne peut pas empecher le scroll natif ; on le\r\n                             *   recouvre. Pendant _viaPb2255Ms apres chaque\r\n                             *   placement, tout defilement qui s ecarte de plus de\r\n                             *   2px de la cible est repositionne immediatement.\r\n                             *   La cible est ABSOLUE (syAvant + delta), recalculee a\r\n                             *   chaque placement : aucune derive possible.\r\n                             *   Revert : window._viaPb2255Off = true (garde inerte).\r\n                             * ================================================ *\/\r\n                            var _duree2255 = (typeof window._viaPb2255Ms === 'number') ? window._viaPb2255Ms : 700;\r\n                            var _cibleSy2255 = _syAv2254 + _delta2254;\r\n                            if (_cibleSy2255 < 0) { _cibleSy2255 = 0; }\r\n                            var _fin2255 = Date.now() + ((window._viaPb2255Off === true) ? 0 : _duree2255);\r\n                            window._viaGarde2255 = { sy: _cibleSy2255, fin: _fin2255, nb: 0 };\r\n                            if (window._viaBilan2255) { clearTimeout(window._viaBilan2255); }\r\n                            window._viaBilan2255 = setTimeout(function () {\r\n                                window._viaBilan2255 = null;\r\n                                var _g2255 = window._viaGarde2255;\r\n                                console.log('[pb2255] garde terminee | cible=' + (_g2255 ? _g2255.sy : '?')\r\n                                    + ' | corrections=' + (_g2255 ? _g2255.nb : 0)\r\n                                    + ' | scrollY final=' + Math.round(window.scrollY || 0));\r\n                            }, _duree2255 + 50);\r\n                            console.log('[pb2254] clavier ouvert -> defilement reel'\r\n                                + ' | champ #' + (_a2199.id || '?')\r\n                                + ' | champNaturel=' + Math.round(_champNat2201)\r\n                                + ' -> vise ' + (_bandeHaut2201 + _marge2201)\r\n                                + ' | delta=' + _delta2254\r\n                                + ' | scrollY ' + _syAv2254 + ' -> ' + _syAp2254\r\n                                + ' | [pb2255] garde ' + _duree2255 + 'ms cible=' + _cibleSy2255\r\n                                + ' | padding=' + _pad2254 + ' (cache=' + _cache2254 + ')'\r\n                                + ' | [pb2216] bandeHaut brut=' + _bandeBrut2216 + ' retenu=' + _bandeHaut2201\r\n                                + ' marge=' + _marge2201\r\n                                + ' | bande=' + _d2188.offsetTop + '..' + _basVisible2254\r\n                                + ' (top iframe=' + (_d2188.iframeTop || 0) + ')'\r\n                                + ' | cause=' + (_d2188._cause2215 || 'bande'));\r\n                            return;\r\n                        }\r\n                        console.log('[pb2201] clavier ouvert -> contenu TRANSLATE de -' + _dy2201 + 'px'\r\n                            + ' | champ #' + (_a2199.id || '?')\r\n                            + ' | champNaturel=' + Math.round(_champNat2201)\r\n                            + ' (translation precedente ' + _dejaT2201 + 'px)'\r\n                            + ' | [pb2216] bandeHaut brut=' + _bandeBrut2216 + ' retenu=' + _bandeHaut2201\r\n                            + ' marge=' + _marge2201 + ' -> champ vise a ' + (_bandeHaut2201 + _marge2201)\r\n                            + ' | bande=' + _d2188.offsetTop + '..' + (_d2188.offsetTop + _d2188.hauteur)\r\n                            + ' (top iframe=' + (_d2188.iframeTop || 0) + ')'\r\n                            + ' | cause=' + (_d2188._cause2215 || 'bande'));\r\n                    } catch (_e2199) { console.warn('[pb2199] ' + _e2199.message); }\r\n                };\r\n                window.addEventListener('message', function (_ev2199) {\r\n                    try {\r\n                        var _d = _ev2199 ? _ev2199.data : null;\r\n                        if (!_d) { return; }\r\n                        if (_d.type !== 'viaBandeVisible2188') { return; }\r\n                        if (window._viaAttente2193) { clearTimeout(window._viaAttente2193); }\r\n                        var _msg = _d;\r\n                        window._viaBande2215 = _msg;   \/\/ pb2215 : derniere bande connue\r\n                        window._viaAttente2193 = setTimeout(function () {\r\n                            window._viaAttente2193 = null;\r\n                            window._viaTraiterBande2188(_msg);\r\n                        }, (typeof window._viaPb2193Ms === 'number') ? window._viaPb2193Ms : 250);\r\n                    } catch (_em2199) { console.warn('[pb2199] message : ' + _em2199.message); }\r\n                });\r\n                console.log('[pb2199] recepteur de bande visible arme (iframe) | rafales filtrees');\r\n\r\n                \/* pb2255 : l ecouteur de garde \u2014 arme une fois. Tout scroll qui\r\n                   survient pendant la fenetre de garde et s ecarte de la cible\r\n                   est repositionne dans la meme frame. scrollTo vers une valeur\r\n                   deja atteinte n emet aucun evenement : pas de boucle possible.\r\n                   pb2258 : le mode \u00ab invariant \u00bb de pb2257 (document racine) est\r\n                   retire \u2014 axe non asservissable, voir le commentaire au\r\n                   placement. Seul reste le pincement scrollY, valide en iframe\r\n                   sites pays. Plafond de 12 corrections par garde conserve. *\/\r\n                window._viaVerifGarde2255 = function () {\r\n                    try {\r\n                        var _g2255 = window._viaGarde2255;\r\n                        if (!_g2255) { return; }\r\n                        if (Date.now() > _g2255.fin) { return; }\r\n                        if (_g2255.nb >= 12) { return; }\r\n                        var _sy2255 = Math.round(window.scrollY || 0);\r\n                        if (Math.abs(_sy2255 - _g2255.sy) <= 2) { return; }\r\n                        _g2255.nb = _g2255.nb + 1;\r\n                        window.scrollTo(0, _g2255.sy);\r\n                    } catch (_e2255) { console.warn('[pb2255] ' + _e2255.message); }\r\n                };\r\n                window.addEventListener('scroll', function () {\r\n                    window._viaVerifGarde2255();\r\n                }, { passive: true });\r\n\r\n                \/* ================================================================\r\n                 * pb2215 : LE 2e CHAMP N EMET AUCUNE BANDE.\r\n                 *   La chaine pb2188 -> pb2201 est declenchee par un vv-resize du\r\n                 *   parent, c est-a-dire par un CHANGEMENT de hauteur du viewport\r\n                 *   visuel. Toucher un second champ alors que le clavier est deja\r\n                 *   ouvert ne change rien a cette hauteur : aucun resize, aucune\r\n                 *   bande, aucun recalcul. Le contenu reste place pour le champ\r\n                 *   PRECEDENT, et le nouveau champ peut se trouver sous le clavier.\r\n                 *   On rejoue donc le placement au focus, sur la DERNIERE bande\r\n                 *   recue \u2014 la geometrie du clavier n a pas change, seule la cible\r\n                 *   a change. Le delai laisse iOS finir son propre ajustement.\r\n                 *   Revert : window._viaPb2215Off = true.\r\n                 * ================================================================ *\/\r\n                document.addEventListener('focusin', function (_ev2215) {\r\n                    try {\r\n                        var _c2215 = _ev2215 ? _ev2215.target : null;\r\n                        if (!_c2215) { return; }\r\n                        if (_c2215.tagName !== 'INPUT') { return; }\r\n                        if (window._viaPb2215Off === true) {\r\n                            console.log('[pb2215] desactive (_viaPb2215Off) | champ #' + (_c2215.id || '?'));\r\n                            return;\r\n                        }\r\n                        var _b2215 = window._viaBande2215;\r\n                        \/* pb2258 : la fabrication de bande vive au focus (pb2257,\r\n                           document racine) est retiree avec l emetteur pb2256.\r\n                           Dans le document racine, _viaBande2215 n est plus jamais\r\n                           ecrit : la sortie \u00ab aucune bande memorisee \u00bb redevient\r\n                           le chemin normal de la regie \u2014 chaine inerte, natif iOS. *\/\r\n                        if (!_b2215) {\r\n                            console.log('[pb2215] focus #' + (_c2215.id || '?')\r\n                                + ' : aucune bande memorisee -> aucun replacement');\r\n                            return;\r\n                        }\r\n                        if (!_b2215.clavier) {\r\n                            console.log('[pb2215] focus #' + (_c2215.id || '?')\r\n                                + ' : derniere bande sans clavier -> aucun replacement');\r\n                            return;\r\n                        }\r\n                        if (window._viaFocus2215) { clearTimeout(window._viaFocus2215); }\r\n                        window._viaFocus2215 = setTimeout(function () {\r\n                            window._viaFocus2215 = null;\r\n                            var _rejoue2215 = {\r\n                                offsetTop: _b2215.offsetTop,\r\n                                hauteur: _b2215.hauteur,\r\n                                iframeTop: _b2215.iframeTop,\r\n                                bandeParent: _b2215.bandeParent,\r\n                                clavier: true,\r\n                                _cause2215: 'focus #' + (_c2215.id || '?')\r\n                            };\r\n                            console.log('[pb2215] focus #' + (_c2215.id || '?')\r\n                                + ' -> replacement sur la derniere bande ('\r\n                                + _b2215.offsetTop + '..' + (_b2215.offsetTop + _b2215.hauteur) + ')');\r\n                            window._viaTraiterBande2188(_rejoue2215);\r\n                        }, (typeof window._viaPb2255Delai === 'number') ? window._viaPb2255Delai : 0);\r\n                        \/* pb2255 : delai 150 -> 0. Il servait a \u00ab laisser iOS finir\r\n                           son ajustement \u00bb ; la garde fait desormais l inverse \u2014 elle\r\n                           l ecrase. Retour a l ancien reglage : _viaPb2255Delai=150. *\/\r\n                    } catch (_e2215) { console.warn('[pb2215] ' + _e2215.message); }\r\n                });\r\n                console.log('[pb2215] replacement au focus arme (iframe)');\r\n\r\n                \/* ================================================================\r\n                 * pb2258 : L EMETTEUR LOCAL pb2256 ET L ECOUTE DU PANOTAGE pb2257\r\n                 *          SONT RETIRES. Le document racine (regie mobile) revient\r\n                 *   au geste natif d iOS \u2014 son comportement de reference, celui\r\n                 *   d avant pb2254. Releve JF : corrections=12 a chaque garde,\r\n                 *   cible 278 -> scrollY final 556, \u00ab la page tremble\r\n                 *   terriblement \u00bb. Pendant le panotage, iOS maintient pageTop\r\n                 *   constant : chaque correction de scrollY est compensee par\r\n                 *   offsetTop et l erreur ressort inchangee \u2014 l axe n est pas\r\n                 *   asservissable depuis JS. Lecon 3 du carnet : retirer au lieu\r\n                 *   d empiler. La chaine bande -> placement -> garde ne vit\r\n                 *   desormais QUE dans l iframe des sites pays, alimentee par\r\n                 *   l unique emetteur d Entete.txt, ou elle est validee.\r\n                 * ================================================================ *\/\r\n                \/* ================================================================\r\n                 * pb2259 : LE NATIF ECHOUE FAUTE DE BUDGET \u2014 ON DONNE LE BUDGET.\r\n                 *   Releves JF : innerH=740, vvH=381 (clavier ~360px), premier\r\n                 *   champ a champNaturel=427-428 \u2014 sous le clavier, il faut\r\n                 *   ~280px de defilement. La page References regie se termine\r\n                 *   peu apres le formulaire : le debordement naturel est trop\r\n                 *   court, iOS compense par le panotage elastique (offsetTop\r\n                 *   jusqu a 299) qui atterrit ou il peut. Les champs suivants\r\n                 *   tombent dans la bande deja acquise \u2014 d ou \u00ab les 2 premiers\r\n                 *   champs seulement \u00bb, mot pour mot le constat de pb2184.\r\n                 *   REMEDE \u2014 le contraire du servo pb2257 qui tremblait : UNE\r\n                 *   ecriture, AUCUNE boucle. Clavier detecte (test pb2235,\r\n                 *   innerHeight - vvHeight > seuil) -> padding-bottom =\r\n                 *   ecart + marge sur le body. C est tout : aucun scrollBy,\r\n                 *   aucune garde, aucune cible \u2014 iOS garde seul le pilotage et\r\n                 *   son scroll-into-view trouve desormais la place, comme sur\r\n                 *   une page longue. Clavier ferme -> padding retire.\r\n                 *   Document racine uniquement : en iframe sites pays, le\r\n                 *   padding est deja pose par le placement pb2254.\r\n                 *   Revert : window._viaPb2259Off = true.\r\n                 *   Seuil : window._viaPb2259Seuil (100). Marge : _viaMarge2216.\r\n                 * ================================================================ *\/\r\n                if (window.parent === window ? !!window.visualViewport : false) {\r\n                    window.visualViewport.addEventListener('resize', function () {\r\n                        try {\r\n                            if (window._viaPb2259Off === true) { return; }\r\n                            var _vv2259 = window.visualViewport;\r\n                            var _ec2259 = Math.round((window.innerHeight || 0) - _vv2259.height);\r\n                            var _seuil2259 = (typeof window._viaPb2259Seuil === 'number') ? window._viaPb2259Seuil : 100;\r\n                            if (_ec2259 > _seuil2259) {\r\n                                var _marge2259 = (typeof window._viaMarge2216 === 'number') ? window._viaMarge2216 : 150;\r\n                                var _pad2259 = _ec2259 + _marge2259;\r\n                                if (window._viaPad2259 === _pad2259) { return; }   \/\/ deja pose a l identique (rafales)\r\n                                document.body.style.setProperty('padding-bottom', _pad2259 + 'px', 'important');\r\n                                window._viaPad2259 = _pad2259;\r\n                                window._viaPad2259Dernier = _pad2259;   \/\/ pb2260 : memoire pour le provisoire\r\n                                \/* ====================================================\r\n                                 * pb2262 : iOS NE FAIT AUCUN GESTE POUR LE CHAMP 1.\r\n                                 *   Releve JF : padding pose au pointerdown meme\r\n                                 *   (45097), piege pb1895 muet 4s, scrollY reste 0 \u2014\r\n                                 *   a l OUVERTURE du clavier, iOS ne scrolle pas,\r\n                                 *   budget ou pas. Il n y a pas de geste a devancer.\r\n                                 *   Clavier deja ouvert (champs 2+), iOS scrolle :\r\n                                 *   mesure (69, 252, 231...).\r\n                                 *   RATTRAPAGE UNIQUE, pas un servo : 350ms apres la\r\n                                 *   passe exacte (animation posee), si le champ actif\r\n                                 *   depasse le bas visible (lu en DIRECT), UN seul\r\n                                 *   scrollBy sur valeurs vives, puis plus rien.\r\n                                 *   Un geste par ouverture (drapeau _viaCorr2262,\r\n                                 *   remis a zero a la fermeture). Un scrollBy isole\r\n                                 *   est prouve effectif ici (pb2254 : 0->277 rendu) ;\r\n                                 *   c est la repetition qui tremblait (pb2257).\r\n                                 *   Revert : window._viaPb2262Off = true.\r\n                                 *   Delai : window._viaPb2262Ms (350).\r\n                                 * ==================================================== *\/\r\n                                if (window._viaPb2262Off === true ? false : !window._viaCorr2262) {\r\n                                    window._viaCorr2262 = true;\r\n                                    setTimeout(function () {\r\n                                        try {\r\n                                            var _a2262 = document.activeElement;\r\n                                            if (!_a2262) {\r\n                                                console.log('[pb2262] aucun element actif -> aucun geste');\r\n                                                return;\r\n                                            }\r\n                                            if (_a2262.tagName === 'INPUT' ? false : _a2262.tagName !== 'TEXTAREA') {\r\n                                                console.log('[pb2262] element actif ' + _a2262.tagName + ' non champ -> aucun geste');\r\n                                                return;\r\n                                            }\r\n                                            var _vv2262 = window.visualViewport;\r\n                                            var _off2262 = Math.round(_vv2262.offsetTop);\r\n                                            if (_off2262 < 0) { _off2262 = 0; }\r\n                                            var _basVis2262 = _off2262 + Math.round(_vv2262.height);\r\n                                            var _r2262 = _a2262.getBoundingClientRect();\r\n                                            if (_r2262.bottom <= _basVis2262 - 10) {\r\n                                                console.log('[pb2262] champ #' + (_a2262.id || '?')\r\n                                                    + ' deja visible (bas=' + Math.round(_r2262.bottom)\r\n                                                    + ' <= ' + (_basVis2262 - 10) + ') -> aucun geste');\r\n                                                return;\r\n                                            }\r\n                                            var _mg2262 = (typeof window._viaMarge2216 === 'number') ? window._viaMarge2216 : 150;\r\n                                            var _av2262 = Math.round(window.scrollY || 0);\r\n                                            var _d2262 = Math.round(_r2262.top - _off2262 - _mg2262);\r\n                                            window.scrollBy(0, _d2262);\r\n                                            console.log('[pb2262] rattrapage UNIQUE : champ #' + (_a2262.id || '?')\r\n                                                + ' bas=' + Math.round(_r2262.bottom)\r\n                                                + ' > visible ' + _basVis2262\r\n                                                + ' (offsetTop=' + _off2262 + ')'\r\n                                                + ' -> scrollBy(' + _d2262 + ')'\r\n                                                + ' | scrollY ' + _av2262 + ' -> ' + Math.round(window.scrollY || 0));\r\n                                        } catch (_ec2262) { console.warn('[pb2262] ' + _ec2262.message); }\r\n                                    }, (typeof window._viaPb2262Ms === 'number') ? window._viaPb2262Ms : 350);\r\n                                }\r\n                                console.log('[pb2259] clavier detecte (ecart=' + _ec2259\r\n                                    + ') -> padding-bottom ' + _pad2259\r\n                                    + 'px pose | iOS reste seul pilote du defilement');\r\n                            } else if (window._viaPad2259) {\r\n                                document.body.style.removeProperty('padding-bottom');\r\n                                console.log('[pb2259] clavier ferme (ecart=' + _ec2259\r\n                                    + ') -> padding retire (' + window._viaPad2259 + 'px)');\r\n                                window._viaPad2259 = 0;\r\n                                window._viaCorr2262 = false;   \/\/ pb2262 : prochain cycle clavier, nouveau rattrapage possible\r\n                            }\r\n                        } catch (_e2259) { console.warn('[pb2259] ' + _e2259.message); }\r\n                    });\r\n                    console.log('[pb2259] budget de defilement arme (document racine)'\r\n                        + ' | innerH=' + Math.round(window.innerHeight || 0));\r\n                    \/* ============================================================\r\n                     * pb2260 : LE CHAMP 1 RESTE SOUS LE CLAVIER \u2014 LE PADDING\r\n                     *          ARRIVE 76ms APRES LE GESTE D iOS.\r\n                     *   Releve JF : focus a 30558, [pb2259] pose a 30634. iOS fait\r\n                     *   son scroll-into-view UNE fois, immediatement au focus, ne\r\n                     *   trouve pas de budget, et ne reessaie jamais. Les champs\r\n                     *   suivants heritent du padding en place \u2014 d ou \u00ab seul le\r\n                     *   premier \u00bb.\r\n                     *   REMEDE : poser un padding PROVISOIRE des focusin \u2014 le\r\n                     *   handler est synchrone, il precede le geste asynchrone\r\n                     *   d iOS. Valeur : la derniere valeur reelle connue\r\n                     *   (_viaPad2259Dernier), sinon 520px (ecart 361 + marge 150,\r\n                     *   arrondi ; reglable _viaPb2260Pad). Le vv-resize suivant\r\n                     *   ecrit la valeur EXACTE par le canal pb2259 : le provisoire\r\n                     *   ne vit que quelques dizaines de ms.\r\n                     *   Toujours une ecriture, toujours zero boucle.\r\n                     *   Securite : au focusout SANS clavier detecte (ecart sous le\r\n                     *   seuil \u2014 clavier materiel, focus programmatique), le\r\n                     *   provisoire est retire pour ne pas laisser un vide au bas\r\n                     *   de page.\r\n                     *   Revert : window._viaPb2260Off = true.\r\n                     * ============================================================ *\/\r\n                    \/* ============================================================\r\n                     * pb2261 : LE FOCUS EST DEJA TROP TARD \u2014 iOS DECIDE AU\r\n                     *          POINTERDOWN.\r\n                     *   Releve JF : [CAPTURE PD] a 36864, focus + pose pb2260 a\r\n                     *   37026 \u2014 162ms d ecart. iOS fige son instantane de la page\r\n                     *   (dont la capacite a defiler) des le pointerdown ; un\r\n                     *   padding pose au focusin est posterieur a cet instantane\r\n                     *   et n est plus regarde. Les champs suivants passaient\r\n                     *   parce que le padding SURVIT d un champ a l autre \u2014 donc\r\n                     *   deja present au pointerdown suivant.\r\n                     *   La pose provisoire se fait donc des le pointerdown\r\n                     *   (phase capture), 160ms avant le focus. Le focusin pb2260\r\n                     *   reste en filet pour les focus programmatiques.\r\n                     *   Revert : window._viaPb2261Off = true (retour pose au\r\n                     *   focusin seule).\r\n                     * ============================================================ *\/\r\n                    document.addEventListener('pointerdown', function (_ev2261) {\r\n                        try {\r\n                            if (window._viaPb2261Off === true) { return; }\r\n                            if (window._viaPb2260Off === true) { return; }\r\n                            var _c2261 = _ev2261 ? _ev2261.target : null;\r\n                            if (!_c2261) { return; }\r\n                            if (_c2261.tagName === 'INPUT' ? false : _c2261.tagName !== 'TEXTAREA') { return; }\r\n                            if (window._viaPad2259) { return; }   \/\/ deja pose (clavier deja ouvert)\r\n                            var _pad2261 = (typeof window._viaPad2259Dernier === 'number' ? window._viaPad2259Dernier : 0)\r\n                                || ((typeof window._viaPb2260Pad === 'number') ? window._viaPb2260Pad : 520);\r\n                            document.body.style.setProperty('padding-bottom', _pad2261 + 'px', 'important');\r\n                            window._viaPad2259 = _pad2261;\r\n                            console.log('[pb2261] pointerdown #' + (_c2261.id || '?')\r\n                                + ' -> padding provisoire ' + _pad2261\r\n                                + 'px pose AVANT l instantane iOS (exact au prochain vv-resize)');\r\n                        } catch (_e2261) { console.warn('[pb2261] ' + _e2261.message); }\r\n                    }, true);\r\n                    document.addEventListener('focusin', function (_ev2260) {\r\n                        try {\r\n                            if (window._viaPb2260Off === true) { return; }\r\n                            var _c2260 = _ev2260 ? _ev2260.target : null;\r\n                            if (!_c2260) { return; }\r\n                            if (_c2260.tagName === 'INPUT' ? false : _c2260.tagName !== 'TEXTAREA') { return; }\r\n                            if (window._viaPad2259) { return; }   \/\/ deja pose (clavier deja ouvert)\r\n                            var _pad2260 = (typeof window._viaPad2259Dernier === 'number' ? window._viaPad2259Dernier : 0)\r\n                                || ((typeof window._viaPb2260Pad === 'number') ? window._viaPb2260Pad : 520);\r\n                            document.body.style.setProperty('padding-bottom', _pad2260 + 'px', 'important');\r\n                            window._viaPad2259 = _pad2260;\r\n                            console.log('[pb2260] focus #' + (_c2260.id || '?')\r\n                                + ' -> padding provisoire ' + _pad2260\r\n                                + 'px pose AVANT le geste iOS (exact au prochain vv-resize)');\r\n                        } catch (_e2260) { console.warn('[pb2260] ' + _e2260.message); }\r\n                    });\r\n                    document.addEventListener('focusout', function () {\r\n                        try {\r\n                            if (window._viaPb2260Off === true) { return; }\r\n                            if (!window._viaPad2259) { return; }\r\n                            var _ecS2260 = Math.round((window.innerHeight || 0) - window.visualViewport.height);\r\n                            var _sS2260 = (typeof window._viaPb2259Seuil === 'number') ? window._viaPb2259Seuil : 100;\r\n                            if (_ecS2260 > _sS2260) { return; }   \/\/ clavier reellement ouvert : on ne touche a rien\r\n                            document.body.style.removeProperty('padding-bottom');\r\n                            console.log('[pb2260] focusout sans clavier (ecart=' + _ecS2260\r\n                                + ') -> padding provisoire retire (' + window._viaPad2259 + 'px)');\r\n                            window._viaPad2259 = 0;\r\n                        } catch (_eS2260) { console.warn('[pb2260] ' + _eS2260.message); }\r\n                    });\r\n                }\r\n            }\r\n\r\n            \/* pb2225 : la sonde pb2200 (scroll force au clic sur tous les ancetres)\r\n               est retiree. Elle etait deja desarmee par pb2201, son releve ayant\r\n               montre qu'AUCUN ancetre de l'iframe ne defile \u2014 c'est ce constat qui\r\n               a conduit a la translation pb2201 puis a pb2215\/pb2216. La question\r\n               qu'elle posait est donc tranchee. *\/\r\n\r\n            if (!window._viaDragCal2142) {\r\n                window._viaDragCal2142 = true;\r\n                (function _viaCalDrag2142() {\r\n                    var _st2142 = null;\r\n                    function _pt2142(_e) {\r\n                        if (_e.touches ? _e.touches.length : 0) {\r\n                            return { x: _e.touches[0].screenX, y: _e.touches[0].screenY };\r\n                        }\r\n                        return { x: _e.screenX, y: _e.screenY };\r\n                    }\r\n                    function _debut2142(_e) {\r\n                        if (window._viaPb2142Off === true) { return; }\r\n                        var _cible = _e.target;\r\n                        if (!_cible) { return; }\r\n                        if (_cible.closest('.ui-datepicker-prev, .ui-datepicker-next')) { return; }\r\n                        var _hdr = _cible.closest('.ui-datepicker-header');\r\n                        if (!_hdr) { return; }\r\n                        var _div = document.getElementById('ui-datepicker-div');\r\n                        if (!_div) { return; }\r\n                        var _r = _div.getBoundingClientRect();\r\n                        var _p = _pt2142(_e);\r\n                        _st2142 = { x: _p.x, y: _p.y, top: _r.top, left: _r.left, div: _div };\r\n                        _div.style.setProperty('position', 'fixed', 'important');\r\n                        _e.preventDefault();\r\n                        console.log('[pb2142] drag calendrier demarre | depart top='\r\n                            + Math.round(_r.top) + ' left=' + Math.round(_r.left));\r\n                    }\r\n                    function _bouge2142(_e) {\r\n                        if (!_st2142) { return; }\r\n                        var _p = _pt2142(_e);\r\n                        var _nTop = _st2142.top + (_p.y - _st2142.y);\r\n                        var _nLeft = _st2142.left + (_p.x - _st2142.x);\r\n                        var _d = _st2142.div;\r\n                        var _r = _d.getBoundingClientRect();\r\n                        var _vw = window.innerWidth, _vh = window.innerHeight;\r\n                        var _keepX = Math.round(_r.width * 0.2);\r\n                        var _keepY = Math.round(_r.height * 0.2);\r\n                        if (_nTop < 0) { _nTop = 0; }\r\n                        if (_nLeft + _r.width < _keepX) { _nLeft = _keepX - _r.width; }\r\n                        if (_nLeft > _vw - _keepX) { _nLeft = _vw - _keepX; }\r\n                        if (_nTop > _vh - _keepY) { _nTop = _vh - _keepY; }\r\n                        _d.style.setProperty('top', _nTop + 'px', 'important');\r\n                        _d.style.setProperty('left', _nLeft + 'px', 'important');\r\n                        _e.preventDefault();\r\n                    }\r\n                    function _fin2142() {\r\n                        if (!_st2142) { return; }\r\n                        _st2142 = null;\r\n                    }\r\n                    document.addEventListener('mousedown', _debut2142, true);\r\n                    document.addEventListener('mousemove', _bouge2142, true);\r\n                    document.addEventListener('mouseup', _fin2142, true);\r\n                    document.addEventListener('touchstart', _debut2142, { capture: true, passive: false });\r\n                    document.addEventListener('touchmove', _bouge2142, { capture: true, passive: false });\r\n                    document.addEventListener('touchend', _fin2142, true);\r\n                    document.addEventListener('touchcancel', _fin2142, true);\r\n                    console.log('[pb2142] moteur de drag des calendriers arme (souris + tactile)');\r\n                })();\r\n            }\r\n            \r\n            $dateDebut.attr('readonly', 'readonly');\r\n            $dateFin.attr('readonly', 'readonly');\r\n            console.log('\ud83d\udcc5 Champs dates en readonly : s\u00e9lection calendrier uniquement');\r\n            \r\n            const minDate = new Date();\r\n            minDate.setDate(minDate.getDate() + 21);\r\n            minDate.setHours(0, 0, 0, 0);\r\n        \r\n            $dateDebut.datepicker({\r\n                dateFormat: 'dd\/mm\/yy',\r\n                minDate: minDate,\r\n                maxDate: '+2y',\r\n                firstDay: 1,\r\n                showButtonPanel: false,\r\n                beforeShow: function(input, inst) {\r\n                    if (isMobile) {\r\n                        $(input).blur();\r\n                    }\r\n                    \r\n                    setTimeout(() => {\r\n                        inst.dpDiv.addClass('via-datepicker');\r\n                        \r\n                        if (isMobile) {\r\n                            const $datepicker = inst.dpDiv;\r\n                            \r\n                            $datepicker.css({\r\n                                'position': 'fixed',\r\n                                'left': '25%',\r\n                                'top': '50%',\r\n                                'transform': 'translate(-50%, -50%) scale(0.7)',\r\n                                'margin': '0',\r\n                                'z-index': '99999'\r\n                            });\r\n                        } else {\r\n                            \/\/ \u2705 v4.9ds Fix 23 v2 (Pb 16) : sur desktop, positionner le datepicker\r\n                            \/\/   AU-DESSUS du champ si la place est suffisante. Sinon (fen\u00eatre\/iframe\r\n                            \/\/   petite \u2014 popup achat), basculer EN DESSOUS pour \u00e9viter que le\r\n                            \/\/   calendrier d\u00e9borde vers le haut et \u00e9crase le r\u00e9cap.\r\n                            \/\/ \u2705 v4.9ds Fix 23 v3 : d\u00e9caler +30px vers le bas par rapport \u00e0 la\r\n                            \/\/   position calcul\u00e9e \u2014 demande user, le calendrier \u00e9tait trop haut.\r\n                            const $inputEl = $(input);\r\n                            const $dpEl = inst.dpDiv;\r\n                            const _inputOffset = $inputEl.offset();\r\n                            const _dpHeight = $dpEl.outerHeight();\r\n                            const _scrollTop = $(window).scrollTop();\r\n                            const _spaceAbove = _inputOffset.top - _scrollTop;\r\n                            if (_spaceAbove >= _dpHeight + 10) {\r\n                                $dpEl.css('top', (_inputOffset.top - _dpHeight - 5 + 30) + 'px');\r\n                            } else {\r\n                                $dpEl.css('top', (_inputOffset.top + $inputEl.outerHeight() + 5) + 'px');\r\n                            }\r\n                        }\r\n                    }, 0);\r\n                },\r\n                onSelect: function(dateText, inst) {\r\n                    \/\/ \u2705 v1.8 : Bloquer si bon de commande cr\u00e9\u00e9\r\n                    if (window.VIA_Panier && window.VIA_Panier.verifierBonCommandeCreeLock()) {\r\n                        \/\/ R\u00e9initialiser la date\r\n                        if (STATE.startDate) {\r\n                            $dateDebut.datepicker('setDate', STATE.startDate);\r\n                        } else {\r\n                            $dateDebut.val('');\r\n                        }\r\n                        return;\r\n                    }\r\n                    \r\n                    const startDate = $dateDebut.datepicker('getDate');\r\n                    STATE.startDate = startDate;\r\n        \r\n                    const minEndDate = new Date(startDate);\r\n                    minEndDate.setDate(minEndDate.getDate() + 1);\r\n                    const finalMinDate = minEndDate > minDate ? minEndDate : minDate;\r\n                    $dateFin.datepicker('option', 'minDate', finalMinDate);\r\n        \r\n                    const currentEndDate = $dateFin.datepicker('getDate');\r\n                    if (AND(currentEndDate, currentEndDate <= startDate)) {\r\n                        $dateFin.val('');\r\n                        STATE.endDate = null;\r\n                        $(CONFIG.FIELDS.dureeContainer).text('');\r\n                    }\r\n        \r\n                    $dateDebut.addClass('date-selected').css('background-color', '#E8F0FE');\r\n                    setTimeout(() => {\r\n                        $dateDebut.removeClass('date-selected').css('background-color', '');\r\n                    }, 600);\r\n        \r\n                    calculateDuration();\r\n                    triggerTarifCalculation();\r\n                    synchroniserDateAvecPanier('dateDebut', dateText);\r\n        \r\n                    if (AND(STATE.emplacementPageWeb, AND(STATE.startDate, STATE.endDate))) {\r\n                        const debut = $.datepicker.formatDate('yy-mm-dd', STATE.startDate);\r\n                        const fin = $.datepicker.formatDate('yy-mm-dd', STATE.endDate);\r\n                        \r\n                        verifierDisponibilite(STATE.emplacementPageWeb, debut, fin)\r\n                            .then(result => {\r\n                                if (!result.available) {\r\n                                    afficherIndisponibilite(result.next_available);\r\n                                } else {\r\n                                    masquerIndisponibilite();\r\n                                }\r\n                            });\r\n                    }\r\n        \r\n                    verifierAffichageMsgSelectEspace();\r\n        \r\n                    console.log('\u2705 Date d\u00e9but s\u00e9lectionn\u00e9e:', dateText);\r\n                    \r\n                    setTimeout(function() {\r\n                        $.datepicker._hideDatepicker();\r\n                        $dateDebut.blur();\r\n                        $('#ui-datepicker-div').hide();\r\n                        \/\/ ================================================================\r\n                        \/\/ pb798 : enchainer sur le calendrier de FIN de campagne.\r\n                        \/\/   Le calendrier de debut se referme juste au-dessus ; on ouvre\r\n                        \/\/   celui de fin APRES cette fermeture, sinon jQuery UI reutilise\r\n                        \/\/   le meme #ui-datepicker-div et le masque aussitot.\r\n                        \/\/   L'ouverture passe par focus() : c'est le declencheur natif du\r\n                        \/\/   widget, il place aussi le curseur dans le champ. Un appel a\r\n                        \/\/   datepicker('show') sans focus laisserait le champ inactif.\r\n                        \/\/   minDate vient d'etre recalcule ci-dessus : le calendrier\r\n                        \/\/   s'ouvre donc deja borne au lendemain du debut.\r\n                        \/\/   Revert : window._viaPb798Off = true.\r\n                        \/\/ ================================================================\r\n                        if (window._viaPb798Off !== true) {\r\n                            setTimeout(function() {\r\n                                try {\r\n                                    if (!$dateFin.length) { return; }\r\n                                    if ($dateFin.is(':disabled')) { return; }\r\n                                    $dateFin.focus();\r\n                                    console.log('[pb798] calendrier de fin de campagne ouvert');\r\n                                } catch (_e798) { console.warn('[pb798]', _e798.message); }\r\n                            }, 120);\r\n                        }\r\n                    }, 50);\r\n                },\r\n                onClose: function() {\r\n                    $(this).blur();\r\n                }\r\n            });\r\n        \r\n            $dateFin.datepicker({\r\n                dateFormat: 'dd\/mm\/yy',\r\n                minDate: minDate,\r\n                maxDate: '+2y',\r\n                firstDay: 1,\r\n                showButtonPanel: false,\r\n                beforeShowDay: function(date) {\r\n                    if (STATE.startDate) {\r\n                        const maxDate = new Date(STATE.startDate);\r\n                        maxDate.setDate(maxDate.getDate() + 360);\r\n                        \r\n                        if (date > maxDate) {\r\n                            return [false, '', 'Dur\u00e9e maximale : 360 jours'];\r\n                        }\r\n                    }\r\n                    return [true, ''];\r\n                },\r\n                beforeShow: function(input, inst) {\r\n                    if (isMobile) {\r\n                        $(input).blur();\r\n                    }\r\n                    \r\n                    setTimeout(() => {\r\n                        inst.dpDiv.addClass('via-datepicker');\r\n                        \r\n                        if (isMobile) {\r\n                            const $datepicker = inst.dpDiv;\r\n                            \r\n                            $datepicker.css({\r\n                                'position': 'fixed',\r\n                                'left': '25%',\r\n                                'top': '50%',\r\n                                'transform': 'translate(-50%, -50%) scale(0.7)',\r\n                                'margin': '0',\r\n                                'z-index': '99999'\r\n                            });\r\n                        } else {\r\n                            \/\/ \u2705 v4.9ds Fix 23 v2 (Pb 16) : sur desktop, positionner le datepicker\r\n                            \/\/   AU-DESSUS du champ si la place est suffisante. Sinon (fen\u00eatre\/iframe\r\n                            \/\/   petite \u2014 popup achat), basculer EN DESSOUS pour \u00e9viter que le\r\n                            \/\/   calendrier d\u00e9borde vers le haut et \u00e9crase le r\u00e9cap.\r\n                            \/\/ \u2705 v4.9ds Fix 23 v3 : d\u00e9caler +30px vers le bas par rapport \u00e0 la\r\n                            \/\/   position calcul\u00e9e \u2014 demande user, le calendrier \u00e9tait trop haut.\r\n                            const $inputEl = $(input);\r\n                            const $dpEl = inst.dpDiv;\r\n                            const _inputOffset = $inputEl.offset();\r\n                            const _dpHeight = $dpEl.outerHeight();\r\n                            const _scrollTop = $(window).scrollTop();\r\n                            const _spaceAbove = _inputOffset.top - _scrollTop;\r\n                            if (_spaceAbove >= _dpHeight + 10) {\r\n                                $dpEl.css('top', (_inputOffset.top - _dpHeight - 5 + 30) + 'px');\r\n                            } else {\r\n                                $dpEl.css('top', (_inputOffset.top + $inputEl.outerHeight() + 5) + 'px');\r\n                            }\r\n                        }\r\n                    }, 0);\r\n                },\r\n                onSelect: function(dateText, inst) {\r\n                    \/\/ \u2705 v1.8 : Bloquer si bon de commande cr\u00e9\u00e9\r\n                    if (window.VIA_Panier && window.VIA_Panier.verifierBonCommandeCreeLock()) {\r\n                        \/\/ R\u00e9initialiser la date\r\n                        if (STATE.endDate) {\r\n                            $dateFin.datepicker('setDate', STATE.endDate);\r\n                        } else {\r\n                            $dateFin.val('');\r\n                        }\r\n                        return;\r\n                    }\r\n                    \r\n                    const endDate = $dateFin.datepicker('getDate');\r\n                    STATE.endDate = endDate;\r\n        \r\n                    $dateFin.addClass('date-selected').css('background-color', '#E8F0FE');\r\n                    setTimeout(() => {\r\n                        $dateFin.removeClass('date-selected').css('background-color', '');\r\n                    }, 600);\r\n        \r\n                    calculateDuration();\r\n                    triggerTarifCalculation();\r\n                    synchroniserDateAvecPanier('dateFin', dateText);\r\n                    \r\n                    if (AND(STATE.emplacementPageWeb, AND(STATE.startDate, STATE.endDate))) {\r\n                        const debut = $.datepicker.formatDate('yy-mm-dd', STATE.startDate);\r\n                        const fin = $.datepicker.formatDate('yy-mm-dd', STATE.endDate);\r\n                        \r\n                        verifierDisponibilite(STATE.emplacementPageWeb, debut, fin)\r\n                            .then(result => {\r\n                                if (!result.available) {\r\n                                    afficherIndisponibilite(result.next_available);\r\n                                } else {\r\n                                    masquerIndisponibilite();\r\n                                }\r\n                            });\r\n                    }\r\n                    \r\n                    verifierAffichageMsgSelectEspace();\r\n        \r\n                    console.log('\u2705 Date fin s\u00e9lectionn\u00e9e:', dateText);\r\n                    \r\n                    setTimeout(function() {\r\n                        $.datepicker._hideDatepicker();\r\n                        $dateFin.blur();\r\n                        $('#ui-datepicker-div').hide();\r\n                    }, 50);\r\n                },\r\n                onClose: function() {\r\n                    $(this).blur();\r\n                }\r\n            });\r\n\r\n            $dateDebut.on('change', function() {\r\n                if (!this.value) {\r\n                    STATE.startDate = null;\r\n                    $dateFin.datepicker('option', 'minDate', minDate);\r\n                    calculateDuration();\r\n                } else {\r\n                    synchroniserDateAvecPanier('dateDebut', this.value);\r\n                }\r\n            });\r\n\r\n            $dateFin.on('change', function() {\r\n                if (!this.value) {\r\n                    STATE.endDate = null;\r\n                    calculateDuration();\r\n                } else {\r\n                    synchroniserDateAvecPanier('dateFin', this.value);\r\n                }\r\n            });\r\n\r\n            console.log('\u2705 Datepickers configur\u00e9s avec synchronisation');\r\n        }\r\n\r\n        function synchroniserDateAvecPanier(cle, valeur) {\r\n            if (AND(window.VIA_Panier, typeof window.VIA_Panier.synchroniserDonnee === 'function')) {\r\n                window.VIA_Panier.synchroniserDonnee(cle, valeur);\r\n                console.log(`\ud83d\udcc5 Date synchronis\u00e9e avec panier: ${cle} = ${valeur}`);\r\n                \r\n                if (AND(cle === 'dateFin', AND(STATE.startDate, STATE.endDate))) {\r\n                    const duree = calculateDuration();\r\n                    if (duree > 0) {\r\n                        window.VIA_Panier.synchroniserDonnee('duree', duree);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        \/\/ pb603 : DUREE MINIMALE DE CAMPAGNE = 7 jours.\r\n        \/\/   Le message est affiche dans #MsgDatesText, qui vit dans le conteneur\r\n        \/\/   #IndisponibilitesMsg \u2014 conteneur PARTAGE avec le message d'indisponibilite\r\n        \/\/   (#IndisponibilitesMsgText, pilote par afficher\/masquerIndisponibilite).\r\n        \/\/   On ne touche donc QUE #MsgDatesText, et on memorise son texte d'origine pour\r\n        \/\/   pouvoir le restaurer : sans cela, le message d'indisponibilite perdrait sa\r\n        \/\/   premiere ligne des qu'une duree courte aurait ete saisie une fois.\r\n        \/\/   Knob : window._viaDureeMin603 (defaut 7 ; 0 pour desactiver la regle).\r\n        \/\/ pb610 : bornes parametrables (Espace Via Agency) via via_parametres_proxy.\r\n        \/\/   Cascade dans _verifierDureeMin603 : knob -> valeur chargee -> defaut.\r\n        (function _viaChargeParams610F() {\r\n            if (window._viaParams610 ? true : window._viaParams610Pending) { return; }\r\n            window._viaParams610Pending = true;\r\n            var _u = new URLSearchParams();\r\n            _u.append('action', 'via_parametres_proxy');\r\n            fetch('https:\/\/yearbook-media.com\/wp-admin\/admin-ajax.php', {\r\n                method: 'POST', credentials: 'omit',\r\n                headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n                body: _u.toString()\r\n            }).then(function(r) { return r.json(); }).then(function(d) {\r\n                window._viaParams610Pending = false;\r\n                if (d ? (d.success ? true : false) : false) {\r\n                    window._viaParams610 = { min: parseInt(d.duree_min, 10), max: parseInt(d.duree_max, 10) };\r\n                    console.log('[pb610] bornes duree chargees:', window._viaParams610.min, '-', window._viaParams610.max, d.fallback ? '(fallback)' : '');\r\n                }\r\n            }).catch(function(e) {\r\n                window._viaParams610Pending = false;\r\n                console.warn('[pb610] bornes duree non chargees:', e.message);\r\n            });\r\n        })();\r\n\r\n        \/\/ pb610 : les knobs _viaDureeMin603 \/ _viaDureeMax609 ne sont PLUS auto-\r\n        \/\/   initialises : s'ils restent undefined, les gardes lisent la valeur\r\n        \/\/   chargee (_viaParams610) puis le defaut en dur. Les definir manuellement\r\n        \/\/   (console\/config) reste possible et prioritaire.\r\n\r\n        window._viaDureeInvalide603 = false;\r\n\r\n        function _verifierDureeMin603(nbJours) {\r\n            var _min603 = (typeof window._viaDureeMin603 === 'number') ? window._viaDureeMin603\r\n                : (window._viaParams610 ? window._viaParams610.min : 7);\r\n            if (_min603 > 0 ? false : true) { return; }\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1143 : POSER LE DRAPEAU AVANT de chercher le conteneur du message.\r\n            \/\/   Constat user : la regle des 7 jours n'est pas appliquee dans le\r\n            \/\/   PROCESS d'achat. Cause : la garde ci-dessous \u2014 #MsgDatesText\r\n            \/\/   n'existe que dans l'achat express, la fonction sortait donc\r\n            \/\/   immediatement dans le process, sans message ET sans poser\r\n            \/\/   window._viaDureeInvalide603.\r\n            \/\/   Or ce drapeau est ce qui fait respecter la regle ailleurs (blocage\r\n            \/\/   de la commande, et desormais completion de l'etape Dates via\r\n            \/\/   pb1142). Il doit donc etre pose dans TOUS les contextes ; seul\r\n            \/\/   l'AFFICHAGE du message depend de la presence du conteneur.\r\n            \/\/   Revert : window._viaPb1143Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1143Off !== true) {\r\n                var _max1143 = (typeof window._viaDureeMax609 === 'number') ? window._viaDureeMax609\r\n                    : (window._viaParams610 ? window._viaParams610.max : 200);\r\n                var _court1143 = (nbJours > 0) ? (nbJours < _min603) : false;\r\n                var _long1143 = (_max1143 > 0) ? ((nbJours > 0) ? (nbJours > _max1143) : false) : false;\r\n                window._viaDureeInvalide603 = _court1143 ? true : _long1143;\r\n                if (_court1143 ? true : _long1143) {\r\n                    console.log('[pb1143] dur\u00e9e ' + nbJours + ' j hors bornes ['\r\n                        + _min603 + '-' + _max1143 + '] -> \u00e9tape Dates non valid\u00e9e');\r\n                }\r\n            }\r\n\r\n            var $txt603 = $('#MsgDatesText');\r\n            if ($txt603.length === 0) { return; }\r\n            var $box603 = $txt603.find('.elementor-widget-container');\r\n            if ($box603.length === 0) { $box603 = $txt603; }\r\n\r\n            \/\/ memoriser le texte d'origine UNE SEULE FOIS\r\n            if (typeof $txt603.data('orig603') === 'undefined') {\r\n                $txt603.data('orig603', $box603.html());\r\n            }\r\n\r\n            var _max609 = (typeof window._viaDureeMax609 === 'number') ? window._viaDureeMax609\r\n                : (window._viaParams610 ? window._viaParams610.max : 200);\r\n            var _tropCourt603 = (nbJours > 0) ? (nbJours < _min603) : false;\r\n            var _tropLong609 = (_max609 > 0) ? ((nbJours > 0) ? (nbJours > _max609) : false) : false;\r\n            window._viaDureeInvalide603 = _tropCourt603 ? true : _tropLong609;\r\n\r\n            if (_tropCourt603 ? true : _tropLong609) {\r\n                var lang603 = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                var msg603;\r\n                if (_tropCourt603) {\r\n                    msg603 = (lang603 === 'EN')\r\n                        ? '<p style=\"text-align: center;\">The minimum campaign duration is ' + _min603 + ' days<\/p>'\r\n                        : '<p style=\"text-align: center;\">La dur\u00e9e minimale d\\'une campagne est de ' + _min603 + ' jours<\/p>';\r\n                } else {\r\n                    msg603 = (lang603 === 'EN')\r\n                        ? '<p style=\"text-align: center;\">The maximum campaign duration is ' + _max609 + ' days<\/p>'\r\n                        : '<p style=\"text-align: center;\">La dur\u00e9e maximale d\\'une campagne est de ' + _max609 + ' jours<\/p>';\r\n                }\r\n                $box603.html(msg603);\r\n                $('#IndisponibilitesMsg').show();\r\n                console.log('[pb603] duree ' + nbJours + ' j hors bornes [' + _min603 + '-' + _max609 + '] -> message affiche');\r\n            } else {\r\n                \/\/ restaurer le texte d'origine (le conteneur peut rester visible pour\r\n                \/\/ l'indisponibilite : c'est masquerIndisponibilite qui decide de le cacher)\r\n                $box603.html($txt603.data('orig603'));\r\n            }\r\n        }\r\n\r\n        \/\/ ================================================================\r\n        \/\/ pb2119 : COULEURS des dates et de la duree dans le process classique\r\n        \/\/   (demande user).\r\n        \/\/   - duree < min (ou > max, meme drapeau _viaDureeInvalide603) :\r\n        \/\/     duree .CampagneNbJours en ROUGE #fb5e2a, dates couleur de base ;\r\n        \/\/   - dates + duree valides : date debut, date fin et duree en VERT\r\n        \/\/     #56be50 ;\r\n        \/\/   - pas de dates : retour couleur de base partout.\r\n        \/\/   Portee : la duree du FORMULAIRE seulement \u2014 les items du panier\r\n        \/\/   portent la meme classe .CampagneNbJours, on scope donc sur\r\n        \/\/   .ProcessDatesDeviseConteneurClass (repli global si absent, comme\r\n        \/\/   les ecrivains existants). Base inline memorisee UNE FOIS dans\r\n        \/\/   data-via-col2119 (regle : jamais d'offset sans base gelee).\r\n        \/\/   Appelants : calculateDuration (portee fichier, pas de classe \u2014\r\n        \/\/   verifie, regle pb2114d). Revert : window._viaPb2119Off = true.\r\n        \/\/ ================================================================\r\n        function _viaColorerDatesProcess2119(nbJours) {\r\n            if (window._viaPb2119Off === true) { return; }\r\n            var _rouge2119 = '#fb5e2a';\r\n            var _vert2119 = '#56be50';\r\n            var $dur2119 = $('.ProcessDatesDeviseConteneurClass .CampagneNbJours');\r\n            if ($dur2119.length === 0) { $dur2119 = $(CONFIG.FIELDS.dureeContainer); }\r\n            var _cibles2119 = [\r\n                document.getElementById(CONFIG.FIELDS.dateDebut),\r\n                document.getElementById(CONFIG.FIELDS.dateFin)\r\n            ];\r\n            $dur2119.each(function () { _cibles2119.push(this); });\r\n            var _valide2119 = false;\r\n            if (nbJours > 0) {\r\n                if (window._viaDureeInvalide603 !== true) { _valide2119 = true; }\r\n            }\r\n            var _etat2119 = 'base';\r\n            if (_valide2119) { _etat2119 = 'vert'; }\r\n            else if (nbJours > 0) { _etat2119 = 'rouge'; }\r\n            \/\/ pb2119b : DRAPEAU lu par l'ecrivain GAGNANT des inputs dates,\r\n            \/\/   _viaUpdateDatesColors (yearbook-media.js, v4.9ds Pb 6) \u2014 il\r\n            \/\/   repeint #4B689B !important a chaque input\/change ET par\r\n            \/\/   interval 800ms : toute couleur posee ici serait ecrasee\r\n            \/\/   (constat HTML JF : data-via-col2119 pose, bleu revenu).\r\n            \/\/   Regle : corriger au gagnant, pas ecrire par-dessus (pb2117c).\r\n            window._viaDatesVertes2119 = (_etat2119 === 'vert');\r\n            var _n2119 = 0;\r\n            _cibles2119.forEach(function (_el) {\r\n                if (!_el) { return; }\r\n                if (typeof _el.dataset.viaCol2119 === 'undefined') {\r\n                    _el.dataset.viaCol2119 = _el.style.color || '';\r\n                }\r\n                var _estDuree = _el.classList.contains('CampagneNbJours');\r\n                if (_etat2119 === 'vert') {\r\n                    _el.style.setProperty('color', _vert2119, 'important');\r\n                } else if (_etat2119 === 'rouge') {\r\n                    if (_estDuree) { _el.style.setProperty('color', _rouge2119, 'important'); }\r\n                    else { _restaurer2119(_el); }\r\n                } else {\r\n                    _restaurer2119(_el);\r\n                }\r\n                _n2119 = _n2119 + 1;\r\n            });\r\n            console.log('[pb2119] etat=' + _etat2119 + ' | nbJours=' + nbJours\r\n                + ' | invalide603=' + (window._viaDureeInvalide603 === true)\r\n                + ' | cibles=' + _n2119);\r\n            function _restaurer2119(_el) {\r\n                var _base = _el.dataset.viaCol2119;\r\n                if (_base) { _el.style.setProperty('color', _base, 'important'); }\r\n                else { _el.style.removeProperty('color'); }\r\n            }\r\n        }\r\n\r\n        window.calculateDuration = function() {\r\n            const $dureeContainer = $(CONFIG.FIELDS.dureeContainer);\r\n            const $dateDebut = $('#' + CONFIG.FIELDS.dateDebut);\r\n            const $dateFin = $('#' + CONFIG.FIELDS.dateFin);\r\n\r\n            if (!STATE.startDate || !STATE.endDate) {\r\n                $dureeContainer.text('');\r\n                try { _viaColorerDatesProcess2119(0); } catch (_e2119) { console.warn('[pb2119]', _e2119.message); }\r\n                return 0;\r\n            }\r\n\r\n            const diffTime = STATE.endDate - STATE.startDate;\r\n            let diffDays = Math.ceil(diffTime \/ (1000 * 60 * 60 * 24));\r\n\r\n            if (diffDays <= 0) {\r\n                console.log('\u26a0\ufe0f Dur\u00e9e n\u00e9gative ou nulle d\u00e9tect\u00e9e:', diffDays, '- correction en cours...');\r\n                \r\n                const nouvelleDateFin = new Date(STATE.startDate);\r\n                nouvelleDateFin.setDate(nouvelleDateFin.getDate() + 1);\r\n                \r\n                STATE.endDate = nouvelleDateFin;\r\n                \r\n                const jour = String(nouvelleDateFin.getDate()).padStart(2, '0');\r\n                const mois = String(nouvelleDateFin.getMonth() + 1).padStart(2, '0');\r\n                const annee = nouvelleDateFin.getFullYear();\r\n                const nouvelleDateFinStr = jour + '\/' + mois + '\/' + annee;\r\n                \r\n                $dateFin.val(nouvelleDateFinStr);\r\n                \r\n                if (typeof $.fn.datepicker !== 'undefined') {\r\n                    try {\r\n                        $dateFin.datepicker('setDate', nouvelleDateFin);\r\n                    } catch(e) {\r\n                        console.warn('Erreur datepicker:', e);\r\n                    }\r\n                }\r\n                \r\n                if (window.VIA_Panier) {\r\n                    if (typeof window.VIA_Panier.synchroniserDonnee === 'function') {\r\n                        window.VIA_Panier.synchroniserDonnee('dateFin', nouvelleDateFinStr);\r\n                        window.VIA_Panier.synchroniserDonnee('duree', 1);\r\n                    }\r\n                }\r\n                \r\n                diffDays = 1;\r\n                \r\n                console.log('\u2705 Date fin corrig\u00e9e automatiquement:', nouvelleDateFinStr);\r\n            }\r\n\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const durationText = diffDays === 1 \r\n                ? (lang === 'EN' ? '1 day' : '1 jour')\r\n                : (lang === 'EN' ? diffDays + ' days' : diffDays + ' jours');\r\n            \r\n            $dureeContainer.text(durationText);\r\n\r\n            console.log('\u2705 Dur\u00e9e calcul\u00e9e:', durationText);\r\n\r\n            _verifierDureeMin603(diffDays);   \/\/ pb603 : regle de duree minimale\r\n\r\n            \/\/ pb2119 : couleurs dates\/duree, APRES la pose du drapeau 603\/1143.\r\n            try { _viaColorerDatesProcess2119(diffDays); } catch (_e2119b) { console.warn('[pb2119]', _e2119b.message); }\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1138 : DUREE HORS BORNES -> MESSAGE D'ALERTE, PAS DE RECALAGE\r\n            \/\/   (demande user : \"afficher un message d'alerte comme dans l'achat\r\n            \/\/   express\").\r\n            \/\/   La version precedente recalait la date de fin. Deux raisons de\r\n            \/\/   l'abandonner :\r\n            \/\/     - le log montrait que le handler du datepicker reposait ensuite la\r\n            \/\/       date choisie par l'utilisateur (07\/09 recale, puis 03\/09 reecrit),\r\n            \/\/       laissant une duree de 7 jours en face d'une date au 03\/09 \u2014\r\n            \/\/       incoherent, et pire que l'etat d'origine ;\r\n            \/\/     - corriger la saisie sans le dire est plus deroutant que la signaler.\r\n            \/\/   _verifierDureeMin603, appele juste au-dessus, affiche DEJA le message\r\n            \/\/   \u2014 le meme que celui de l'achat express \u2014 et pose\r\n            \/\/   window._viaDureeInvalide603, qui bloque la commande. Il n'y avait donc\r\n            \/\/   rien a ajouter : il suffisait de ne pas recaler par-dessus.\r\n            \/\/ ================================================================\r\n\r\n            return diffDays;\r\n        };\r\n\r\n        function setupCountryAutocomplete() {\r\n            const $paysInput = $('#' + CONFIG.FIELDS.pays);\r\n        \r\n            if ($paysInput.length === 0) {\r\n                console.warn('\u26a0\ufe0f Champ pays introuvable');\r\n                return;\r\n            }\r\n        \r\n            if (typeof window.VIA_Countries === 'undefined') {\r\n                console.error('\u274c Configuration pays non charg\u00e9e');\r\n                return;\r\n            }\r\n        \r\n            \/\/ \u2705 v2.5 : Ne pas pr\u00e9-remplir le pays \u2014 l'utilisateur saisit lui-m\u00eame\r\n        \r\n            $paysInput.autocomplete({\r\n                source: function(request, response) {\r\n                    const term = request.term.trim();\r\n                    \r\n                    \/\/ pb789 : liste ouverte des la 1re lettre (etait 2), comme pb787\r\n                    \/\/   sur le champ du popup Tarifs.\r\n                    if (term.length < 1) {\r\n                        response([]);\r\n                        return;\r\n                    }\r\n                    \r\n                    \/\/ \u2705 v2.0 : Utiliser searchCountries() si disponible, sinon fallback\r\n                    \/\/ pb789 : meme traitement qu'en pb787\/pb787b sur le popup Tarifs.\r\n                    \/\/   searchCountries applique son propre minimum et ne rend rien a une\r\n                    \/\/   seule lettre -> repli sur le filtre local (celui du fallback\r\n                    \/\/   d'origine, deja eprouve). searchCountries n'est PAS modifiee :\r\n                    \/\/   elle est partagee par les deux champs.\r\n                    \/\/   Revert : window._viaPb789Off = true.\r\n                    let results;\r\n                    var _filtreLocal789 = function() {\r\n                        var _tl789 = term.toLowerCase();\r\n                        return (window.VIA_Countries.COUNTRIES_DATA || []).filter(function(country) {\r\n                            return String(country.label || '').toLowerCase().includes(_tl789);\r\n                        });\r\n                    };\r\n                    if (typeof window.VIA_Countries.searchCountries === 'function') {\r\n                        results = window.VIA_Countries.searchCountries(term) || [];\r\n                        if (results.length === 0 ? (window._viaPb789Off !== true) : false) {\r\n                            results = _filtreLocal789();\r\n                            console.log('[pb789] searchCountries vide pour \"' + term\r\n                                + '\" -> repli filtre local : ' + results.length + ' pays');\r\n                        }\r\n                    } else {\r\n                        results = _filtreLocal789();\r\n                    }\r\n                    \/\/ pb789 : les pays COMMENCANT par la saisie d'abord, les autres apres.\r\n                    \/\/   Tri AVANT le slice(0,10) : un prefixe classe au-dela du 10e rang\r\n                    \/\/   serait sinon perdu avant d'etre remonte.\r\n                    if (window._viaPb789Off !== true) {\r\n                        var _norm789 = function(s) {\r\n                            var _t = String(s || '');\r\n                            return _t.normalize ? _t.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase()\r\n                                                : _t.toLowerCase();\r\n                        };\r\n                        var _q789 = _norm789(term);\r\n                        var _pre789 = [], _aut789 = [];\r\n                        results.forEach(function(_c789) {\r\n                            if (_norm789(_c789.label).indexOf(_q789) === 0) { _pre789.push(_c789); }\r\n                            else { _aut789.push(_c789); }\r\n                        });\r\n                        results = _pre789.concat(_aut789);\r\n                        console.log('[pb789] \"' + term + '\" -> ' + _pre789.length + ' par prefixe + '\r\n                            + _aut789.length + ' autres');\r\n                    }\r\n                    \r\n                    if (results.length === 1) {\r\n                        setTimeout(() => {\r\n                            STATE.selectedCountry = results[0];\r\n                            $paysInput.val(results[0].label);\r\n                            $paysInput.prop('readonly', true);\r\n                            $paysInput.blur();\r\n                            \r\n                            setTimeout(() => {\r\n                                $paysInput.prop('readonly', false);\r\n                            }, 500);\r\n                            \r\n                            _fond789(false);   \/\/ pb789 : pays choisi -> fond de saisie retire\r\n                    $paysInput.addClass('country-selected').css('background-color', '#E8F0FE');\r\n                            setTimeout(() => {\r\n                                $paysInput.removeClass('country-selected').css('background-color', '');\r\n                            }, 1000);\r\n                            \r\n                            synchroniserPaysGlobal(results[0].label);\r\n                            \r\n                            console.log('\u2705 Pays auto-s\u00e9lectionn\u00e9:', results[0].label);\r\n                        }, 150);\r\n                        \r\n                        response([]);\r\n                        return;\r\n                    }\r\n                    \r\n                    response(results.slice(0, 10));\r\n                },\r\n                minLength: 1,   \/\/ pb789 (etait 2)\r\n                delay: 300,\r\n                appendTo: 'body',\r\n                select: function(event, ui) {\r\n                    \/\/ \u2705 v1.8 : Bloquer si bon de commande cr\u00e9\u00e9\r\n                    if (window.VIA_Panier && window.VIA_Panier.verifierBonCommandeCreeLock()) {\r\n                        \/\/ R\u00e9initialiser le pays\r\n                        if (STATE.selectedCountry) {\r\n                            $paysInput.val(STATE.selectedCountry.label);\r\n                        } else {\r\n                            $paysInput.val('');\r\n                        }\r\n                        return false;\r\n                    }\r\n                    \r\n                    STATE.selectedCountry = ui.item;\r\n        \r\n                    _fond789(false);   \/\/ pb789 : pays choisi -> fond de saisie retire\r\n                    $paysInput.addClass('country-selected').css('background-color', '#E8F0FE');\r\n                    setTimeout(() => {\r\n                        $paysInput.removeClass('country-selected').css('background-color', '');\r\n                    }, 1000);\r\n        \r\n                    synchroniserPaysGlobal(ui.item.label);\r\n        \r\n                    console.log('\u2705 Pays s\u00e9lectionn\u00e9:', ui.item.label);\r\n        \r\n                    return false;\r\n                },\r\n                focus: function(event, ui) {\r\n                    return false;\r\n                },\r\n                \/\/ pb791 : a chaque ouverture, le menu est place au-dessus des popups.\r\n                open: function() {\r\n                    try {\r\n                        var _menu791 = $paysInput.autocomplete('widget')[0];\r\n                        if (!_menu791) { console.warn('[pb791] widget introuvable'); return; }\r\n                        \/\/ ================================================================\r\n                        \/\/ pb791 : le menu s'affiche SOUS le popup Process. Il est ajoute au\r\n                        \/\/   body (appendTo:'body') tandis que les popups sont en\r\n                        \/\/   position:fixed avec leur propre z-index \u2014 le menu passe dessous.\r\n                        \/\/   Je NE re-parente PAS le menu dans le popup : celui-ci a un\r\n                        \/\/   overflow et un transform, qui le rogneraient et fausseraient son\r\n                        \/\/   positionnement. Menu et popups sont freres dans le contexte\r\n                        \/\/   d'empilement racine : il suffit donc que le menu ait un z-index\r\n                        \/\/   superieur.\r\n                        \/\/   Valeur CALCULEE a l'ouverture sur les popups reellement affiches,\r\n                        \/\/   jamais codee en dur : les z-index des VLP bougent au bring-to-front\r\n                        \/\/   (pb45), une constante serait depassee au premier clic.\r\n                        \/\/   Revert : window._viaPb791Off = true.\r\n                        \/\/ ================================================================\r\n                        if (window._viaPb791Off !== true) {\r\n                            var _max791 = 0;\r\n                            \/* pb2131 : les colonnes du layout 3 colonnes ([id^=\"via-col-\"],\r\n                               dont #via-col-ColonneDroite) rejoignent les candidats \u2014 la\r\n                               liste passait sous elles (constat JF, autocomplete client). *\/\r\n                            var _cands791 = document.querySelectorAll('.via-link-popup, #popup3, .elementor-popup-modal, [id^=\"via-col-\"]');\r\n                            for (var _i791 = 0; _i791 < _cands791.length; _i791++) {\r\n                                var _e791 = _cands791[_i791];\r\n                                if (_e791.getBoundingClientRect().height < 5) { continue; }   \/\/ ferme\r\n                                var _z791 = parseInt(getComputedStyle(_e791).zIndex, 10);\r\n                                if (_z791 > _max791) { _max791 = _z791; }\r\n                            }\r\n                            var _cible791 = (_max791 > 0) ? (_max791 + 10) : 9999;\r\n                            _menu791.style.setProperty('z-index', String(_cible791), 'important');\r\n                            if (window._viaSigZ791 !== _cible791) {\r\n                                window._viaSigZ791 = _cible791;\r\n                                console.log('[pb791] z-index du menu -> ' + _cible791\r\n                                    + ' (max des popups affiches : ' + _max791 + ')');\r\n                            }\r\n                        }\r\n                    } catch (_e791) { console.warn('[pb791] open:', _e791.message); }\r\n                }\r\n            });\r\n        \r\n            \/\/ ================================================================\r\n            \/\/ pb789 : fond #ddeeff pendant la saisie (pb788 applique a ce champ).\r\n            \/\/   Pose au focus, maintenu a chaque frappe, retire a la selection et au\r\n            \/\/   blur. Couleur d'origine memorisee puis restauree : pas de\r\n            \/\/   removeProperty, qui rendrait la main aux valeurs Elementor (pb668).\r\n            \/\/   NB : ce champ a DEJA un flash #E8F0FE de 1 s a la selection (v1.8).\r\n            \/\/   Il est conserve tel quel ; notre restauration est appelee AVANT, donc\r\n            \/\/   le flash reste le dernier a ecrire et reste visible.\r\n            \/\/   Revert : window._viaPb789Off = true.\r\n            \/\/ ================================================================\r\n            var _fond789 = function(actif) {\r\n                if (window._viaPb789Off === true) { return; }\r\n                try {\r\n                    var _el789 = $paysInput[0];\r\n                    if (!_el789) { return; }\r\n                    if (!_el789.dataset.bg789) {\r\n                        _el789.dataset.bg789 = getComputedStyle(_el789).backgroundColor || 'transparent';\r\n                    }\r\n                    _el789.style.setProperty('background-color',\r\n                        actif ? '#ddeeff' : _el789.dataset.bg789, 'important');\r\n                    if (window._viaSigFond789 !== actif) {\r\n                        window._viaSigFond789 = actif;\r\n                        console.log('[pb789] fond champ annonceur (process) -> '\r\n                            + (actif ? '#ddeeff (saisie)' : 'origine'));\r\n                    }\r\n                } catch (_e789) { console.warn('[pb789]', _e789.message); }\r\n            };\r\n            $paysInput.on('focus', function() { _fond789(true); });\r\n            $paysInput.on('input', function() { _fond789(true); });\r\n\r\n            $paysInput.on('blur', function() {\r\n                _fond789(false);   \/\/ pb789\r\n                setTimeout(() => {\r\n                    if (!STATE.isUpdatingPays) {\r\n                        const value = $(this).val().trim();\r\n                        \r\n                        if (value.length === 0) {\r\n                            STATE.selectedCountry = null;\r\n                            return;\r\n                        }\r\n                        \r\n                        const country = window.VIA_Countries.getCountryByLabel(value);\r\n                        \r\n                        if (country) {\r\n                            STATE.selectedCountry = country;\r\n                            $(this).val(country.label);\r\n                            \r\n                            synchroniserPaysGlobal(country.label);\r\n                            \r\n                            console.log('\u2705 Pays valid\u00e9 par blur:', country.label);\r\n                        } else if (!STATE.selectedCountry) {\r\n                            console.log('\u23f3 Saisie en cours, pas de validation');\r\n                        }\r\n                    }\r\n                }, 200);\r\n            });\r\n        \r\n            $paysInput.on('focus', function() {\r\n                $(this).select();\r\n            });\r\n        \r\n            console.log('\u2705 Autocomplete pays configur\u00e9 (config centralis\u00e9e)');\r\n        }\r\n\r\n        \/\/ \u2705 v4.9ds Pb 1 : helper expos\u00e9 pour permettre \u00e0 Panier_manager (lors d'un switch\r\n        \/\/   d'item via remplirFormulaireDepuisItem) de re-poser STATE.selectedCountry \u00e0\r\n        \/\/   partir d'un label (ex: \"France\"). Sans \u00e7a, reinitialiserDatesFormulaire pose\r\n        \/\/   STATE.selectedCountry=null, et le simple .val() sur #form-field-Nationalite_Societe\r\n        \/\/   ne suffit pas \u2014 triggerTarifCalculation refuse de calculer (\"En attente de la\r\n        \/\/   s\u00e9lection du pays\") car STATE.selectedCountry reste null.\r\n        \/\/   Ce helper r\u00e9utilise la fonction VIA_Countries.getCountryByLabel pour mapper\r\n        \/\/   le label vers l'objet {label, code, ...} attendu par STATE.selectedCountry.\r\n        window.viaSetSelectedCountry = function(label) {\r\n            try {\r\n                if (!label) {\r\n                    STATE.selectedCountry = null;\r\n                    return false;\r\n                }\r\n                if (window.VIA_Countries ? typeof window.VIA_Countries.getCountryByLabel === 'function' : false) {\r\n                    var _country = window.VIA_Countries.getCountryByLabel(label);\r\n                    if (_country) {\r\n                        STATE.selectedCountry = _country;\r\n                        console.log('\u2705 [viaSetSelectedCountry] STATE.selectedCountry pos\u00e9:', _country.label, '(' + _country.code + ')');\r\n                        \/\/ ============================================================\r\n                        \/\/ pb2175 : LA ZONE TVA SUIT LE PAYS, QUEL QUE SOIT LE CHEMIN.\r\n                        \/\/   Constat JF : par le process classique l'info remonte ;\r\n                        \/\/   par le popup tarifs, non \u2014 \u00ab Donnees TVA: {zoneTVA: null} \u00bb\r\n                        \/\/   pour un annonceur Fidji, puis le regime francais par\r\n                        \/\/   defaut et le forcage EUR.\r\n                        \/\/   Cause : ZoneTVA n'a qu'un ecrivain, appliquerLogiqueTVA\r\n                        \/\/   (References.txt l.984), atteint par l'API publique\r\n                        \/\/   VIA_References.mettreAJourLogiqueTVA. Le process classique\r\n                        \/\/   l'appelle (Panier_manage l.11678, au changement du champ\r\n                        \/\/   pays de l'etape 1) ; ce chemin-ci resolvait le pays sans\r\n                        \/\/   jamais la joindre. Le log s'arretait exactement ici.\r\n                        \/\/   On appelle donc LA MEME fonction \u2014 pas une regle\r\n                        \/\/   dupliquee : la table pays -> zone reste unique, et le\r\n                        \/\/   comportement du popup devient celui du process classique.\r\n                        \/\/   Garde de disponibilite : References peut ne pas etre\r\n                        \/\/   charge dans tous les contextes ; l'absence est\r\n                        \/\/   journalisee plutot que subie (regle 5.2).\r\n                        \/\/   Revert : window._viaPb2175Off = true.\r\n                        \/\/ ============================================================\r\n                        if (window._viaPb2175Off !== true) {\r\n                            try {\r\n                                var _api2175 = window.VIA_References;\r\n                                if (_api2175 ? (typeof _api2175.mettreAJourLogiqueTVA === 'function') : false) {\r\n                                    _api2175.mettreAJourLogiqueTVA(_country.label);\r\n                                    console.log('[pb2175] logique TVA declenchee pour ' + _country.label\r\n                                        + ' | ZoneTVA en session = '\r\n                                        + (sessionStorage.getItem('ZoneTVA') || '(toujours vide)'));\r\n                                } else {\r\n                                    console.warn('[pb2175] VIA_References.mettreAJourLogiqueTVA indisponible'\r\n                                        + ' | VIA_References=' + (_api2175 ? 'present' : 'ABSENT')\r\n                                        + ' | pays=' + _country.label\r\n                                        + ' | ZoneTVA du pays=' + (_country.ZoneTVA || '(non renseignee)'));\r\n                                }\r\n                            } catch (_e2175) { console.warn('[pb2175] ' + _e2175.message); }\r\n                        }\r\n                        return true;\r\n                    }\r\n                    console.log('\u26a0\ufe0f [viaSetSelectedCountry] pays non trouv\u00e9:', label);\r\n                }\r\n            } catch(_e) { console.warn('[viaSetSelectedCountry] erreur:', _e); }\r\n            return false;\r\n        };\r\n        \r\n        async function synchroniserPaysGlobal(pays) {\r\n            console.log('\ud83c\udf0d Synchronisation pays global:', pays);\r\n            \r\n            if (AND(window.VIA_Panier, typeof window.VIA_Panier.mettreAJourPaysGlobal === 'function')) {\r\n                await window.VIA_Panier.mettreAJourPaysGlobal(pays);\r\n            }\r\n            \r\n            $('#' + CONFIG.FIELDS.pays).val(pays);\r\n            \r\n            triggerTarifCalculation();\r\n            \r\n            synchroniserPaysAvecPanier(pays);\r\n        }\r\n\r\n        function synchroniserPaysAvecPanier(pays) {\r\n            if (AND(window.VIA_Panier, typeof window.VIA_Panier.synchroniserDonnee === 'function')) {\r\n                STATE.isUpdatingPays = true;\r\n                window.VIA_Panier.synchroniserDonnee('pays', pays);\r\n                console.log(`\ud83c\udf0d Pays synchronis\u00e9 avec panier: ${pays}`);\r\n                setTimeout(() => {\r\n                    STATE.isUpdatingPays = false;\r\n                }, 300);\r\n            }\r\n        }\r\n        \r\n        function verifierAffichageMsgSelectEspace() {\r\n            console.log('\ud83d\udd0d V\u00e9rification affichage MsgSelectEspace...');\r\n            \r\n            if ($('#IndisponibilitesMsg').is(':visible')) {\r\n                console.log('\ud83d\udeab Espace indisponible - pas d\\'affichage du message');\r\n                $('#MsgSelectEspace').hide();\r\n                return;\r\n            }\r\n            \r\n            const tarifActuel = $('#Tariftobedisplayed').text();\r\n            if (AND(tarifActuel, AND(tarifActuel !== '-', tarifActuel !== ''))) {\r\n                console.log('\ud83d\udcb0 Tarif existant d\u00e9tect\u00e9:', tarifActuel, '- pas d\\'affichage du message');\r\n                $('#MsgSelectEspace').hide();\r\n                return;\r\n            }\r\n            \r\n            const dateDebut = $('#form-field-DebutCampagne').val();\r\n            const dateFin = $('#form-field-FinCampagne').val();\r\n            const pays = $('#form-field-Nationalite_Societe').val();\r\n            \r\n            console.log('\ud83d\udcc5 Dates et pays:', { dateDebut, dateFin, pays });\r\n            \r\n            if (!dateDebut || !dateFin || !pays) {\r\n                console.log('\u274c Donn\u00e9es manquantes, masquage du message');\r\n                $('#MsgSelectEspace').hide();\r\n                return;\r\n            }\r\n            \r\n            const fileReceived = sessionStorage.getItem('FileReceived');\r\n            const envoiUlterieur = sessionStorage.getItem('EnvoiUlterieur');\r\n            \r\n            console.log('\ud83d\udcc1 FileReceived:', fileReceived);\r\n            console.log('\ud83d\udce4 EnvoiUlterieur:', envoiUlterieur);\r\n            \r\n            if (fileReceived !== 'Yes') {\r\n                if (envoiUlterieur !== 'true') {\r\n                    console.log('\u2705 CONDITIONS REMPLIES - AFFICHAGE DU MESSAGE');\r\n                    $('#MsgSelectEspace').show();\r\n                } else {\r\n                    console.log('\ud83d\udce4 Envoi ult\u00e9rieur activ\u00e9, masquage du message');\r\n                    $('#MsgSelectEspace').hide();\r\n                }\r\n            } else {\r\n                console.log('\ud83d\udcc1 Fichier re\u00e7u, masquage du message');\r\n                $('#MsgSelectEspace').hide();\r\n            }\r\n        }\r\n\r\n        async function triggerTarifCalculation() {\r\n            console.log('\ud83d\udd04 Tentative de calcul du tarif...');\r\n            \r\n            checkEspacePubData();\r\n        \r\n            if (!STATE.espacePubSelected) {\r\n                console.log('\u23f3 En attente de la s\u00e9lection d\\'un espace publicitaire');\r\n                verifierAffichageMsgSelectEspace();\r\n                return;\r\n            }\r\n        \r\n            if (!STATE.startDate || !STATE.endDate) {\r\n                console.log('\u23f3 En attente de la s\u00e9lection des dates');\r\n                return;\r\n            }\r\n        \r\n            if (!STATE.selectedCountry) {\r\n                console.log('\u23f3 En attente de la s\u00e9lection du pays');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v1.7 : V\u00e9rifier que l'espace pub est s\u00e9lectionn\u00e9\r\n            if (!STATE.emplacementPageWeb) {\r\n                console.log('\u23f3 En attente de la s\u00e9lection de l\\'espace pub');\r\n                return;\r\n            }\r\n        \r\n            const duree = calculateDuration();\r\n            if (duree <= 0) {\r\n                console.log('\u26a0\ufe0f Dur\u00e9e invalide');\r\n                return;\r\n            }\r\n\r\n            \/\/ pb603 : REGLE BLOQUANTE \u2014 duree minimale de campagne.\r\n            \/\/   On calque exactement le traitement de l'indisponibilite (quelques lignes plus\r\n            \/\/   bas) : masquerTarif() + return. Pas de tarif calcule -> pas de commande\r\n            \/\/   possible, puisque tout le tunnel en depend. Le message reste affiche dans\r\n            \/\/   #MsgDatesText, pose par _verifierDureeMin603 via calculateDuration().\r\n            \/\/   masquerTarif() est indispensable : sans lui, un tarif VALIDE calcule avant\r\n            \/\/   la modification des dates resterait affiche et commandable.\r\n            if (window._viaDureeInvalide603) {\r\n                console.log('[pb603] duree < ' + window._viaDureeMin603 + ' j -> tarif masque, commande bloquee');\r\n                masquerTarif();\r\n                return;\r\n            }\r\n        \r\n            const dateDebut = $.datepicker.formatDate('yy-mm-dd', STATE.startDate);\r\n            const dateFin = $.datepicker.formatDate('yy-mm-dd', STATE.endDate);\r\n            \r\n            console.log('\ud83d\udd04 Lancement calcul parall\u00e8le (tarif + disponibilit\u00e9)...');\r\n        \r\n            \/* ============================================================\r\n             * pb1597 : UN APPEL QUI ECHOUE NE DOIT PAS EMPORTER L'AUTRE.\r\n             *   Constat user : l'espace etait indisponible sur les dates choisies, et\r\n             *   AUCUNE alerte n'est remontee \u2014 seul un \u00ab POST calculer-tarif 400 \u00bb dans\r\n             *   la console.\r\n             *   Promise.all rejette des que L'UN de ses appels rejette : le 400 du tarif\r\n             *   emportait donc la verification de disponibilite, et la ligne qui teste\r\n             *   \u00ab !dispo.available \u00bb n'etait jamais atteinte. L'utilisateur ne voyait ni\r\n             *   tarif ni explication.\r\n             *   Les deux appels sont pourtant independants : l'indisponibilite doit\r\n             *   s'afficher meme si le tarif echoue \u2014 c'est meme le cas ou elle est LA\r\n             *   PLUS utile, puisqu'elle explique l'absence de tarif.\r\n             *   Promise.allSettled ne rejette jamais : chaque resultat est traite pour\r\n             *   ce qu'il est. Le repli conserve le comportement d'origine \u2014\r\n             *   verifierDisponibilite rend deja { available: true } sur erreur (l.3011),\r\n             *   et un tarif absent est traite plus bas par \u00ab resultat.success \u00bb.\r\n             *   Revert : window._viaPb1597Off = true (Promise.all d'origine).\r\n             * ============================================================ *\/\r\n            let dispo, resultat;\r\n            if (window._viaPb1597Off === true) {\r\n                [dispo, resultat] = await Promise.all([\r\n                    verifierDisponibilite(STATE.emplacementPageWeb, dateDebut, dateFin),\r\n                    _proxyCalculerTarif(STATE.format, STATE.position, duree, STATE.selectedCountry.code)\r\n                ]);\r\n            } else {\r\n                const _r1597 = await Promise.allSettled([\r\n                    verifierDisponibilite(STATE.emplacementPageWeb, dateDebut, dateFin),\r\n                    _proxyCalculerTarif(STATE.format, STATE.position, duree, STATE.selectedCountry.code)\r\n                ]);\r\n                dispo = (_r1597[0].status === 'fulfilled') ? _r1597[0].value : { available: true };\r\n                resultat = (_r1597[1].status === 'fulfilled') ? _r1597[1].value : { success: false };\r\n                if (_r1597[0].status !== 'fulfilled') {\r\n                    console.warn('[pb1597] verification de disponibilite en echec : '\r\n                        + (_r1597[0].reason ? _r1597[0].reason.message : '?')\r\n                        + ' \u2014 on suppose disponible');\r\n                }\r\n                if (_r1597[1].status !== 'fulfilled') {\r\n                    console.warn('[pb1597] calcul du tarif en echec : '\r\n                        + (_r1597[1].reason ? _r1597[1].reason.message : '?')\r\n                        + ' \u2014 la disponibilite reste evaluee');\r\n                }\r\n            }\r\n            \r\n            if (!dispo.available) {\r\n                console.log('\u274c Espace indisponible, tarif masqu\u00e9'\r\n                    + ' | prochaine date : ' + (dispo.next_available || '(non fournie)'));\r\n                afficherIndisponibilite(dispo.next_available);\r\n                masquerTarif();\r\n                return;\r\n            }\r\n            \r\n            masquerIndisponibilite();\r\n            \r\n            if (resultat.success) {\r\n                \/\/ \u2705 v4.9ds Fix 22 (Pb 15) : ajouter itemId \u00e0 dernierResultatCalcul.\r\n                \/\/   Sans \u00e7a, sur nouvel item, synchroniserAvecPanier (T+200ms via setTimeout\r\n                \/\/   ligne 1727) copiait le tarif P\u00c9RIM\u00c9 du pr\u00e9c\u00e9dent calcul dans le nouvel\r\n                \/\/   item alors que le vrai calcul prenait ~1.5s. R\u00e9sultat : tarif visible\r\n                \/\/   dans la r\u00e9servation \u00e0 T+200ms (mais c'\u00e9tait l'ancien tarif), tarif\r\n                \/\/   visible dans #Tariftobedisplayed \u00e0 T+1.5s (le vrai). D\u00e9calage per\u00e7u.\r\n                \/\/   Avec itemId pos\u00e9, la condition resultAppartientAItem (Panier_manager:5019)\r\n                \/\/   bloque la copie du tarif p\u00e9rim\u00e9 \u2192 la r\u00e9servation reste vide jusqu'au\r\n                \/\/   vrai calcul, puis tarif apparait simultan\u00e9ment dans les 2 endroits.\r\n                var _itemActifFix22 = window.VIA_Panier ? window.VIA_Panier.state.itemActif : null;\r\n                window.VIA_App.state.dernierResultatCalcul = {\r\n                    tarif_ht: resultat.tarif_ht,\r\n                    tarif_ttc: resultat.tarif_ttc,\r\n                    itemId: _itemActifFix22\r\n                };\r\n                \r\n                afficherTarif(resultat, window.VIA_App.state.deviseActuelle);\r\n                synchroniserAvecPanier();\r\n            } else {\r\n                console.error('\u274c Erreur calcul:', resultat.message);\r\n                afficherErreurTarif(resultat.message);\r\n            }\r\n        }\r\n        \r\n        function masquerTarif() {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const labelTarif = lang === 'EN' ? 'Price excl. VAT' : 'Tarif H.T.';\r\n            \r\n            console.log('\ud83d\udd12 masquerTarif() appel\u00e9e');\r\n            \r\n            $(CONFIG.FIELDS.tarifDisplay).html('-').css('color', '');\r\n\r\n            if (AND(window.VIA_Panier, window.VIA_Panier.state.itemActif)) {\r\n                const item = window.VIA_Panier.state.items.find(i => i.id === window.VIA_Panier.state.itemActif);\r\n                if (item) {\r\n                    item.disponibilite = false;\r\n                    item.statut = 'indisponible';\r\n                    \/\/ \u2705 v1.8 : Remettre le tarif \u00e0 0 pour qu'il ne soit pas comptabilis\u00e9\r\n                    item.tarifHT = 0;\r\n                    \r\n                    const $item = $(`#${item.id}`);\r\n                    $item.find('.CampagneTarifClass').html(`${labelTarif} -`);\r\n                    \r\n                    window.VIA_Panier.rafraichirItemHTML(item.id);\r\n                }\r\n                \r\n                window.VIA_Panier.calculerTotalPanier();\r\n            } else {\r\n                $('#SyntheseConteneur').hide();\r\n            }\r\n            \r\n            setTimeout(() => {\r\n                verifierAffichageMsgSelectEspace();\r\n            }, 100);\r\n            \r\n            console.log('\ud83d\udd12 Tarif masqu\u00e9 (indisponibilit\u00e9)');\r\n        }\r\n        \r\n        async function sauvegarderClient() {\r\n            const annonceurId = sessionStorage.getItem('ClientIdActif');\r\n            \r\n            if (!annonceurId) {\r\n                console.warn('\u26a0\ufe0f Aucun client s\u00e9lectionn\u00e9');\r\n                return { success: false, message: 'Aucun client s\u00e9lectionn\u00e9' };\r\n            }\r\n            \r\n            const nomContact = $('#form-field-annonceur_nom_contact').val().trim();\r\n            const nomContactSplit = nomContact.split(' ');\r\n            const prenom = nomContactSplit.slice(0, -1).join(' ') || '';\r\n            const nom = nomContactSplit.slice(-1)[0] || '';\r\n            \r\n            const formData = {\r\n                action: 'update',\r\n                annonceur_id: annonceurId,\r\n                nom_societe: $('#form-field-annonceur_nom_societe').val(),\r\n                annonceur_prenom: prenom,\r\n                annonceur_nom: nom,\r\n                annonceur_email: $('#form-field-annonceur_email_contact').val(),\r\n                direction_service: $('#form-field-annonceur_direction_service').val(),\r\n                numero_immatriculation: $('#form-field-annonceur_numero_immatriculation').val(),\r\n                numero_tva: $('#form-field-annonceur_numero_tva').val(),\r\n                adresse_ligne1: $('#form-field-annonceur_adresse_ligne1').val(),\r\n                code_postal: $('#form-field-annonceur_code_postal').val(),\r\n                ville: $('#form-field-annonceur_ville').val(),\r\n                pays: $('#form-field-annonceur_pays').val(),\r\n                telephone: $('#form-field-annonceur_telephone_contact').val(),\r\n                mobile: '',\r\n                facturation_contact: $('#form-field-facturation_contact').val(),\r\n                facturation_adresse: $('#form-field-facturation_adresse').val(),\r\n                facturation_code_postal: $('#form-field-facturation_code_postal').val(),\r\n                facturation_ville: $('#form-field-facturation_ville').val(),\r\n                facturation_pays: $('#form-field-facturation_pays').val(),\r\n                facturation_email: $('#form-field-facturation_email').val(),\r\n                facturation_telephone: $('#form-field-facturation_telephone').val()\r\n            };\r\n            \r\n            console.log('\ud83d\udcbe Sauvegarde client:', formData);\r\n            \r\n            try {\r\n                const response = await $.ajax({\r\n                    url: API_CLIENTS.url,\r\n                    type: 'POST',\r\n                    data: formData,\r\n                    dataType: 'json'\r\n                });\r\n                \r\n                if (response.success) {\r\n                    console.log('\u2705 Client sauvegard\u00e9 avec succ\u00e8s');\r\n                    \r\n                    $('#ButtonValidDataAnnonceur2')\r\n                        .addClass('country-selected')\r\n                        .css('background-color', '#E8F0FE')\r\n                        .find('.elementor-button-text')\r\n                        .text('\u2713 Sauvegard\u00e9');\r\n                    \r\n                    setTimeout(() => {\r\n                        $('#ButtonValidDataAnnonceur2')\r\n                            .removeClass('country-selected')\r\n                            .css('background-color', '')\r\n                            .find('.elementor-button-text')\r\n                            .text('');\r\n                    }, 2000);\r\n                }\r\n                \r\n                return response;\r\n                \r\n            } catch (error) {\r\n                console.error('\u274c Erreur sauvegarde client:', error);\r\n                return { success: false, message: 'Erreur r\u00e9seau' };\r\n            }\r\n        }\r\n        \r\n        function initSauvegardeClientAuto() {\r\n            const $formulaire = $('#Formulaire_Annonceur_donnees_notconnected2');\r\n            \r\n            if ($formulaire.length === 0) {\r\n                console.warn('\u26a0\ufe0f Formulaire client introuvable');\r\n                return;\r\n            }\r\n            \r\n            $formulaire.find('input[type=\"text\"], input[type=\"email\"]').on('blur', function() {\r\n                const annonceurId = sessionStorage.getItem('ClientIdActif');\r\n                \r\n                if (annonceurId) {\r\n                    console.log('\ud83d\udcbe D\u00e9clenchement sauvegarde auto');\r\n                    sauvegarderClient();\r\n                }\r\n            });\r\n            \r\n            $formulaire.on('submit', function(e) {\r\n                e.preventDefault();\r\n                sauvegarderClient();\r\n                return false;\r\n            });\r\n            \r\n            console.log('\u2705 Sauvegarde auto client configur\u00e9e');\r\n        }\r\n        \r\n        function synchroniserAvecPanier() {\r\n            if (window.VIA_Panier) {\r\n                window.VIA_Panier.synchroniserAvecEtape1();\r\n            }\r\n        }\r\n        \r\n        function setupSynchronisationPanier() {\r\n            const $dateDebut = $('#' + CONFIG.FIELDS.dateDebut);\r\n            const $dateFin = $('#' + CONFIG.FIELDS.dateFin);\r\n            const $pays = $('#' + CONFIG.FIELDS.pays);\r\n            \r\n            $dateDebut.on('change', function() {\r\n                setTimeout(() => synchroniserAvecPanier(), 200);\r\n            });\r\n            \r\n            $dateFin.on('change', function() {\r\n                setTimeout(() => synchroniserAvecPanier(), 200);\r\n            });\r\n            \r\n            $pays.on('change', function() {\r\n                setTimeout(() => synchroniserAvecPanier(), 200);\r\n            });\r\n            \r\n            $('#' + CONFIG.FIELDS.devise).on('change', function() {\r\n                setTimeout(() => synchroniserAvecPanier(), 200);\r\n            });\r\n            \r\n            console.log('\u2705 Synchronisation panier configur\u00e9e');\r\n        }\r\n\r\n        function afficherTarif(tarifData, devise = 'EUR') {\r\n            $('#MsgSelectEspace').hide();\r\n            console.log('\ud83d\udcb0 Tarif affich\u00e9 - MsgSelectEspace masqu\u00e9');\r\n\r\n            if (STATE.isCommercial) {\r\n                console.log('\ud83d\udc54 Commercial connect\u00e9 : affichage dans champ commercial');\r\n                \r\n                \/\/ pb2126 : toutes les instances (ids dupliques par clonage des cartes).\r\n                const $tarifCommercialInput = $('input[name=\"form_fields[TarifCommercial]\"]');\r\n                \r\n                if ($tarifCommercialInput.length > 0) {\r\n                    const montantEUR = tarifData.tarif_ht;\r\n                    let montantAffiche = montantEUR;\r\n                    \r\n                    if (AND(devise !== 'EUR', verifierTauxDeChange())) {\r\n                        montantAffiche = window.VIA_App.convertirDevise(montantEUR, 'EUR', devise);\r\n                    }\r\n                    \r\n                    const montantArrondi = Math.round(montantAffiche);\r\n                    \r\n                    if (AND(window.VIA_Panier, window.VIA_Panier.state.itemActif)) {\r\n                        const item = window.VIA_Panier.state.items.find(i => i.id === window.VIA_Panier.state.itemActif);\r\n                        if (item) {\r\n                            item.tarifHT_initial = montantEUR;\r\n                            console.log('\ud83d\udcca Tarif initial mis \u00e0 jour:', montantEUR, 'EUR');\r\n                        }\r\n                    }\r\n                    \r\n                    $('[id=\"tarif-commercial-erreur\"]').remove();\r\n                    $tarifCommercialInput.css('border-color', '');\r\n                    \r\n                    $tarifCommercialInput.val(montantArrondi);\r\n                    STATE.tarifCommercialSaisi = montantArrondi;\r\n                    STATE.deviseTarifCommercial = devise;\r\n                    \r\n                    mettreAJourTarifCommercialDansCommande(montantArrondi, devise);\r\n                    _majDeviseTarifCommercial2122();   \/\/ pb2122 : .val() programmatique, pas d'event 'input'\r\n                    \/\/ pb2123 : le tarif de la resa active s'affiche -> le champ de\r\n                    \/\/   saisie apparait (inline important : gererAffichageCommerciaux\r\n                    \/\/   et Panier ecrivent aussi sur cet element).\r\n                    if (window._viaPb2123Off !== true) {\r\n                        \/\/ ============================================================\r\n                        \/\/ pb2181 : LE CHAMP COMMERCIAL SE VERIFIE AU MOMENT DE\r\n                        \/\/   S AFFICHER, PAS A L INITIALISATION.\r\n                        \/\/   Constat JF : au changement de devise, le champ de saisie\r\n                        \/\/   reserve aux commerciaux apparait (capture : conteneur\r\n                        \/\/   rendu, champ vide).\r\n                        \/\/   La garde amont de ce bloc lit STATE.isCommercial, fige\r\n                        \/\/   UNE fois par gererAffichageCommerciaux. Une cl\u00e9\r\n                        \/\/   CommercialConnected restee en session \u2014 ou un etat\r\n                        \/\/   capture avant deconnexion \u2014 suffit donc a rouvrir le\r\n                        \/\/   champ a chaque passage d afficherTarif, et un changement\r\n                        \/\/   de devise en declenche un.\r\n                        \/\/   On relit donc la source au moment d agir. Le refus est\r\n                        \/\/   journalise AVEC la valeur brute de la cle : si elle vaut\r\n                        \/\/   'Yes' alors que l utilisateur n est pas commercial, c est\r\n                        \/\/   la cle qu il faudra purger (et non ce writer).\r\n                        \/\/   Revert : window._viaPb2181Off = true.\r\n                        \/\/ ============================================================\r\n                        var _com2181 = (window._viaPb2181Off === true)\r\n                            ? true : (sessionStorage.getItem('CommercialConnected') === 'Yes');\r\n                        if (!_com2181) {\r\n                            if (window._viaSig2181 !== true) {\r\n                                window._viaSig2181 = true;\r\n                                console.warn('[pb2181] champ tarif commercial NON affiche'\r\n                                    + ' | CommercialConnected=\"'\r\n                                    + (sessionStorage.getItem('CommercialConnected') || '(absent)') + '\"'\r\n                                    + ' | STATE.isCommercial=' + STATE.isCommercial);\r\n                            }\r\n                        } else {\r\n                            $('[id=\"TarifCommercialtobedisplayedConteneur\"]').each(function() {\r\n                                this.style.setProperty('display', 'block', 'important');\r\n                            });\r\n                            console.log('[pb2123] tarif affiche -> champ tarif commercial visible'\r\n                                + ' | [pb2181] CommercialConnected verifie a l instant');\r\n                        }\r\n                    }\r\n                    \r\n                    console.log('\u2705 Tarif commercial pr\u00e9-rempli:', montantArrondi);\r\n                }\r\n                \r\n                return;\r\n            }\r\n            \r\n            const $tarifContainer = $(CONFIG.FIELDS.tarifDisplay);\r\n            if ($tarifContainer.length === 0) {\r\n                console.warn('\u26a0\ufe0f Champ d\\'affichage tarif introuvable');\r\n                return;\r\n            }\r\n            \r\n            const montantEUR = tarifData.tarif_ht;\r\n            let montantAffiche = montantEUR;\r\n            \r\n            if (devise !== 'EUR') {\r\n                if (!verifierTauxDeChange()) {\r\n                    console.warn('\u26a0\ufe0f Taux de change non disponibles, attente...');\r\n                    \r\n                    const intervalAttente = setInterval(() => {\r\n                        if (verifierTauxDeChange()) {\r\n                            clearInterval(intervalAttente);\r\n                            console.log('\u2705 Taux disponibles, nouvelle tentative de conversion');\r\n                            afficherTarif(tarifData, devise);\r\n                        }\r\n                    }, 200);\r\n                    \r\n                    setTimeout(() => {\r\n                        clearInterval(intervalAttente);\r\n                        if (!verifierTauxDeChange()) {\r\n                            $tarifContainer.html('Erreur: Taux non disponibles').css({'color': '#ef4444'});\r\n                        }\r\n                    }, 10000);\r\n                    \r\n                    return;\r\n                }\r\n                \r\n                try {\r\n                    montantAffiche = window.VIA_App.convertirDevise(montantEUR, 'EUR', devise);\r\n                    \r\n                    if (AND(montantAffiche === montantEUR, devise !== 'EUR')) {\r\n                        console.error('\u26a0\ufe0f La conversion n\\'a pas eu lieu, montant identique');\r\n                    }\r\n                } catch (error) {\r\n                    console.error('\u274c Erreur lors de la conversion:', error);\r\n                    $tarifContainer.html('Erreur de conversion').css({'color': '#ef4444'});\r\n                    return;\r\n                }\r\n            }\r\n            \r\n            const tarifFormate = window.VIA_App.formaterMontant(montantAffiche, devise);\r\n            \r\n            $tarifContainer.html(tarifFormate).css({'color': '#4B689B'});\r\n            \r\n            if (AND(window.VIA_Panier, window.VIA_Panier.state.itemActif)) {\r\n                const $itemActif = $(`#${window.VIA_Panier.state.itemActif}`);\r\n                \r\n                if ($itemActif.length) {\r\n                    const $tarifElement = $itemActif.find('.CampagneTarifClass');\r\n                    \r\n                    if ($tarifElement.length === 0) {\r\n                        console.error('\u274c .CampagneTarifClass introuvable dans item:', window.VIA_Panier.state.itemActif);\r\n                    } else {\r\n                        $tarifElement\r\n                            .html(`Tarif H.T. ${tarifFormate}`)\r\n                            .show();\r\n                        \r\n                        console.log('\u2705 Tarif campagne mis \u00e0 jour et visible');\r\n                    }\r\n                }\r\n                \r\n                window.VIA_Panier.mettreAJourItem(window.VIA_Panier.state.itemActif, {\r\n                    tarifHT: montantEUR,\r\n                    tarifTTC: montantEUR * 1.20,\r\n                    devise: devise,\r\n                    statut: 'valide'\r\n                });\r\n            }\r\n            \r\n            console.log(`\u2705 Tarif affich\u00e9 et donn\u00e9es mises \u00e0 jour`);\r\n        }\r\n        \r\n        function afficherErreurTarif(message) {\r\n            const $tarifContainer = $(CONFIG.FIELDS.tarifDisplay);\r\n\r\n            if ($tarifContainer.length === 0) {\r\n                return;\r\n            }\r\n\r\n            $tarifContainer.html('Erreur').css({'color': '#ef4444'});\r\n            console.error('\u274c Erreur affichage tarif:', message);\r\n        }\r\n\r\n        function initDeviseListener() {\r\n            const $deviseSelect = $('#' + CONFIG.FIELDS.devise);\r\n            \r\n            if ($deviseSelect.length === 0) {\r\n                console.warn('\u26a0\ufe0f S\u00e9lecteur de devise introuvable');\r\n                return;\r\n            }\r\n            \r\n            window.VIA_App.state.deviseActuelle = $deviseSelect.val() || 'EUR';\r\n            \r\n            $deviseSelect.on('change', function() {\r\n                const nouvelleDevise = $(this).val();\r\n                \r\n                if (AND(nouvelleDevise !== 'EUR', !verifierTauxDeChange())) {\r\n                    console.warn('\u26a0\ufe0f Taux de change non disponibles, changement de devise annul\u00e9');\r\n                    $(this).val(window.VIA_App.state.deviseActuelle);\r\n                    alert('Les taux de change sont en cours de chargement. Veuillez patienter quelques secondes.');\r\n                    return;\r\n                }\r\n                \r\n                console.log('\ud83d\udcb1 Changement devise:', window.VIA_App.state.deviseActuelle, '\u2192', nouvelleDevise);\r\n                \r\n\r\n                window.VIA_App.state.deviseActuelle = nouvelleDevise;\r\n                \r\n                if (window.VIA_Panier) {\r\n                    window.VIA_Panier.state.deviseAffichage = nouvelleDevise;\r\n                    \r\n                    if (window.VIA_App.state.dernierResultatCalcul) {\r\n                        afficherTarif(window.VIA_App.state.dernierResultatCalcul, nouvelleDevise);\r\n                    }\r\n                    \r\n                    window.VIA_Panier.state.items.forEach(item => {\r\n                        if (item.tarifHT) {\r\n                            window.VIA_Panier.rafraichirItemHTML(item.id);\r\n                        }\r\n                    });\r\n                    \r\n                    window.VIA_Panier.afficherTotal();\r\n                }\r\n            });\r\n            \r\n            console.log('\u2705 Listener devise initialis\u00e9');\r\n        }\r\n\r\n        \/**\r\n         * \u2705 v3.4 : R\u00e9initialise le formulaire pour une nouvelle commande\r\n         *\/\r\n        function reinitialiserFormulairePourNouvelleCommande() {\r\n            console.log('\ud83d\udd04 R\u00e9initialisation formulaire pour nouvelle commande...');\r\n            \r\n            \/\/ \u2705 Vider les dates\r\n            $('#' + CONFIG.FIELDS.dateDebut).val('');\r\n            $('#' + CONFIG.FIELDS.dateFin).val('');\r\n            $(CONFIG.FIELDS.dureeContainer).text('');\r\n            \r\n            \/\/ \u2705 NE PAS vider le pays car il est global\r\n            \/\/ $('#' + CONFIG.FIELDS.pays).val('');\r\n            \r\n            \/\/ \u2705 R\u00e9initialiser l'affichage du tarif\r\n            $(CONFIG.FIELDS.tarifDisplay).html('-');\r\n            \r\n            \/\/ \u2705 v1.7 : R\u00e9initialiser STATE compl\u00e8tement (incluant emplacementPageWeb)\r\n            STATE.startDate = null;\r\n            STATE.endDate = null;\r\n            STATE.espacePubSelected = false;\r\n            STATE.emplacementPageWeb = null;\r\n            STATE.format = null;\r\n            STATE.position = null;\r\n            STATE.lienEspacePub = null;\r\n            STATE.cheminFichierAnnonce = null;\r\n            \r\n            \/\/ \u2705 R\u00e9initialiser le dernier calcul\r\n            if (window.VIA_App && window.VIA_App.state) {\r\n                window.VIA_App.state.dernierResultatCalcul = null;\r\n            }\r\n            \r\n            console.log('\u2705 Formulaire r\u00e9initialis\u00e9');\r\n        }\r\n        \r\n        \/\/ \u2705 v1.7 : Exposer la fonction de r\u00e9initialisation pour panier-manager\r\n        window.reinitialiserFormulaireDatesTarif = reinitialiserFormulairePourNouvelleCommande;\r\n        \r\n        \/\/ \u2705 v2.7 : Reset cibl\u00e9 dates uniquement \u2014 pour changement d'item actif (multi-achat)\r\n        \/\/ N'efface pas espace\/format\/position \u2014 contrairement \u00e0 reinitialiserFormulairePourNouvelleCommande\r\n        window.reinitialiserDatesFormulaire = function() {\r\n            $('#' + CONFIG.FIELDS.dateDebut).val('');\r\n            $('#' + CONFIG.FIELDS.dateFin).val('');\r\n            try { $('#' + CONFIG.FIELDS.dateDebut).datepicker('setDate', null); } catch(e) {}\r\n            try { $('#' + CONFIG.FIELDS.dateFin).datepicker('setDate', null); } catch(e) {}\r\n            $(CONFIG.FIELDS.dureeContainer).text('');\r\n            STATE.startDate = null;\r\n            STATE.endDate = null;\r\n            \/\/ \u2705 v2.7 : Reset aussi le pays \u2014 \u00e9vite que item 2 h\u00e9rite du pays de l'annonceur de item 1\r\n            STATE.selectedCountry = null;\r\n            if (window.VIA_App && window.VIA_App.state) {\r\n                window.VIA_App.state.dernierResultatCalcul = null;\r\n            }\r\n            console.log('\ud83d\udd04 [reinitialiserDatesFormulaire] STATE dates+pays r\u00e9initialis\u00e9s');\r\n        };\r\n\r\n        \/**\r\n         * \u2705 v3.4 : PostMessage avec anti-doublon\r\n         *\/\r\n        function setupPostMessage() {\r\n            \/\/ \u2705 ANTI-DOUBLON : \u00c9viter les listeners multiples\r\n            if (window.VIA_PostMessageSetup) {\r\n                console.log('\u26a0\ufe0f PostMessage d\u00e9j\u00e0 configur\u00e9, skip');\r\n                return;\r\n            }\r\n            window.VIA_PostMessageSetup = true;\r\n            \r\n            window.addEventListener('message', async function(event) {\r\n                const message = event.data;\r\n        \r\n                if (message.type === 'dataFromIframeEspacePub') {\r\n                    console.log('\ud83d\udfe3 [Formulaire] dataFromIframeEspacePub re\u00e7u');\r\n                    const iframeData = message.data;\r\n                    console.log('\ud83d\udfe3 [Formulaire] emplacement:', iframeData.Commande_Emplacement_Page_Web, '| EnvoiUlterieur:', iframeData.EnvoiUlterieur, '| FileReceived:', iframeData.FileReceived);\r\n                    \r\n                    \/\/ \u2705 v3.4 : ANTI-DOUBLON avec timestamp\r\n                    \/\/ \u2705 FIX : Inclure EnvoiUlterieur dans la cl\u00e9 pour ne pas bloquer le clic envoi diff\u00e9r\u00e9\r\n                    \/\/ v4.9ds : ajouter Formatchoisi pour diff\u00e9rencier envoi diff\u00e9r\u00e9 seul (Formatchoisi absent)\r\n                    \/\/   du clic R\u00e9server effectif (Formatchoisi='Yes'). Sans \u00e7a, les 2 events ont la m\u00eame\r\n                    \/\/   cl\u00e9 MDG..._envoi_true et le clic R\u00e9server 1-2s apr\u00e8s l'envoi diff\u00e9r\u00e9 est ignor\u00e9.\r\n                    const messageKey = iframeData.Commande_Emplacement_Page_Web + '_' + (iframeData.Upload_File_Name || 'envoi') + '_' + (iframeData.EnvoiUlterieur || 'false') + '_' + (iframeData.Formatchoisi || '');\r\n                    const maintenant = Date.now();\r\n                    const dernierTraitement = ANTI_DOUBLON.derniersTraitements[messageKey];\r\n                    console.log('\ud83d\udfe3 [Formulaire] messageKey:', messageKey, '| dernierTraitement:', dernierTraitement, '| delta:', dernierTraitement ? maintenant - dernierTraitement : 'N\/A');\r\n                    \r\n                    if (dernierTraitement && (maintenant - dernierTraitement) < ANTI_DOUBLON.DELAI_MS) {\r\n                        console.log('\u26a0\ufe0f ANTI-DOUBLON: Message ignor\u00e9 (trait\u00e9 il y a moins de 2s):', messageKey);\r\n                        return;\r\n                    }\r\n                    ANTI_DOUBLON.derniersTraitements[messageKey] = maintenant;\r\n                    \r\n                    \/\/ Nettoyer les vieux messages (> 10s)\r\n                    Object.keys(ANTI_DOUBLON.derniersTraitements).forEach(key => {\r\n                        if (maintenant - ANTI_DOUBLON.derniersTraitements[key] > 10000) {\r\n                            delete ANTI_DOUBLON.derniersTraitements[key];\r\n                        }\r\n                    });\r\n                    \r\n                    console.log('\u2705 iframeData re\u00e7us :', iframeData);\r\n                    \r\n                    if (iframeData.Commande_Format_Transmis === 'Image') {\r\n                        iframeData.Commande_Format_Transmis = 'Banni\u00e8re';\r\n                    }\r\n                    \/\/ pb658 : normaliser les formats sans accent (iframe) vers la forme\r\n                    \/\/   accentuee des classes CSS Elementor.\r\n                    var _accentsFmt658 = { 'Banniere': 'Banni\u00e8re', 'Video': 'Vid\u00e9o', 'Communique': 'Communiqu\u00e9' };\r\n                    if (_accentsFmt658[iframeData.Commande_Format_Transmis]) {\r\n                        iframeData.Commande_Format_Transmis = _accentsFmt658[iframeData.Commande_Format_Transmis];\r\n                    }\r\n                    \r\n                    mettreAJourSelectionFormat(iframeData);\r\n                    \r\n                    const commandePage = sessionStorage.getItem('Commande_Page') || 'Homepage';\r\n                    const position = calculerPositionFromRank(\r\n                        iframeData.Rank_Emplacement_Page_Web, \r\n                        commandePage\r\n                    );\r\n                    \r\n                    console.log('\ud83d\udccd Position calcul\u00e9e:', position);\r\n                    \r\n                    const dateDebut = $('#' + CONFIG.FIELDS.dateDebut).val();\r\n                    const dateFin = $('#' + CONFIG.FIELDS.dateFin).val();\r\n                    \r\n                    let estDisponible = true;\r\n                    \r\n                    if (AND(dateDebut, dateFin)) {\r\n                        const [d1, m1, y1] = dateDebut.split('\/');\r\n                        const [d2, m2, y2] = dateFin.split('\/');\r\n                        \r\n                        const result = await verifierDisponibilite(\r\n                            iframeData.Commande_Emplacement_Page_Web,\r\n                            `${y1}-${m1}-${d1}`,\r\n                            `${y2}-${m2}-${d2}`\r\n                        );\r\n                        \r\n                        if (!result.available) {\r\n                            estDisponible = false;\r\n                            afficherIndisponibilite(result.next_available);\r\n                        } else {\r\n                            masquerIndisponibilite();\r\n                        }\r\n                    }\r\n                    \r\n                    const emplacementWeb = iframeData.Commande_Emplacement_Page_Web;\r\n                    \r\n                    \/\/ \u2705 v1.7 : Chercher d'abord par emplacementPageWeb\r\n                    let commandeExistante = window.VIA_Panier?.state.items.find(\r\n                        i => i.emplacementPageWeb === emplacementWeb\r\n                    );\r\n                    \r\n                    \/\/ \u2705 v1.7 : Si pas trouv\u00e9, chercher une commande sans espace pub (partielle OU en_cours)\r\n                    if (!commandeExistante) {\r\n                        console.log('\ud83d\udd0d DEBUG - Recherche commande sans espace pub...');\r\n                        console.log('   Items:', JSON.stringify(window.VIA_Panier?.state.items.map(i => ({\r\n                            id: i.id,\r\n                            statut: i.statut,\r\n                            linkSecteurPage: i.linkSecteurPage,\r\n                            emplacementPageWeb: i.emplacementPageWeb\r\n                        }))));\r\n                        \r\n                        \/\/ Chercher commande partielle OU en_cours OU anticipee (pb174b) SANS emplacementPageWeb\r\n                        \/\/ \u2705 Bug fix : filtrer par linkSecteurPage pour ne pas impacter une autre page\r\n                        const _loadedUrl = iframeData.LoadedPageUrl || '';\r\n                        const _normalizeUrl = (u) => u ? u.replace(\/\\\/?(\\?.*)?$\/, '').replace(\/\\\/$\/, '') : '';\r\n                        \/\/ \u2705 Filtrer aussi par rank pour distinguer 2 annonces sur la m\u00eame page\r\n                        const _currentRank = iframeData.Rank_Emplacement_Page_Web || '';\r\n                        const _candidatsSansEspace = (window.VIA_Panier?.state.items || []).filter(\r\n                            i => (i.statut === 'partielle' || i.statut === 'en_cours' || i.statut === 'anticipee') && !i.emplacementPageWeb\r\n                                && (_loadedUrl === '' || _normalizeUrl(i.linkSecteurPage) === _normalizeUrl(_loadedUrl))\r\n                                \/\/ \u2705 Exclure les items d\u00e9j\u00e0 associ\u00e9s \u00e0 un rank diff\u00e9rent (\u00e9vite r\u00e9utilisation pour 2e espace)\r\n                                && !(i.donneesIframe && i.donneesIframe.Rank_Emplacement_Page_Web\r\n                                     && _currentRank && i.donneesIframe.Rank_Emplacement_Page_Web !== _currentRank)\r\n                        );\r\n                        \/\/ \u2705 Priorit\u00e9 : item dont le rank correspond au courant ; sinon premier candidat\r\n                        const commandeSansEspace = _candidatsSansEspace.reduce(function(best, candidate) {\r\n                            if (!best) return candidate;\r\n                            var _bestRankMatch = best.donneesIframe && best.donneesIframe.Rank_Emplacement_Page_Web === _currentRank;\r\n                            var _candRankMatch = candidate.donneesIframe && candidate.donneesIframe.Rank_Emplacement_Page_Web === _currentRank;\r\n                            if (_candRankMatch && !_bestRankMatch) return candidate;\r\n                            return best;\r\n                        }, null);\r\n                        \r\n                        if (commandeSansEspace) {\r\n                            console.log('\u2705 Commande sans espace pub trouv\u00e9e:', commandeSansEspace.reference, '(statut:', commandeSansEspace.statut + ')');\r\n                            commandeExistante = commandeSansEspace;\r\n                        } else {\r\n                            console.log('\u274c Aucune commande sans espace pub dans le panier');\r\n                        }\r\n                    }\r\n                    \r\n                    if (commandeExistante) {\r\n                        console.log('\ud83d\udd04 Mise \u00e0 jour commande existante:', commandeExistante.reference);\r\n                        mettreAJourCommandeExistante(commandeExistante, iframeData, estDisponible);\r\n                    } else {\r\n                        console.log('\ud83c\udd95 Cr\u00e9ation nouvelle commande');\r\n                        \r\n                        \/\/ \u2705 v3.4 : R\u00c9INITIALISER le formulaire AVANT la cr\u00e9ation\r\n                        reinitialiserFormulairePourNouvelleCommande();\r\n                        \r\n                        updateHiddenField(CONFIG.FIELDS.espacepubId, iframeData.espacepub_id);\r\n                        updateHiddenField(CONFIG.FIELDS.format, iframeData.Commande_Format_Transmis);\r\n                        updateHiddenField(CONFIG.FIELDS.position, position);\r\n                        updateHiddenField(CONFIG.FIELDS.emplacementPageWeb, iframeData.Commande_Emplacement_Page_Web);\r\n                        \r\n                        STATE.espacePubSelected = true;\r\n                        STATE.format = iframeData.Commande_Format_Transmis;\r\n                        STATE.position = position;\r\n                        STATE.emplacementPageWeb = iframeData.Commande_Emplacement_Page_Web;\r\n                        STATE.lienEspacePub = iframeData.EspPubLienAnnonce || null;\r\n                        STATE.cheminFichierAnnonce = iframeData.FullPathAdFile || null;\r\n                        \r\n                        \/\/ \u2705 v1.7 : Masquer le message \"Merci de s\u00e9lectionner un espace publicitaire\"\r\n                        $('[data-id=\"656f02e0\"]').hide();\r\n                        \r\n                        console.log('\ud83d\udd17 Lien espace pub:', STATE.lienEspacePub);\r\n                        console.log('\ud83d\udcc1 Fichier annonce:', STATE.cheminFichierAnnonce);\r\n                        \r\n                        creerItemPanier(iframeData, 0, estDisponible);\r\n                    }\r\n                    \r\n                    const isMobile = window.innerWidth <= 1015 || \/iPhone|iPad|iPod|Android\/i.test(navigator.userAgent);\r\n                    \r\n                    function getIframeDepth() {\r\n                        let depth = 0;\r\n                        let win = window;\r\n                        try {\r\n                            while (win !== win.top) {\r\n                                depth++;\r\n                                win = win.parent;\r\n                            }\r\n                        } catch (e) {\r\n                            depth = -1;\r\n                        }\r\n                        return depth;\r\n                    }\r\n                    \r\n                    \r\n                    \/\/ \u2705 v3.4 : NE PAS calculer le tarif automatiquement pour nouvelle commande\r\n                    \/\/ Le tarif sera calcul\u00e9 quand l'utilisateur saisira les dates\r\n                    if (AND(commandeExistante, AND(estDisponible, AND(dateDebut, dateFin)))) {\r\n                        triggerTarifCalculation();\r\n                    }\r\n                }\r\n            });\r\n        }\r\n        \r\n        function mettreAJourSelectionFormat(iframeData) {\r\n            const format = iframeData.Commande_Format_Transmis;\r\n            const rank = iframeData.Rank_Emplacement_Page_Web || '';\r\n            \r\n            if (!format) return;\r\n            \r\n            const isPopup = rank.startsWith('Ele0');\r\n            \r\n            sessionStorage.setItem('PopUpChoice', isPopup ? 'Yes' : 'No');\r\n            sessionStorage.setItem('FormatSelect', format);\r\n            sessionStorage.setItem('Commande_Format_Transmis', format);\r\n            \r\n            console.log('\ud83d\udccb Format sessionStorage mis \u00e0 jour:', {\r\n                PopUpChoice: isPopup ? 'Yes' : 'No',\r\n                FormatSelect: format\r\n            });\r\n            \r\n            $('.FormatClassique, .FormatPopup').css('border', 'none');\r\n            \r\n            const typeSelector = isPopup ? '.FormatPopup' : '.FormatClassique';\r\n            const formatSelector = typeSelector + '.FormatSelect' + format;\r\n            \r\n            const $target = $(formatSelector);\r\n            \r\n            if ($target.length) {\r\n                $target.css({\r\n                    'border': '4px solid rgb(0, 255, 25)',\r\n                    'box-sizing': 'border-box'\r\n                });\r\n                console.log('\u2705 Bordure format appliqu\u00e9e:', formatSelector);\r\n            } else {\r\n                const $fallback = $('.FormatSelect' + format).first();\r\n                if ($fallback.length) {\r\n                    $fallback.css({\r\n                        'border': '4px solid rgb(0, 255, 25)',\r\n                        'box-sizing': 'border-box'\r\n                    });\r\n                    console.log('\u2705 Bordure format appliqu\u00e9e (fallback):', format);\r\n                } else {\r\n                    console.warn('\u26a0\ufe0f Format non trouv\u00e9:', format);\r\n                }\r\n            }\r\n            \/\/ \u2705 v2.3.4 : FormatMessageTexte \u2014 \"Pop-up Vid\u00e9o\" si format sous-jacent connu\r\n            var formatText = isPopup\r\n                ? ('Pop-up' + (format && format !== 'PopUp' && format !== 'Pop-up' ? ' ' + format : ''))\r\n                : format;\r\n            var lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            var msg = (lang === 'EN') ? 'The chosen format is ' : 'Le format choisi est ';\r\n            $('#FormatMessageTexte').text(msg + formatText);\r\n            $('#FormatMessageContainer').show();\r\n            $('#FormatMessagePreselectionContainer').hide();\r\n            \/\/ \u2705 v2.0 : Ne plus fermer l'accord\u00e9on format - l'utilisateur peut fermer manuellement\r\n            \/\/ if (typeof window.closeChoixFormat === 'function') {\r\n            \/\/     window.closeChoixFormat();\r\n            \/\/ } else {\r\n            \/\/     \/\/ Fallback manuel\r\n            \/\/     $('.ChoixFormatClass').hide();\r\n            \/\/     $('#ChoixFormatTitreIconeUp').hide();\r\n            \/\/     $('#ChoixFormatTitreIconeDown').show();\r\n            \/\/ }\r\n            console.log('\u2705 FormatMessageTexte mis \u00e0 jour:', formatText);\r\n        }\r\n        \r\n        async function mettreAJourCommandeExistante(commande, iframeData, estDisponible = true) {\r\n            console.log('\ud83d\udd04 Mise \u00e0 jour commande avec nouvelles donn\u00e9es iframe');\r\n            \r\n            const $item = $(`#${commande.id}`);\r\n            \r\n            \/\/ \u2705 v1.7 : Mettre \u00e0 jour emplacementPageWeb (important pour les commandes partielles)\r\n            \/\/ \u2705 Guard : ne transformer en r\u00e9servation que si l'utilisateur a cliqu\u00e9 \"R\u00e9server\"\r\n            \/\/           (EnvoiUlterieur ou FileReceived) \u2014 pas sur simple changement de format\r\n            \/\/ \u2705 R\u00e9servation r\u00e9elle = clic \"R\u00e9server cet espace\" (AddNewRefInVosCampagnes=Yes)\r\n            const _estReservation = iframeData.AddNewRefInVosCampagnes === 'Yes';\r\n            if (iframeData.Commande_Emplacement_Page_Web && _estReservation) {\r\n                commande.emplacementPageWeb = iframeData.Commande_Emplacement_Page_Web;\r\n                STATE.emplacementPageWeb = iframeData.Commande_Emplacement_Page_Web;\r\n                STATE.espacePubSelected = true;\r\n                \/\/ v4.9ds (estReserveEffective) : flag pos\u00e9 uniquement \u00e0 la r\u00e9servation\r\n                \/\/   effective (_estReservation === true = AddNewRefInVosCampagnes='Yes' = clic R\u00e9server).\r\n                \/\/   Distingue \"r\u00e9serv\u00e9\" de \"d\u00e9pos\u00e9\" dans les conditions de Panier_manager.\r\n                commande.estReserveEffective = true;\r\n                console.log('\ud83d\udccd emplacementPageWeb mis \u00e0 jour:', commande.emplacementPageWeb);\r\n                \r\n                \/\/ \u2705 Mettre \u00e0 jour .CampagneNoClass \u2192 \"Espace r\u00e9serv\u00e9 ESPACE\" (v4.9ds)\r\n                const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                \/\/ v4.9ds : .CampagneNoClass \u2014 texte FR raccourci + retrait span font-size:12px\r\n                const _lblReserveF = lang === 'EN' ? 'Reserved advertising space ' : 'Espace r\u00e9serv\u00e9 ';\r\n                const texteNoClass = _lblReserveF + iframeData.Commande_Emplacement_Page_Web;\r\n                console.log('\u2705 [mettreAJourCommandeExistante] CampagneNoClass =', texteNoClass);\r\n                $item.find('.CampagneNoClass').html(texteNoClass).show();\r\n\r\n                \/\/ \u2705 v2.4.5 : Injecter position dans #CampagnePageText\r\n                var _rankMAJ = iframeData.Rank_Emplacement_Page_Web || '';\r\n                console.log('[position] mettreAJour \u2014 rank:', _rankMAJ);\r\n                if (_rankMAJ && window.VIA_Panier) {\r\n                    var _pageMAJ = sessionStorage.getItem('Commande_Page') || 'Homepage';\r\n                    var _posMAJ = window.VIA_Panier.convertirPositionEnLibelle(\r\n                        window.VIA_Panier.calculerPosition(_rankMAJ, _pageMAJ)\r\n                    );\r\n                    console.log('[position] mettreAJour \u2014 posLib:', _posMAJ);\r\n                    var $_ptMAJ = $item.find('.CampagnePageTextClass, #CampagnePageText').first();\r\n                    console.log('[position] mettreAJour \u2014 $pageText.length:', $_ptMAJ.length, '| avant:', $_ptMAJ.text());\r\n                    if (_posMAJ && $_ptMAJ.length) {\r\n                        \/\/ pb207 : pour un espace pop-up (Ele0A -> position \"Pop-up\"), NE PAS\r\n                        \/\/   ajouter \"Pop-up\" au secteur. Le format affiche deja \"Pop-up\r\n                        \/\/   Interview\" -> sinon doublon \"Agro-industries Pop-up\" + format.\r\n                        \/\/   Ajout conserve pour les autres rangs (Haut\/Bas de page) = positions reelles.\r\n                        var _isPopupMAJ = (_rankMAJ === 'Ele0A');\r\n                        if (!_isPopupMAJ) { if (('' + _posMAJ).toLowerCase().indexOf('pop-up') === 0) { _isPopupMAJ = true; } }\r\n                        if (_isPopupMAJ) {\r\n                            console.log('[position] mettreAJour \u2014 pop-up (' + _rankMAJ + ') : pas d ajout au secteur (pb207)');\r\n                        } else {\r\n                            var _currentText = $_ptMAJ.text().split('\u00a0')[0].trim();\r\n                            $_ptMAJ.text(_currentText + '\u00a0\u00a0' + _posMAJ);\r\n                            console.log('[position] mettreAJour \u2014 apres:', $_ptMAJ.text());\r\n                        }\r\n                    }\r\n                }\r\n\r\n                \/\/ $item.find('.CampagneInfoEspaceMessage').hide(); \/\/ \u2699\ufe0f [COMMENT\u00c9] g\u00e9r\u00e9 par message global\r\n                \/\/ \u2705 Masquer message global (espace r\u00e9serv\u00e9 pour cette page)\r\n                if (typeof window.updateRecapInfoMessage === 'function') {\r\n                    const _urlReservation = iframeData.LoadedPageUrl || sessionStorage.getItem('LinkSecteurPage') || '';\r\n                    window.updateRecapInfoMessage(_urlReservation);\r\n                }\r\n                \r\n                \/\/ \u2705 v1.7 : Masquer le message \"Merci de s\u00e9lectionner un espace publicitaire\"\r\n                $('[data-id=\"656f02e0\"]').hide();\r\n                \r\n                \/\/ \u2705 v4.9ds+ : Mettre \u00e0 jour la r\u00e9f\u00e9rence si elle contient '???' (placeholder\r\n                \/\/   pos\u00e9 par creerReservationAnticipee avant que codeSite\/codePage soient connus).\r\n                \/\/   A ce stade (espace pub s\u00e9lectionn\u00e9 + R\u00e9server cliqu\u00e9), codeSite et codePage\r\n                \/\/   sont disponibles dans sessionStorage.\r\n                if (commande.reference && commande.reference.indexOf('???') !== -1) {\r\n                    var _codeSiteRef = sessionStorage.getItem('codeSite') || '';\r\n                    var _codePageRef = sessionStorage.getItem('IdPage') || sessionStorage.getItem('codePage') || '';\r\n                    if (_codeSiteRef && _codePageRef) {\r\n                        var _codeUnique = commande.reference.split('-')[0] || '';\r\n                        var _newRef = _codeUnique + '-' + _codeSiteRef + '-' + _codePageRef;\r\n                        commande.reference = _newRef;\r\n                        $item.attr('data-reference', _newRef);\r\n                        $item.find('.CampagneReferenceClass').text('Ref. espace pub. ' + _newRef);\r\n                        console.log('\u2705 [mettreAJourCommandeExistante] R\u00e9f\u00e9rence mise \u00e0 jour:', _newRef);\r\n                    }\r\n                }\r\n\r\n                \/\/ \u2705 v1.7 : Si c'\u00e9tait une commande partielle, passer en 'en_cours'\r\n                if (commande.statut === 'partielle' || commande.statut === 'anticipee') {\r\n                    var _ancienStatut174b = commande.statut;\r\n                    commande.statut = 'en_cours';\r\n                    console.log('\ud83d\udcdd Statut mis \u00e0 jour [pb174b]: ' + _ancienStatut174b + ' \u2192 en_cours');\r\n                }\r\n                \/\/ \u2705 Rafra\u00eechir .CampagneMsgAccompagnement (statut pass\u00e9 \u00e0 en_cours \u2192 \"Merci de choisir des dates...\")\r\n                if (window.VIA_Panier && typeof window.VIA_Panier.ajouterMsgAccompagnement === 'function') {\r\n                    window.VIA_Panier.ajouterMsgAccompagnement($item, {\r\n                        espace: iframeData.Commande_Emplacement_Page_Web,\r\n                        estReserve: true,\r\n                        tarifHT: commande.tarifHT || null,\r\n                        statut: commande.statut\r\n                    });\r\n                }\r\n\r\n                \/\/ \u2705 D\u00e9bloquer #ProcessAchatInside\r\n                $('#ProcessAchatInside').css('pointer-events', '').css('opacity', '');\r\n                $('#MsgBlockDates').hide();\r\n                \/\/ \u2705 Mettre \u00e0 jour #LabelDatesDureeReservation imm\u00e9diatement (sans attendre setItemActif)\r\n                if (window.VIA_Panier && typeof window.VIA_Panier.afficherEtape1DansItem === 'function') {\r\n                    window.VIA_Panier.afficherEtape1DansItem(commande.id);\r\n                }\r\n            } else if (iframeData.Commande_Emplacement_Page_Web && !_estReservation) {\r\n                console.log('\u2139\ufe0f Emplacement pr\u00e9sent mais pas de r\u00e9servation \u2014 format seul, statut conserv\u00e9');\r\n            }\r\n            \r\n            const nouvellePosition = calculerPositionFromRank(\r\n                iframeData.Rank_Emplacement_Page_Web,\r\n                commande.commandePage || 'Homepage'\r\n            );\r\n            \r\n            const nouveauFormat = iframeData.Commande_Format_Transmis;\r\n            \r\n            \/\/ \u2705 v1.7 : TOUJOURS synchroniser STATE.format (m\u00eame si identique)\r\n            if (nouveauFormat) {\r\n                if (nouveauFormat !== commande.format) {\r\n                    console.log(`\ud83d\udcdd Changement format: ${commande.format} \u2192 ${nouveauFormat}`);\r\n                }\r\n                commande.format = nouveauFormat;\r\n                STATE.format = nouveauFormat;\r\n                updateHiddenField(CONFIG.FIELDS.format, nouveauFormat);\r\n                \r\n                let formatAffiche = nouveauFormat;\r\n                \r\n                if (iframeData.Rank_Emplacement_Page_Web?.startsWith('Ele0')) {\r\n                    formatAffiche = 'Pop-up ' + nouveauFormat;\r\n                }\r\n                \r\n                $item.find('.CampagneFormatClass').html(formatAffiche);\r\n                console.log('\u2705 STATE.format synchronis\u00e9:', STATE.format);\r\n            }\r\n            \r\n            \/\/ \u2705 v1.7 : TOUJOURS synchroniser STATE.position (m\u00eame si identique)\r\n            if (nouvellePosition) {\r\n                if (nouvellePosition !== commande.position) {\r\n                    console.log(`\ud83d\udccd Changement position: ${commande.position} \u2192 ${nouvellePosition}`);\r\n                }\r\n                commande.position = nouvellePosition;\r\n                STATE.position = nouvellePosition;\r\n                updateHiddenField(CONFIG.FIELDS.position, nouvellePosition);\r\n                console.log('\u2705 STATE.position synchronis\u00e9:', STATE.position);\r\n            }\r\n            \r\n            commande.donneesIframe = {\r\n                AddNewRefInVosCampagnes: iframeData.AddNewRefInVosCampagnes,\r\n                Commande_Emplacement_Page_Web: iframeData.Commande_Emplacement_Page_Web,\r\n                Commande_Format_Transmis: iframeData.Commande_Format_Transmis,\r\n                EnvoiUlterieur: iframeData.EnvoiUlterieur,\r\n                FileReceived: iframeData.FileReceived,\r\n                codePage: iframeData.codePage,\r\n                LoadedPageUrl: iframeData.LoadedPageUrl,\r\n                Rank_Emplacement_Page_Web: iframeData.Rank_Emplacement_Page_Web,\r\n                FullPathAdFile: iframeData.FullPathAdFile,\r\n                Upload_File_Name: iframeData.Upload_File_Name,\r\n                EspPubLienAnnonce: iframeData.EspPubLienAnnonce\r\n            };\r\n            \r\n            \/\/ \u2705 CampagneEnvoiUlterieurClass \u2014 r\u00e8gle r\u00e9servation : ne pas changer le texte\r\n            \/\/    Le texte a \u00e9t\u00e9 d\u00e9fini lors du d\u00e9p\u00f4t (Annonce ins\u00e9r\u00e9e \/ Annonce \u00e0 transmettre...)\r\n            \/\/    On g\u00e8re uniquement la visibilit\u00e9\r\n            {\r\n                const _langF = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                const $_envoiF = $item.find('.CampagneEnvoiUlterieurClass');\r\n                const _isFileF = iframeData.FileReceived === 'Yes';\r\n                const _isDiffereF = iframeData.EnvoiUlterieur === 'true' || iframeData.EnvoiUlterieur === true;\r\n                var $_annonceDeposeF = $item.find('.CampagneAnnonceDeposeClass');\r\n                if (_isFileF && !_isDiffereF) {\r\n                    \/\/ Annonce d\u00e9pos\u00e9e \u2192 CampagneAnnonceDeposeClass, pas CampagneEnvoiUlterieurClass\r\n                    $_envoiF.hide();\r\n                    $_annonceDeposeF.show();\r\n                    console.log('\u2705 Fichier re\u00e7u \u2014 CampagneAnnonceDeposeClass affich\u00e9');\r\n                } else if (_isDiffereF) {\r\n                    const _existingTxt = $_envoiF.find('p').text().trim();\r\n                    if (!_existingTxt || _existingTxt === 'Annonce transmise') {\r\n                        $_envoiF.find('p').text(_langF === 'EN' ? 'Ad to be sent within 8 days of payment' : \"Annonce \u00e0 transmettre jusqu'\u00e0 8 jours apr\u00e8s paiement, un lien vous sera adress\u00e9 par contact@via-agency.media\");\r\n                    }\r\n                    $_envoiF.show();\r\n                    $_annonceDeposeF.hide();\r\n                    console.log('\ud83d\udce4 Envoi ult\u00e9rieur \u2014 CampagneEnvoiUlterieurClass affich\u00e9');\r\n                } else {\r\n                    $_envoiF.hide();\r\n                    $_annonceDeposeF.hide();\r\n                }\r\n            }\r\n            \r\n            if (!estDisponible) {\r\n                console.log('\ud83d\udeab Espace indisponible, pas de recalcul de tarif');\r\n                commande.disponibilite = false;\r\n                commande.statut = 'indisponible';\r\n                \/\/ \u2705 v2.1.2 : Sync sessionStorage M\u00caME si indisponible (pour restauration annonce)\r\n                if (window.VIA_Adaptateur) {\r\n                    window.VIA_Adaptateur.syncItemToSessionStorage(commande.id);\r\n                }\r\n                return;\r\n            }\r\n            \r\n            if (AND(nouveauFormat, AND(commande.dateDebut, AND(commande.dateFin, AND(commande.duree, commande.pays))))) {\r\n                \/\/ pb661 : verrou \"recalcul tarif en cours\". pb657 validait l'Etape 1 sur le\r\n                \/\/   tarif PERIME (herite du popup Tarifs) pendant que ce recalcul tournait :\r\n                \/\/   le vrai tarif arrivait apres -> setItemActif reaffichait l'Etape 1\r\n                \/\/   (fermeture puis reouverture). pb657 attend desormais ce verrou.\r\n                window._viaRecalcTarif661 = true;\r\n                console.log('\ud83d\udcb0 Recalcul du tarif avec nouveau format...');\r\n                \r\n                const country = window.VIA_Countries?.getCountryByLabel(commande.pays);\r\n                \r\n                if (AND(country, window.VIA_App)) {\r\n                    try {\r\n                        const resultat = await _proxyCalculerTarif(\r\n                            nouveauFormat,\r\n                            commande.position,\r\n                            commande.duree,\r\n                            country.code\r\n                        );\r\n                        \r\n                        if (resultat.success) {\r\n                            commande.tarifHT = resultat.tarif_ht;\r\n                            commande.tarifTTC = resultat.tarif_ttc;\r\n                            commande.statut = 'valide';\r\n                            \r\n                            console.log('\u2705 Tarif recalcul\u00e9:', resultat.tarif_ht, 'EUR');\r\n                            \r\n                            if (window.VIA_Panier) {\r\n                                window.VIA_Panier.rafraichirItemHTML(commande.id);\r\n                                window.VIA_Panier.calculerTotalPanier();\r\n                            }\r\n                            \r\n                            if (commande.id === window.VIA_Panier?.state.itemActif) {\r\n                                const devise = window.VIA_Panier.state.deviseAffichage || 'EUR';\r\n                                const montantConverti = devise === 'EUR' ? \r\n                                    resultat.tarif_ht : \r\n                                    window.VIA_App.convertirDevise(resultat.tarif_ht, 'EUR', devise);\r\n                                \r\n                                const tarifFormate = window.VIA_App.formaterMontant(montantConverti, devise, 2);\r\n                                \r\n                                $('#Tariftobedisplayed')\r\n                                    .html(tarifFormate)\r\n                                    .css('color', '#4B689B');\r\n                            }\r\n                        } else {\r\n                            console.warn('\u26a0\ufe0f Impossible de recalculer le tarif:', resultat.message);\r\n                        }\r\n                    } catch (error) {\r\n                        console.error('\u274c Erreur recalcul tarif:', error);\r\n                    }\r\n                }\r\n                \/\/ pb661 : fin du recalcul -> pb657 peut valider (voir pose ci-dessus).\r\n                window._viaRecalcTarif661 = false;\r\n            }\r\n            \r\n            if (window.VIA_Adaptateur) {\r\n                window.VIA_Adaptateur.syncItemToSessionStorage(commande.id);\r\n            }\r\n            \r\n            if (window.VIA_Panier) {\r\n                window.VIA_Panier.setItemActif(commande.id);\r\n            }\r\n            \r\n            console.log('\u2705 Commande mise \u00e0 jour:', commande.reference);\r\n        }        \r\n        \r\n        \/* ====================================================================\r\n         * pb1936 : LE CONTROLE DE DISPONIBILITE, EXPOSE.\r\n         *   Demande user : l'achat express ne verifie pas la disponibilite de\r\n         *   l'espace, alors que le process classique le fait (pb1597 -> pb1603).\r\n         *   Verifie : zero occurrence de verifierDisponibilite ni de\r\n         *   check-availability dans JS_Grille_tarifaire.txt.\r\n         *   Les trois fonctions restent DEFINIES ICI, et ici seulement. On les\r\n         *   expose, comme pb1640 l'a fait pour _vlpOpenColumn, pb1400 pour\r\n         *   _mode3col943 et pb1904 pour la famille de format : une seule\r\n         *   definition, plusieurs consommateurs. Reecrire l'appel a l'API dans la\r\n         *   grille aurait cree une seconde verite \u2014 et deux endroits ou corriger\r\n         *   le jour ou l'endpoint change.\r\n         *   L'appel reste sans effet quand l'emplacement est vide : la fonction\r\n         *   rend { available: true } des sa premiere ligne. Sur la regie express,\r\n         *   ou l'espace n'est choisi qu'ensuite dans le VLP, l'appel ne coute donc\r\n         *   rien et ne bloque rien.\r\n         * ==================================================================== *\/\r\n        \/* ====================================================================\r\n         * pb1939 : L'API ATTEND DE L'ISO. LE POINT EXPOSE NORMALISE.\r\n         *   Constat user, preuve a l'appui : un bon de commande couvre CMR48442L1A du\r\n         *   25\/09\/2026 au 09\/10\/2026, et le controle a rendu \u00ab disponible \u00bb pour\r\n         *   20\/09 -> 30\/09, qui chevauche pourtant.\r\n         *   La cause est le FORMAT. Tous les appelants du process classique\r\n         *   convertissent avant d'appeler \u2014 l.1270, l.1405 et l.2031 :\r\n         *       const debut = $.datepicker.formatDate('yy-mm-dd', STATE.startDate);\r\n         *   L'appel venu de la grille passait les valeurs BRUTES des champs, en\r\n         *   jj\/mm\/aaaa. check-availability.php ne trouve alors aucun chevauchement et\r\n         *   rend { available: true } : un faux \u00ab disponible \u00bb, silencieux, qui laisse\r\n         *   reserver un espace deja pris. Le pire genre de defaut.\r\n         *   ON NORMALISE ICI, dans le point d'entree partage, plutot que chez chaque\r\n         *   appelant : c'est le seul endroit ou tous passent, et un consommateur futur\r\n         *   heriterait sinon du meme piege. La conversion est IDEMPOTENTE \u2014 une date\r\n         *   deja en aaaa-mm-jj traverse sans etre touchee, donc les trois appelants\r\n         *   classiques gardent exactement leur comportement.\r\n         *   Un format non reconnu n'est PAS envoye : mieux vaut un avertissement\r\n         *   visible qu'un \u00ab disponible \u00bb faux. La fonction rend alors\r\n         *   { available: true } comme sur erreur reseau \u2014 mais la console le dit.\r\n         *   Revert : window._viaPb1939Off = true (transmission brute, comme avant).\r\n         * ==================================================================== *\/\r\n        function _isoDate1939(_v) {\r\n            var _s = String(_v || '').trim();\r\n            if (!_s) { return ''; }\r\n            if (\/^\\d{4}-\\d{2}-\\d{2}$\/.test(_s)) { return _s; }   \/* deja ISO *\/\r\n            var _m = _s.match(\/^(\\d{1,2})\\\/(\\d{1,2})\\\/(\\d{4})$\/);\r\n            if (!_m) { return null; }                              \/* inconnu *\/\r\n            return _m[3] + '-' + ('0' + _m[2]).slice(-2) + '-' + ('0' + _m[1]).slice(-2);\r\n        }\r\n\r\n        window._viaVerifierDispo1936 = function (emplacement, dateDebut, dateFin) {\r\n            if (window._viaPb1939Off === true) {\r\n                return verifierDisponibilite(emplacement, dateDebut, dateFin);\r\n            }\r\n            var _d1939 = _isoDate1939(dateDebut);\r\n            var _f1939 = _isoDate1939(dateFin);\r\n            if (_d1939 === null || _f1939 === null) {\r\n                console.warn('[pb1939] format de date non reconnu, contr\u00f4le ABANDONN\u00c9'\r\n                    + ' | debut=\"' + dateDebut + '\" fin=\"' + dateFin + '\"'\r\n                    + ' \u2014 attendu jj\/mm\/aaaa ou aaaa-mm-jj');\r\n                return Promise.resolve({ available: true });\r\n            }\r\n            if (_d1939 !== dateDebut || _f1939 !== dateFin) {\r\n                console.log('[pb1939] dates normalis\u00e9es pour l API | ' + dateDebut + '>' + dateFin\r\n                    + '  ->  ' + _d1939 + '>' + _f1939);\r\n            }\r\n            return verifierDisponibilite(emplacement, _d1939, _f1939);\r\n        };\r\n        window._viaAfficherIndispo1936 = function (prochaineDate) {\r\n            return afficherIndisponibilite(prochaineDate);\r\n        };\r\n        window._viaMasquerIndispo1936 = function () {\r\n            return masquerIndisponibilite();\r\n        };\r\n\r\n        async function verifierDisponibilite(emplacement, dateDebut, dateFin) {\r\n            if (!dateDebut || !dateFin || !emplacement) {\r\n                return { available: true };\r\n            }\r\n            \r\n            try {\r\n                const response = await fetch('https:\/\/via-agency.media\/wp-content\/plugins\/via-agency\/includes\/api\/check-availability.php', {\r\n                    method: 'POST',\r\n                    headers: { 'Content-Type': 'application\/json' },\r\n                    body: JSON.stringify({\r\n                        emplacement_page_web: emplacement,\r\n                        date_debut: dateDebut,\r\n                        date_fin: dateFin\r\n                    })\r\n                });\r\n                \r\n                return await response.json();\r\n            } catch (error) {\r\n                console.error('\u274c Erreur v\u00e9rification disponibilit\u00e9:', error);\r\n                return { available: true };\r\n            }\r\n        }\r\n        \r\n        function afficherIndisponibilite(prochaineDate) {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            \/* ====================================================================\r\n             * pb1940 : LE MESSAGE PASSE A DEUX LIGNES, DEUX COULEURS (demande user).\r\n             *   Ligne 1, rouge : le constat \u2014 l espace n est pas disponible.\r\n             *   Ligne 2, verte : la sortie \u2014 a partir de quand il le sera.\r\n             *   Separer le constat de la solution, et les distinguer par la couleur,\r\n             *   c est deja la convention du popup : rouge pour ce qui bloque\r\n             *   (#FB5E2A, pb1186 pour l etape active, pb1602 pour ce message meme),\r\n             *   vert pour ce qui est acquis (#3EAA13, les sous-titres de pb644). On\r\n             *   reprend ces deux teintes plutot que d en introduire de nouvelles.\r\n             *   Le conteneur garde sa couleur rouge : elle sert de repli si l une des\r\n             *   deux lignes perdait la sienne.\r\n             *   La date n est PAS mise en forme ici : elle arrive deja formatee du\r\n             *   serveur (next_available), et la reformater serait un second endroit ou\r\n             *   se tromper.\r\n             *   Le texte est injecte par .html() l.3250, qui accepte donc ce balisage\r\n             *   sans changement.\r\n             *   Revert : window._viaPb1940Off = true (ligne unique d origine).\r\n             * ==================================================================== *\/\r\n            var _msgL1_1940 = (lang === 'EN')\r\n                ? 'The advertising space is not available on the selected dates'\r\n                : 'L\\'espace publicitaire n\\'est pas disponible aux dates choisies';\r\n            var _msgL2_1940 = (lang === 'EN')\r\n                ? ('Please choose dates from ' + prochaineDate)\r\n                : ('Merci de choisir des dates \u00e0 partir du ' + prochaineDate);\r\n            const message = (window._viaPb1940Off === true)\r\n                ? (lang === 'EN'\r\n                    ? `The advertising space is available from ${prochaineDate}`\r\n                    : `L'espace publicitaire est disponible \u00e0 partir du ${prochaineDate}`)\r\n                : ('<div style=\"color:#FB5E2A;\">' + _msgL1_1940 + '<\/div>'\r\n                    + '<div style=\"color:#3EAA13;\">' + _msgL2_1940 + '<\/div>');\r\n            \r\n            \/* pb1600 : FORCER L'AFFICHAGE, .show() NE SUFFIT PAS.\r\n               Log user : \u00ab Espace indisponible, tarif masque | prochaine date :\r\n               01\/10\/2026 \u00bb \u2014 la detection fonctionne depuis pb1597 \u2014 puis\r\n               \u00ab masquerTarif() appelee \u00bb, \u00ab Dates masquees \u00bb, \u00ab Tarif masque \u00bb. Tout\r\n               s'execute, mais le message reste invisible.\r\n               .show() de jQuery pose display:'' : il ne peut pas battre un display:none\r\n               en !important, et ce fichier en compte plusieurs (pb1412 en pose cinq sur\r\n               les conteneurs voisins). On ecrit donc la propriete avec la meme priorite,\r\n               et on journalise l'etat rendu pour que l'echec ne puisse plus etre muet. *\/\r\n            \/* ============================================================\r\n             * pb1602 : LE CONTENEUR N'EXISTE PAS DANS LE POPUP \u2014 ON LE CREE.\r\n             *   Releve pb1600 : \u00ab rendu=ABSENT \u00bb. Le message n'etait pas masque, il\r\n             *   n'existait pas : #IndisponibilitesMsg appartient au gabarit de la regie\r\n             *   et n'est pas rendu dans le popup des sites pays. Toutes mes tentatives\r\n             *   d'affichage \u2014 .show(), display important, remontee au parent \u2014 visaient\r\n             *   un element inexistant.\r\n             *   On le cree donc a la volee, juste apres l'etape des dates, avec le meme\r\n             *   identifiant : le reste du code (pb603 pour la duree, masquerIndisponibilite)\r\n             *   continue de fonctionner sans changement.\r\n             *   Et surtout, demande explicite : l'utilisateur ne doit pas pouvoir\r\n             *   continuer. On neutralise le bouton Finaliser tant que l'espace est\r\n             *   indisponible ; masquerIndisponibilite le retablit.\r\n             *   Revert : window._viaPb1602Off = true.\r\n             * ============================================================ *\/\r\n            if (window._viaPb1602Off !== true) {\r\n                if (!document.getElementById('IndisponibilitesMsg')) {\r\n                    \/* pb1603 : DANS l'etape des dates, pas a cote.\r\n                       pb1602 inserait le message en FRERE de #ProcessDatesDeviseEtape.\r\n                       Il doit vivre DEDANS : c'est la que l'utilisateur vient de choisir\r\n                       ses dates, donc la que l'avertissement doit apparaitre \u2014 et il suit\r\n                       ainsi le sort de l'etape (ouverture, fermeture, marges) au lieu de\r\n                       flotter entre deux blocs. *\/\r\n                    \/* ============================================================\r\n                     * pb1936 : DANS LE POPUP PAYS, L'ETAPE DES DATES N'EST PAS CELLE-CI.\r\n                     *   pb1603 ancre le message dans #ProcessDatesDeviseEtape \u2014 l'etape\r\n                     *   des dates du process CLASSIQUE. Or pb1917 masque ce conteneur\r\n                     *   sur les sites pays, ou le catalogue tarifaire a pris la place du\r\n                     *   process : le message y serait cree dans un bloc invisible, et\r\n                     *   pb1600 journaliserait \u00ab hauteur=0 \u00bb sans que personne ne le voie.\r\n                     *   L'etape des dates y est #PopupTarifsDatesCampagnesContainer. On\r\n                     *   la place donc EN TETE de la liste d'ancrages, et seulement quand\r\n                     *   elle est effectivement rendue : hors popup pays elle est absente\r\n                     *   ou masquee, et la liste d'origine reprend la main sans changement.\r\n                     *   Meme principe que pb1603 : le message vit DANS l'etape que\r\n                     *   l'utilisateur vient de manipuler, pas a cote.\r\n                     *   Revert : window._viaPb1936Off = true.\r\n                     * ============================================================ *\/\r\n                    \/* ============================================================\r\n                      * pb1942 : \u00ab display \u00bb NE DIT PAS SI C'EST RENDU.\r\n                      *   Regression constatee sur la REGIE :\r\n                      *     [pb1603] #IndisponibilitesMsg cree DANS\r\n                      *              #PopupTarifsDatesCampagnesContainer | hauteur=0\r\n                      *   Le message a ete ancre dans l etape Dates du CATALOGUE alors\r\n                      *   qu on est dans le process classique, et il y est invisible.\r\n                      *   Ma garde testait getComputedStyle(...).display !== 'none'. Or\r\n                      *   le display CALCULE d un element ne devient pas 'none' parce qu un\r\n                      *   ANCETRE l est : il garde sa propre valeur declaree. Sur la regie,\r\n                      *   #popup3 est masque mais son etape Dates repond toujours 'flex'.\r\n                      *   Le test paraissait mesurer la visibilite ; il ne mesurait que la\r\n                      *   declaration.\r\n                      *   La boite rendue, elle, ne ment pas : un element sous un ancetre\r\n                      *   masque a une largeur de 0. C est la meme lecon que pb1934c, deux\r\n                      *   tours plus tot \u2014 un etat logique ne prouve pas un etat rendu \u2014 et\r\n                      *   que pb1785 : mesurer ce qui SORT.\r\n                      *   Regie : popup Tarifs masque -> largeur 0 -> on retombe sur\r\n                      *   #ProcessDatesDeviseEtape, comportement d origine retabli.\r\n                      *   Sites pays : catalogue affiche -> largeur > 0 -> ancrage dans le\r\n                      *   catalogue, comme voulu.\r\n                      * ============================================================ *\/\r\n                    var _ancX1936 = null;\r\n                    if (window._viaPb1936Off !== true) {\r\n                        var _cd1936 = document.getElementById('PopupTarifsDatesCampagnesContainer');\r\n                        if (_cd1936) {\r\n                            var _w1942 = _cd1936.getBoundingClientRect().width;\r\n                            if (_w1942 > 0) {\r\n                                _ancX1936 = _cd1936;\r\n                            } else {\r\n                                console.log('[pb1942] \u00e9tape Dates du catalogue non rendue'\r\n                                    + ' (largeur ' + Math.round(_w1942) + ') -> ancrage sur'\r\n                                    + ' le process classique');\r\n                            }\r\n                        }\r\n                    }\r\n                    var _anc1602 = _ancX1936\r\n                        || document.getElementById('ProcessDatesDeviseEtape')\r\n                        || document.getElementById('FormatContainer')\r\n                        || document.getElementById('ColonneGauche');\r\n                    if (_anc1602) {\r\n                        var _box1602 = document.createElement('div');\r\n                        _box1602.id = 'IndisponibilitesMsg';\r\n                        _box1602.setAttribute('data-via1602', 'cree');\r\n                        \/* pb1606b : ni fond ni lisere (demande user) \u2014 le message se\r\n                           signale par sa couleur et sa graisse, comme les autres\r\n                           avertissements du process. *\/\r\n                        _box1602.style.cssText = 'display:block;width:100%;box-sizing:border-box;'\r\n                            + 'margin:8px 0;color:#FB5E2A;'\r\n                            \/* pb1940 : 14px au lieu de 15 (demande user) \u2014 le message\r\n                               occupe desormais deux lignes, il pesait trop. *\/\r\n                            + 'font-family:Roboto,sans-serif;'\r\n                            + 'font-size:' + ((window._viaPb1940Off === true) ? '15' : '14') + 'px;'\r\n                            + 'font-weight:600;'\r\n                            + 'text-align:center;';\r\n                        var _txt1602 = document.createElement('div');\r\n                        _txt1602.id = 'IndisponibilitesMsgText';\r\n                        _box1602.appendChild(_txt1602);\r\n                        _anc1602.appendChild(_box1602);   \/* pb1603 : DANS l'etape *\/\r\n                        console.log('[pb1603] #IndisponibilitesMsg cree DANS #' + _anc1602.id\r\n                            + ' | parent display=' + window.getComputedStyle(_anc1602).display\r\n                            + ' | rendu=' + window.getComputedStyle(_box1602).display\r\n                            + ' | hauteur=' + Math.round(_box1602.getBoundingClientRect().height));\r\n                    } else {\r\n                        console.warn('[pb1602] aucun point d ancrage trouve pour creer le message');\r\n                    }\r\n                }\r\n                \/* Blocage de la progression tant que l'espace est indisponible. *\/\r\n                \/* pb1603c : un avertissement place dans une etape FERMEE ne se verrait\r\n                   pas. On ouvre l'etape des dates si elle est repliee \u2014 c'est celle que\r\n                   l'utilisateur vient de manipuler. *\/\r\n                \/* ====================================================================\r\n                 * pb1946 : ON N'OUVRE QUE L'ETAPE QUI PORTE LE MESSAGE.\r\n                 *   Constat user, sites pays mobile : l etape Dates du process CLASSIQUE\r\n                 *   reapparait en haut, dupliquant celle du catalogue.\r\n                 *   C est ce bloc qui la revele. pb1603c ouvre #ProcessDatesDeviseEtape\r\n                 *   \u00ab pour montrer l avertissement \u00bb \u2014 vrai sur la regie, ou le message y\r\n                 *   est ancre. Sur les sites pays, depuis pb1936\/pb1942, il est ancre\r\n                 *   dans #PopupTarifsDatesCampagnesContainer : ouvrir l etape classique\r\n                 *   n y montre rien, et defait le masquage de pb1917.\r\n                 *   Et elle le defait forcement : pb1917 masque par FEUILLE, ce bloc\r\n                 *   ecrit un display inline en !important \u2014 \u00ab une feuille !important perd\r\n                 *   contre un inline !important \u00bb, c est la regle du projet, et elle joue\r\n                 *   ici contre nous.\r\n                 *   Le critere juste n est pas \u00ab quelle etape \u00bb, c est \u00ab laquelle PORTE le\r\n                 *   message \u00bb \u2014 et ca se constate : _etD1603.contains(#IndisponibilitesMsg).\r\n                 *   Un fait, pas une supposition sur le contexte.\r\n                 *   Regie : le message est bien dans cette etape -> elle s ouvre comme\r\n                 *   avant. Sites pays : il est ailleurs -> on n y touche pas, et pb1917\r\n                 *   garde la main.\r\n                 *   Revert : window._viaPb1946Off = true (ouverture inconditionnelle).\r\n                 * ==================================================================== *\/\r\n                var _etD1603 = document.getElementById('ProcessDatesDeviseEtape');\r\n                var _porte1946 = false;\r\n                if (_etD1603) {\r\n                    if (window._viaPb1946Off === true) {\r\n                        _porte1946 = true;\r\n                    } else {\r\n                        var _msg1946 = document.getElementById('IndisponibilitesMsg');\r\n                        _porte1946 = _msg1946 ? _etD1603.contains(_msg1946) : false;\r\n                        if (!_porte1946) {\r\n                            if (window._viaSig1946 !== 'ailleurs') {\r\n                                window._viaSig1946 = 'ailleurs';\r\n                                console.log('[pb1946] le message n est PAS dans'\r\n                                    + ' #ProcessDatesDeviseEtape -> \u00e9tape classique laiss\u00e9e'\r\n                                    + ' masqu\u00e9e (elle est remplac\u00e9e par le catalogue)');\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n                if (_porte1946 ? (window.getComputedStyle(_etD1603).display === 'none') : false) {\r\n                    _etD1603.style.setProperty('display', 'flex', 'important');\r\n                    console.log('[pb1603] etape des dates rouverte pour montrer l avertissement');\r\n                }\r\n                var _cl1603 = _porte1946\r\n                    ? document.querySelector('.ProcessDatesDeviseConteneurClass')\r\n                    : null;\r\n                if (_cl1603 ? (window.getComputedStyle(_cl1603).display === 'none') : false) {\r\n                    _cl1603.style.setProperty('display', 'block', 'important');\r\n                }\r\n                var _fin1602 = document.querySelector('.FinaliserBouton');\r\n                if (_fin1602) {\r\n                    _fin1602.setAttribute('data-via1602-bloque', '1');\r\n                    _fin1602.style.setProperty('pointer-events', 'none', 'important');\r\n                    _fin1602.style.setProperty('opacity', '0.45', 'important');\r\n                    _fin1602.style.setProperty('cursor', 'not-allowed', 'important');\r\n                }\r\n                var _cb1602 = document.getElementById('ReserverCheckbox')\r\n                    || document.querySelector('.ReserverCheckbox input[type=\"checkbox\"]');\r\n                if (_cb1602) { _cb1602.disabled = true; }\r\n                console.log('[pb1602] progression bloquee : espace indisponible'\r\n                    + (_fin1602 ? '' : ' (bouton Finaliser introuvable)'));\r\n            }\r\n            $('#IndisponibilitesMsg').show();\r\n            var _im1600 = document.getElementById('IndisponibilitesMsg');\r\n            if (_im1600) {\r\n                _im1600.style.setProperty('display', 'block', 'important');\r\n                _im1600.style.setProperty('visibility', 'visible', 'important');\r\n                var _p1600 = _im1600.parentElement;\r\n                if (_p1600) {\r\n                    if (window.getComputedStyle(_p1600).display === 'none') {\r\n                        _p1600.style.setProperty('display', 'block', 'important');\r\n                    }\r\n                }\r\n            }\r\n            $('#IndisponibilitesMsgText').html(message);\r\n            var _t1600 = document.getElementById('IndisponibilitesMsgText');\r\n            if (_t1600) { _t1600.style.setProperty('display', 'block', 'important'); }\r\n            console.log('[pb1600] message d indisponibilite | rendu='\r\n                + (_im1600 ? window.getComputedStyle(_im1600).display : 'ABSENT')\r\n                + ' | visibilite=' + (_im1600 ? window.getComputedStyle(_im1600).visibility : '-')\r\n                + ' | hauteur=' + (_im1600 ? Math.round(_im1600.getBoundingClientRect().height) : '-')\r\n                + ' | texte=\"' + message + '\"');\r\n            \r\n            $('#MsgSelectEspace').hide();\r\n            \r\n            if (AND(window.VIA_Panier, window.VIA_Panier.state.itemActif)) {\r\n                window.VIA_Panier.rafraichirItemHTML(window.VIA_Panier.state.itemActif);\r\n            }\r\n        }\r\n        \r\n        function masquerIndisponibilite() {\r\n            \/\/ pb603 : le conteneur est PARTAGE. S'il porte encore le message de duree\r\n            \/\/   minimale, on ne le cache pas \u2014 sinon l'espace redevenu disponible ferait\r\n            \/\/   disparaitre un avertissement toujours valable.\r\n            if (window._viaDureeInvalide603 ? false : true) { $('#IndisponibilitesMsg').hide(); }\r\n            \/* pb1602b : symetrie \u2014 rendre la progression des que l'espace redevient\r\n               disponible. Sans cela, un blocage pose une fois ne se leverait jamais. *\/\r\n            if (window._viaPb1602Off !== true) {\r\n                var _fin1602b = document.querySelector('.FinaliserBouton[data-via1602-bloque]');\r\n                if (_fin1602b) {\r\n                    _fin1602b.removeAttribute('data-via1602-bloque');\r\n                    _fin1602b.style.removeProperty('pointer-events');\r\n                    _fin1602b.style.removeProperty('opacity');\r\n                    _fin1602b.style.removeProperty('cursor');\r\n                    console.log('[pb1602] progression retablie : espace disponible');\r\n                }\r\n                var _cb1602b = document.getElementById('ReserverCheckbox')\r\n                    || document.querySelector('.ReserverCheckbox input[type=\"checkbox\"]');\r\n                if (_cb1602b) { _cb1602b.disabled = false; }\r\n            }\r\n            \r\n            if (AND(window.VIA_Panier, window.VIA_Panier.state.itemActif)) {\r\n                const item = window.VIA_Panier.state.items.find(i => i.id === window.VIA_Panier.state.itemActif);\r\n                if (item) {\r\n                    item.disponibilite = true;\r\n                    item.statut = 'en_cours';\r\n                    \r\n                    window.VIA_Panier.rafraichirItemHTML(item.id);\r\n                }\r\n            }\r\n        }\r\n\r\n        \/**\r\n         * \u2705 v3.4 : Fonction robuste de cr\u00e9ation d'item avec anti-doublon\r\n         *\/\r\n        async function creerItemPanier(donnees, tentative = 0, estDisponible = true) {\r\n            const MAX_TENTATIVES = 5;\r\n            const DELAI_RETRY = 500;\r\n            \r\n            if (typeof window.VIA_Panier === 'undefined') {\r\n                if (tentative < MAX_TENTATIVES) {\r\n                    console.warn(`\u26a0\ufe0f VIA_Panier non disponible, retry dans ${DELAI_RETRY}ms...`);\r\n                    setTimeout(() => creerItemPanier(donnees, tentative + 1, estDisponible), DELAI_RETRY);\r\n                } else {\r\n                    console.error('\u274c VIA_Panier toujours indisponible apr\u00e8s 5 tentatives');\r\n                    alert('Erreur: Le gestionnaire de panier n\\'est pas charg\u00e9. Veuillez recharger la page.');\r\n                }\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v3.4 : ANTI-DOUBLON GLOBAL\r\n            const emplacementActuel = donnees.Commande_Emplacement_Page_Web;\r\n            if (emplacementActuel) {\r\n                const maintenant = Date.now();\r\n                const dernierTraitement = ANTI_DOUBLON.derniersTraitements['create_' + emplacementActuel];\r\n                \r\n                if (dernierTraitement && (maintenant - dernierTraitement) < ANTI_DOUBLON.DELAI_MS) {\r\n                    console.log('\u26a0\ufe0f ANTI-DOUBLON: Cr\u00e9ation ignor\u00e9e (trait\u00e9e il y a moins de 2s):', emplacementActuel);\r\n                    return;\r\n                }\r\n                ANTI_DOUBLON.derniersTraitements['create_' + emplacementActuel] = maintenant;\r\n            }\r\n            \r\n            \/\/ \u2705 CAS 1 : D\u00e9placement d'annonce\r\n            if (AND(donnees.FirstUploadFileorMoved === 'Moved', donnees.dragstart_Commande_Emplacement_Page_Web)) {\r\n                console.log('\ud83d\udd04 D\u00e9placement d\\'annonce d\u00e9tect\u00e9');\r\n                \r\n                const ancienEmplacement = donnees.dragstart_Commande_Emplacement_Page_Web;\r\n                const nouvelEmplacement = donnees.Commande_Emplacement_Page_Web;\r\n                \r\n                const commandeExistante = window.VIA_Panier.state.items.find(\r\n                    i => i.emplacementPageWeb === ancienEmplacement\r\n                );\r\n                \r\n                if (commandeExistante) {\r\n                    console.log('\u2705 Commande trouv\u00e9e, mise \u00e0 jour:', commandeExistante.reference);\r\n                    window.VIA_Panier.deplacerAnnonce(commandeExistante.id, donnees);\r\n                    return;\r\n                } else {\r\n                    console.warn('\u26a0\ufe0f Commande source introuvable, cr\u00e9ation nouvelle commande');\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 CAS 2 : V\u00e9rifier si item existe d\u00e9j\u00e0\r\n            if (window.VIA_Panier.state) {\r\n                const itemExistant = window.VIA_Panier.state.items.find(\r\n                    i => i.emplacementPageWeb === donnees.Commande_Emplacement_Page_Web\r\n                );\r\n                \r\n                if (itemExistant) {\r\n                    console.log('\u26a0\ufe0f Item d\u00e9j\u00e0 cr\u00e9\u00e9 pour cet espace:', itemExistant.reference);\r\n                    window.VIA_Panier.setItemActif(itemExistant.id);\r\n                    return;\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 CAS 3 : Cr\u00e9ation normale\r\n            console.log(`\ud83d\uded2 Tentative ${tentative + 1}\/${MAX_TENTATIVES} de cr\u00e9ation d'item panier...`);\r\n            \r\n            \/\/ \u2705 v3.4 : R\u00c9INITIALISER avant cr\u00e9ation\r\n            if (AND(window.VIA_App, window.VIA_App.state)) {\r\n                window.VIA_App.state.dernierResultatCalcul = null;\r\n                console.log('\ud83d\udd04 Dernier r\u00e9sultat de calcul r\u00e9initialis\u00e9 (avant cr\u00e9ation)');\r\n            }\r\n            \r\n            try {\r\n                const donneesCompletes = {\r\n                    ...donnees,\r\n                    lienEspacePub: STATE.lienEspacePub,\r\n                    cheminFichierAnnonce: STATE.cheminFichierAnnonce,\r\n                    skipTarifCalculation: !estDisponible\r\n                };\r\n                \r\n                console.log('\ud83d\udce6 Donn\u00e9es compl\u00e8tes avec lien:', {\r\n                    lien: donneesCompletes.lienEspacePub,\r\n                    fichier: donneesCompletes.cheminFichierAnnonce,\r\n                    emplacement: donneesCompletes.Commande_Emplacement_Page_Web,\r\n                    skipTarif: donneesCompletes.skipTarifCalculation\r\n                });\r\n                \r\n                const nouvelItem = await window.VIA_Panier.creerNouvelItem(donneesCompletes);\r\n                \r\n                if (nouvelItem) {\r\n                    console.log('\u2705 Item cr\u00e9\u00e9 avec succ\u00e8s:', nouvelItem.reference);\r\n                    console.log('\ud83d\udd17 Lien enregistr\u00e9:', nouvelItem.lienEspacePub);\r\n                    \r\n                    if (!estDisponible) {\r\n                        nouvelItem.disponibilite = false;\r\n                        nouvelItem.statut = 'indisponible';\r\n                        console.log('\ud83d\udeab Item marqu\u00e9 comme indisponible');\r\n                    }\r\n                } else {\r\n                    console.error('\u274c \u00c9chec de la cr\u00e9ation d\\'item (retour null)');\r\n                    if (tentative < MAX_TENTATIVES) {\r\n                        setTimeout(() => creerItemPanier(donnees, tentative + 1, estDisponible), DELAI_RETRY);\r\n                    }\r\n                }\r\n            } catch (error) {\r\n                console.error('\u274c Erreur lors de la cr\u00e9ation d\\'item:', error);\r\n                if (tentative < MAX_TENTATIVES) {\r\n                    setTimeout(() => creerItemPanier(donnees, tentative + 1, estDisponible), DELAI_RETRY);\r\n                } else {\r\n                    alert('Erreur lors de la cr\u00e9ation de la campagne. Veuillez r\u00e9essayer.');\r\n                }\r\n            }\r\n        }\r\n        \r\n        \/\/ ================================================================\r\n        \/\/ pb2135 : Z-INDEX DU MENU CLIENTS \u2014 DELEGATION autocompleteopen.\r\n        \/\/   Constat JF : FORM-pb2133 SERVI, menu fonctionnel, mais AUCUNE ligne\r\n        \/\/   [pb2131] (ni succes ni warn) -> le handler open: de NOS options\r\n        \/\/   n'est jamais execute : l'autocomplete actif sur le champ n'a pas\r\n        \/\/   ete initialise par setupClientAutocomplete (initialiseur externe\r\n        \/\/   possible : main.js du plugin, hors corpus). Doctrine pb2126 :\r\n        \/\/   delegation par NAME au niveau document \u2014 l'evenement jQuery UI\r\n        \/\/   'autocompleteopen' bulle depuis l'input, quel que soit\r\n        \/\/   l'initialiseur et quelle que soit l'instance. Sonde integree :\r\n        \/\/   nombre d'instances du champ et hauteur de celle qui ouvre.\r\n        \/\/   Pose au document, une fois, hors de setupClientAutocomplete (qui\r\n        \/\/   peut sortir tot sans log). Revert : window._viaPb2135Off = true.\r\n        \/\/ ================================================================\r\n        $(document).on('autocompleteopen', 'input[name=\"form_fields[RechercherFicheClient]\"]', function () {\r\n            try {\r\n                if (window._viaPb2135Off === true) { return; }\r\n                var _menu2135 = $(this).autocomplete('widget')[0];\r\n                if (!_menu2135) { console.warn('[pb2135] widget introuvable'); return; }\r\n                var _max2135 = 0;\r\n                var _cands2135 = document.querySelectorAll('.via-link-popup, #popup3, .elementor-popup-modal, [id^=\"via-col-\"]');\r\n                for (var _i2135 = 0; _i2135 < _cands2135.length; _i2135++) {\r\n                    var _e2135 = _cands2135[_i2135];\r\n                    if (_e2135.getBoundingClientRect().height < 5) { continue; }\r\n                    var _z2135 = parseInt(getComputedStyle(_e2135).zIndex, 10);\r\n                    if (_z2135 > _max2135) { _max2135 = _z2135; }\r\n                }\r\n                var _cible2135 = (_max2135 > 0) ? (_max2135 + 10) : 100000010;\r\n                _menu2135.style.setProperty('z-index', String(_cible2135), 'important');\r\n                var _all2135 = document.querySelectorAll('input[name=\"form_fields[RechercherFicheClient]\"]');\r\n                console.log('[pb2135] menu clients -> z=' + _cible2135\r\n                    + ' | max popups=' + _max2135\r\n                    + ' | instances champ=' + _all2135.length\r\n                    + ' | h(input ouvrant)=' + Math.round(this.getBoundingClientRect().height));\r\n            } catch (_e2135b) { console.warn('[pb2135]', _e2135b.message); }\r\n        });\r\n\r\n        function setupClientAutocomplete() {\r\n            const $rechercheInput = $('#form-field-RechercherFicheClient');\r\n            \r\n            if ($rechercheInput.length === 0) {\r\n                console.warn('\u26a0\ufe0f Champ recherche client introuvable');\r\n                return;\r\n            }\r\n        \r\n            const commercialId = sessionStorage.getItem('CommercialId');\r\n            \r\n            if (!commercialId) {\r\n                console.warn('\u26a0\ufe0f ID commercial manquant');\r\n                return;\r\n            }\r\n        \r\n            $rechercheInput.autocomplete({\r\n                source: function(request, response) {\r\n                    const term = request.term.trim();\r\n                    \r\n                    if (term.length < 2) {\r\n                        response([]);\r\n                        return;\r\n                    }\r\n        \r\n                    $.ajax({\r\n                        url: API_CLIENTS.url,\r\n                        type: 'GET',\r\n                        data: {\r\n                            action: 'search',\r\n                            commercial_id: commercialId,\r\n                            search: term\r\n                        },\r\n                        success: function(responseText, status, xhr) {\r\n                            console.log('\ud83d\udce1 R\u00e9ponse brute API:', responseText);\r\n                            \r\n                            let data;\r\n                            try {\r\n                                if (typeof responseText === 'object') {\r\n                                    data = responseText;\r\n                                } else {\r\n                                    data = JSON.parse(responseText);\r\n                                }\r\n                                \r\n                                console.log('\u2705 Donn\u00e9es pars\u00e9es:', data);\r\n                                \r\n                                if (data.clients.length > 0) {\r\n                                    const results = data.clients.map(client => ({\r\n                                        label: client.nom_societe,\r\n                                        value: client.nom_societe,\r\n                                        data: client\r\n                                    }));\r\n                                    response(results);\r\n                                } else {\r\n                                    console.log('\u26a0\ufe0f Aucun client trouv\u00e9');\r\n                                    response([]);\r\n                                }\r\n                            } catch (e) {\r\n                                console.error('\u274c R\u00e9ponse API invalide (pas du JSON):', e);\r\n                                console.error('Contenu re\u00e7u:', responseText.substring(0, 500));\r\n                                response([]);\r\n                            }\r\n                        },\r\n                        error: function(xhr, status, error) {\r\n                            console.error('\u274c Erreur AJAX:', {\r\n                                status: xhr.status,\r\n                                statusText: xhr.statusText,\r\n                                error: error,\r\n                                responseText: xhr.responseText ? xhr.responseText.substring(0, 200) : 'vide'\r\n                            });\r\n                            response([]);\r\n                        }\r\n                    });\r\n                },\r\n                minLength: 2,\r\n                delay: 300,\r\n                appendTo: 'body',\r\n                select: function(event, ui) {\r\n                    console.log('\u2705 Client s\u00e9lectionn\u00e9:', ui.item.data);\r\n                    remplirFormulaireClient(ui.item.data);\r\n                    return true;\r\n                },\r\n                \/\/ ================================================================\r\n                \/\/ pb2131 : la liste s'affichait SOUS #via-col-ColonneDroite\r\n                \/\/   (constat JF, capture desktop). Meme defaut et meme remede que\r\n                \/\/   pb791 sur le champ pays : le menu est dans le body, les popups\r\n                \/\/   en fixed avec des z-index qui montent au bring-to-front (base\r\n                \/\/   1e7, process a 2e7) \u2014 la feuille .ui-autocomplete a 9999 perd.\r\n                \/\/   Valeur CALCULEE a chaque ouverture sur les popups reellement\r\n                \/\/   affiches (hauteur > 5, regle des instances masquees), jamais\r\n                \/\/   codee en dur. Candidats = ceux de pb791 + [id^=\"via-col-\"].\r\n                \/\/   Revert : window._viaPb2131Off = true.\r\n                \/\/ ================================================================\r\n                open: function() {\r\n                    try {\r\n                        if (window._viaPb2131Off === true) { return; }\r\n                        var _menu2131 = $rechercheInput.autocomplete('widget')[0];\r\n                        if (!_menu2131) { console.warn('[pb2131] widget introuvable'); return; }\r\n                        var _max2131 = 0;\r\n                        var _cands2131 = document.querySelectorAll('.via-link-popup, #popup3, .elementor-popup-modal, [id^=\"via-col-\"]');\r\n                        for (var _i2131 = 0; _i2131 < _cands2131.length; _i2131++) {\r\n                            var _e2131 = _cands2131[_i2131];\r\n                            if (_e2131.getBoundingClientRect().height < 5) { continue; }\r\n                            var _z2131 = parseInt(getComputedStyle(_e2131).zIndex, 10);\r\n                            if (_z2131 > _max2131) { _max2131 = _z2131; }\r\n                        }\r\n                        var _cible2131 = (_max2131 > 0) ? (_max2131 + 10) : 9999;\r\n                        _menu2131.style.setProperty('z-index', String(_cible2131), 'important');\r\n                        if (window._viaSigZ2131 !== _cible2131) {\r\n                            window._viaSigZ2131 = _cible2131;\r\n                            console.log('[pb2131] z-index du menu clients -> ' + _cible2131\r\n                                + ' (max des popups affiches : ' + _max2131 + ')');\r\n                        }\r\n                    } catch (_e2131b) { console.warn('[pb2131] open:', _e2131b.message); }\r\n                }\r\n            });\r\n        \r\n            console.log('\u2705 Autocomplete clients configur\u00e9 (avec parsing manuel)');\r\n        }\r\n        \r\n        function updateHiddenField(fieldId, value) {\r\n            let $field = $('#' + fieldId);\r\n\r\n            if ($field.length === 0) {\r\n                $field = $('<input type=\"hidden\">');\r\n                $field.attr('id', fieldId);\r\n                $field.attr('name', fieldId);\r\n                $('body').append($field);\r\n            }\r\n\r\n            $field.val(value || '');\r\n        }\r\n\r\n        function afficherNotificationEspace(id, format, position) {\r\n            let $notifContainer = $('#espace-notification');\r\n\r\n            if ($notifContainer.length === 0) {\r\n                const $firstField = $('.elementor-field-group').first();\r\n                if ($firstField.length > 0) {\r\n                    $notifContainer = $('<div id=\"espace-notification\" style=\"margin-bottom: 20px;\"><\/div>');\r\n                    $firstField.before($notifContainer);\r\n                } else {\r\n                    return;\r\n                }\r\n            }\r\n\r\n            $notifContainer.html(`\r\n                <div style=\"background: #e8f5e9; border-left: 4px solid #00fa19; padding: 16px; border-radius: 6px;\">\r\n                    <div style=\"color: #2e7d32; font-weight: 600; margin-bottom: 8px;\">\r\n                        \u2713 Espace publicitaire s\u00e9lectionn\u00e9\r\n                    <\/div>\r\n                    <div style=\"display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; font-size: 13px;\">\r\n                        <div>\r\n                            <div style=\"color: #1b5e20; font-weight: 500;\">ID<\/div>\r\n                            <div style=\"color: #2e7d32;\">${id}<\/div>\r\n                        <\/div>\r\n                        <div>\r\n                            <div style=\"color: #1b5e20; font-weight: 500;\">Format<\/div>\r\n                            <div style=\"color: #2e7d32;\">${format}<\/div>\r\n                        <\/div>\r\n                        <div>\r\n                            <div style=\"color: #1b5e20; font-weight: 500;\">Position<\/div>\r\n                            <div style=\"color: #2e7d32;\">${position}<\/div>\r\n                        <\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            `);\r\n        }\r\n\r\n        function initGestionVosCommandes() {\r\n            $('.RecapitulatifVosCommandestitre').on('click', function(event) {\r\n                event.preventDefault();\r\n                if ($('.VosCampagnesConteneurClass').is(':hidden')) {\r\n                    $('.VosCampagnesConteneurClass, #PayableText').show();\r\n                    $('#RecapitulatifVosCommandesIconeUp').show();\r\n                    $('#RecapitulatifVosCommandesIconeDown').hide();\r\n                } else {\r\n                    $('.VosCampagnesConteneurClass, #PayableText').hide();\r\n                    $('#RecapitulatifVosCommandesIconeUp').hide();\r\n                    $('#RecapitulatifVosCommandesIconeDown').show();\r\n                }\r\n            });\r\n            console.log('\u2705 Gestion Vos Commandes initialis\u00e9e');\r\n        }\r\n        \r\n        function initGestionReferences() {\r\n            $('.ReferencesTitre').on('click', function(event) {\r\n                event.preventDefault();\r\n                \r\n                \/\/ \u2705 v1.8 : Bloquer si bon de commande cr\u00e9\u00e9\r\n                if (window.VIA_Panier && window.VIA_Panier.verifierBonCommandeCreeLock()) {\r\n                    return;\r\n                }\r\n                \r\n                if ($('.ReferencesConteneur').is(':hidden')) {\r\n                    $('.ReferencesConteneur').show();\r\n                    $('#ReferencesTitreIconeUp').show();\r\n                    $('#ReferencesTitreIconeDown').hide();\r\n                } else {\r\n                    $('.ReferencesConteneur').hide();\r\n                    $('#ReferencesTitreIconeUp').hide();\r\n                    $('#ReferencesTitreIconeDown').show();\r\n                }\r\n            });\r\n            console.log('\u2705 Gestion References initialis\u00e9e');\r\n        }\r\n        \r\n        function initGestionChoisirPaiement() {\r\n            $('.ChoisirPaiementTitre').on('click', function(event) {\r\n                event.preventDefault();\r\n                \r\n                \/\/ \u2705 v1.8 : Bloquer si bon de commande cr\u00e9\u00e9\r\n                if (window.VIA_Panier && window.VIA_Panier.verifierBonCommandeCreeLock()) {\r\n                    return;\r\n                }\r\n                \r\n                if ($('#ChoisirPaiement').is(':hidden')) {\r\n                    $('.ChoisirPaiementClass').show();\r\n                    $('#ChoisirPaiementTitreIconeUp').show();\r\n                    $('#ChoisirPaiementTitreIconeDown').hide();\r\n                } else {\r\n                    $('.ChoisirPaiementClass').hide();\r\n                    $('#ChoisirPaiementTitreIconeUp').hide();\r\n                    $('#ChoisirPaiementTitreIconeDown').show();\r\n                }\r\n            });\r\n            console.log('\u2705 Gestion ChoisirPaiement initialis\u00e9e');\r\n        }\r\n        \r\n        function initGestionRecapitulatif() {\r\n            $('.ValidationsTitre').on('click', function(event) {\r\n                event.preventDefault();\r\n                if ($('#ValidationsConteneur').is(':hidden')) {\r\n                    $('#ValidationsConteneur').show();\r\n                    $('#ValidationsTitreIconeUp').show();\r\n                    $('#ValidationsTitreIconeDown').hide();\r\n                } else {\r\n                    $('#ValidationsConteneur').hide();\r\n                    $('#ValidationsTitreIconeUp').hide();\r\n                    $('#ValidationsTitreIconeDown').show();\r\n                }\r\n            });\r\n            console.log('\u2705 Gestion Recapitulatif initialis\u00e9e');\r\n        }\r\n        \r\n        function initGestionProcederPaiement() {\r\n            $('.ProcederPaiementTitre').on('click', function(event) {\r\n                event.preventDefault();\r\n                \r\n                \/\/ \u2705 v1.9 : V\u00e9rifier si l'\u00e9tape est active\r\n                if ($(this).attr('data-etape-active') === 'false') {\r\n                    console.log('\ud83d\udd12 ProcederPaiementTitre d\u00e9sactiv\u00e9, clic ignor\u00e9');\r\n                    return;\r\n                }\r\n                \r\n                if ($('#ProcederPaiementConteneur').is(':hidden')) {\r\n                    $('#ProcederPaiementConteneur').show();\r\n                    $('#ProcederPaiementTitre').show();\r\n                    $('#ProcederPaiementTitreIconeUp').show();\r\n                    $('#ProcederPaiementTitreIconeDown').hide();\r\n                    \r\n                    \/\/ \u2705 v2.0 : Scroll to bottom dans #ColonneDroite apr\u00e8s ouverture Paiement\r\n                    setTimeout(function() {\r\n                        \/* ====================================================================\r\n                         * pb2354 : UN SEUL DEFILEMENT VERS LE BAS, PARTAGE PAR LES QUATRE APPELS.\r\n                         *   pb2353 a etabli la cause sur un site : le code visait #ColonneDroite,\r\n                         *   qui ne defile pas \u2014 le piege pb1895 montrait une animation dont les\r\n                         *   pas valaient 0,016 px, donc une cible de zero. Le defileur reel est\r\n                         *   .via-col-popup-body (overflow:hidden auto).\r\n                         *   Les trois autres appels sont byte-identiques a celui qui echouait, et\r\n                         *   ils se declenchent sur des CHEMINS DIFFERENTS : ouvrir l etape en\r\n                         *   cliquant le titre passe par Formulaire, pas par Validations. Le meme\r\n                         *   geste marchait ou non selon le chemin.\r\n                         *   Les corriger en recopiant la solution serait refaire la faute que\r\n                         *   pb2346 vient de payer : quatre copies divergent, et l une se fait\r\n                         *   oublier. La fonction est donc definie UNE fois, par le premier fichier\r\n                         *   charge, et les quatre l appellent. Aucun ordre de chargement a tenir.\r\n                         *   Elle cherche le defileur au lieu de le nommer, et attend qu il y ait\r\n                         *   quelque chose a defiler \u2014 un delai fixe ne sait pas quand la mise en\r\n                         *   page est posee.\r\n                         *   Reglages : _viaPb2353Max (1500), _viaPb2353Duree (300).\r\n                         *   Revert : _viaPb2353Off = true -> ancien comportement (#ColonneDroite).\r\n                         * ==================================================================== *\/\r\n                        if (typeof window._viaScrollBas2354 !== 'function') {\r\n                            window._viaScrollBas2354 = function (_origine) {\r\n                                var _dur = (typeof window._viaPb2353Duree === 'number') ? window._viaPb2353Duree : 300;\r\n                                if (window._viaPb2353Off === true) {\r\n                                    var $_cd = jQuery('#ColonneDroite');\r\n                                    if ($_cd.length) { $_cd.animate({ scrollTop: $_cd[0].scrollHeight }, _dur); }\r\n                                    console.log('[pb2354] ' + _origine + ' : DESARME -> ancien comportement #ColonneDroite');\r\n                                    return;\r\n                                }\r\n                                var _cible = document.getElementById('ProcederPaiementTitre')\r\n                                    || document.getElementById('EtapePaiement');\r\n                                var _t0 = Date.now();\r\n                                var _max = (typeof window._viaPb2353Max === 'number') ? window._viaPb2353Max : 1500;\r\n                                var _trouver = function (_el) {\r\n                                    var _n = _el;\r\n                                    while (_n ? (_n !== document.body) : false) {\r\n                                        var _oy = '';\r\n                                        try { _oy = window.getComputedStyle(_n).overflowY; } catch (_e) { _oy = ''; }\r\n                                        if (_oy === 'auto' ? true : _oy === 'scroll') {\r\n                                            if (_n.scrollHeight > _n.clientHeight + 4) { return _n; }\r\n                                        }\r\n                                        _n = _n.parentElement;\r\n                                    }\r\n                                    return null;\r\n                                };\r\n                                var _essayer = function () {\r\n                                    var _ec = Date.now() - _t0;\r\n                                    var _sc = _cible ? _trouver(_cible) : null;\r\n                                    if (_sc) {\r\n                                        var _nom = _sc.tagName + (_sc.id ? ('#' + _sc.id) : '')\r\n                                            + (_sc.classList.length ? ('.' + Array.prototype.join.call(_sc.classList, '.').slice(0, 60)) : '');\r\n                                        console.log('[pb2354] ' + _origine + ' : defileur trouve apres ' + _ec + 'ms : ' + _nom\r\n                                            + ' | scrollHeight=' + _sc.scrollHeight + ' clientHeight=' + _sc.clientHeight\r\n                                            + ' scrollTop=' + Math.round(_sc.scrollTop));\r\n                                        jQuery(_sc).stop(true, false).animate({ scrollTop: _sc.scrollHeight }, _dur);\r\n                                        return;\r\n                                    }\r\n                                    if (_ec >= _max) {\r\n                                        console.log('[pb2354] ' + _origine + ' : aucun ancetre defilant apres ' + _ec + 'ms'\r\n                                            + (_cible ? '' : ' (cible absente)') + ' -> repli sur #ColonneDroite');\r\n                                        var $_r = jQuery('#ColonneDroite');\r\n                                        if ($_r.length) { $_r.animate({ scrollTop: $_r[0].scrollHeight }, _dur); }\r\n                                        return;\r\n                                    }\r\n                                    setTimeout(_essayer, 100);\r\n                                };\r\n                                _essayer();\r\n                            };\r\n                        }\r\n                        window._viaScrollBas2354('clic ProcederPaiementTitre');\r\n                    }, 100);\r\n                } else {\r\n                    $('#ProcederPaiementConteneur').hide();\r\n                    $('#ProcederPaiementTitreIconeUp').hide();\r\n                    $('#ProcederPaiementTitreIconeDown').show();\r\n                }\r\n            });\r\n            console.log('\u2705 Gestion ProcederPaiement initialis\u00e9e');\r\n        }\r\n        \r\n        function initGestionAssocierPays() {\r\n            $('.AssocierPaysTitre').off('click').on('click', function(event) {\r\n                event.preventDefault();\r\n                if ($('.AssocierPaysClass').is(':hidden')) {\r\n                    $('.AssocierPaysClass').show();\r\n                    $('.AssocierPaysClass .SousTitre').show();\r\n                    $('#AssocierPaysTitreIconeUp').show();\r\n                    $('#AssocierPaysTitreIconeDown').hide();\r\n                    \/\/ \u2705 v1.9 : Masquer le message quand l'accord\u00e9on est ouvert\r\n                    $('#AssocierPaysMessageContainer').hide();\r\n                    _viaPb465Release(); \/\/ pb465 : etape ouverte -> rendre la main a Elementor (32px)\r\n                } else {\r\n                    \/\/ \u2705 v1.16.0 : Masquer SousTitre imm\u00e9diatement\r\n                    $('.AssocierPaysClass .SousTitre').hide();\r\n                    $('.AssocierPaysClass').hide();\r\n                    $('#AssocierPaysTitreIconeUp').hide();\r\n                    $('#AssocierPaysTitreIconeDown').show();\r\n                    \/\/ \u2705 v1.9 : Afficher le message si un pays est s\u00e9lectionn\u00e9\r\n                    \/\/ \u2705 v3.6 : R\u00e9activ\u00e9\r\n                    const continentPaysTitre = sessionStorage.getItem('ContinentPaysTitre');\r\n                    if (continentPaysTitre) {\r\n                        const siteName = sessionStorage.getItem('ContinentPaysTitreDisplayed') || continentPaysTitre.split(\/[\\s]+\/)[0];\r\n                        \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction EN\r\n                        var _isEN_AP2 = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                        var _msgAP2 = _isEN_AP2\r\n                            ? 'Communication linked to the ' + siteName + ' site'\r\n                            : 'Communication associ\u00e9e au site ' + siteName;\r\n                        $('#AssocierPaysMessageTexte').text(_msgAP2);\r\n                        $('#AssocierPaysMessageContainer').show();\r\n                        _viaPb465Apply(); \/\/ pb465 : etape fermee + message affiche -> margin-bottom 27px\r\n                    }\r\n                }\r\n            });\r\n            console.log('\u2705 Gestion AssocierPays initialis\u00e9e');\r\n        }\r\n        \r\n        function createTestButton() {\r\n            if ($('#test-values-btn').length > 0) {\r\n                return;\r\n            }\r\n\r\n            const $testContainer = $(`\r\n                <div id=\"via-test-controls\" style=\"position: fixed; bottom: 20px; right: 20px; z-index: 10000; display: flex; flex-direction: column; gap: 10px;\">\r\n                    <div style=\"background: white; padding: 12px 15px; border-radius: 6px; box-shadow: 0 2px 8px rgba(0,0,0,0.2); display: flex; align-items: center; gap: 10px;\">\r\n                        <label style=\"margin: 0; font-size: 13px; font-weight: 600; cursor: pointer;\">\r\n                            <input type=\"checkbox\" id=\"commercial-switch\" style=\"margin-right: 8px; cursor: pointer;\">\r\n                            <span id=\"commercial-status\">\ud83d\udc64 Standard<\/span>\r\n                        <\/label>\r\n                    <\/div>\r\n                <\/div>\r\n            `);\r\n\r\n            $('body').append($testContainer);\r\n\r\n            const isCommercial = isCommercialConnected();\r\n            $('#commercial-switch').prop('checked', isCommercial);\r\n            updateCommercialStatus(isCommercial);\r\n\r\n            $('#commercial-switch').on('change', function() {\r\n                const isChecked = $(this).is(':checked');\r\n                \r\n                if (isChecked) {\r\n                    sessionStorage.setItem('CommercialConnected', 'Yes');\r\n                    sessionStorage.setItem('CommercialId', '37');\r\n                    console.log('\ud83d\udc54 Mode commercial activ\u00e9 (ID: 37)');\r\n                } else {\r\n                    sessionStorage.setItem('CommercialConnected', 'No');\r\n                    console.log('\ud83d\udc64 Mode standard activ\u00e9');\r\n                }\r\n                \r\n                updateCommercialStatus(isChecked);\r\n                gererAffichageCommerciaux();\r\n                \r\n                if (isChecked) {\r\n                    setupClientAutocomplete();\r\n                    initSauvegardeClientAuto();\r\n                }\r\n            });\r\n        }\r\n\r\n        function updateCommercialStatus(isCommercial) {\r\n            const $status = $('#commercial-status');\r\n            if (isCommercial) {\r\n                $status.html('\ud83d\udc54 Commercial');\r\n                $status.css('color', '#007cba');\r\n            } else {\r\n                $status.html('\ud83d\udc64 Standard');\r\n                $status.css('color', '#666');\r\n            }\r\n        }\r\n\r\n        function verifierTauxDeChange() {\r\n            if (!window.VIA_App || !window.VIA_App.tauxDeChange) {\r\n                return false;\r\n            }\r\n            \r\n            const tauxRequis = ['EUR', 'USD', 'GBP', 'CHF', 'XAF', 'XOF', 'CDF', 'MGA'];\r\n            for (const devise of tauxRequis) {\r\n                if (!window.VIA_App.tauxDeChange[devise] || window.VIA_App.tauxDeChange[devise] === null) {\r\n                    return false;\r\n                }\r\n            }\r\n            \r\n            return true;\r\n        }\r\n\r\n        function desactiverDeviseSelect() {\r\n            const $deviseSelect = $('#' + CONFIG.FIELDS.devise);\r\n            \r\n            if ($deviseSelect.length > 0) {\r\n                $deviseSelect.prop('disabled', true);\r\n            }\r\n        }\r\n\r\n        function activerDeviseSelect() {\r\n            const $deviseSelect = $('#' + CONFIG.FIELDS.devise);\r\n            if ($deviseSelect.length > 0) {\r\n                $deviseSelect.prop('disabled', false);\r\n                console.log('\u2705 S\u00e9lecteur de devise activ\u00e9');\r\n            }\r\n        }\r\n        \r\n        function calculerPositionFromRank(rankEmplacement, typePage) {\r\n            if (!rankEmplacement) {\r\n                console.warn('\u26a0\ufe0f Rank_Emplacement_Page_Web manquant');\r\n                return 'cdp Autres P.';\r\n            }\r\n            \r\n            const match = rankEmplacement.match(\/Ele(\\d+)[A-Z]\/);\r\n            \r\n            if (!match) {\r\n                console.warn('\u26a0\ufe0f Format Rank invalide:', rankEmplacement);\r\n                return 'cdp Autres P.';\r\n            }\r\n            \r\n            const rang = parseInt(match[1]);\r\n            console.log('\ud83d\udcca Rank extrait:', rang, 'de', rankEmplacement);\r\n            \r\n            let positionBase;\r\n            if (rang === 0) {\r\n                positionBase = 'Pop-up';\r\n            } else if (rang === 1 || rang === 2) {\r\n                positionBase = 'hdp';\r\n            } else {\r\n                positionBase = 'cdp';\r\n            }\r\n            \r\n            let position;\r\n            if (positionBase === 'Pop-up') {\r\n                position = typePage === 'Homepage' ? 'Pop-up Homepage' : 'Pop-up Autres P.';\r\n            } else {\r\n                position = typePage === 'Homepage' ? \r\n                    `${positionBase} Home P.` : \r\n                    `${positionBase} Autres P.`;\r\n            }\r\n            \r\n            console.log(`\u2705 Position: ${position} (rang=${rang}, type=${typePage})`);\r\n            return position;\r\n        }\r\n\r\n        async function init() {\r\n            try {\r\n                console.log('\ud83d\udd04 Chargement jQuery UI...');\r\n                await loadJQueryUI();\r\n\r\n                console.log('\ud83c\udfa8 Injection des styles...');\r\n                injectStyles();\r\n\r\n                console.log('\ud83d\udcc5 Configuration datepickers...');\r\n                setupDatePickers();\r\n\r\n                console.log('\ud83c\udf0d Configuration autocomplete pays...');\r\n                setupCountryAutocomplete();\r\n                \r\n                console.log('\ud83d\udcb1 Configuration s\u00e9lecteur devise...');\r\n                \r\n                let tauxVerifies = false;\r\n                let tentatives = 0;\r\n                const maxTentatives = 10;\r\n                \r\n                desactiverDeviseSelect();\r\n                \r\n                const intervalTaux = setInterval(() => {\r\n                    tentatives++;\r\n                    \r\n                    if (verifierTauxDeChange()) {\r\n                        clearInterval(intervalTaux);\r\n                        tauxVerifies = true;\r\n                        console.log('\u2705 Tous les taux de change sont disponibles:', window.VIA_App.tauxDeChange);\r\n                        initDeviseListener();\r\n                        activerDeviseSelect();\r\n                        \r\n                        if (window.VIA_App.state.dernierResultatCalcul) {\r\n                            const devise = $('#' + CONFIG.FIELDS.devise).val() || 'EUR';\r\n                            afficherTarif(window.VIA_App.state.dernierResultatCalcul, devise);\r\n                        }\r\n                    } else if (tentatives >= maxTentatives) {\r\n                        clearInterval(intervalTaux);\r\n                        console.error('\u274c Timeout: Les taux de change n\\'ont pas pu \u00eatre charg\u00e9s apr\u00e8s 5 secondes');\r\n                        console.error('\u00c9tat des taux:', window.VIA_App?.tauxDeChange);\r\n                        \r\n                        console.log('\ud83d\udd04 Nouvelle tentative de chargement des taux...');\r\n                        if (AND(window.VIA_App, typeof window.VIA_App.initTauxDeChange === 'function')) {\r\n                            window.VIA_App.initTauxDeChange().then(() => {\r\n                                if (verifierTauxDeChange()) {\r\n                                    console.log('\u2705 Taux charg\u00e9s apr\u00e8s retry');\r\n                                    initDeviseListener();\r\n                                    activerDeviseSelect();\r\n                                } else {\r\n                                    console.error('\u274c \u00c9chec du rechargement des taux');\r\n                                }\r\n                            });\r\n                        }\r\n                    }\r\n                }, 100);\r\n\r\n                console.log('\ud83d\udce1 Configuration postMessage...');\r\n                setupPostMessage();\r\n\r\n                console.log('\ud83d\udc54 Gestion des commerciaux...');\r\n                gererAffichageCommerciaux();\r\n                initTarifCommercial();\r\n                \r\n                if (STATE.isCommercial) {\r\n                    setupClientAutocomplete();\r\n                    initSauvegardeClientAuto();\r\n                }\r\n\r\n                console.log('\ud83d\udce6 Initialisation sections expandables...');\r\n                initGestionVosCommandes();\r\n                initGestionChoisirPaiement();\r\n                initGestionProcederPaiement();\r\n                initGestionReferences();\r\n                initGestionRecapitulatif();\r\n                \/\/ initGestionAssocierPays() d\u00e9j\u00e0 initialis\u00e9 au d\u00e9but (imm\u00e9diat)\r\n\r\n                \/\/console.log('\ud83e\uddea Cr\u00e9ation bouton test...');\r\n                \/\/createTestButton();\r\n                \r\n                console.log('\ud83d\udd17 Configuration synchronisation panier...');\r\n                setupSynchronisationPanier();\r\n\r\n                console.log('\u2705 Formulaire Elementor v3.6 initialis\u00e9!');\r\n                \r\n                setTimeout(() => checkEspacePubData(), 1000);\r\n                        \r\n                \/\/ \u2705 mode=popup : si le postMessage d'espace pub est arriv\u00e9 avant setupPostMessage,\r\n                \/\/ le rejouer maintenant que le listener est enregistr\u00e9\r\n                if (window._viaPendingEspacePubData) {\r\n                    var _pending = window._viaPendingEspacePubData;\r\n                    window._viaPendingEspacePubData = null;\r\n                    setTimeout(function() {\r\n                        console.log('\ud83d\udd04 [Formulaire] Replay _viaPendingEspacePubData (race condition fix)');\r\n                        window.postMessage({ type: 'dataFromIframeEspacePub', data: _pending }, '*');\r\n                    }, 300);\r\n                }\r\n\r\n            } catch (error) {\r\n                console.error('\u274c Erreur lors de l\\'initialisation:', error);\r\n            }\r\n        }\r\n\r\n        init();\r\n\r\n        window.VIA_Elementor = {\r\n            calculerTarif: triggerTarifCalculation,\r\n            calculerDuree: calculateDuration,\r\n            checkData: checkEspacePubData,\r\n            state: STATE,\r\n            COUNTRIES_DATA: window.VIA_Countries.COUNTRIES_DATA,\r\n            reinitWidgets: function() {\r\n                console.log('\ud83d\udd04 R\u00e9initialisation des datepickers et autocomplete...');\r\n                setupDatePickers();\r\n                setupCountryAutocomplete();\r\n                console.log('\u2705 Widgets r\u00e9initialis\u00e9s');\r\n            }\r\n        };\r\n\r\n    }\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', initFormulaire);\r\n    } else {\r\n        initFormulaire();\r\n    }\r\n\r\n    console.log('\u2705 formulaire-elementor-cross-domain.js v3.6 charg\u00e9');\r\n\r\n    \/\/ pb465 : au chargement, si l'etape Pays est deja fermee (message container visible), aucun clic\r\n    \/\/   n'a lieu -> appliquer le -5px a l'init. Retry court car Elementor pose son inline tardivement ;\r\n    \/\/   des qu'Apply branche le MutationObserver, celui-ci gere toutes les reecritures suivantes.\r\n    (function _viaPb465Init() {\r\n        var _tries465 = 0;\r\n        function _try465() {\r\n            var _el465i = document.getElementById('AssocierPaysMessageContainer');\r\n            var _vis465 = _el465i ? (window.getComputedStyle(_el465i).display !== 'none') : false;\r\n            if (_el465i ? _vis465 : false) { _viaPb465Apply(); return; }\r\n            _tries465++;\r\n            if (_tries465 < 30) { setTimeout(_try465, 300); }\r\n        }\r\n        if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', _try465); } else { _try465(); }\r\n    })();\r\n\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6e09ef26 elementor-widget elementor-widget-html\" data-id=\"6e09ef26\" data-element_type=\"widget\" data-e-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\/* ========================================================================\r\n   pb916 : BANNER DE VERSION. Panier_manager.txt etait le seul fichier du\r\n   projet sans marqueur de version (Entete.txt a _viaEnteteVer,\r\n   yearbook-media.js a _viaYbmVer). Consequence concrete : impossible de\r\n   savoir si le snippet en base est a jour, et un diagnostic entier a ete\r\n   mene sur des symptomes qui n'etaient que ceux d'une version ancienne\r\n   encore servie (cascade de font-size a 0.7 + etape dates absente de\r\n   etapesConfig). A bumper a CHAQUE modification de ce fichier.\r\n   Verification rapide en console : window._viaPanierVer\r\n   ======================================================================== *\/\r\nwindow._viaPanierVer = 'PM-pb2410';\r\n\r\n\/\/ ================================================================\r\n\/\/ pb2121 : COMMERCIAL CONNECTE \u2014 la carte de la resa ACTIVE n'affiche\r\n\/\/   que le libelle \u00ab Tarif H.T. \u00bb (le montant vit dans la zone de\r\n\/\/   saisie #form-field-TarifCommercial, pre-remplie par afficherTarif\r\n\/\/   cote Formulaire). Les cartes INACTIVES gardent le montant complet\r\n\/\/   \u2014 item.tarifHT porte deja le montant COMMERCIAL apres\r\n\/\/   mettreAJourTarifCommercialDansCommande, les writers le relisent au\r\n\/\/   changement d'actif (reponse JF : c'est le montant modifie qui\r\n\/\/   s'affiche quand la resa devient inactive).\r\n\/\/   HELPER UNIQUE, applique par CHAQUE writer de .CampagneTarifClass\r\n\/\/   qui pose un montant (regle : N writers, une constante partagee ;\r\n\/\/   les writers restent maitres de leur pose \u2014 pas de post-passe qui\r\n\/\/   recreerait la concurrence pb1045). La remise <small> du writer\r\n\/\/   commercial est conservee (reponse JF).\r\n\/\/   Appele aussi par Formulaire.txt (mettreAJourTarifCommercialDans\r\n\/\/   Commande) \u2014 garde typeof cote appelant.\r\n\/\/   Revert : window._viaPb2121Off = true (texte complet partout).\r\n\/\/ ================================================================\r\nwindow._viaLibelleTarif2121 = function (itemId, texteComplet) {\r\n    try {\r\n        if (window._viaPb2121Off === true) { return texteComplet; }\r\n        if (sessionStorage.getItem('CommercialConnected') !== 'Yes') { return texteComplet; }\r\n        if (!itemId) { return texteComplet; }\r\n        if (!window.VIA_Panier) { return texteComplet; }\r\n        if (itemId !== window.VIA_Panier.state.itemActif) { return texteComplet; }\r\n        var _lg2121 = sessionStorage.getItem('SiteLangue') || 'FR';\r\n        var _lbl2121 = (_lg2121 === 'EN') ? 'Price excl. VAT' : 'Tarif H.T.';\r\n        \/\/ pb2124 : la remise est RECONSTRUITE depuis l'ITEM, plus extraite du\r\n        \/\/   texte d'entree. Constat JF : elle ne s'affichait pas \u2014 seul le\r\n        \/\/   writer commercial (Formulaire) porte le <small>, et un writer PM\r\n        \/\/   repeint la carte active apres lui (calculerTotalPanier ->\r\n        \/\/   rafraichissement) avec un texte SANS remise : l'extraction ne\r\n        \/\/   trouvait rien. item.montantRemise \/ deviseRemiseCommission sont\r\n        \/\/   poses par mettreAJourTarifCommercialDansCommande : l'etat de\r\n        \/\/   l'item est la seule source stable, quel que soit le writer.\r\n        \/\/   Affichee si > 0. Repli : <small> du texte d'entree s'il existe.\r\n        var _sm2121 = \/(<small>[\\s\\S]*<\\\/small>)\/.exec(texteComplet || '');\r\n        var _rem2124 = '';\r\n        try {\r\n            var _it2124 = window.VIA_Panier.state.items.find(function (_i) { return _i.id === itemId; });\r\n            if (_it2124 ? (typeof _it2124.montantRemise === 'number' ? _it2124.montantRemise > 0 : false) : false) {\r\n                var _dv2124 = _it2124.deviseRemiseCommission || _it2124.devise || 'EUR';\r\n                var _fm2124 = window.VIA_App\r\n                    ? window.VIA_App.formaterMontant(_it2124.montantRemise, _dv2124, 2)\r\n                    : (_it2124.montantRemise + ' ' + _dv2124);\r\n                _rem2124 = ' <small>(' + ((_lg2121 === 'EN') ? 'discount' : 'remise') + ': ' + _fm2124 + ')<\/small>';\r\n            }\r\n        } catch (_e2124) { console.warn('[pb2124]', _e2124.message); }\r\n        if (_rem2124 === '') { _rem2124 = _sm2121 ? (' ' + _sm2121[1]) : ''; }\r\n        var _txt2121 = _lbl2121 + _rem2124;\r\n        if (window._viaSig2121 !== itemId + '|' + _txt2121) {\r\n            window._viaSig2121 = itemId + '|' + _txt2121;\r\n            console.log('[pb2121] resa active commerciale -> libelle seul : \"' + _txt2121 + '\" | item=' + itemId);\r\n        }\r\n        return _txt2121;\r\n    } catch (_e2121) { console.warn('[pb2121]', _e2121.message); return texteComplet; }\r\n};\r\n\r\n\/\/ ================================================================\r\n\/\/ pb2130 : COMMERCIAL \u2014 LE PROCESS S'ARRETE AU MODE DE PAIEMENT.\r\n\/\/   Constat JF : apres le choix CB\/Virement en mode commercial, l'email\r\n\/\/   part (Mode_de_paiement, branche commerciale correcte : pas de\r\n\/\/   passerEtapeSuivante, message MsgAlerteModedePaiement affiche) MAIS\r\n\/\/   l'etape Validations s'ouvre quand meme.\r\n\/\/   Cause : les handlers CB\/Vir posent mode_paiement AVANT la branche\r\n\/\/   commerciale ; pb1639 lit l'etat vivant du module -> etape paiement\r\n\/\/   \u00ab faite \u00bb -> la cible avance a 'validations' -> pb2046 affiche\r\n\/\/   l'etape ACTIVE. Le sequenceur ne connaissait pas la regle metier :\r\n\/\/   un commercial ne valide ni ne paie a la place du client (le client\r\n\/\/   recoit le lien de paiement par email).\r\n\/\/   Clamp : tant que CommercialConnected === 'Yes', la cible ne peut\r\n\/\/   JAMAIS valoir 'validations' ni 'paiementFinal' \u2014 elle reste sur\r\n\/\/   'paiement', ou le message au commercial est affiche.\r\n\/\/   Revert : window._viaPb2130Off = true.\r\n\/\/ ================================================================\r\nwindow._viaClampCommercial2130 = function (cible) {\r\n    try {\r\n        if (window._viaPb2130Off === true) { return cible; }\r\n        if (sessionStorage.getItem('CommercialConnected') !== 'Yes') { return cible; }\r\n        if (cible === 'validations' || cible === 'paiementFinal') {\r\n            if (window._viaSig2130 !== cible) {\r\n                window._viaSig2130 = cible;\r\n                console.log('[pb2130] mode commercial : cible ' + cible\r\n                    + ' -> paiement (le process s\\'arrete la, le client paie via l\\'email)');\r\n            }\r\n            return 'paiement';\r\n        }\r\n        return cible;\r\n    } catch (_e2130) { return cible; }\r\n};\r\nvar NL_1729 = String.fromCharCode(10) + '    ';\r\n\/* ========================================================================\r\n * pb2049 : LE MASQUAGE ARRIVAIT APRES L AFFICHAGE.\r\n *   Constat JF, page pays NON EN CACHE : \u00ab Choix des modes de paiement \u00bb\r\n *   s affiche, alors que pb2046 doit le masquer. Les deux sont vrais \u2014 c est\r\n *   une course, et JF l a nommee lui-meme : \u00ab quand je vais trop vite \u00bb.\r\n *   CE QUI SE PASSE : pb2046 vit dans _couleurEtapes1169, qui sort des sa\r\n *   premiere ligne tant que state.etapesConfig n existe pas. Sur une page\r\n *   froide, la feuille n est donc INJECTEE qu apres l init du process. Entre\r\n *   le rendu Elementor et cette init, rien ne masque.\r\n *   POURQUOI LE TITRE ET PAS LE CONTENU : la regle precoce de yearbook-media\r\n *   (#EtapeModedePaiement:not(.via-etape-visible)) ne couvre que les WRAPPERS.\r\n *   Les TITRES vivent hors d eux \u2014 pb1183b l avait deja constate \u2014 et n etaient\r\n *   masques que par la feuille de pb1183, puis par celle de pb2046. Les deux\r\n *   arrivent trop tard. Le trou preexiste donc a pb2046 ; il devient seulement\r\n *   visible parce que le titre est desormais le seul repere.\r\n *   LA PARADE : poser la feuille ET les quatre classes AU PLUS TOT, sans rien\r\n *   attendre du process. L etat pre-masque est de toute facon l etat de regime\r\n *   avant la premiere passe, dans les deux contextes : sur la regie les quatre\r\n *   etapes sont \u00ab a venir \u00bb tant que Finaliser n est pas clique, sur un site\r\n *   pays de meme. La premiere passe de pb2046 corrige ensuite ce qui doit l etre.\r\n *   UNE SEULE DEFINITION : la table et l injection vivent ici, pb2046 les\r\n *   consomme. Deux copies de selecteurs finiraient par diverger \u2014 c est ce que\r\n *   pb1899 a paye avec ses huit listes indexees.\r\n *   FILET, TIRE UNE FOIS : si aucune passe de pb2046 n a eu lieu au bout de\r\n *   huit secondes (VIA_Panier casse en amont), le pre-masquage est LEVE et le\r\n *   log le dit. Un masquage muet et definitif serait pire que le defaut.\r\n *   Revert : window._viaPb2049Off = true (pre-masquage non pose).\r\n * ======================================================================== *\/\r\nwindow._viaTable2046 = [\r\n    { id: 'references',    cls: 'via-m2046-ref',\r\n      sel: ['#EtapeReferences', '.ReferencesTitre', '#ReferencesTitreContainer'] },\r\n    { id: 'paiement',      cls: 'via-m2046-pay',\r\n      sel: ['#EtapeModedePaiement', '.ChoisirPaiementTitre', '#ChoisirPaiementTitreContainer'] },\r\n    { id: 'validations',   cls: 'via-m2046-val',\r\n      sel: ['#EtapeValidations', '.ValidationsTitre', '#ValidationsTitreContainer'] },\r\n    { id: 'paiementFinal', cls: 'via-m2046-fin',\r\n      sel: ['#EtapePaiement', '.ProcederPaiementTitre', '#ProcederPaiementTitreContainer'] }\r\n];\r\nwindow._viaFeuille2046 = function () {\r\n    if (document.getElementById('via-masque-avenir-2046')) { return true; }\r\n    if (!document.head) { return false; }\r\n    var _r2049 = [];\r\n    window._viaTable2046.forEach(function (_e2049) {\r\n        _e2049.sel.forEach(function (_s2049) {\r\n            _r2049.push('body.' + _e2049.cls + ' ' + _s2049);\r\n        });\r\n    });\r\n    var _st2049 = document.createElement('style');\r\n    _st2049.id = 'via-masque-avenir-2046';\r\n    _st2049.textContent = _r2049.join(',' + String.fromCharCode(10))\r\n        + ' { display: none !important; }';\r\n    document.head.appendChild(_st2049);\r\n    console.log('[pb2046] feuille de masquage des \u00e9tapes \u00e0 venir inject\u00e9e ('\r\n        + _r2049.length + ' s\u00e9lecteurs)');\r\n    return true;\r\n};\r\n\/* ========================================================================\r\n * pb2051 : LA RACINE DE pb2050 REPOSAIT SUR UN RESIDU.\r\n *   pb2050 chaine les quatre etapes aval sur faits.recapitulatif, soit\r\n *   sessionStorage.FinaliserStep === 'Yes'. C est EXACTEMENT la cle que\r\n *   pb1220 avait deja identifiee comme residuelle : \u00ab une valeur laissee par\r\n *   une session precedente suffisait a lever le masquage \u00bb. J avais bouche la\r\n *   fuite en aval et laisse le robinet ouvert en amont.\r\n *   POURQUOI PAS LE REMEDE DE pb1220 : il exigeait la cle ET un item finalise.\r\n *   pb1222 l a invalide, et sa mesure fait foi \u2014 \u00ab les items sont restaures\r\n *   depuis sessionStorage avec leur statut complete ; aucun des deux ne\r\n *   distingue finalise MAINTENANT de finalise UN JOUR \u00bb. Reprendre pb1220\r\n *   aurait ete refaire une correction deja constatee insuffisante.\r\n *   CE QUI TIENT : un drapeau pose AU CLIC, en memoire, qui disparait a chaque\r\n *   chargement \u2014 il ne peut pas etre perime par construction (pb1222).\r\n *   Le handler est installe ICI, tot et sans dependance : celui de pb1183\r\n *   vivait dans un bloc que la garde pb2046 ne traverse plus, et son temoin\r\n *   etait donc mort. Le reinstaller ici le rend disponible aux deux \u2014 pb2050\r\n *   s en sert, et pb1183 le retrouve intact si on le reactive.\r\n *   PHASE DE CAPTURE et delegation sur document : le bouton est recree a\r\n *   chaque rendu du recapitulatif (motif pb1222), et .FinaliserBouton est le\r\n *   conteneur de .PasserCommandeBouton \u2014 on accepte les deux.\r\n *   CE QU ON PERD, ASSUME : un rechargement en plein parcours aval remet le\r\n *   drapeau a faux, donc les etapes deja faites se remasquent. L etape EN\r\n *   COURS reste affichee, elle passe par la cible et non par la chaine ; le\r\n *   parcours n est donc pas bloque. C est le comportement d avant pb2046,\r\n *   choisi par pb1222 en connaissance de cause.\r\n *   Revert : window._viaPb2051Off = true (racine = faits.recapitulatif).\r\n * ======================================================================== *\/\r\n(function _temoinFinaliser2051() {\r\n    if (window._viaArmeFin1222) { return; }\r\n    window._viaArmeFin1222 = true;\r\n    document.addEventListener('click', function (_e2051) {\r\n        try {\r\n            var _b2051 = _e2051.target.closest\r\n                ? _e2051.target.closest('.PasserCommandeBouton, .FinaliserBouton')\r\n                : null;\r\n            if (!_b2051) { return; }\r\n            window._viaFinaliseClique1222 = true;\r\n            console.log('[pb2051] Finaliser cliqu\u00e9 -> racine de la cha\u00eene aval ouverte');\r\n        } catch (_e) {}\r\n    }, true);\r\n})();\r\nwindow._viaRacineAval2051 = function (faits) {\r\n    if (window._viaPb2051Off === true) { return faits ? !!faits.recapitulatif : false; }\r\n    if (window._viaFinaliseClique1222 === true) { return true; }\r\n    \/* second temoin memoire, pose par le handler de initListeners (l.11106) :\r\n       meme sens, meme duree de vie. Deux sources memoire, aucune session. *\/\r\n    return (window._viaFinaliserClique === true);\r\n};\r\n(function _preMasque2049() {\r\n    if (window._viaPb2049Off === true) { return; }\r\n    var _pose2049 = function () {\r\n        if (!document.body) { return false; }\r\n        if (!window._viaFeuille2046()) { return false; }\r\n        window._viaTable2046.forEach(function (_e) {\r\n            document.body.classList.add(_e.cls);\r\n        });\r\n        console.log('[pb2049] pr\u00e9-masquage des 4 \u00e9tapes aval pos\u00e9 (avant init du process)');\r\n        return true;\r\n    };\r\n    if (!_pose2049()) {\r\n        document.addEventListener('DOMContentLoaded', function () { _pose2049(); });\r\n    }\r\n    setTimeout(function () {\r\n        \/* _viaSig2046 n est defini que par une passe de pb2046. *\/\r\n        if (window._viaSig2046 !== undefined) { return; }\r\n        if (!document.body) { return; }\r\n        window._viaTable2046.forEach(function (_e) {\r\n            document.body.classList.remove(_e.cls);\r\n        });\r\n        console.warn('[pb2049] aucune passe de pb2046 apr\u00e8s 8 s'\r\n            + ' -> pr\u00e9-masquage LEV\u00c9 (les 4 \u00e9tapes redeviennent visibles)');\r\n    }, 8000);\r\n})();\r\n\/* ============================================================\r\n * pb1713 : LE JUGE, MAIS ADOSSE A LA VALIDITE DU PAYS.\r\n *   pb1711 avait le bon champ et le mauvais critere : il testait la PRESENCE de\r\n *   paysAnnonceur. Des le premier caractere saisi le champ est non vide, l etape\r\n *   passait a \u00ab faite \u00bb et se refermait sous les doigts (constat user, pb1712).\r\n *   Le predicat correct existe et il est deja expose : window._viaPaysValide949\r\n *   (yearbook-media.js l.38311, expose par pb1329 pour ce motif exact \u2014 \u00ab une\r\n *   seule definition de : ce pays existe-t-il ? \u00bb). pb1328 s en sert deja pour ne\r\n *   pas conclure sur une saisie partielle.\r\n *   Pourquoi c est necessaire : le choix d un espace nullifie item.pays ET\r\n *   item.paysAnnonceur (l.4431). pb1693 rend paysAnnonceur, mais deux ecrivains\r\n *   de la completion lisent item.PAYS \u2014 or pb1189 a etabli que pays porte selon\r\n *   les chemins le pays du SITE. D ou l etape qui redevient active a la selection\r\n *   d un site.\r\n *   Je ne touche QUE ces deux ecrivains. Le troisieme (l.12220, !!annonceur) lit\r\n *   deja la bonne source et n a jamais pose probleme : le modifier n apporterait\r\n *   que du risque.\r\n *   Si le predicat n est pas disponible, on ne conclut pas : on rend le\r\n *   comportement d origine plutot que d inventer un verdict.\r\n *   Revert : window._viaPb1713Off = true.\r\n * ============================================================ *\/\r\nwindow._viaAnnonceurFait1713 = function (_it) {\r\n    if (!_it) { return false; }\r\n    if (window._viaPb1713Off === true) { return !!_it.pays; }\r\n    var _v1713 = _it.paysAnnonceur || '';\r\n    if (!_v1713) { return false; }\r\n    if (typeof window._viaPaysValide949 !== 'function') { return !!_it.pays; }\r\n    var _ok1713 = (window._viaPaysValide949(_v1713) === true);\r\n    if (window._viaSig1713 !== (_v1713 + '|' + _ok1713)) {\r\n        window._viaSig1713 = _v1713 + '|' + _ok1713;\r\n        console.log('[pb1713] annonceur \"' + _v1713 + '\" -> '\r\n            + (_ok1713 ? 'pays complet, etape faite' : 'saisie partielle, etape active'));\r\n    }\r\n    return _ok1713;\r\n};\r\n\/* pb1712 : REVERT DE pb1711. Constat user : la saisie de l annonceur devenait\r\n   impossible \u2014 des le premier caractere, paysAnnonceur etait non vide, l etape\r\n   passait a \u00ab faite \u00bb et se refermait sous les doigts.\r\n   Mon juge testait la PRESENCE du champ ; il fallait tester sa VALIDITE. Le\r\n   controle existe deja \u2014 _paysValide949, utilise par pb1328 (yearbook-media.js\r\n   l.37788) precisement pour ne pas conclure sur une saisie partielle.\r\n   Les trois ecrivains d origine sont retablis a l identique. L incoherence\r\n   pays \/ paysAnnonceur reste ouverte, mais elle ne se corrige pas sans passer\r\n   par ce controle de validite. *\/\r\ntry { console.log('[PANIER ECHO] ' + window._viaPanierVer + ' SERVI'); } catch (_ePMV) {}\r\n\/**\r\n * VIA Agency - Gestion du Panier (Panier Manager)\r\n * Version 1.10 - FIX Fermeture PageWeb conditionnelle + Visualisation \u00e9tapes\r\n * @version 1.10 - Janvier 2026\r\n * pb277 : synchro VLP sites pays <-> resa panier (clic resa -> ouvre\/ramene le VLP ; suppression derniere resa d'une page -> ferme le VLP)\r\n * \u2705 v1.6 : Flag BonCommandeCree pour verrouillage apr\u00e8s cr\u00e9ation\r\n * \u2705 v1.6 : gererModificationCommande() pour invalider validations ou bloquer\r\n * \u2705 v1.7 : Anti-rebond afficherSynthese() pour \u00e9viter affichages multiples\r\n * \u2705 v1.7 : Pas de scroll mobile si FinaliserStep = Yes\r\n * \u2705 v1.7 : V\u00e9rification \u00e9tape ouverte avant retourModificationCommande()\r\n * \u2705 v1.7 : Ignorer clics provenant des \u00e9tapes et formulaires\r\n * \u2705 v1.7 : Croix suppression visibles apr\u00e8s Finaliser\r\n * \u2705 v1.7 : Fermeture PageWeb mobile si aucune commande\r\n * \u2705 v1.8 : FIX RecapitulatifMessageContainer ne s'affiche plus lors de s\u00e9lection espace pub\r\n * \u2705 v1.8 : FIX gererModeFinalisationCommandes() garde Etape1Container visible sur mobile\r\n * \u2705 v1.10 : PageWeb ne se ferme que si annonce d\u00e9pos\u00e9e OU envoi diff\u00e9r\u00e9\r\n * \u2705 v1.10 : Visualisation \u00e9tapes R\u00e9f\u00e9rences\/Paiement sans message si bon commande cr\u00e9\u00e9\r\n * \u2705 v1.10 : toggleEtapeReferences() et toggleEtapePaiement() avec flag enVisualisationEtape\r\n * \u2705 v1.10 : ouvrirRecapitulatif() n'ouvre pas si \u00e9tape suivante d\u00e9j\u00e0 ouverte\r\n * \u2705 v1.10 : afficherSynthese() n'affiche pas si \u00e9tape suivante d\u00e9j\u00e0 ouverte\r\n * \u2705 v1.10 : Synchronisation pays \u00c9tape 1 \u2192 R\u00e9f\u00e9rences (bidirectionnelle)\r\n * \u2705 v1.10 : Handlers directs sur #ReferencesTitre et #ChoisirPaiementTitre avec .off().on()\r\n * \u2705 v1.10 : Protection contre touche Enter sur formulaires Elementor\r\n * \u2705 v1.10 : Mise \u00e0 jour logique TVA quand pays change dans \u00c9tape 1\r\n * \u2705 v1.10 : Bouton #Etape1BoutonValider pour valider \u00c9tape 1 (plus d'ouverture auto du r\u00e9cap)\r\n * \u2705 v1.10 : D\u00e9lai 300ms dans fermerPageWeb pour afficher #PageWebMessageContainer\r\n * \u2705 v1.10 : toggleEtapePaiementFinal() pour ouvrir\/fermer #ProcederPaiementContenu avec #ProcederPaiementTitre\r\n * \u2705 v1.10 : griserEtape() et degriserEtape() pour griser titre\/ic\u00f4nes des \u00e9tapes termin\u00e9es\r\n * \u2705 v1.11 : creerReservationAnticipee() \u2014 item statut 'anticipee' cr\u00e9\u00e9 d\u00e8s le changement pays\/secteur\r\n *             FB4 dans creerCommandePartielle pour upgrader 'anticipee' \u2192 'partielle' \u00e0 l'arriv\u00e9e de l'URL\r\n * \u2705 v1.12 (pb493) : fermerTout() reset bandeaux pays\/secteur\/format (_viaHideColonneCentre) +\r\n *             centrage #AutreCommandeBouton + clic croix via-msg-close-btn \u2192 reload page\r\n *\/\r\n\r\n(function() {\r\n    'use strict';\r\n\r\n    console.log('\ud83d\uded2 Initialisation du Panier Manager v1.15 (pb503 : title S\u00e9lectionner->S\u00e9lectionn\u00e9 sur resa active ; pb493 v4 reset bandeaux+messages verts + centrage ACB flex H+V + reload croix)');\r\n\r\n    \/\/ v4.9ds : injection PR\u00c9COCE de la variable CSS --via-etape-active-color\r\n    \/\/   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n    \/\/   La couleur \"\u00e9tape active\" (titre + chevrons) est d\u00e9finie ICI en UN\r\n    \/\/   SEUL endroit. Toute autre r\u00e8gle CSS ou code JS lit cette variable :\r\n    \/\/     CSS  : color: var(--via-etape-active-color);\r\n    \/\/     JS   : window._viaEtapeActiveColor()\r\n    \/\/\r\n    \/\/   POUR CHANGER LA COULEUR, modifier UNIQUEMENT la valeur de\r\n    \/\/   --via-etape-active-color dans le CSS inject\u00e9 ci-dessous.\r\n    \/\/\r\n    \/\/   Cette injection pr\u00e9coce (avant init VIA_Panier) garantit que la\r\n    \/\/   variable est disponible d\u00e8s les premiers rendus, et que les r\u00e8gles\r\n    \/\/   override sur titres Dates \/ R\u00e9cap \/ etc. s'appliquent aussi t\u00f4t que\r\n    \/\/   possible (avant que les bleus inline d'Elementor soient visibles).\r\n    \/\/   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n    (function _viaInjectEtapeActiveColor() {\r\n        if (document.getElementById('via-etape-active-color-style')) { return; }\r\n        var _styleEAC = document.createElement('style');\r\n        _styleEAC.id = 'via-etape-active-color-style';\r\n        _styleEAC.textContent =\r\n            ':root { --via-etape-active-color: #FB5E2A; }' +\r\n            \/\/ Force la couleur active sur tous les titres + chevrons d'\u00e9tape\r\n            \/\/   qui ne sont PAS gris\u00e9s. Bat les styles inline Elementor\r\n            \/\/   (color: rgb(34, 93, 169) !important) gr\u00e2ce \u00e0 html body + ID + !important\r\n            \/\/ \u2705 v4.9ds Pb 7 : r\u00e8gles DatesDureeCampagneTitre\/IconeUp\/IconeDown RETIR\u00c9ES\r\n            \/\/   (\u00e9tape Dates supprim\u00e9e d'Elementor \u2014 \u00e9l\u00e9ments inexistants).\r\n            'html body .RecapitulatifVosCommandestitre:not(.via-etape-grisee),' +\r\n            'html body .RecapitulatifVosCommandestitre:not(.via-etape-grisee) *,' +\r\n            'html body #RecapitulatifVosCommandestitreTexte:not(.via-etape-grisee),' +\r\n            'html body #RecapitulatifVosCommandestitreTexte:not(.via-etape-grisee) *,' +\r\n            'html body #RecapitulatifVosCommandesIconeUp:not(.via-etape-grisee),' +\r\n            'html body #RecapitulatifVosCommandesIconeUp:not(.via-etape-grisee) *,' +\r\n            'html body #RecapitulatifVosCommandesIconeDown:not(.via-etape-grisee),' +\r\n            'html body #RecapitulatifVosCommandesIconeDown:not(.via-etape-grisee) * {' +\r\n              'color: var(--via-etape-active-color) !important;' +\r\n              'fill:  var(--via-etape-active-color) !important;' +\r\n            '}';\r\n        \/\/ Ins\u00e9rer en T\u00caTE de <head> pour priorit\u00e9 sur les styles ajout\u00e9s ensuite\r\n        if (document.head) {\r\n            document.head.insertBefore(_styleEAC, document.head.firstChild);\r\n        } else {\r\n            document.documentElement.appendChild(_styleEAC);\r\n        }\r\n    })();\r\n    \/\/ Helper JS pour lire la couleur active\r\n    window._viaEtapeActiveColor = function() {\r\n        try {\r\n            var _v = getComputedStyle(document.documentElement)\r\n                .getPropertyValue('--via-etape-active-color').trim();\r\n            return _v || '#FB5E2A';\r\n        } catch(_e) { return '#FB5E2A'; }\r\n    };\r\n\r\n    \/\/ v4.9ds : centrage de la ligne \"Madagascar \/ Homepage \/ Haut de page \/ Banni\u00e8re\"\r\n    \/\/   dans le r\u00e9cap de commande (cf capture user). Les widgets concern\u00e9s :\r\n    \/\/     - .CampagnePaysClass (pays \u2014 ex: Madagascar)\r\n    \/\/     - .CampagnePageTextClass (page + position \u2014 ex: Homepage Haut de page)\r\n    \/\/     - .CampagneFormatClass (format \u2014 ex: Banni\u00e8re)\r\n    \/\/   sont enfants directs du conteneur flex .1rdtPartCommandeContainer (classe\r\n    \/\/   commen\u00e7ant par chiffre, cibl\u00e9e via [class~] qui matche un mot dans la liste).\r\n    \/\/   Double r\u00e8gle pour couvrir les 2 cas Elementor :\r\n    \/\/     - flex-column width:100% \u2192 text-align:center centre le contenu inline\r\n    \/\/     - flex-row width:auto \u2192 justify-content:center sur le parent centre les enfants\r\n    \/\/   IMPORTANT : injection dans Panier_manager.txt et non Entete.txt car le r\u00e9cap\r\n    \/\/   de commande vit dans l'iframe popup process d'achat (#via-process-iframe), pas\r\n    \/\/   dans la page parente. Panier_manager s'ex\u00e9cute dans cette iframe.\r\n    (function _viaInjectCommandeCenterCSS() {\r\n        if (document.getElementById('via-commande-center-style')) { return; }\r\n        var _styleCC = document.createElement('style');\r\n        _styleCC.id = 'via-commande-center-style';\r\n        \/\/ pb802 : SOURCE UNIQUE du decalage mobile, partagee avec _mt801.\r\n        \/\/   Doit etre declaree AVANT la concatenation : la feuille est construite\r\n        \/\/   comme une seule expression de chaines, aucune instruction ne peut s'y\r\n        \/\/   glisser (erreur de ma passe precedente, rattrapee par node --check).\r\n        \/\/   Lue a la construction ; pour la changer a chaud, poser window._viaDecale801\r\n        \/\/   avant le chargement.\r\n        var _dec802 = (typeof window._viaDecale801 === 'number') ? window._viaDecale801 : -15;   \/\/ pb867 : 10 - 25 (remontee mobile)\r\n        \/\/ pb803 : decalage DESKTOP, source unique partagee avec _mt801.\r\n        var _decDesk803 = (typeof window._viaDecaleDesk803 === 'number') ? window._viaDecaleDesk803 : 5;\r\n        if (window._viaPb801Off === true) { _dec802 = 0; _decDesk803 = 0; }\r\n        _styleCC.textContent =\r\n            'html body .CampagnePaysClass,' +\r\n            'html body .CampagnePageTextClass,' +\r\n            'html body .CampagneFormatClass{' +\r\n                'text-align:center !important;' +\r\n            '}' +\r\n            \/\/ \u2705 Pb 2 : CampagneTarifModeReduit visible UNIQUEMENT en mode r\u00e9duit.\r\n            \/\/   En mode agrandi (data-via-reduit=\"false\" ou absent), masqu\u00e9.\r\n            \/\/   M\u00eame style que CampagneFormatClass (text-align:center).\r\n            'html body .CampagneTarifModeReduit{' +\r\n                'display:none !important;' +\r\n            '}' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .CampagneTarifModeReduit{' +\r\n                'display:inline-block !important;' +\r\n                'text-align:center !important;' +\r\n            '}' +\r\n            \/\/ pb122 : chevron \u203a ajout\u00e9 \u00e0 GAUCHE UNIQUEMENT du message dates (\u00ab Merci de choisir\r\n            \/\/   les dates de campagne pour un tarif \u00bb \/ EN \u00ab Please select campaign dates\u2026 \u00bb),\r\n            \/\/   via ::before sur .CampagneMsgAccompagnement.via-msg-dates. La classe marqueur\r\n            \/\/   via-msg-dates est pos\u00e9e en JS uniquement quand le texte correspond (cf plus bas).\r\n            \/\/   Revert : restaurer les 2 r\u00e8gles via-chevron62 + l'injection JS pb62.\r\n            'html body .CampagneMsgAccompagnement.via-msg-dates::before{' +\r\n                'content:\"\u203a\" !important;' +\r\n                'color:#FB5E2A !important;' +\r\n                'font-size:20.7px !important;' +\r\n                'font-weight:900 !important;' +\r\n                'line-height:1 !important;' +\r\n                'vertical-align:middle !important;' +\r\n                'position:relative !important;' +\r\n                'top:-3px !important;' +\r\n                'margin-right:4px !important;' +\r\n                'display:inline !important;' +\r\n            '}' +\r\n            \/\/ pb295 : texte du message dates +3px (11px -> 14px). Surcharge le style inline.\r\n            'html body .CampagneMsgAccompagnement.via-msg-dates{' +\r\n                'font-size:14px !important;' +\r\n            '}' +\r\n            \/\/ pb63 : lien \"Modifier\" VLP \u2014 aplat bleu + liser\u00e9 gris comme #ValiderReferencesBouton\r\n            \/\/ pb931 : les DEUX boutons (.via-selectionner-btn et .via-vlp-modifier-btn)\r\n            \/\/   sont MASQUES sur demande user. Regle posee en premier et en 'html body'\r\n            \/\/   pour battre les nombreuses regles d'affichage qui suivent (elles sont\r\n            \/\/   conservees telles quelles : elles redeviennent actives si on revert).\r\n            \/\/   Revert : window._viaPb931Off = true (voir aussi les gardes JS).\r\n            'html body .via-selectionner-btn, html body .via-vlp-modifier-btn{' +\r\n                'display:none !important;' +\r\n            '}' +\r\n            'html body .via-vlp-modifier-btn{' +\r\n                'position:absolute !important;top:3px !important;left:5px !important;' +\r\n                'display:none;z-index:10 !important;' +\r\n                'color:#4B689B !important;cursor:pointer !important;' +\r\n                'font-size:11px !important;font-weight:600 !important;' +\r\n                'background:#e8f2fb !important;border:1px solid #bbbbbb !important;' +\r\n                'border-radius:4px !important;padding:3px 10px !important;' +\r\n                'text-align:center !important;line-height:1.4 !important;' +\r\n            '}' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-vlp-modifier-btn{' +\r\n                'transform:translateY(0px) !important;' +\r\n            '}' +\r\n            \/\/ pb63\/pb77 : d\u00e9caler le contenu de l'item UNIQUEMENT quand le bouton Modifier\r\n            \/\/   est r\u00e9ellement visible (style=\"display: block\" inline).\r\n            \/\/   :has() \u00e9vite le d\u00e9calage r\u00e9siduel quand le bouton est masqu\u00e9 (VLP ouvert).\r\n            \/\/ pb77 : padding-top sur container supprim\u00e9 \u2014 g\u00e9r\u00e9 par #CampagnePage margin-top\r\n            \/\/ pb77 : #CampagnePage h\u00e9rite margin-top:20px Elementor \u2192 valeur fixe uniforme.\r\n            \/\/   justify-content:flex-start global (desktop + mobile) pour stabiliser.\r\n            'html body .CampagneTemplateClass #CampagnePage{' +\r\n                'margin-top:' + (20 + _decDesk803) + 'px !important;' +   \/\/ pb803\r\n                'justify-content:flex-start !important;' +\r\n                'align-content:flex-start !important;' +\r\n                'z-index:0 !important;' +\r\n                'position:relative !important;' +\r\n            '}' +\r\n            \/\/ pb802 : le CSS suit le MEME knob que les writers inline. Auparavant il\r\n            \/\/   portait 41px en dur : changer window._viaDecale801 ne deplacait que\r\n            \/\/   la moitie du dispositif, et un rendu ne passant pas par un writer\r\n            \/\/   inline retombait sur l'ancienne valeur. Base 16px + decalage.\r\n            '@media (max-width:999px){' +\r\n                'html body .CampagneTemplateClass #CampagnePage{' +\r\n                    'margin-top:' + (16 + _dec802) + 'px !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/\/ pb113 : d\u00e9calage CONDITIONNEL pilot\u00e9 par la classe via-has-modifier (pos\u00e9e\r\n            \/\/   par le JS quand le bouton Modifier est affich\u00e9, retir\u00e9e sinon). Stable\r\n            \/\/   (classe JS, pas de :has()). Cette r\u00e8gle CSS est un FILET de secours :\r\n            \/\/   l'\u00e9criture inline JS (GetURLCommandeFromItem\/pb63, _viaShowModifierForItem\/\r\n            \/\/   pb128) l'emporte toujours en pratique.\r\n            \/\/ pb890 : INVERSION demand\u00e9e \u2014 au lieu de pousser vers le bas (ancien +12px,\r\n            \/\/   32 = base 20 + 12, pour \u00e9viter le chevauchement avec le bouton), on\r\n            \/\/   remonte par rapport \u00e0 la base. Revert : remettre (32 + _decDesk803) \/\r\n            \/\/   (30 + _dec802) ci-dessous.\r\n            \/\/ pb890b : d\u00e9calage -20px -> -10px par rapport \u00e0 la base\r\n            \/\/   (desktop 20px -> 10px, mobile 16px -> 6px).\r\n            'html body .CampagneTemplateClass.via-has-modifier #CampagnePage{' +\r\n                'margin-top:' + (10 + _decDesk803) + 'px !important;' +   \/\/ pb803\/pb890b : base(20)-10\r\n            '}' +\r\n            \/\/ pb802\/pb890b : mobile \u2014 base 16px - 10px = 6px + d\u00e9calage, m\u00eame knob.\r\n            '@media (max-width:999px){' +\r\n                'html body .CampagneTemplateClass.via-has-modifier #CampagnePage{' +\r\n                    'margin-top:' + (6 + _dec802) + 'px !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/\/ pb63\/pb77 : r\u00e8gles :has() sur items r\u00e9duits supprim\u00e9es \u2014 causaient des sauts\r\n            \/\/   visuels au changement d'\u00e9tat du bouton Modifier.\r\n            'html body [class~=\"1rdtPartCommandeContainer\"],' +\r\n            'html body [class~=\"1rdtPartCommandeContainer\"] > .e-con,' +\r\n            'html body [class~=\"1rdtPartCommandeContainer\"] > .e-con{' +\r\n                'justify-content:center !important;' +\r\n                'align-items:center !important;' +\r\n                'text-align:center !important;' +\r\n            '}' +\r\n            '#CampagnePageText{' +\r\n                'width:auto !important;' +\r\n            '}' +\r\n            \/\/ pb674 : MOBILE ? centrer #Etape1BoutonValider. Le bouton est un element\r\n            \/\/   Elementor pur (aucun style JS ne le touche), il heritait donc de\r\n            \/\/   l'alignement de son conteneur. On couvre les deux mises en page\r\n            \/\/   possibles sans connaitre celle d'Elementor :\r\n            \/\/     - parent en bloc ou flex-row : margin-left\/right auto centre la boite ;\r\n            \/\/     - parent en flex-column     : align-self:center la centre ;\r\n            \/\/     - contenu interne (texte \/ bouton Elementor) : text-align:center.\r\n            \/\/   Desktop inchange (regle scopee au media mobile, convention du fichier).\r\n            '@media (max-width:999px){' +\r\n                'html body #Etape1BoutonValider{' +\r\n                    'margin-left:auto !important;' +\r\n                    'margin-right:auto !important;' +\r\n                    'align-self:center !important;' +\r\n                    'text-align:center !important;' +\r\n                '}' +\r\n                'html body #Etape1BoutonValider > .elementor-widget-container{' +\r\n                    'margin-left:auto !important;' +\r\n                    'margin-right:auto !important;' +\r\n                    'text-align:center !important;' +\r\n                '}' +\r\n            '}';\r\n        if (document.head) {\r\n            document.head.appendChild(_styleCC);\r\n        } else {\r\n            document.documentElement.appendChild(_styleCC);\r\n        }\r\n    })();\r\n\r\n    \/\/ v4.9ds : d\u00e9tection contexte d'ex\u00e9cution Panier_manager (r\u00e9gie vs pays)\r\n    \/\/   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n    \/\/   Architecture confirm\u00e9e user :\r\n    \/\/     - Sites pays (madagascar.yearbook-media.com, etc.) :\r\n    \/\/         Panier_manager s'ex\u00e9cute DANS l'iframe popup d'achat\r\n    \/\/         (#via-process-iframe qui charge yearbook-media.com\/?mode=popup)\r\n    \/\/         \u2192 window !== window.top\r\n    \/\/     - Site r\u00e9gie (yearbook-media.com sans sous-domaine, pas de popup) :\r\n    \/\/         Panier_manager s'ex\u00e9cute directement sur la page r\u00e9gie en top\r\n    \/\/         \u2192 window === window.top\r\n    \/\/   Donc : r\u00e9gie = (window === window.top) ET hostname r\u00e9gie.\r\n    \/\/   On pose la classe via-from-regie sur <html> pour permettre le ciblage CSS.\r\n    \/\/   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n    (function _viaDetectRegieContext() {\r\n        try {\r\n            var _isTop = (window === window.top);\r\n            var _host = window.location.hostname || '';\r\n            \/\/ Site r\u00e9gie = yearbook-media.com (avec ou sans www, pas de sous-domaine pays).\r\n            \/\/   Match : yearbook-media.com OU www.yearbook-media.com\r\n            \/\/   Ne match PAS : madagascar.yearbook-media.com (sous-domaine pays)\r\n            var _isRegieHost = \/^(?:www\\.)?yearbook-media\\.com$\/.test(_host);\r\n            \/\/ R\u00e9gie = on est en top window ET hostname r\u00e9gie.\r\n            \/\/   (Si dans une iframe popup pays, _isTop=false \u2192 pas r\u00e9gie m\u00eame si\r\n            \/\/   l'iframe est servie par yearbook-media.com.)\r\n            var _isRegie = _isTop ? _isRegieHost : false;\r\n            console.log('[v4.9ds detectRegie] top:', _isTop, '| host:', _host, '| isRegieHost:', _isRegieHost, '| \u2192 isRegie:', _isRegie);\r\n            if (_isRegie) {\r\n                document.documentElement.classList.add('via-from-regie');\r\n                console.log('[v4.9ds] contexte = SITE R\u00c9GIE \u2014 classe via-from-regie pos\u00e9e');\r\n            }\r\n        } catch(_eR) {}\r\n    })();\r\n\r\n    \/\/   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n    \/\/   Quand un item .CampagneTemplateClass a data-via-reduit=\"true\", on\r\n    \/\/   masque TOUT son contenu sauf :\r\n    \/\/     - la 1\u00e8re ligne .CampagneNoClass\r\n    \/\/     - la croix de fermeture .CampagneCloseButton\r\n    \/\/     - le bouton R\u00e9duire\/Agrandir .via-reduire-btn (le carr\u00e9 qui permet\r\n    \/\/       de r\u00e9-agrandir)\r\n    \/\/   Technique : on n'utilise PAS display:none car le code de remplissage\r\n    \/\/   pose explicitement style=\"display:block !important\" sur certains\r\n    \/\/   \u00e9l\u00e9ments (ex: CampagneFormatClass ligne 1990) \u2014 l'inline bat le CSS\r\n    \/\/   \u00e0 sp\u00e9cificit\u00e9 \u00e9gale. \u00c0 la place : visibility:hidden + height:0 +\r\n    \/\/   margin:0 + padding:0 + overflow:hidden + border:0 (font-size:0\r\n    \/\/   pour absorber les espaces blancs r\u00e9siduels). Cette combinaison\r\n    \/\/   \u00e9crase l'inline display car elle utilise des propri\u00e9t\u00e9s diff\u00e9rentes.\r\n    \/\/   P\u00c9RIM\u00c8TRE : Panier_manager.txt s'ex\u00e9cute UNIQUEMENT dans iframe popup\r\n    \/\/   d'achat, donc r\u00e8gles inoffensives ailleurs.\r\n    \/\/   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n    (function _viaInjectReducerCSS() {\r\n        if (document.getElementById('via-reducer-style')) { return; }\r\n        var _styleR = document.createElement('style');\r\n        \/\/ pb804 : decalages du picto Reduire en mode reduit. Declares AVANT la\r\n        \/\/   concatenation : la feuille est une seule expression de chaines, aucune\r\n        \/\/   instruction ne peut s'y glisser (lecon pb802).\r\n        \/\/ pb814 : DESKTOP \u2014 le picto Agrandir (item reduit) descend de 3px.\r\n        \/\/   pb804 l'avait remonte de 2px ; -2 + 3 = +1. Le picto Reduire\r\n        \/\/   (data-via-reduit=\"false\") n'est pas concerne par cette regle et reste\r\n        \/\/   inchange, conformement au constat utilisateur.\r\n        \/\/   MOBILE inchange (-3px, pb804).\r\n        var _redDesk804 = (typeof window._viaReduireDesk804 === 'number') ? window._viaReduireDesk804 : 1;\r\n        var _redMob804  = (typeof window._viaReduireMob804  === 'number') ? window._viaReduireMob804  : -3;\r\n        \/\/ pb1027 : largeur des cartes de reservation sur mobile, en % de l'ecran.\r\n        \/\/   Declaree AVANT la concatenation : la feuille est une seule expression de\r\n        \/\/   chaines, aucune instruction ne peut s'y glisser (lecon pb802).\r\n        var _larg1027 = (window._viaPb1027Off === true)\r\n            ? 100\r\n            : ((typeof window._viaLargeurResa1027 === 'number') ? window._viaLargeurResa1027 : 95);\r\n        _styleR.id = 'via-reducer-style';\r\n        \/\/ v4.9ds : taille bouton r\u00e9duite de 15% (20\u219217px) + repositionn\u00e9\r\n        \/\/   (display block + margin-top n\u00e9gatif pour aligner sur la 1\u00e8re ligne)\r\n        var _hideRules =\r\n            'visibility:hidden !important;' +\r\n            'height:0 !important;' +\r\n            'min-height:0 !important;' +\r\n            'max-height:0 !important;' +\r\n            'margin:0 !important;' +\r\n            'padding:0 !important;' +\r\n            'border:0 !important;' +\r\n            'overflow:hidden !important;' +\r\n            'font-size:0 !important;' +\r\n            'line-height:0 !important;';\r\n        _styleR.textContent =\r\n            \/\/ Bouton R\u00e9duire\/Agrandir\r\n            \/\/   v4.9ds : 17\u00d717px (au lieu 20\u00d720 = -15%)\r\n            \/\/   Position : absolu en haut-droite de l'item, juste \u00e0 gauche de la croix.\r\n            \/\/   La croix .CampagneCloseButton est d\u00e9j\u00e0 en absolu top:5px right:5px (Elementor).\r\n            \/\/   On place notre bouton \u00e0 right:20px (10px plus \u00e0 droite que la version\r\n            \/\/   pr\u00e9c\u00e9dente right:30px \u2014 demande user) pour rapprocher de la croix.\r\n            \/\/   L'item .CampagneTemplateClass doit \u00eatre position:relative pour que ce\r\n            \/\/   absolu se r\u00e9f\u00e8re bien \u00e0 l'item (CSS forc\u00e9 ci-dessous).\r\n            'html body .CampagneTemplateClass{' +\r\n                'position:relative !important;' +\r\n            '}' +\r\n            \/\/ pb1244 : picto Reduire decale de 5px vers la GAUCHE (demande user).\r\n            \/\/   L'element est ancre par son bord DROIT : augmenter 'right' l'eloigne\r\n            \/\/   du bord, donc le deplace vers la gauche. 20 -> 25.\r\n            \/\/   Verifie : c'est la SEULE declaration 'right' de ce bloc \u2014 la valeur\r\n            \/\/   de 40px vue plus bas appartient a .via-selection-btn, un autre\r\n            \/\/   bouton. (Lecon pb1241c : une propriete declaree deux fois dans le\r\n            \/\/   meme bloc rend la premiere sans effet.)\r\n            \/\/   Le bouton Selectionner n'est pas decale : il garde ses 40px, l'ecart\r\n            \/\/   entre les deux passe donc de 20 a 15px.\r\n            'html body .via-reduire-btn{' +\r\n                'position:absolute !important;' +\r\n                'top:5px !important;' +\r\n                'right:25px !important;' +\r\n                'display:inline-flex !important;' +\r\n                'align-items:center !important;' +\r\n                'justify-content:center !important;' +\r\n                'width:17px !important;' +\r\n                'height:17px !important;' +\r\n                'background:transparent !important;' +\r\n                'border:none !important;' +\r\n                'cursor:pointer !important;' +\r\n                'color:#4B689B !important;' +\r\n                'padding:0 !important;' +\r\n                'margin:0 !important;' +\r\n                'z-index:120 !important;' +\r\n            '}' +\r\n            \/\/ pb206 : picto \"S\u00e9lectionner\" (case \u00e0 cocher) \u2014 plac\u00e9 \u00e0 gauche du bouton\r\n            \/\/   R\u00e9duire. Couleur : verte #01f41a si la r\u00e9servation est active\r\n            \/\/   (data-via-reduit=\"false\"), grise #bbbbbb sinon. SVG stroke=currentColor.\r\n            \/\/   Positionnement DYNAMIQUE : right:40px quand R\u00e9duire est pr\u00e9sent\r\n            \/\/   (croix=5, R\u00e9duire=20, S\u00e9lectionner=40). Quand R\u00e9duire est masqu\u00e9\r\n            \/\/   (data-via-no-ref=\"true\" \u2192 display:none, cf r\u00e8gle plus bas), S\u00e9lectionner\r\n            \/\/   glisse \u00e0 right:20px (place de R\u00e9duire) pour ne pas laisser de trou.\r\n            'html body .via-selectionner-btn{' +\r\n                'position:absolute !important;' +\r\n                'top:5px !important;' +\r\n                'right:40px !important;' +\r\n                'display:inline-flex !important;' +\r\n                'align-items:center !important;' +\r\n                'justify-content:center !important;' +\r\n                'width:17px !important;' +\r\n                'height:17px !important;' +\r\n                'background:transparent !important;' +\r\n                'border:none !important;' +\r\n                'cursor:pointer !important;' +\r\n                'color:#4B689B !important;' +  \/* pb216 : bleu comme les autres pictos sur r\u00e9sa inactive (\u00e9tait #bbbbbb gris) *\/\r\n                'padding:0 !important;' +\r\n                'margin:0 !important;' +\r\n                'z-index:120 !important;' +\r\n            '}' +\r\n            \/\/   pb222 : R\u00e9duire n'est plus masqu\u00e9 en no-ref \u2192 S\u00e9lectionner reste \u00e0 right:40px\r\n            \/\/   (plus besoin de glisser \u00e0 right:20px). Bloc d'origine en commentaire.\r\n            \/\/ 'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] .via-selectionner-btn{' +\r\n            \/\/     'right:20px !important;' +\r\n            \/\/ '}' +\r\n            '' +\r\n            'html body .CampagneTemplateClass[data-via-item-actif=\"true\"] .via-selectionner-btn{' +\r\n                'color:#01f41a !important;' +  \/* pb227 : vert si r\u00e9sa r\u00e9ellement active (pas selon r\u00e9duit\/agrandi) *\/\r\n            '}' +\r\n            'html body .via-selectionner-btn:hover{' +\r\n                'opacity:0.7 !important;' +\r\n            '}' +\r\n            'html body .via-selectionner-btn svg{' +\r\n                'pointer-events:none !important;' +\r\n                'width:14px !important;' +\r\n                'height:14px !important;' +\r\n            '}' +\r\n            \/\/ pb206 : ALIGNEMENT HORIZONTAL des 3 pictos \u2014 uniformiser la bo\u00eete (17x17) et\r\n            \/\/   le svg (14x14) sur les trois. Le `top` de S\u00e9lectionner suit celui de R\u00e9duire\r\n            \/\/   (m\u00eames r\u00e8gles top + m\u00eames transform, cf ajouts ci-dessus\/dessous) pour rester\r\n            \/\/   sur la m\u00eame ligne. On ne FORCE pas un top commun ici (cela casserait les\r\n            \/\/   ajustements fins de R\u00e9duire) ; on aligne S\u00e9lectionner SUR R\u00e9duire.\r\n            'html body .CampagneTemplateClass .via-selectionner-btn,' +\r\n            'html body .CampagneTemplateClass .via-reduire-btn,' +\r\n            'html body .CampagneTemplateClass .CampagneCloseButton{' +\r\n                'width:17px !important;' +\r\n                'height:17px !important;' +\r\n                'display:inline-flex !important;' +\r\n                'align-items:center !important;' +\r\n                'justify-content:center !important;' +\r\n            '}' +\r\n            'html body .CampagneTemplateClass .via-selectionner-btn svg,' +\r\n            'html body .CampagneTemplateClass .via-reduire-btn svg,' +\r\n            'html body .CampagneTemplateClass .CampagneCloseButton svg{' +\r\n                'width:14px !important;' +\r\n                'height:14px !important;' +\r\n            '}' +\r\n            \/\/ v4.9ds : le bouton R\u00e9duire (item agrandi = data-via-reduit=\"false\") est\r\n            \/\/   remont\u00e9 de 2px (top:5\u21923) \u2014 demande user. pb206 : S\u00e9lectionner suit le m\u00eame\r\n            \/\/   top pour rester align\u00e9 horizontalement avec R\u00e9duire.\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-reduire-btn,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-selectionner-btn,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"false\"] .CampagneCloseButton{' +\r\n                'top:3px !important;' +\r\n            '}' +\r\n            \/\/ v4.9ds : tant que la 1\u00e8re ligne .CampagneNoClass n'est pas affich\u00e9e,\r\n            \/\/   masquer le bouton R\u00e9duire\/Agrandir.\r\n            \/\/   Demande user : pas de r\u00e9duction possible si la ligne d'identification\r\n            \/\/   de la commande n'est m\u00eame pas visible.\r\n            \/\/   pb222 : masquage de via-reduire-btn en no-ref RETIR\u00c9 \u2014 le bouton R\u00e9duire\r\n            \/\/   doit \u00eatre TOUJOURS pr\u00e9sent quelle que soit la config (demande user). Bloc\r\n            \/\/   d'origine conserv\u00e9 en commentaire, cha\u00eene vide pour pr\u00e9server la concat\u00e9nation.\r\n            \/\/ 'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] .via-reduire-btn{' +\r\n            \/\/     'display:none !important;' +\r\n            \/\/ '}' +\r\n            '' +\r\n            \/\/ \u2705 v4.9ds Pb 7 : quand l'espace pub n'est pas encore choisi\r\n            \/\/   (data-via-no-ref=\"true\" \u2192 CampagneNoClass non rempli), repositionner\r\n            \/\/   les donn\u00e9es pays \/ secteurs \/ format selon la plateforme :\r\n            \/\/   - Desktop (\u22651000px) : remont\u00e9e de 10px\r\n            \/\/   - Mobile  (<1000px) : remont\u00e9e de 8px (demande user)\r\n            '@media (min-width:1000px){' +\r\n                'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] .CampagnePaysClass,' +\r\n                'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] .CampagnePageTextClass,' +\r\n                'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] .CampagneFormatClass,' +\r\n                'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] #CampagnePaysTexte,' +\r\n                'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] #CampagnePageText{' +\r\n                    'margin-top:-10px !important;' +\r\n                '}' +\r\n            '}' +\r\n            '@media (max-width:999px){' +\r\n                'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] .CampagnePaysClass,' +\r\n                'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] .CampagnePageTextClass,' +\r\n                'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] .CampagneFormatClass,' +\r\n                'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] #CampagnePaysTexte,' +\r\n                'html body .CampagneTemplateClass[data-via-no-ref=\"true\"] #CampagnePageText{' +\r\n                    'margin-top:-8px !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/* pb2127 : la remise <small> de la carte (ecrite par le helper\r\n               pb2121\/pb2124) +2px (demande JF). Le small navigateur vaut ~0.8em\r\n               du parent : on repart de cette base et on ajoute 2px \u2014 pas de\r\n               valeur absolue, la taille du parent reste maitresse. *\/\r\n            'html body .CampagneTarifClass small{' +\r\n                'font-size:calc(0.8em + 2px) !important;' +\r\n            '}' +\r\n            \/\/ \u2705 v4.9ds Pb 7 : FinaliserBouton (.PasserCommandeBouton) en rouge #FB5E2A.\r\n            \/\/   Demande user. Override des r\u00e8gles Elementor potentielles.\r\n            'html body .FinaliserBouton .PasserCommandeBouton,' +\r\n            'html body .FinaliserBouton .PasserCommandeBouton *,' +\r\n            'html body .PasserCommandeBouton,' +\r\n            'html body .PasserCommandeBouton *{' +\r\n                'color:#FB5E2A !important;' +\r\n            '}' +\r\n            \/\/ pb1859 : premiere ligne du bouton (\"Cliquer ici pour finaliser...\")\r\n            \/\/   agrandie de 1.5px, mobile et desktop. Demande JF.\r\n            \/\/   Le libelle et le prix sont deux NOEUDS TEXTE separes par un <br>,\r\n            \/\/   sans element autour : rien a cibler en CSS. La premiere ligne est\r\n            \/\/   donc balisee a la SOURCE, dans le seul ecrivain du contenu\r\n            \/\/   (l.~9253 et l.~9264), plutot que rattrapee apres coup par un\r\n            \/\/   observateur qui devrait courir derriere chaque changement de prix.\r\n            \/\/   calc(1em + Xpx) : le 1em d'une declaration font-size designe le\r\n            \/\/   font-size du PARENT. La taille derive donc du bouton et jamais\r\n            \/\/   d'elle-meme \u2014 aucune derive cumulative possible, quel que soit le\r\n            \/\/   nombre de reecritures du bouton (lecon pb1750).\r\n            \/\/   Reglage a chaud, sans redeploiement :\r\n            \/\/   document.documentElement.style.setProperty('--via-fin-l1', '3px')\r\n            \/\/   pb2144 : la valeur par defaut passe de 1.5px a 3px, puis a 3.5px\r\n            \/\/     (pb2144b, demande JF).\r\n            \/\/     Seule la BASE change ; le supplement mobile de pb2052 reste en\r\n            \/\/     plus, donc la ligne 1 vaut 3px en desktop et 4.5px en mobile.\r\n            'html body .PasserCommandeBouton .via-fin-l1{' +\r\n                'font-size:calc(1em + var(--via-fin-l1, 3.5px)) !important;' +\r\n            '}' +\r\n            \/\/ pb2052 : SUR MOBILE, LES DEUX LIGNES PRENNENT 1.5px DE PLUS.\r\n            \/\/   Demande JF, mobile uniquement, en SUPPLEMENT de l'etat visible :\r\n            \/\/   la ligne 1 passe donc de base+3.5 a base+5 (valeurs pb2144b), la\r\n            \/\/   ligne 2 de base a base+1.5. Desktop inchange.\r\n            \/\/   POURQUOI PAS UNE SEULE REGLE SUR LE BOUTON : les deux lignes en\r\n            \/\/   heriteraient d'un coup, mais le 1em d'une declaration font-size\r\n            \/\/   designe le font-size du PARENT (pb1859). Pose sur le bouton, le\r\n            \/\/   calc partirait de la taille de son conteneur Elementor et non de\r\n            \/\/   la sienne : la base serait fausse. Sur les deux spans, le parent\r\n            \/\/   EST le bouton \u2014 la base est juste, et rien ne derive.\r\n            \/\/   Placee APRES la regle de pb1859 : meme specificite, c'est l'ordre\r\n            \/\/   de la feuille qui tranche.\r\n            \/\/   Le seuil 999px est celui de tout ce fichier. La media query mesure\r\n            \/\/   le viewport du DOCUMENT \u2014 dans le popup des sites pays, celui de\r\n            \/\/   l'iframe : desktop mesure 1404px, mobile bien moins. Elle discrimine\r\n            \/\/   donc juste dans les deux contextes.\r\n            \/\/   Reglage a chaud, sans redeploiement :\r\n            \/\/   document.documentElement.style.setProperty('--via-fin-mob', '3px')\r\n            '@media (max-width:999px){' +\r\n                'html body .PasserCommandeBouton .via-fin-l1{' +\r\n                    'font-size:calc(1em + var(--via-fin-l1, 3.5px)'   \/* pb2144b : 3 -> 3.5 *\/\r\n                        + ' + var(--via-fin-mob, 1.5px)) !important;' +\r\n                '}' +\r\n                'html body .PasserCommandeBouton .via-fin-l2{' +\r\n                    'font-size:calc(1em + var(--via-fin-mob, 1.5px)) !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/\/ \u2705 v4.9ds Pb 7 : .CampagneEnvoiUlterieurClass (\"Annonce ins\u00e9r\u00e9e\") appara\u00eet\r\n            \/\/   trop haute par rapport aux autres d\u00e9tails (Pays \/ Page \/ Format) \u00e0 cause\r\n            \/\/   du flow Elementor. On la baisse de 17px pour aligner sa baseline avec\r\n            \/\/   les \u00e9l\u00e9ments voisins. Demande user (5 + 10 + 2 px d'ajustements successifs).\r\n            'html body .CampagneTemplateClass .CampagneEnvoiUlterieurClass{' +\r\n                'margin-top:17px !important;' +\r\n            '}' +\r\n            \/\/ \u2705 v4.9ds Pb 7 : sur mobile uniquement, .CampagneEnvoiUlterieurClass \u00e0\r\n            \/\/   margin-top:0 (ajustements successifs demand\u00e9s par l'user \u2014 layout mobile\r\n            \/\/   diff\u00e9rent du desktop).\r\n            '@media (max-width:999px){' +\r\n                'html body .CampagneTemplateClass .CampagneEnvoiUlterieurClass{' +\r\n                    'margin-top:0 !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/\/ \u2705 v4.9ds Pb 7 \/ pb107 : sur mobile uniquement, .CampagneAnnonceDeposeClass.\r\n            \/\/   \u00c9tait remont\u00e9e de -25px \u2192 chevauchait \u00ab \u2026\u00e0 r\u00e9server \u00bb. Valeur finale : 0px.\r\n            '@media (max-width:999px){' +\r\n                'html body .CampagneTemplateClass .CampagneAnnonceDeposeClass{' +\r\n                    'margin-top:0px !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/\/ v4.9ds : sur site r\u00e9gie desktop UNIQUEMENT, d\u00e9caler les boutons\r\n            \/\/ v4.9ds : sur site r\u00e9gie desktop UNIQUEMENT, d\u00e9caler les boutons\r\n            \/\/   R\u00e9duire\/Agrandir (demandes successives user, valeurs finales) :\r\n            \/\/     Agrandir top:7  (sur item r\u00e9duit, r\u00e8gle g\u00e9n\u00e9rale)\r\n            \/\/     R\u00e9duire  top:8  (sur item agrandi, override [data-via-reduit=\"false\"])\r\n            \/\/   - html.via-from-regie : panier_manager s'ex\u00e9cute en top window sur\r\n            \/\/     yearbook-media.com (= site r\u00e9gie, pas iframe popup pays)\r\n            \/\/   - @media (min-width:1000px) : desktop uniquement (mobile inchang\u00e9)\r\n            \/\/   Override des top:5px (Agrandir) et top:3px (R\u00e9duire) plus haut.\r\n            \/\/   \u2705 v4.9ds Pb 3 v5 : ajustements demande user.\r\n            \/\/     Desktop : Agrandir top:3 (Pb 3 v4 \u00e9tait \u00e0 4, -1) | R\u00e9duire top:0 (inchang\u00e9)\r\n            \/\/     Mobile  : R\u00e9duire top:2 (inchang\u00e9) | Agrandir top:4 (NOUVELLE r\u00e8gle, -1 par\r\n            \/\/               rapport au global top:5)\r\n            \/\/     Desktop item r\u00e9duit : .CampagnePageRefClass remont\u00e9e de 10px (transform\r\n            \/\/               translateY) \u2192 \"Espace r\u00e9serv\u00e9 GAB44766L1A\" (la ligne 1) plus haute,\r\n            \/\/               r\u00e9duit l'espace blanc visible de l'item r\u00e9duit. Pos\u00e9 en transform\r\n            \/\/               et non margin-top n\u00e9gatif pour \u00e9viter de chambouler le flow flex.\r\n            '@media (min-width:1000px){' +\r\n                'html.via-from-regie body .CampagneTemplateClass .via-reduire-btn{' +\r\n                    'top:3px !important;' +\r\n                '}' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-reduire-btn,' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-selectionner-btn,' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"false\"] .CampagneCloseButton{' +\r\n                    'top:0px !important;' +\r\n                '}' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"true\"] .CampagnePageRefClass{' +\r\n                    'transform:translateY(-10px) !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/\/ \u2705 v4.9ds Pb 3 v5 : sur site r\u00e9gie MOBILE UNIQUEMENT, remonter R\u00e9duire et\r\n            \/\/   Agrandir de 1px par rapport aux r\u00e8gles globales :\r\n            \/\/     R\u00e9duire (item agrandi) top:2 (-1 par rapport au global top:3)\r\n            \/\/     Agrandir (item r\u00e9duit) top:4 (-1 par rapport au global top:5)\r\n            \/\/   Demande user. Pos\u00e9 en @media (max-width:999px) pour ne pas affecter desktop.\r\n            '@media (max-width:999px){' +\r\n                'html.via-from-regie body .CampagneTemplateClass .via-reduire-btn,' +\r\n                'html.via-from-regie body .CampagneTemplateClass .via-selectionner-btn,' +\r\n                'html.via-from-regie body .CampagneTemplateClass .CampagneCloseButton{' +\r\n                    'top:4px !important;' +\r\n                '}' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-reduire-btn,' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-selectionner-btn,' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"false\"] .CampagneCloseButton{' +\r\n                    'top:2px !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/* ====================================================================\r\n             * pb2349 : LE PICTO REDUIRE EST MASQUE (demande JF : sans interet).\r\n             *   Il est injecte a TROIS endroits (creation anticipee l.4956,\r\n             *   remplirItemPartiel l.5355, remplirItemComplet l.7437). Le masquer par\r\n             *   une regle plutot que par trois suppressions : un seul endroit a lire,\r\n             *   un seul a annuler, et aucun risque d en oublier un quatrieme demain.\r\n             *   La fonction Reduire\/Agrandir reste intacte dessous \u2014 seul son bouton\r\n             *   disparait. Revert : window._viaPb2349Off = true (recharger la page).\r\n             * ==================================================================== *\/\r\n            \/* pb2352 : la regle de pb2349 perdait par SPECIFICITE, pas par erreur.\r\n                 l.707  html body .CampagneTemplateClass .via-reduire-btn  -> 0-2-2\r\n                        display:inline-flex !important\r\n                 pb2349 html body .via-reduire-btn                         -> 0-1-2\r\n                        display:none !important\r\n               Les deux sont !important : c est la plus specifique qui gagne, donc\r\n               inline-flex. Ma regle n avait aucune chance, et l ordre dans la feuille\r\n               n y changeait rien \u2014 l ordre ne departage qu a specificite EGALE.\r\n               La classe est repetee trois fois : 0-3-2, au-dessus de toutes les regles\r\n               qui touchent ce bouton (la plus forte est 0-3-2 sur le seul `top`). Le\r\n               selecteur reste le meme element, sans dependre d un ancetre \u2014 le bouton\r\n               est donc masque partout ou il est injecte, aujourd hui et demain. *\/\r\n            (window._viaPb2349Off === true ? '' :\r\n                'html body .via-reduire-btn.via-reduire-btn.via-reduire-btn{' +\r\n                'display:none !important;' +\r\n                '} ') +\r\n            'html body .via-reduire-btn:hover{' +\r\n                'opacity:0.7 !important;' +\r\n            '}' +\r\n            'html body .via-reduire-btn svg{' +\r\n                'pointer-events:none !important;' +\r\n                'width:12px !important;' +\r\n                'height:12px !important;' +\r\n            '}' +\r\n            \/\/ \u2705 v4.9ds Fix 17 (Pb 13) : d\u00e9caler de +5px vers le bas les boutons R\u00e9duire\r\n            \/\/   (.via-reduire-btn) et Supprimer (.CampagneCloseButton) UNIQUEMENT sur l'item\r\n            \/\/   ACTIF (= data-via-reduit=\"false\", pos\u00e9 par setItemActif ligne 3518).\r\n            \/\/   Sur les items inactifs (data-via-reduit=\"true\"), les boutons restent \u00e0\r\n            \/\/   leur position d'origine. Demande user \u2014 applicable \u00e0 tous contextes :\r\n            \/\/   mobile\/desktop, site pays\/r\u00e9gie. translateY est additif et n'\u00e9crase pas\r\n            \/\/   les r\u00e8gles top:Xpx existantes.\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-reduire-btn,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-selectionner-btn,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"false\"] .CampagneCloseButton{' +\r\n                'transform:translateY(5px) !important;' +\r\n            '}' +\r\n            \/\/ \u2705 v4.9ds Fix 22 : remonter de 5px les boutons R\u00e9duire\/Agrandir\/Supprimer\r\n            \/\/   UNIQUEMENT sur les sites pays (= popup achat depuis un site pays, donc\r\n            \/\/   PAS html.via-from-regie). Demande user :\r\n            \/\/     \u2022 desktop (\u22651000px) : sur TOUS les items\r\n            \/\/     \u2022 mobile (<1000px) : sur l'item ACTIF uniquement (data-via-reduit=\"false\")\r\n            \/\/   Pos\u00e9 APR\u00c8S Fix 17 pour gagner en ordre de cascade \u2014 sur site pays desktop\r\n            \/\/   item actif, ce Fix 22 (-5px) \u00e9crase Fix 17 (+5px) \u2192 r\u00e9sultat net : -5px.\r\n            \/\/   Sur la r\u00e9gie, Fix 17 reste actif (via :not(.via-from-regie) ne match pas).\r\n            '@media (min-width:1000px){' +\r\n                'html:not(.via-from-regie) body .CampagneTemplateClass .via-reduire-btn,' +\r\n                'html:not(.via-from-regie) body .CampagneTemplateClass .via-selectionner-btn,' +\r\n                'html:not(.via-from-regie) body .CampagneTemplateClass .CampagneCloseButton{' +\r\n                    'transform:translateY(-5px) !important;' +\r\n                '}' +\r\n            '}' +\r\n            '@media (max-width:999px){' +\r\n                'html:not(.via-from-regie) body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-reduire-btn,' +\r\n                'html:not(.via-from-regie) body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-selectionner-btn,' +\r\n                'html:not(.via-from-regie) body .CampagneTemplateClass[data-via-reduit=\"false\"] .CampagneCloseButton{' +\r\n                    'transform:translateY(-5px) !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/\/ \u2705 pb119 : sur la R\u00c9GIE MOBILE uniquement (html.via-from-regie), dans la r\u00e9sa\r\n            \/\/   ACTIVE (data-via-reduit=\"false\") :\r\n            \/\/     \u2022 descendre tout le bloc texte de 10px via margin-top sur le wrapper\r\n            \/\/       .CampagnePageRefClass (qui contient .CampagneNoClass) : margin pousse le\r\n            \/\/       FLUX, donc le titre ET les lignes en dessous (#CampagnePage, message)\r\n            \/\/       descendent ensemble \u2192 pas de chevauchement. (translateY ne d\u00e9pla\u00e7ait que\r\n            \/\/       le titre visuellement, hors flux \u2192 il recouvrait le texte du dessous.)\r\n            \/\/     \u2022 remonter les pictos R\u00e9duire (.via-reduire-btn) + Supprimer\r\n            \/\/       (.CampagneCloseButton) de 5px : Fix 17 les pose \u00e0 +5px sur la r\u00e9gie,\r\n            \/\/       donc translateY(0) = -5px visuel. Pictos en absolu \u2192 non affect\u00e9s par\r\n            \/\/       le margin du flux. (transform n'est pas additif : la r\u00e8gle la plus\r\n            \/\/       tardive gagne, d'o\u00f9 la valeur nette explicite.)\r\n            \/\/   Sites pays non concern\u00e9s (d\u00e9j\u00e0 r\u00e9gl\u00e9s par Fix 22). Demande user.\r\n            '@media (max-width:999px){' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"false\"] .CampagnePageRefClass{' +\r\n                    'margin-top:-15px !important;' +\r\n                '}' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-reduire-btn,' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-selectionner-btn,' +\r\n                'html.via-from-regie body .CampagneTemplateClass[data-via-reduit=\"false\"] .CampagneCloseButton{' +\r\n                    'transform:translateY(0px) !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/\/ Item r\u00e9duit : tous les enfants directs masqu\u00e9s SAUF\r\n            \/\/   - .CampagneNoClass (1\u00e8re ligne)\r\n            \/\/   - .CampagneCloseButton + .via-reduire-btn (croix + bouton)\r\n            \/\/   - .CampagnePageRefClass (wrapper qui contient .CampagneNoClass)\r\n            \/\/   - les conteneurs internes (.e-con) ne doivent PAS \u00eatre collaps\u00e9s\r\n            \/\/     car ils contiennent .CampagneNoClass \u2014 on cible donc directement\r\n            \/\/     les classes feuille \u00e0 masquer.\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .CampagneEnvoiUlterieurClass,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .CampagneAnnonceDeposeClass,' +\r\n            \/\/ \u2705 Pb 1 : CampagneMsgAccompagnement retir\u00e9 de cette liste \u2192 visible m\u00eame sur\r\n            \/\/   items inactifs (data-via-reduit=\"true\"), pour que le message d'accompagnement\r\n            \/\/   (ex: \"Merci de s\u00e9lectionner\u2026\") reste lisible quel que soit l'item actif.\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .CampagnePaysSocieteContainer,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .CampagneDatesContainer,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .DatesDureeTarifContainer,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .ReferencesAnnonceurContainer,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .ChoisirPaiementContainer,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .ProcederPaiementContainer,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .CampagnePositionClass,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .TarifClosedClass,' +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .ArticleTitre,' +\r\n            \/\/ \u2705 v4.9ds Pb 4 : .CampagneFormatClass \/ .CampagnePaysClass \/ .CampagnePageTextClass\r\n            \/\/   masqu\u00e9es UNIQUEMENT quand l'item est r\u00e9duit ET a un espace pub choisi\r\n            \/\/   (data-via-no-ref absent ou false). Sur item r\u00e9duit SANS espace pub\r\n            \/\/   (data-via-no-ref=\"true\"), on garde Pays\/Secteur\/Format visibles pour ne\r\n            \/\/   pas avoir un item compl\u00e8tement vide.\r\n            \/\/ \u2705 Pb 2 : retrait de CampagneFormatClass, CampagnePaysClass, CampagnePageTextClass\r\n            \/\/   de ce bloc \u2014 ils doivent \u00eatre visibles en mode r\u00e9duit pour TOUS les items\r\n            \/\/   (avec ou sans r\u00e9f\u00e9rence), comme pour les items anticip\u00e9s (data-via-no-ref).\r\n            \/\/ \u2705 v4.9ds Fix 19 v2 (Pb 14) : checkbox du r\u00e9cap visible UNIQUEMENT sur item\r\n            \/\/   actif (data-via-reduit=\"false\"). Sur items inactifs, on la cache.\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .via-recap-reserver-cb{' +\r\n                _hideRules +\r\n            '}' +\r\n            \/\/ \u2705 Pb 1 v2 : r\u00e8gle positive pour forcer CampagneMsgAccompagnement visible m\u00eame\r\n            \/\/   sur items inactifs. La suppression du s\u00e9lecteur dans _hideRules ne suffit\r\n            \/\/   pas : visibility:hidden peut \u00eatre h\u00e9rit\u00e9 d'un parent (flex container Elementor),\r\n            \/\/   et jQuery .hide() pose un inline display:none qui bat le CSS sans !important.\r\n            \/\/   Cette r\u00e8gle surclasse les deux m\u00e9canismes.\r\n            \/\/   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            \/\/   Pb 1 v3 : CampagneMsgAccompagnement est enfant de 59647d28 (e-con Elementor).\r\n            \/\/   Elementor pose overflow:hidden sur les .e-con via son CSS natif. Si son\r\n            \/\/   ResizeObserver calcule la hauteur de 59647d28 avant l'injection du message,\r\n            \/\/   le container a une hauteur fixe + overflow:hidden \u2192 le message est clips\u00e9.\r\n            \/\/   Fix : forcer overflow:visible sur CampagnePageClass ET sur son enfant .e-con\r\n            \/\/   direct (= 59647d28, parent imm\u00e9diat du message).\r\n            'html body .CampagneTemplateClass .CampagnePageClass {' +\r\n                'overflow:visible !important;' +\r\n            '}' +\r\n            'html body .CampagneTemplateClass .CampagnePageClass > .e-con {' +\r\n                'overflow:visible !important;' +\r\n            '}' +\r\n            \/* pb218 : l'item a un fond gris clair #f8f8f8 (actif comme inactif). Le message\r\n               dates (via-msg-dates) et le bloc dates doivent rester blancs, y compris les\r\n               espaces lat\u00e9raux du message \u2192 width:100% pour couvrir toute la largeur. *\/\r\n            'html body .CampagneTemplateClass .via-msg-dates,' +\r\n            'html body .CampagneTemplateClass .DatesDureeCampagneClass{' +\r\n                'background-color:#ffffff !important;' +\r\n            '}' +\r\n            'html body .CampagneTemplateClass .via-msg-dates{' +\r\n                'display:block !important;' +\r\n                'width:100% !important;' +\r\n                'max-width:100% !important;' +\r\n                'box-sizing:border-box !important;' +\r\n            '}' +\r\n            \/* pb218 : DatesDureeCampagneClass conteneur flex Elementor. On neutralise les\r\n               marges lat\u00e9rales (qui laissaient du gris \u00e0 gauche) sans forcer width:100%\r\n               (qui d\u00e9bordait sur le liser\u00e9 vert \u00e0 droite). Le bloc remplit alors le\r\n               content-box sans couvrir la border de l'item. *\/\r\n            'html body .CampagneTemplateClass .DatesDureeCampagneClass{' +\r\n                'width:auto !important;' +\r\n                'margin-left:0 !important;' +\r\n                'margin-right:0 !important;' +\r\n                'box-sizing:border-box !important;' +\r\n            '}' +\r\n            \/\/ ================================================================\r\n            \/\/ pb1493 : EN CSS, PAS EN JAVASCRIPT.\r\n            \/\/   Cinq tentatives en JS ont echoue, toutes pour la meme raison : je\r\n            \/\/   raccrochais le masquage a un writer, et aucun de ces writers ne\r\n            \/\/   repasse APRES le depot de l'annonce. Le log pb1492 le prouve \u2014 la\r\n            \/\/   garde n'a ete evaluee QU'UNE FOIS, quand la carte affichait encore\r\n            \/\/   \u00ab Commande reference \u00bb et n'avait pas de case a cocher. Elle a\r\n            \/\/   repondu faux, correctement, et n'a jamais ete rappelee.\r\n            \/\/   Une regle CSS n'a pas ce probleme : elle est reevaluee par le\r\n            \/\/   navigateur a chaque changement du DOM, sans hook, sans battement,\r\n            \/\/   sans predicat. Le signal est celui propose par l'utilisateur : la\r\n            \/\/   case a cocher de reservation, qui n'existe que lorsqu'une annonce\r\n            \/\/   est deposee et pas encore reservee.\r\n            \/\/   :has() est disponible sur les navigateurs cibles de ce projet\r\n            \/\/   (Chrome et Safari recents) ; la garde JS reste en place en filet\r\n            \/\/   pour les autres.\r\n            \/\/   Revert : window._viaPb1493Off = true (retire les deux regles).\r\n            \/\/ ================================================================\r\n            (window._viaPb1493Off === true ? '' :\r\n                'html body .CampagneTemplateClass:has(.via-recap-reserver-cb) .via-invite-haut-1262{' +\r\n                    'display:none !important;' +\r\n                '}' +\r\n                'html body .CampagneTemplateClass:has(.via-recap-reserver-cb) .CampagneMsgAccompagnement{' +\r\n                    'display:none !important;' +\r\n                '}' +\r\n                \/\/ ============================================================\r\n                \/\/ pb1494 : RENDRE LA PLACE QUE L'INVITE OCCUPAIT (mobile).\r\n                \/\/   L'invite ne prenait pas seulement la hauteur de sa ligne :\r\n                \/\/   pb1262b\/c lui posent margin-top -20px et margin-bottom 30px.\r\n                \/\/   En la masquant, ces trois hauteurs disparaissent d'un coup et\r\n                \/\/   la carte remonte \u2014 d'ou le decalage constate.\r\n                \/\/   Mecanisme repris tel quel de l'existant, comme demande : la\r\n                \/\/   compensation se fait sur .CampagnePageRefClass, l'element\r\n                \/\/   devant lequel l'invite est inseree (voir pb1262, $anc1262). Le\r\n                \/\/   fichier corrige deja cette meme zone par regle CSS ailleurs\r\n                \/\/   (l.553 et l.630, data-via-reduit) \u2014 c'est le point de calage\r\n                \/\/   habituel de cette ligne, on ne cree pas un chemin de plus.\r\n                \/\/   Mobile uniquement (max-width:999px, convention du fichier) :\r\n                \/\/   sur desktop le positionnement actuel convient.\r\n                \/\/   Knob : window._viaInvite1494Compense (defaut 15).\r\n                \/\/   Revert : window._viaInvite1494Compense = 0.\r\n                \/\/ ============================================================\r\n                \/\/ pb1494b : LA COMPENSATION VA SUR LA CARTE, PAS SUR UNE LIGNE.\r\n                \/\/   pb1494 la posait sur .CampagnePageRefClass, \u00ab l'element devant\r\n                \/\/   lequel l'invite est inseree \u00bb. Vrai dans le DOM, faux a l'ecran :\r\n                \/\/   cette carte est ordonnee par la propriete CSS order (le HTML\r\n                \/\/   fourni le montre, \u00ab order: 8 \u00bb sur .CampagneNoClass). La ligne\r\n                \/\/   de reference n'est donc pas la premiere affichee, et la pousser\r\n                \/\/   ne decale que ce qui la suit \u2014 la premiere ligne, elle, restait\r\n                \/\/   collee au bord, exactement ce que montre la capture.\r\n                \/\/   On pousse donc le CONTENU de la carte, par un padding sur la\r\n                \/\/   carte elle-meme : insensible a l'ordre d'affichage, et le\r\n                \/\/   resultat est celui de la capture \u00ab reserve \u00bb, ou une bande\r\n                \/\/   vide separe le bord haut de la premiere ligne.\r\n                \/\/   padding plutot que margin : pas de fusion de marges, et\r\n                \/\/   l'espacement exterieur de la carte n'est pas touche.\r\n                '@media (max-width:999px){' +\r\n                    'html body .CampagneTemplateClass:has(.via-recap-reserver-cb){' +\r\n                        'padding-top:' + ((typeof window._viaInvite1494Compense === 'number')\r\n                            ? window._viaInvite1494Compense : 15) + 'px !important;' +\r\n                    '}' +\r\n                '}'\r\n            ) +\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .CampagneMsgAccompagnement{' +\r\n                'display:block !important;' +\r\n                'visibility:visible !important;' +\r\n                'height:auto !important;' +\r\n                'min-height:0 !important;' +\r\n                'max-height:none !important;' +\r\n                'overflow:visible !important;' +\r\n                'opacity:1 !important;' +\r\n                'margin:4px auto 0 !important;' +\r\n                'padding:2px 6px !important;' +\r\n                'font-size:11px !important;' +\r\n                'line-height:1.4 !important;' +\r\n            '}' +\r\n            \/\/ \u2705 Pb 9 : forcer le rendu visuel de la checkbox .via-recap-reserver-cb en rouge.\r\n            \/\/   Sans appearance:none le navigateur applique son th\u00e8me OS par-dessus border \u2192 gris.\r\n            \/\/   On supprime l'apparence native et on reconstruit : bordure rouge, fond blanc,\r\n            \/\/   \u00e9tat coch\u00e9 = fond #FB5E2A + coche blanche SVG inline.\r\n            'html body .via-recap-reserver-cb {' +\r\n                '-webkit-appearance:none !important;' +\r\n                'appearance:none !important;' +\r\n                'border:1px solid #FB5E2A !important;' +\r\n                'background-color:#fff !important;' +\r\n                'border-radius:2px !important;' +\r\n                'display:inline-block !important;' +\r\n                'vertical-align:middle !important;' +\r\n                'cursor:pointer !important;' +\r\n            '}' +\r\n            'html body .via-recap-reserver-cb:checked {' +\r\n                'background-color:#3eaa13 !important;' +  \/* pb219 : vert au lieu d'orange *\/\r\n                'border-color:#3eaa13 !important;' +\r\n                'background-image:url(\"data:image\/svg+xml,%3Csvg xmlns=\\'http:\/\/www.w3.org\/2000\/svg\\' viewBox=\\'0 0 10 10\\'%3E%3Cpath d=\\'M1.5 5l2.5 2.5L8.5 2\\' stroke=\\'%23fff\\' stroke-width=\\'1.5\\' fill=\\'none\\' stroke-linecap=\\'round\\' stroke-linejoin=\\'round\\'\/%3E%3C\/svg%3E\") !important;' +\r\n                'background-repeat:no-repeat !important;' +\r\n                'background-position:center !important;' +\r\n                'background-size:8px 8px !important;' +\r\n            '}' +\r\n            \/\/ \u2705 v4.9ds Fix 19 v6 (Pb 14) : .CampagneCloseButton n'est plus dans le template\r\n            \/\/   Elementor (user a simplifi\u00e9), on l'injecte programmatiquement dans\r\n            \/\/   remplirItemPartiel\/Complet (cf code ci-dessous). CSS positionnement :\r\n            \/\/   \u00e0 droite de .via-reduire-btn (lui \u00e0 right:20px \u2192 croix \u00e0 right:5px,\r\n            \/\/   correspond au comportement initial d'Elementor).\r\n            'html body .CampagneTemplateClass .CampagneCloseButton{' +\r\n                'position:absolute !important;' +\r\n                'top:5px !important;' +\r\n                'right:5px !important;' +\r\n                'display:inline-flex !important;' +\r\n                'align-items:center !important;' +\r\n                'justify-content:center !important;' +\r\n                'width:14px !important;' +\r\n                'height:14px !important;' +\r\n                'background:transparent !important;' +\r\n                'border:none !important;' +\r\n                'cursor:pointer !important;' +\r\n                'color:#4B689B !important;' +\r\n                'padding:0 !important;' +\r\n                'margin:0 !important;' +\r\n                'z-index:120 !important;' +\r\n            '}' +\r\n            'html body .CampagneCloseButton:hover{' +\r\n                'opacity:0.7 !important;' +\r\n            '}' +\r\n            'html body .CampagneCloseButton svg{' +\r\n                'pointer-events:none !important;' +\r\n                'width:12px !important;' +\r\n                'height:12px !important;' +\r\n            '}' +\r\n            \/\/ \u2705 v4.9ds Fix 26 : sur les sites pays (pas r\u00e9gie), pour les items \"\u00c0 r\u00e9server\"\r\n            \/\/   (data-via-areserver=\"true\" \u2014 pos\u00e9 par remplirItemPartiel + remplirItemComplet\r\n            \/\/   selon estReserveEffective), ajouter +3px de padding-bottom \u00e0\r\n            \/\/   .CampagneEnvoiUlterieurClass. Mobile + desktop. Quand l'item devient r\u00e9serv\u00e9,\r\n            \/\/   data-via-areserver passe \u00e0 \"false\" \u2192 la r\u00e8gle ne s'applique plus \u2192 pas de\r\n            \/\/   padding suppl\u00e9mentaire (r\u00e9sa R\u00e9serv\u00e9e).\r\n            'html:not(.via-from-regie) body .CampagneTemplateClass[data-via-areserver=\"true\"] .CampagneEnvoiUlterieurClass{' +\r\n                'padding-bottom:3px !important;' +\r\n            '}' +\r\n            \/\/ Compactage du padding\/margin de l'item r\u00e9duit pour qu'il prenne moins de place\r\n            'html body .CampagneTemplateClass[data-via-reduit=\"true\"]{' +\r\n                'padding-top:6px !important;' +\r\n                'padding-bottom:6px !important;' +\r\n            '}' +\r\n            \/\/ \u2705 v4.9ds Fix 15 (Pb 11) : SyntheseConteneur (Elementor) a margin-top:-55px\r\n            \/\/   qui le fait chevaucher visuellement l'item partiel \"A r\u00e9server\" (Ele1A).\r\n            \/\/   En cons\u00e9quence, les clics souris qui visent l'item atterrissent sur\r\n            \/\/   SyntheseConteneur \u00e0 la place \u2192 l'item parait non-cliquable et le cursor\r\n            \/\/   pointer n'apparait pas (cursor par d\u00e9faut de SyntheseConteneur l'\u00e9crase).\r\n            \/\/   Solution : rendre SyntheseConteneur transparent au clic (pointer-events:\r\n            \/\/   none), tout en gardant ses enfants interactifs (boutons, liens) cliquables\r\n            \/\/   via pointer-events:auto. Les clics passent \u00e0 travers vers les items en\r\n            \/\/   dessous, le cursor pointer de l'item redevient visible au survol.\r\n            'html body #SyntheseConteneur{' +\r\n                'pointer-events:none !important;' +\r\n            '}' +\r\n            'html body #SyntheseConteneur *,' +\r\n            'html body #SyntheseConteneur a,' +\r\n            'html body #SyntheseConteneur button,' +\r\n            'html body #SyntheseConteneur input,' +\r\n            'html body #SyntheseConteneur [role=\"button\"]{' +\r\n                'pointer-events:auto !important;' +\r\n            '}' +\r\n            \/\/ pb206 (remplace pb205) : d\u00e9calages FINAUX des pictos, tous contextes\r\n            \/\/   (r\u00e9gie + sites pays). Pos\u00e9s en margin (additif, ne touche pas aux top\/\r\n            \/\/   transform existants) et en DERNIER \u2192 cascade gagnante.\r\n            \/\/   margin-right positif = d\u00e9cale vers la GAUCHE (\u00e9l\u00e9ment right-ancr\u00e9).\r\n            \/\/   R\u00e9duire  = item agrandi (data-via-reduit=\"false\").\r\n            \/\/   Agrandir = item r\u00e9duit (data-via-reduit=\"true\").\r\n            '@media (min-width:1000px){' +\r\n                \/\/ Desktop : R\u00e9duire -4px haut ; Agrandir +2px bas ; les deux -1px gauche.\r\n                'html body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-reduire-btn{' +\r\n                    'margin-top:-4px !important;' +\r\n                    'margin-right:1px !important;' +\r\n                '}' +\r\n                'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .via-reduire-btn{' +\r\n                    'margin-top:1px !important;' +\r\n                    'margin-right:1px !important;' +\r\n                '}' +\r\n                'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .via-selectionner-btn{' +\r\n                    'margin-top:-1px !important;' +\r\n                '}' +\r\n            '}' +\r\n            '@media (max-width:999px){' +\r\n                \/\/ Mobile : R\u00e9duire -3px haut ; Agrandir -3px haut ; les deux -1px gauche ;\r\n                \/\/   S\u00e9lectionner -2px haut.\r\n                'html body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-reduire-btn{' +\r\n                    'margin-top:-4px !important;' +\r\n                    'margin-right:1px !important;' +\r\n                '}' +\r\n                'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .via-reduire-btn{' +\r\n                    'margin-top:-2px !important;' +\r\n                    'margin-right:1px !important;' +\r\n                '}' +\r\n                'html body .CampagneTemplateClass .via-selectionner-btn{' +\r\n                    'margin-top:-2px !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/* \u2705 pb220 : popup process d'achat site pays (#ViaPopupProcessAchat \u2192 body.via-popup-achat).\r\n               Bloc plac\u00e9 en dernier = cascade gagnante. *\/\r\n            \/* T1 : +2px sous le titre r\u00e9cap (mobile + desktop). padding-bottom additif (ne\r\n               touche pas au margin Elementor). *\/\r\n            'html body.via-popup-achat #RecapitulatifVosCommandestitreContainer{' +\r\n                'padding-bottom:2px !important;' +\r\n            '}' +\r\n            \/* T2 : r\u00e9servation active (data-via-reduit=\"false\") \u2192 d\u00e9caler les pictos\r\n               S\u00e9lectionner et Croix de +4px vers le bas (mobile + desktop). via-reduire-btn\r\n               est trait\u00e9 par pb221 (-4px). margin-top additif : n'\u00e9crase pas les translateY\r\n               des Fix 17\/22. *\/\r\n            'html body.via-popup-achat .CampagneTemplateClass[data-via-reduit=\"false\"] .via-selectionner-btn,' +\r\n            'html body.via-popup-achat .CampagneTemplateClass[data-via-reduit=\"false\"] .CampagneCloseButton{' +\r\n                'margin-top:4px !important;' +\r\n            '}' +\r\n            \/* \u2705 pb221 : sites pays (popup + standalone, donc :not(.via-from-regie)),\r\n               mobile + desktop. via-reduire-btn avec label \"R\u00e9duire\" (= item actif,\r\n               data-via-reduit=\"false\") d\u00e9cal\u00e9 de 1px vers le HAUT. *\/\r\n            'html:not(.via-from-regie) body .CampagneTemplateClass[data-via-reduit=\"false\"] .via-reduire-btn{' +\r\n                'margin-top:-1px !important;' +\r\n            '}' +\r\n            \/* \u2705 pb228 : r\u00e9sa r\u00e9ellement active (data-via-item-actif=\"true\") \u2192 remonter le\r\n               picto S\u00e9lectionner de 1px suppl\u00e9mentaire (margin-top additif). *\/\r\n            'html body .CampagneTemplateClass[data-via-item-actif=\"true\"] .via-selectionner-btn{' +\r\n                'margin-top:-1px !important;' +\r\n            '}' +\r\n            \/* pb228 mobile : sur mobile (regie + sites pays), resa active -> remonter le\r\n               picto Selectionner d'1px SUPPLEMENTAIRE (total -2px). max-width:999px override\r\n               la regle globale -1px ci-dessus (meme specificite, source order plus tardif). *\/\r\n            '@media (max-width:999px){' +\r\n                'html body .CampagneTemplateClass[data-via-item-actif=\"true\"] .via-selectionner-btn{' +\r\n                    'margin-top:-2px !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/* pb1869 : MOBILE \u2014 le contenu de la resa ACTIVE descend de 15px.\r\n               Demande JF, capture a l appui : dans la carte au lisere vert, la\r\n               premiere ligne \u00ab Annonceur \u2026 \u00bb est collee au bord haut.\r\n               PADDING et non margin : le lisere vert est une bordure de la carte,\r\n               une marge la deplacerait tout entiere au lieu de pousser son contenu.\r\n               Les pictos reduire et fermer sont en position absolue par rapport a\r\n               la carte : ils ne bougent pas, ce qui est bien ce que montre la\r\n               capture \u2014 seul le texte doit descendre.\r\n               data-via-item-actif=\"true\" est le marqueur de la resa REELLEMENT\r\n               active (pb227), pas celui du replie\/deplie : les cartes inactives\r\n               ne sont donc pas touchees.\r\n               MOBILE SEUL : la capture est mobile, le desktop n a pas ete signale.\r\n               Reglage a chaud, sans redeploiement :\r\n               document.documentElement.style.setProperty('--via-pad-1869', '20px')\r\n               Revert : --via-pad-1869 = 0px *\/\r\n            \/* pb1884 : pb1869 restreint aux SITES PAYS, demande JF.\r\n               La media query max-width:999px couvrait aussi la regie en mobile,\r\n               ou ce decalage de 15px n a jamais ete demande ni verifie.\r\n               body.via-popup-achat n est posee que dans l iframe\r\n               #ViaPopupProcessAchat des sites pays ; absente sur la regie\r\n               top-level. Meme discriminant que pb1883.\r\n               Reglage inchange : --via-pad-1869 (defaut 15px, 0px pour annuler). *\/\r\n            '@media (max-width:999px){' +\r\n                'html body.via-popup-achat .CampagneTemplateClass[data-via-item-actif=\"true\"]{' +\r\n                    'padding-top:var(--via-pad-1869, 15px) !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/* \u2705 pb225 : desktop, sites pays popup process d'achat (body.via-popup-achat),\r\n               d\u00e9caler .CampagneEnvoiUlterieurClass de 3px vers le bas. Le margin-top sur le\r\n               widget Elementor externe n'avait aucun effet \u2192 on d\u00e9cale le conteneur interne\r\n               (.elementor-widget-container, qui porte le texte) via translateY. *\/\r\n            '@media (min-width:1000px){' +\r\n                'html body.via-popup-achat .CampagneEnvoiUlterieurClass > .elementor-widget-container{' +\r\n                    'transform:translateY(3px) !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/* \u2705 pb220 T3 : desktop popup, item \u00e0 r\u00e9server \u00e0 sa 1re activation (classe\r\n               via-blue-shift-220 pos\u00e9e en JS) \u2192 d\u00e9caler les textes bleus de 5px vers le bas.\r\n               Cible CampagnePageRefClass (demande user) + les autres lignes bleues. *\/\r\n            '@media (min-width:1000px){' +\r\n                'html body.via-popup-achat .CampagneTemplateClass.via-blue-shift-220 .CampagnePageRefClass,' +\r\n                'html body.via-popup-achat .CampagneTemplateClass.via-blue-shift-220 .CampagneFormatClass,' +\r\n                'html body.via-popup-achat .CampagneTemplateClass.via-blue-shift-220 .CampagnePageTextClass,' +\r\n                'html body.via-popup-achat .CampagneTemplateClass.via-blue-shift-220 .CampagneSecteurClass{' +\r\n                    'transform:translateY(5px) !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/* pb804 : picto Reduire en MODE REDUIT (data-via-reduit=\"true\") remonte de\r\n               2px sur desktop, 3px sur mobile.\r\n               Les regles existantes (pb221, pb228) ne visent que data-via-reduit=\"false\",\r\n               l'item ACTIF : le mode reduit n'etait traite nulle part.\r\n               margin-top ADDITIF plutot que transform : le picto porte deja des\r\n               translateY ailleurs dans la cascade (Fix 17\/22), qu'un transform ecraserait.\r\n               Place en DERNIER dans la feuille -> gagne a specificite egale.\r\n               Knobs : window._viaReduireDesk804 (-2) \/ _viaReduireMob804 (-3),\r\n               negatif = vers le haut. *\/\r\n            '@media (min-width:1000px){' +\r\n                'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .via-reduire-btn{' +\r\n                    'margin-top:' + _redDesk804 + 'px !important;' +\r\n                '}' +\r\n            '}' +\r\n            '@media (max-width:999px){' +\r\n                'html body .CampagneTemplateClass[data-via-reduit=\"true\"] .via-reduire-btn{' +\r\n                    'margin-top:' + _redMob804 + 'px !important;' +\r\n                '}' +\r\n            '}' +\r\n            \/* ================================================================\r\n               pb1027 : MOBILE \u2014 cartes de reservation a 95% de la largeur ecran,\r\n                 centrees (demande user).\r\n                 Place en DERNIER dans la feuille : a specificite egale, la regle\r\n                 la plus tardive gagne. Les cartes portent des largeurs posees par\r\n                 Elementor et, sur la regie, une largeur fixe de 450px \u2014 d'ou le\r\n                 !important sur width ET max-width, sans quoi la valeur fixe\r\n                 l'emporterait sur le pourcentage.\r\n                 margin auto centre la boite ; float:none neutralise un eventuel\r\n                 flottement Elementor qui empecherait le centrage. box-sizing en\r\n                 border-box pour que le lisere de 3px reste DANS les 95% au lieu\r\n                 de deborder.\r\n                 Le conteneur est vise aussi : une carte a 95% dans un parent plus\r\n                 etroit resterait visuellement decalee.\r\n                 Desktop inchange (regle scopee au media mobile, convention du\r\n                 fichier). Knob : window._viaLargeurResa1027 (defaut 95).\r\n                 Revert : window._viaPb1027Off = true.\r\n               ================================================================ *\/\r\n            '@media (max-width:999px){' +\r\n                'html body .VosCampagnesConteneurClass{' +\r\n                    'width:100% !important;' +\r\n                    'max-width:100% !important;' +\r\n                    'box-sizing:border-box !important;' +\r\n                '}' +\r\n                \/* pb1027b : #AutreCommandeBouton suit la meme largeur que les cartes\r\n                   (demande user) \u2014 il est aligne avec elles dans le recapitulatif,\r\n                   une largeur differente se verrait immediatement. *\/\r\n                'html body .CampagneTemplateClass,' +\r\n                'html body #AutreCommandeBouton{' +\r\n                    'width:' + _larg1027 + '% !important;' +\r\n                    'max-width:' + _larg1027 + '% !important;' +\r\n                    'margin-left:auto !important;' +\r\n                    'margin-right:auto !important;' +\r\n                    'float:none !important;' +\r\n                    'box-sizing:border-box !important;' +\r\n                '}' +\r\n            '}';\r\n        if (document.head) {\r\n            document.head.appendChild(_styleR);\r\n        } else {\r\n            document.documentElement.appendChild(_styleR);\r\n        }\r\n    })();\r\n\r\n    \/\/ pb1 mobile : _viaInstallFakeScrollbar supprim\u00e9e (comportement d\u00e9faillant, doublon).\r\n    (function _viaInstallFakeScrollbar() {\r\n        \/\/ Nettoyage des \u00e9l\u00e9ments cr\u00e9\u00e9s par des versions ant\u00e9rieures\r\n        var _oldTrack = document.getElementById('via-fake-sb-track');\r\n        if (_oldTrack) { _oldTrack.parentNode.removeChild(_oldTrack); }\r\n        var _oldStyle = document.getElementById('via-fake-sb-style');\r\n        if (_oldStyle) { _oldStyle.parentNode.removeChild(_oldStyle); }\r\n    })();\r\n\r\n\r\n    \/\/ v4.9ds : Watchdog couleur \u00e9tape active\r\n\r\n\r\n    \/\/ v4.9ds : Watchdog couleur \u00e9tape active\r\n    \/\/   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n    \/\/   Elementor (et certains widgets) posent un style inline sur les titres\r\n    \/\/   d'\u00e9tapes : `style=\"color: rgb(34, 93, 169) !important\"`. Ce style inline\r\n    \/\/   !important bat les r\u00e8gles CSS inject\u00e9es ci-dessus (\u00e0 sp\u00e9cificit\u00e9 \u00e9gale,\r\n    \/\/   inline gagne). Notre seule recette est d'observer ces \u00e9l\u00e9ments et de\r\n    \/\/   r\u00e9\u00e9crire la couleur active d\u00e8s qu'un style inline est pos\u00e9.\r\n    \/\/\r\n    \/\/   Surveille : titres + chevrons des \u00e9tapes Dates et R\u00e9cap dans l'iframe\r\n    \/\/   popup (sites pays). Skip si l'\u00e9tape est gris\u00e9e (termin\u00e9e).\r\n    \/\/   \u2705 v4.9ds Pb 4 v2 : r\u00e8gles invers\u00e9es pour Recap et nouvelle entr\u00e9e \"R\u00e9server les\r\n    \/\/     espaces pub\" (= titre #PageWebTitre \/ .PageWebTitre + chevrons IconeUp\/Down).\r\n    \/\/     La r\u00e8gle Dates reste inchang\u00e9e (gris\/rouge).\r\n    \/\/       R\u00e9servation \"\u00c0 r\u00e9server\" : Recap BLEU,  R\u00e9server pub ROUGE, Dates gris\r\n    \/\/       R\u00e9servation \"R\u00e9serv\u00e9e\"   : Recap ROUGE, R\u00e9server pub BLEU,  Dates rouge\r\n    \/\/     \"R\u00e9serv\u00e9e\" = item.estReserveEffective === true || item.statut === 'complete'.\r\n    \/\/   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n    (function _viaEtapeActiveColorWatchdog() {\r\n        var _selectorsRecap = [\r\n            '.RecapitulatifVosCommandestitre',\r\n            '#RecapitulatifVosCommandestitreTexte',\r\n            '#RecapitulatifVosCommandesIconeUp',\r\n            '#RecapitulatifVosCommandesIconeDown'\r\n        ];\r\n        \/\/ \u2705 v4.9ds Pb 7 : \u00e9tape Dates supprim\u00e9e d'Elementor \u2014 _selectorsDates vid\u00e9.\r\n        \/\/   Le watchdog continue d'op\u00e9rer sur cette liste vide sans effet (pas de crash).\r\n        var _selectorsDates = [];\r\n        \/\/ \u2705 v4.9ds Pb 4 : nouveau bloc \"R\u00e9server les espaces publicitaires de votre choix\"\r\n        \/\/   = titre #PageWebTitre + clones (PageWebTitreContainer) + chevrons IconeUp\/Down.\r\n        \/\/   Note : les CLONES (#PageWebTitreContainerClone) sont g\u00e9r\u00e9s ailleurs (gris fixe)\r\n        \/\/   et ne sont PAS dans cette liste. On cible uniquement le titre principal.\r\n        var _selectorsReserverPub = [\r\n            '#PageWebTitre',\r\n            '.PageWebTitre',\r\n            '#PageWebTitreIconeUp',\r\n            '#PageWebTitreIconeDown'\r\n        ];\r\n        \/\/ D\u00e9termine si la r\u00e9servation active est \"R\u00e9serv\u00e9e\" (true) ou \"\u00c0 r\u00e9server\" (false)\r\n        function _checkIsReservee() {\r\n            try {\r\n                var _pm = window.VIA_Panier;\r\n                if (!_pm) { return false; }\r\n                if (!_pm.state) { return false; }\r\n                if (!_pm.state.itemActif) { return false; }\r\n                var _it = _pm.state.items.find(function(i) { return i.id === _pm.state.itemActif; });\r\n                if (!_it) { return false; }\r\n                return _it.estReserveEffective === true ? true : _it.statut === 'complete';\r\n            } catch(_e) { return false; }\r\n        }\r\n        function _forceColor(_el, _color, _ignoreGrisee) {\r\n            if (!_el) { return; }\r\n            \/\/ Skip si l'\u00e9tape est gris\u00e9e (termin\u00e9e) \u2014 la couleur grise doit rester\r\n            \/\/ \u2705 v4.9ds Pb 4 : sauf si _ignoreGrisee=true (cas de R\u00e9server pub : la classe\r\n            \/\/   via-etape-grisee est pos\u00e9e par griserEtape('pageWeb') m\u00eame quand on veut\r\n            \/\/   afficher rouge\/bleu selon \u00e9tat de r\u00e9servation).\r\n            if (!_ignoreGrisee) {\r\n                if (_el.classList ? _el.classList.contains('via-etape-grisee') : false) { return; }\r\n            }\r\n            \/\/ \u2705 v4.9ds Pb 4 : skip si l'\u00e9l\u00e9ment est dans un clone (PageWebTitreContainerClone\r\n            \/\/   ou DatesDureeTitreContainerClone) \u2014 ces clones doivent rester gris (demande user\r\n            \/\/   pr\u00e9c\u00e9dente). Sans ce skip, .PageWebTitre matcherait aussi les .PageWebTitre dans\r\n            \/\/   les clones et imposerait la couleur dynamique au lieu du gris.\r\n            try {\r\n                if (_el.closest ? _el.closest('#PageWebTitreContainerClone, #DatesDureeTitreContainerClone') : false) {\r\n                    return;\r\n                }\r\n            } catch(_eC) {}\r\n            \/\/ Le forcing inline doit utiliser !important pour battre les inline Elementor\r\n            try { _el.style.setProperty('color', _color, 'important'); } catch(_e) {}\r\n            \/\/ Boucler aussi sur les descendants directs (les <p>, <span>, <i>, <a> etc.)\r\n            var _children = _el.querySelectorAll('*');\r\n            for (var i = 0; i < _children.length; i++) {\r\n                var _c = _children[i];\r\n                if (!_ignoreGrisee) {\r\n                    if (_c.classList ? _c.classList.contains('via-etape-grisee') : false) { continue; }\r\n                }\r\n                try {\r\n                    _c.style.setProperty('color', _color, 'important');\r\n                    \/\/ Pour les SVG\/ic\u00f4nes\r\n                    if (_c.tagName === 'svg' ? true : _c.tagName === 'path') {\r\n                        _c.style.setProperty('fill', _color, 'important');\r\n                    }\r\n                } catch(_e) {}\r\n            }\r\n        }\r\n        function _scanAndForce() {\r\n            var _isReservee = _checkIsReservee();\r\n            \/\/ \u2705 v4.9ds Pb 4 : couleurs invers\u00e9es pour Recap et nouvelle entr\u00e9e R\u00e9server pub\r\n            \/\/   \u00c0 r\u00e9server : Recap BLEU,  R\u00e9server pub ROUGE, Dates gris\r\n            \/\/   R\u00e9serv\u00e9e   : Recap ROUGE, R\u00e9server pub BLEU,  Dates rouge\r\n            \/\/ pb294 : le titre R\u00e9capitulatif ne doit JAMAIS passer en rouge -> toujours bleu #4B689B\r\n            \/\/   (la r\u00e8gle de grisage est conserv\u00e9e : _forceColor respecte via-etape-grisee car ignoreGrisee=false).\r\n            \/\/ ================================================================\r\n            \/\/ pb1206 : la COULEUR du recapitulatif suit les trois etats.\r\n            \/\/   Trois tentatives precedentes ont echoue en s'attaquant au\r\n            \/\/   MECANISME : couper la boucle (pb1200), passer une couleur vide\r\n            \/\/   (pb1200b), reecrire en differe (pb1203). Toutes ont casse le calcul\r\n            \/\/   du tarif ou accumule des timers \u2014 ce watchdog porte des effets de\r\n            \/\/   bord dont d'autres blocs dependent.\r\n            \/\/   On ne touche donc ni a la boucle, ni a _forceColor, ni au rythme.\r\n            \/\/   On change UNIQUEMENT la valeur qu'il ecrit : le watchdog garde son\r\n            \/\/   parcours a l'identique, il pose simplement la bonne couleur.\r\n            \/\/   #4B689B (pb294) devient la valeur de repli, conservee si l'etat\r\n            \/\/   n'est pas determinable \u2014 au chargement, avant que le sequenceur\r\n            \/\/   n'ait publie sa cible.\r\n            \/\/   Revert : window._viaPb1206Off = true (bleu fixe, comme pb294).\r\n            \/\/ ================================================================\r\n            var _recapColor = '#4B689B';\r\n            if (window._viaPb1206Off !== true) {\r\n                try {\r\n                    var _cibleRec1206 = window._viaCibleProcess1091 || '';\r\n                    if (_cibleRec1206 === 'recapitulatif') {\r\n                        _recapColor = '#fb5e2a';                 \/\/ etape active\r\n                    } else if (_cibleRec1206) {\r\n                        var _pm1206 = window.VIA_Panier;\r\n                        var _faits1206 = (_pm1206 ? (typeof _pm1206._completions1076 === 'function') : false)\r\n                            ? _pm1206._completions1076() : null;\r\n                        if (_faits1206) {\r\n                            _recapColor = _faits1206.recapitulatif ? '#7f7f7f' : '#525252';\r\n                        }\r\n                    }\r\n                } catch (_e1206) { _recapColor = '#4B689B'; }\r\n            }\r\n            var _reserverPubColor = _isReservee ? '#4B689B' : '#FB5E2A';\r\n            var _datesColor = _isReservee ? '#FB5E2A' : '#6e6e6e';   \/\/ pb1123\r\n            for (var i = 0; i < _selectorsRecap.length; i++) {\r\n                var _listR = document.querySelectorAll(_selectorsRecap[i]);\r\n                for (var j = 0; j < _listR.length; j++) {\r\n                    _forceColor(_listR[j], _recapColor, false);\r\n                }\r\n            }\r\n            for (var k = 0; k < _selectorsDates.length; k++) {\r\n                var _listD = document.querySelectorAll(_selectorsDates[k]);\r\n                for (var m = 0; m < _listD.length; m++) {\r\n                    _forceColor(_listD[m], _datesColor, false);\r\n                }\r\n            }\r\n            \/\/ \u2705 v4.9ds+ : sur mobile, le titre \"R\u00e9server les espaces pub\" doit rester\r\n            \/\/   gris (couleur Elementor par d\u00e9faut) \u2014 pas de rouge\/bleu dynamique.\r\n            \/\/   Sur mobile il n'y a pas d'iframe page web, le titre est un simple accord\u00e9on.\r\n            \/\/ \u2705 v4.9ds+ Pb 3 : d\u00e9tection DVM = via-desktop-origin + innerWidth < 1000.\r\n            \/\/   En DVM le watchdog skip la colorisation ET remet le gris Elementor.\r\n            var _isDVM = document.body.classList.contains('via-desktop-origin') ? (window.innerWidth < 1000) : false;\r\n            var _isMobileWatchdog = window.innerWidth <= 768 || _isDVM;\r\n            if (!_isMobileWatchdog) {\r\n            for (var p = 0; p < _selectorsReserverPub.length; p++) {\r\n                var _listP = document.querySelectorAll(_selectorsReserverPub[p]);\r\n                for (var q = 0; q < _listP.length; q++) {\r\n                    \/\/ \u2705 v4.9ds Pb 4 : ignoreGrisee=true \u2192 forcer la couleur m\u00eame si via-etape-grisee\r\n                    \/\/   est pos\u00e9e (cas apr\u00e8s griserEtape('pageWeb') qui pose la classe sur le titre).\\\r\n                    _forceColor(_listP[q], _reserverPubColor, true);\r\n                }\r\n            }\r\n            } else if (_isDVM) {\r\n                \/\/ DVM : forcer le gris #999999 sur l'\u00e9l\u00e9ment ET ses enfants\r\n                \/\/ (removeProperty laisse le blanc Elementor par d\u00e9faut sur les <a>)\r\n                for (var pr = 0; pr < _selectorsReserverPub.length; pr++) {\r\n                    var _listPr = document.querySelectorAll(_selectorsReserverPub[pr]);\r\n                    for (var qr = 0; qr < _listPr.length; qr++) {\r\n                        _listPr[qr].style.setProperty('color', '#6e6e6e', 'important');\r\n                        var _kids = _listPr[qr].querySelectorAll('*');\r\n                        for (var cr = 0; cr < _kids.length; cr++) {\r\n                            _kids[cr].style.setProperty('color', '#6e6e6e', 'important');\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        \/\/ Exposer pour que setItemActif (et toute autre logique de switch d'item)\r\n        \/\/ puisse forcer un re-scan imm\u00e9diat \u00e0 chaque changement d'item actif.\r\n        window._viaScanEtapeColors = _scanAndForce;\r\n        function _install() {\r\n            \/\/ Premi\u00e8re passe imm\u00e9diate\r\n            _scanAndForce();\r\n            \/\/ Re-passes pour attraper les rendus diff\u00e9r\u00e9s\r\n            [50, 200, 500, 1000, 2000, 4000].forEach(function(_t) {\r\n                setTimeout(_scanAndForce, _t);\r\n            });\r\n            \/\/ Observer document.body \u2014 si un titre appara\u00eet plus tard ou si un style inline est pos\u00e9\r\n            try {\r\n                \/\/ \u2705 v4.9ds : combinaison Recap + Dates (variable _selectors a \u00e9t\u00e9 splitt\u00e9e)\r\n                \/\/ \u2705 v4.9ds Pb 4 : ajout _selectorsReserverPub \u00e0 la liste surveill\u00e9e\r\n                var _allSelectors = _selectorsRecap.concat(_selectorsDates).concat(_selectorsReserverPub);\r\n                var _obs = new MutationObserver(function(_muts) {\r\n                    var _shouldForce = false;\r\n                    for (var i = 0; i < _muts.length; i++) {\r\n                        var _m = _muts[i];\r\n                        if (_m.type === 'attributes' ? _m.attributeName === 'style' : false) {\r\n                            \/\/ V\u00e9rifier si l'\u00e9l\u00e9ment ou un parent matche nos s\u00e9lecteurs\r\n                            var _t = _m.target;\r\n                            for (var k = 0; k < _allSelectors.length; k++) {\r\n                                if (_t.matches ? _t.matches(_allSelectors[k]) : false) { _shouldForce = true; break; }\r\n                                if (_t.closest ? _t.closest(_allSelectors[k]) : false) { _shouldForce = true; break; }\r\n                            }\r\n                            if (_shouldForce) { break; }\r\n                        }\r\n                        if (_m.type === 'childList') { _shouldForce = true; break; }\r\n                    }\r\n                    if (_shouldForce) { _scanAndForce(); }\r\n                });\r\n                _obs.observe(document.body, {\r\n                    childList: true,\r\n                    subtree: true,\r\n                    attributes: true,\r\n                    attributeFilter: ['style', 'class']\r\n                });\r\n            } catch(_e) {}\r\n        }\r\n        if (document.readyState === 'loading') {\r\n            document.addEventListener('DOMContentLoaded', _install);\r\n        } else {\r\n            _install();\r\n        }\r\n    })();\r\n\r\n    \/\/ \u2705 v4.9ds Pb 7 : d\u00e9placement de #ProcessAchatInside dans l'item actif si r\u00e9serv\u00e9\r\n    \/\/   ET agrandi. \u00c9tape Dates supprim\u00e9e d'Elementor (#DatesDureeCampagneTitre*,\r\n    \/\/   #LabelDatesDureeReservation, etc.) \u2014 d\u00e9sormais ProcessAchatInside vit dans\r\n    \/\/   l'item de la r\u00e9servation active quand celle-ci est compl\u00e8te et d\u00e9ploy\u00e9e.\r\n    \/\/   Conditions :\r\n    \/\/     - item actif R\u00e9serv\u00e9 : estReserveEffective === true || statut === 'complete'\r\n    \/\/     - item agrandi : data-via-reduit !== 'true'\r\n    \/\/   Sinon, ProcessAchatInside est remis \u00e0 sa position d'origine (sauvegard\u00e9e au load).\r\n    (function _viaProcessAchatRelocator() {\r\n        function _restoreToHome(_pai) {\r\n            var _h = window._viaProcessAchatHome;\r\n            if (!_h ? true : !_h.parent) { return; }\r\n            if (_pai.parentNode === _h.parent ? !_h.next : false) { return; }\r\n            try {\r\n                if (_h.next ? _h.next.parentNode === _h.parent : false) {\r\n                    _h.parent.insertBefore(_pai, _h.next);\r\n                } else {\r\n                    _h.parent.appendChild(_pai);\r\n                }\r\n            } catch(_e) {}\r\n        }\r\n        window._viaUpdateProcessAchatLocation = function() {\r\n            try {\r\n                var _pai = document.getElementById('ProcessAchatInside');\r\n                if (!_pai) { return; }\r\n                \/\/ Sauvegarder la position d'origine au tout premier appel\r\n                if (!window._viaProcessAchatHome) {\r\n                    window._viaProcessAchatHome = {\r\n                        parent: _pai.parentNode,\r\n                        next: _pai.nextSibling\r\n                    };\r\n                }\r\n                var _pm = window.VIA_Panier;\r\n                if (!_pm ? true : (!_pm.state ? true : !_pm.state.itemActif)) {\r\n                    _restoreToHome(_pai);\r\n                    return;\r\n                }\r\n                var _it = _pm.state.items.find(function(i) { return i.id === _pm.state.itemActif; });\r\n                if (!_it) { _restoreToHome(_pai); return; }\r\n                var _isReserved = _it.estReserveEffective === true ? true : _it.statut === 'complete';\r\n                var _itemEl = document.getElementById(_pm.state.itemActif);\r\n                if (!_itemEl) { _restoreToHome(_pai); return; }\r\n                var _isAgrandi = _itemEl.getAttribute('data-via-reduit') !== 'true';\r\n                if (_isReserved ? _isAgrandi : false) {\r\n                    \/\/ Append dans l'item actif si pas d\u00e9j\u00e0 dedans (ou pas en derni\u00e8re position)\r\n                    if (_pai.parentNode !== _itemEl ? true : _itemEl.lastElementChild !== _pai) {\r\n                        _itemEl.appendChild(_pai);\r\n                    }\r\n                } else {\r\n                    _restoreToHome(_pai);\r\n                }\r\n            } catch(_eU) {}\r\n        };\r\n        function _install() {\r\n            \/\/ Sauvegarder la position d'origine au load + premier appel\r\n            window._viaUpdateProcessAchatLocation();\r\n            \/\/ Re-passes pour rendus diff\u00e9r\u00e9s\r\n            [100, 500, 1500].forEach(function(_t) {\r\n                setTimeout(window._viaUpdateProcessAchatLocation, _t);\r\n            });\r\n            \/\/ Polling l\u00e9ger pour suivre les changements d'\u00e9tat\r\n            setInterval(window._viaUpdateProcessAchatLocation, 500);\r\n        }\r\n        if (document.readyState === 'loading') {\r\n            document.addEventListener('DOMContentLoaded', _install);\r\n        } else {\r\n            _install();\r\n        }\r\n    })();\r\n\r\n    \/\/ \u2705 v4.9ds Pb 3 : helper qui synchronise l'\u00e9tat des checkbox \"R\u00e9server cet espace\r\n    \/\/   publicitaire\" dans la page web avec l'\u00e9tat des items du panier. Pour chaque item\r\n    \/\/   r\u00e9serv\u00e9 (estReserveEffective || statut='complete'), la checkbox correspondant \u00e0\r\n    \/\/   son emplacementPageWeb est coch\u00e9e. Sinon, d\u00e9coch\u00e9e.\r\n    \/\/   Appel\u00e9e par setItemActif (avec retries) et apr\u00e8s d\u00e9pose d'annonce (Pb 6).\r\n    window._viaSyncReserverCheckboxFromItem = function() {\r\n        try {\r\n            var _pm = window.VIA_Panier;\r\n            if (!_pm ? true : !_pm.state) { return; }\r\n            var _items = _pm.state.items || [];\r\n            for (var _i = 0; _i < _items.length; _i++) {\r\n                var _it = _items[_i];\r\n                var _empl = (_it.donneesIframe ? _it.donneesIframe.Commande_Emplacement_Page_Web : '') || _it.emplacementPageWeb || '';\r\n                if (!_empl) { continue; }\r\n                var _isReserved = _it.estReserveEffective === true ? true : _it.statut === 'complete';\r\n                \/\/ Localiser le drop par data-empl, data-emplacement ou ID\r\n                var _$drops = $('[data-empl=\"' + _empl + '\"], [data-emplacement=\"' + _empl + '\"], #' + _empl);\r\n                _$drops.each(function() {\r\n                    var $here = $(this);\r\n                    var $cb = $here.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"], .reserver-dynamic-checkbox').first();\r\n                    if (!$cb.length) {\r\n                        $cb = $here.closest('.OrdiMobileConteneurClass, .EspPubFormatContainer').find('input[name=\"form_fields[ReserverEspacePublicitaire]\"], .reserver-dynamic-checkbox').first();\r\n                    }\r\n                    if ($cb.length) {\r\n                        $cb.prop('checked', _isReserved);\r\n                    }\r\n                });\r\n            }\r\n        } catch(_e) {}\r\n    };\r\n    \/\/   instance .CampagneMsgAccompagnement pr\u00e9sente dans le DOM, \u00e0 intervalles\r\n    \/\/   r\u00e9guliers + via MutationObserver. Demande user : ce message ne doit JAMAIS\r\n    \/\/   s'afficher. Garantit le retrait m\u00eame si :\r\n    \/\/     - un autre code (legacy, cache navigateur, fichier non red\u00e9ploy\u00e9) le cr\u00e9e\r\n    \/\/     - Elementor le r\u00e9injecte au re-render\r\n    \/\/     - une fonction tierce non identifi\u00e9e le pose\r\n    \/\/   Le polling 500ms est tr\u00e8s peu co\u00fbteux (querySelectorAll sur une classe).\r\n    (function _viaCampagneMsgKiller() {\r\n        \/\/ \u2705 v4.9ds Pb 7 : \u00e9tendu pour supprimer aussi #LabelDatesDureeReservation\r\n        \/\/   (\u00e9tape Dates retir\u00e9e d'Elementor \u2014 ce label legacy doit \u00e9galement dispara\u00eetre).\r\n        \/\/ \u2705 v4.9ds R\u00c9ACTIVATION CampagneMsgAccompagnement : .CampagneMsgAccompagnement\r\n        \/\/   RETIR\u00c9 de la liste des s\u00e9lecteurs \u00e0 tuer. L'user veut maintenant que les\r\n        \/\/   messages d'accompagnement (\"Merci de faire un choix d'espace publicitaire...\",\r\n        \/\/   \"Merci de s\u00e9lectionner un th\u00e8me ou un secteur\"...) s'affichent \u00e0 nouveau.\r\n        \/\/   Le killer continue \u00e0 supprimer #LabelDatesDureeReservation (label legacy).\r\n        var _killSelectors = [\r\n            '#LabelDatesDureeReservation'\r\n        ];\r\n        function _killAll() {\r\n            try {\r\n                for (var _ks = 0; _ks < _killSelectors.length; _ks++) {\r\n                    var _list = document.querySelectorAll(_killSelectors[_ks]);\r\n                    for (var _k = 0; _k < _list.length; _k++) {\r\n                        var _el = _list[_k];\r\n                        if (_el ? _el.parentNode : false) {\r\n                            _el.parentNode.removeChild(_el);\r\n                        }\r\n                    }\r\n                }\r\n            } catch(_e) {}\r\n        }\r\n        function _matchesKill(_node) {\r\n            if (!_node ? true : !_node.matches) { return false; }\r\n            for (var _ms = 0; _ms < _killSelectors.length; _ms++) {\r\n                try { if (_node.matches(_killSelectors[_ms])) { return true; } } catch(_e) {}\r\n            }\r\n            return false;\r\n        }\r\n        function _install() {\r\n            _killAll();\r\n            \/\/ Re-passes sur les rendus diff\u00e9r\u00e9s\r\n            [50, 200, 500, 1000, 2000].forEach(function(_t) {\r\n                setTimeout(_killAll, _t);\r\n            });\r\n            \/\/ Polling continu\r\n            setInterval(_killAll, 500);\r\n            \/\/ MutationObserver pour r\u00e9agir imm\u00e9diatement aux insertions\r\n            try {\r\n                var _obs = new MutationObserver(function(_muts) {\r\n                    for (var _mi = 0; _mi < _muts.length; _mi++) {\r\n                        var _m = _muts[_mi];\r\n                        if (_m.addedNodes ? _m.addedNodes.length : false) {\r\n                            for (var _ni = 0; _ni < _m.addedNodes.length; _ni++) {\r\n                                var _n = _m.addedNodes[_ni];\r\n                                if (_matchesKill(_n)) {\r\n                                    if (_n.parentNode) { _n.parentNode.removeChild(_n); }\r\n                                } else if (_n.querySelectorAll) {\r\n                                    for (var _qs = 0; _qs < _killSelectors.length; _qs++) {\r\n                                        var _sub = _n.querySelectorAll(_killSelectors[_qs]);\r\n                                        for (var _si = 0; _si < _sub.length; _si++) {\r\n                                            if (_sub[_si].parentNode) {\r\n                                                _sub[_si].parentNode.removeChild(_sub[_si]);\r\n                                            }\r\n                                        }\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                });\r\n                _obs.observe(document.body, { childList: true, subtree: true });\r\n            } catch(_e) {}\r\n        }\r\n        if (document.readyState === 'loading') {\r\n            document.addEventListener('DOMContentLoaded', _install);\r\n        } else {\r\n            _install();\r\n        }\r\n    })();\r\n\r\n    \/* ====================================================================\r\n     * pb1986 : LE REMEDE ETAIT ENFERME DANS LA MALADIE.\r\n     *   Constat JF : \u00ab pb1982 toujours aucun log \u00bb. Ni la ligne de pose, ni\r\n     *   le constat d'absence a 60s. Or pb1982b avait ete ecrit precisement\r\n     *   pour que l'un des deux tombe TOUJOURS (regle 5.2). Un veilleur qui\r\n     *   ne rend meme pas compte de son echec n'est pas arme du tout.\r\n     *   CAUSE, LUE DANS LE FICHIER, PAS DEDUITE : le veilleur etait pose a\r\n     *   l'interieur de DEUX gardes englobantes,\r\n     *     l.1530  if (_modePopupCheck) ...                  \/\/ #mode=popup\r\n     *     l.1531  if (!getElementById('via-references-scale-style')) ...\r\n     *   Hors du contexte popup, le bloc n'est jamais atteint :\r\n     *   window._viaCalageOblig1982 n'est meme pas DEFINIE, et le setInterval\r\n     *   n'est jamais installe. Silence total, conforme au code.\r\n     *   C'est la meme erreur que celle que pb1982 corrigeait, commise dans\r\n     *   le geste qui la corrigeait : j'ai sorti le calage de la passe\r\n     *   d'echelle, puis je l'ai repose dans la piece dont la passe d'echelle\r\n     *   etait prisonniere. Le diagnostic de pb1982 (\u00ab #ReferencesFormulaires\r\n     *   pas rendu \u00bb) n'etait qu'un verrou sur trois \u2014 les deux autres etaient\r\n     *   un cran au-dessus, hors du champ que je regardais.\r\n     *   REGLE : avant de conclure \u00ab ce code ne tourne pas \u00bb, remonter TOUTES\r\n     *   les ouvertures de bloc englobantes jusqu'a la racine du script. Une\r\n     *   garde a trois lignes de distance et une garde a mille lignes de\r\n     *   distance ont exactement le meme effet.\r\n     *   Le calage remonte donc au niveau du script. Il reste UN SEUL\r\n     *   ECRIVAIN : la passe d'echelle continue de l'appeler, elle ne le\r\n     *   porte toujours pas.\r\n     * ==================================================================== *\/\r\n    \/* pb1986b : ET LE LOG DOIT POUVOIR SORTIR DE L'IFRAME.\r\n       Second verrou possible sur le meme symptome, deja paye une fois par\r\n       pb1754 dans Entete.txt : un console.log emis depuis une iframe\r\n       n'atteint le bouton \u00ab Copier logs \u00bb du top que si le transfert v4.9ds\r\n       est actif, c'est-a-dire si debug=1 figure dans l'URL de l'iframe\r\n       elle-meme. Sur la regie mobile rien ne le garantit.\r\n       On emet donc sur les DEUX canaux connus, comme _log1753 :\r\n         'vlp-diag-log'    ecoute par yearbook-media.js (regie)\r\n         '__viaIframeLog'  ecoute par le buffer de Entete.txt\r\n       Le recepteur absent ignore le message, sans effet de bord. *\/\r\n    function _log1986(_s1986) {\r\n        try { console.log(_s1986); } catch (_eL1986) {}\r\n        if (window !== window.top) {\r\n            try {\r\n                window.parent.postMessage({ type: 'vlp-diag-log', source: 'iframe',\r\n                    msg: _s1986, url: window.location.search }, '*');\r\n            } catch (_eP1986) {}\r\n            try {\r\n                window.parent.postMessage({ type: '__viaIframeLog', level: 'log',\r\n                    args: [_s1986] }, '*');\r\n            } catch (_eQ1986) {}\r\n        }\r\n    }\r\n    \/* pb1986 : temoin d'armement. Si meme cette ligne manque, le fichier n'est\r\n       pas servi ou le script s'arrete avant \u2014 et ce n'est plus une deduction\r\n       (pb1754). *\/\r\n    _log1986('[pb1986] calage ChampsObligatoiresNEW arme (ver=' + window._viaPanierVer\r\n        + ' top=' + (window === window.top) + ' outerW=' + window.outerWidth\r\n        + ' popup=' + (('' + window.location.hash).indexOf('mode=popup') !== -1)\r\n        + ' regie=' + document.documentElement.classList.contains('via-from-regie') + ')');\r\n    \/* ====================================================================\r\n     * pb1982 : LE CALAGE DE ChampsObligatoiresNEW N'EST PLUS PRISONNIER\r\n     *   DE LA PASSE D'ECHELLE.\r\n     *   Constat JF : \u00ab pb1612 aucun log, pb1891 aucun log \u00bb. Ces deux\r\n     *   lignes sont emises par _viaEchelleReferences1612, qui n'est\r\n     *   appelee que si #ReferencesFormulaires est RENDU (largeur > 0) \u2014\r\n     *   condition posee aux deux sites d'appel, pb1621 ici et pb1620 dans\r\n     *   yearbook-media.js. Sur la regie mobile cette condition n'est pas\r\n     *   remplie : la passe ne tourne jamais, et le calage pb1894a\/pb1897\r\n     *   qu'elle porte depuis le debut n'a jamais agi dans ce contexte.\r\n     *   D'ou \u00ab il doit deja exister un code qui decale cet element \u00bb \u2014\r\n     *   il existe, mais il n'etait effectif qu'en desktop.\r\n     *   UN SEUL ECRIVAIN, DEUX DECLENCHEURS. On ne duplique pas la regle :\r\n     *   elle est extraite ici et la passe d'echelle l'appelle desormais au\r\n     *   lieu de la porter. Un veilleur autonome l'appelle aussi, des que\r\n     *   l'element est rendu, sans rien exiger de #ReferencesFormulaires.\r\n     *   Les bases restent memorisees dans data-mt1894 \/ data-ml1894 : le\r\n     *   calage repart de l'origine, il ne s'ajoute jamais au precedent,\r\n     *   quel que soit le nombre d'appels.\r\n     *   Reglages : window._viaMt1896 \/ window._viaMl1896 (forcent les deux\r\n     *   contextes). Revert du palier mobile : window._viaPb1978Off = true.\r\n     * ==================================================================== *\/\r\n    \/* pb1982b : LE VEILLEUR. Il appelle le calage des que l'element est\r\n       RENDU, sans rien exiger d'autre \u2014 c'est tout l'objet du marqueur.\r\n       Il rend compte de son propre echec : sans cela, l'absence de log ne\r\n       distinguerait pas \u00ab element jamais rendu \u00bb de \u00ab veilleur jamais\r\n       arme \u00bb (regle 5.2, la meme qui m'a coute deux tours ce matin).\r\n       PAS DE BUDGET COMPTE DEPUIS LE CHARGEMENT pour la reussite : la\r\n       scrutation continue tant que l'element n'est pas rendu, parce que\r\n       l'utilisateur peut arriver a l'etape References trois minutes plus\r\n       tard (regle 5.4). Seul le CONSTAT D'ABSENCE est journalise a 60s.\r\n       Une fois pose, on repasse toutes les 2s : le calage est idempotent,\r\n       et Elementor reecrit les marges apres chaque re-rendu.\r\n       Revert : window._viaPb1982Off = true. *\/\r\n    \/* ====================================================================\r\n     * pb1988 : LA GARDE QUE J'AI RETIREE N'ETAIT PAS QU'UNE PRISON.\r\n     *   Constat JF : \u00ab pb1986 affecte les sites pays au lieu du site regie \u00bb.\r\n     *   Exact, et c'est ma faute de raisonnement, pas un effet de bord.\r\n     *   pb1986 a sorti le calage de if (_modePopupCheck) en n'y voyant qu'un\r\n     *   verrou. Or le commentaire d'architecture de ce fichier, l.320, dit\r\n     *   noir sur blanc ce que ce test signifie :\r\n     *     - SITES PAYS  : Panier_manage tourne DANS l'iframe popup d'achat,\r\n     *                     qui charge yearbook-media.com\/?mode=popup\r\n     *                     -> window !== window.top\r\n     *     - SITE REGIE  : Panier_manage tourne directement sur la page, en\r\n     *                     top -> window === window.top\r\n     *   Autrement dit mode=popup est le marqueur des SITES PAYS. En le\r\n     *   supprimant j'ai fait exactement l'inverse de la demande : le calage\r\n     *   \u00ab regie mobile uniquement \u00bb s'est mis a agir sur les sites pays.\r\n     *   C'est la regle 5.3, violee dans le geste meme qui pretendait liberer\r\n     *   le code : une garde peut etre A LA FOIS un verrou et un discriminant\r\n     *   de contexte. Retirer la premiere fonction supprime la seconde.\r\n     *   AVANT DE LEVER UNE GARDE, NOMMER CE QU'ELLE DISCRIMINE.\r\n     *   Le bon discriminant n'est pas a inventer : il est deja calcule dans\r\n     *   ce fichier, une seule fois, par _viaDetectRegieContext (l.331), qui\r\n     *   pose la classe via-from-regie sur <html> quand top ET hostname regie.\r\n     *   On la LIT, on n'en fabrique pas une deuxieme : un troisieme test\r\n     *   d'hostname dans le corpus serait une valeur a deux ecrivains.\r\n     *   Lue a chaque appel, jamais figee (regle 5.4).\r\n     *   Ce que cela retablit exactement :\r\n     *     - sites pays \/ popup : comportement d'AVANT pb1986, inchange. La\r\n     *       passe d'echelle reste seule a appeler le calage, avec le palier\r\n     *       desktop pb1897 (+15 \/ +30) qu'elle a toujours applique la.\r\n     *     - regie : le veilleur tourne, et lui seul y applique le palier\r\n     *       mobile pb1978 (-25 \/ +40) demande par JF.\r\n     *   Revert : window._viaPb1988Off = true (aucune discrimination, on\r\n     *   retombe sur le comportement de pb1986).\r\n     * ==================================================================== *\/\r\n    function _estRegie1988() {\r\n        if (window._viaPb1988Off === true) { return true; }\r\n        if (!document.documentElement) { return false; }\r\n        return document.documentElement.classList.contains('via-from-regie');\r\n    }\r\n    (function _viaVeille1982() {\r\n        var _n = 0;\r\n        var _pose = false;\r\n        var _dit = false;\r\n        var _horsRegie1988 = false;\r\n        var _dit2005 = false;\r\n        setInterval(function () {\r\n            if (window._viaPb1982Off === true) { return; }\r\n            _n++;\r\n            \/* pb1988 : hors regie, ce veilleur n'a rien a faire. La passe\r\n               d'echelle continue d'appeler le calage dans le popup pays,\r\n               comme avant pb1986. Le motif du refus est journalise une fois\r\n               (regle 5.2) : sans lui, \u00ab aucune ligne \u00bb redeviendrait\r\n               indiscernable d'un fichier non servi. *\/\r\n            if (!_estRegie1988()) {\r\n                if (!_horsRegie1988) {\r\n                    _horsRegie1988 = true;\r\n                    _log1986('[pb1988] hors regie (via-from-regie absent, top='\r\n                        + (window === window.top) + ' host=' + window.location.hostname\r\n                        + ') -> veilleur en retrait, le calage reste pilote par la'\r\n                        + ' passe d echelle');\r\n                }\r\n                return;\r\n            }\r\n\r\n            \/* pb2005 : appele AVANT et INDEPENDAMMENT du bloc ci-dessous. Ce\r\n               dernier sort par return des que ChampsObligatoiresNEW est rendu :\r\n               placer l'appel apres l'aurait rendu inatteignable dans le cas\r\n               nominal \u2014 la meme famille d'erreur que pb2003, en plus discret.\r\n               Le premier resultat non trivial est journalise une fois. *\/\r\n            var _r2005 = window._viaCalageDataFact2005();\r\n            if (!_dit2005) {\r\n                if (('' + _r2005).indexOf('mt ') !== -1) {\r\n                    _dit2005 = true;\r\n                    _log1986(_r2005 + ' | passage ' + _n);\r\n                }\r\n            }\r\n\r\n            var _e = document.getElementById('ChampsObligatoiresNEW');\r\n            var _rendu = _e ? (_e.getBoundingClientRect().height > 5) : false;\r\n            if (_rendu) {\r\n                var _r = window._viaCalageOblig1982(_e);\r\n                if (!_pose) {\r\n                    _pose = true;\r\n                    _log1986('[pb1982] calage pose au passage ' + _n + ' | ' + _r);\r\n                }\r\n                return;\r\n            }\r\n            if (_n === 30) {\r\n                if (!_dit) {\r\n                    _dit = true;\r\n                    _log1986('[pb1982] pas encore pose apres 60s : '\r\n                        + (_e ? 'ChampsObligatoiresNEW present mais pas rendu (h='\r\n                            + _e.getBoundingClientRect().height.toFixed(1) + ')'\r\n                            : 'ChampsObligatoiresNEW ABSENT du DOM')\r\n                        + ' | la scrutation continue');\r\n                }\r\n            }\r\n        }, 2000);\r\n    })();\r\n    \/* ====================================================================\r\n     * pb2005 : CALAGE DU GROUPE DataFacturation.\r\n     *   Demande JF : +20px de margin-top, en delta. Contexte lu de l'en-tete\r\n     *   du message, \u00ab Sites regie mobile \u00bb \u2014 le meme que la demande jumelle\r\n     *   sur ChampsObligatoiresNEW, dont les 20px viennent d'etre retires\r\n     *   (pb2004b). Si la demande valait aussi ailleurs, c'est une ligne.\r\n     *   LA CIBLE, D'APRES LE HTML FOURNI PAR JF : le groupe de champ est\r\n     *     div.elementor-field-group-DataFacturation\r\n     *   Il n'y a pas d'id : les seuls identifiants voisins, #DataFacturationForm\r\n     *   et #ChoixDataFacturationForm, designent les FORMULAIRES, pas ce groupe.\r\n     *   On vise donc la classe metier, jamais elementor-element-XXXX qui change\r\n     *   a chaque purge de cache.\r\n     *   UN ECRIVAIN NEUF, PARCE QU'IL N'Y EN AVAIT PAS : la seule regle du\r\n     *   corpus sur ce groupe touche la case a cocher interne (yearbook-media.js\r\n     *   l.1834, margin-top 3px sur l'input). Le groupe lui-meme n'a aucun\r\n     *   ecrivain de marge \u2014 j'ai verifie avant d'en ecrire un.\r\n     *   POURQUOI PAS DANS pb1891, QUI TRAITE DEJA #ChoixDataFacturationForm :\r\n     *   parce que cette passe ne tourne pas sur la regie mobile. C'est la faute\r\n     *   exacte de pb2003, dont le log n'est jamais apparu. Le declencheur retenu\r\n     *   est donc le veilleur pb1986, dont le log de JF prouve qu'il tourne la\r\n     *   (\u00ab calage pose au passage 13 \u00bb).\r\n     *   BASE MEMORISEE dans data-mt2005, delta recalcule depuis elle a chaque\r\n     *   appel : aucun cumul, quel que soit le nombre de passages. Ecriture\r\n     *   idempotente. La ligne de log donne la base \u2014 de quoi exprimer la\r\n     *   prochaine demande en cible, comme pour les trois autres contextes.\r\n     *   Reglage : window._viaPb2005Delta = 30\r\n     *   Revert  : window._viaPb2005Off = true (la base est reposee telle quelle).\r\n     * ==================================================================== *\/\r\n    window._viaCalageDataFact2005 = function () {\r\n        var _el2005 = document.querySelector('.elementor-field-group-DataFacturation');\r\n        if (!_el2005) { return 'DataFacturation=absent'; }\r\n        if (!(_el2005.getBoundingClientRect().height > 3)) { return 'DataFacturation=pas rendu'; }\r\n        var _b2005 = _el2005.getAttribute('data-mt2005');\r\n        if (_b2005 === null) {\r\n            _b2005 = String(parseFloat(window.getComputedStyle(_el2005).marginTop) || 0);\r\n            _el2005.setAttribute('data-mt2005', _b2005);\r\n        }\r\n        \/* ====================================================================\r\n         * pb2044 : CE CALAGE ETAIT POUR LA REGIE MOBILE, PAS POUR LE DESKTOP.\r\n         *   Constat JF, capture DevTools de la regie desktop :\r\n         *     .elementor-field-group-DataFacturation  data-mt2005=\"0\"\r\n         *     style=\"margin-top: 50px !important;\"\r\n         *   L'attribut data-mt2005 signe l'ecrivain : c'est celui-ci. La demande\r\n         *   de JF portait sur \u00ab sites regie mobile \u00bb \u2014 pb2005, puis les paliers\r\n         *   pb2005b et pb2005c jusqu'a 50. Je l'avais garde par le veilleur\r\n         *   pb1986, qui se retire hors regie (pb1988) mais ne dit rien de la\r\n         *   largeur. Regie desktop recevait donc les 50 px.\r\n         *   C'est la quatrieme fois de la session qu'une valeur validee dans un\r\n         *   contexte s'applique a un autre : pb2013 -> pb2016, pb2015 -> pb2018,\r\n         *   pb2033, et celle-ci. A chaque fois le manque est le meme \u2014 un\r\n         *   discriminant sur deux, \u00ab regie \u00bb sans \u00ab mobile \u00bb, ou \u00ab mobile \u00bb sans\r\n         *   \u00ab regie \u00bb. Les deux vont ensemble ou ne valent rien.\r\n         *   LARGEUR LUE PAR L'ACCESSEUR GARDE _viaLargeur1263, celui qu'emploient\r\n         *   deja pb1179 et pb1253 dans ce fichier ; jamais innerWidth, nul dans\r\n         *   une iframe masquee, ni outerWidth en direct.\r\n         *   Sur desktop le delta vaut 0 et la marge revient a data-mt2005, soit\r\n         *   la valeur d'origine \u2014 0 dans la capture de JF. Rien a nettoyer : le\r\n         *   mecanisme repart toujours de la base memorisee.\r\n         *   Revert : window._viaPb2044Off = true (50 px dans les deux largeurs,\r\n         *   comportement pb2005c).\r\n         * ==================================================================== *\/\r\n        var _d2005 = 0;\r\n        if (window._viaPb2005Off !== true) {\r\n            var _mob2044 = true;\r\n            if (window._viaPb2044Off !== true) {\r\n                var _lg2044 = (typeof window._viaLargeur1263 === 'function')\r\n                    ? window._viaLargeur1263() : window.outerWidth;\r\n                _mob2044 = (_lg2044 < 1000);\r\n            }\r\n            if (_mob2044) {\r\n                \/* Paliers regie mobile : pb2005 +20, pb2005b +40, pb2005c +50.\r\n                   Palier sur le seul defaut ; le delta reste calcule depuis\r\n                   data-mt2005, donc rien ne se cumule quel que soit le nombre\r\n                   de passages du veilleur. *\/\r\n                _d2005 = (typeof window._viaPb2005Delta === 'number')\r\n                    ? window._viaPb2005Delta : 50;\r\n            }\r\n        }\r\n        var _c2005 = (parseFloat(_b2005) + _d2005) + 'px';\r\n        if (_el2005.style.marginTop !== _c2005) {\r\n            _el2005.style.setProperty('margin-top', _c2005, 'important');\r\n        }\r\n        return '[pb2005] DataFacturation mt ' + _b2005 + '->' + _c2005\r\n            + ' (delta ' + _d2005 + ', largeur '\r\n            + ((typeof window._viaLargeur1263 === 'function')\r\n                ? window._viaLargeur1263() : window.outerWidth) + ')';\r\n    };\r\n    window._viaCalageOblig1982 = function (_el) {\r\n        if (!_el) { _el = document.getElementById('ChampsObligatoiresNEW'); }\r\n        if (!_el) { return 'ChampsObligatoiresNEW=absent'; }\r\n        var _bmt = _el.getAttribute('data-mt1894');\r\n        if (_bmt === null) {\r\n            _bmt = String(parseFloat(window.getComputedStyle(_el).marginTop) || 0);\r\n            _el.setAttribute('data-mt1894', _bmt);\r\n        }\r\n        var _bml = _el.getAttribute('data-ml1894');\r\n        if (_bml === null) {\r\n            _bml = String(parseFloat(window.getComputedStyle(_el).marginLeft) || 0);\r\n            _el.setAttribute('data-ml1894', _bml);\r\n        }\r\n        \/* pb1978 : palier mobile. La bascule est LUE ICI, a chaque appel,\r\n           jamais figee a l'initialisation (regle 5.4). outerWidth et non\r\n           innerWidth : ce dernier vaut 0 dans une iframe masquee et rendrait\r\n           \u00ab mobile \u00bb vrai sur un ecran de 1400px \u2014 le defaut de pb1969.\r\n             pb1894a  +10 bas  +20 droite\r\n             pb1896a  +15 bas  +25 droite\r\n             pb1897   +15 bas  +30 droite   (reste le desktop)\r\n             pb1978   -25 bas  +40 droite   (mobile seul)\r\n           \u00ab 25 vers le haut \u00bb se lit depuis l'ORIGINE, comme les trois\r\n           demandes precedentes. *\/\r\n        \/* pb1988 : \u00ab mobile \u00bb ne suffit pas a nommer le contexte, \u00ab regie\r\n           mobile \u00bb si. Un ecran de 430px sur un site pays reste un site pays.\r\n           Les deux conditions sont lues ICI, a chaque appel. *\/\r\n        var _mob = false;\r\n        if (window._viaPb1978Off !== true) {\r\n            if (window.outerWidth < 1000) {\r\n                if (_estRegie1988()) { _mob = true; }\r\n            }\r\n        }\r\n        \/* ====================================================================\r\n         * pb1997 : TROISIEME CONTEXTE \u2014 SITES PAYS DESKTOP.\r\n         *   Demande JF : sur les sites pays en desktop, #ChampsObligatoiresNEW\r\n         *   passe a 10px de police, 25px vers le HAUT et 30px vers la GAUCHE.\r\n         *   Les deux valeurs sont NEGATIVES et se lisent depuis l'ORIGINE,\r\n         *   comme les quatre paliers precedents : la base memorisee dans\r\n         *   data-mt1894 \/ data-ml1894 n'est jamais touchee, le delta est\r\n         *   recalcule depuis elle a chaque appel. Aucun cumul, et le retour en\r\n         *   arriere est un simple changement de nombre.\r\n         *   La table complete des paliers devient :\r\n         *     pb1894a  +10 bas  +20 droite\r\n         *     pb1896a  +15 bas  +25 droite\r\n         *     pb1897   +15 bas  +30 droite   regie desktop, sites pays mobile\r\n         *     pb1978   -25 bas  +40 droite   regie mobile   (via _estRegie1988)\r\n         *     pb1997   -25 bas  -30 droite   sites pays desktop\r\n         *   LE DISCRIMINANT N'EST PAS REECRIT : window._viaPaysDesktop1994,\r\n         *   pose pour pb1994\/pb1996, repond deja exactement a cette question.\r\n         *   Trois contextes, trois predicats nommes, aucune largeur relue a la\r\n         *   main \u2014 c'est ce qui a manque a pb1986 et coute pb1988.\r\n         *   ORDRE DES DEUX TESTS : la branche pays-desktop est evaluee AVANT\r\n         *   _mob. Les deux sont exclusifs par construction (l'un exige\r\n         *   outerWidth < 1000 et la regie, l'autre >= 1000 et un site pays),\r\n         *   mais les ecrire dans un ordre explicite evite d'avoir a s'en\r\n         *   remettre a cette exclusivite si un jour un seuil bouge.\r\n         *   Reglages : window._viaMt1896 \/ window._viaMl1896 forcent les trois\r\n         *   contextes a la fois ; window._viaPb1997Fs regle la taille.\r\n         *   Revert : window._viaPb1997Off = true (retour au palier desktop\r\n         *   pb1897, taille laissee a pb1893b).\r\n         * ==================================================================== *\/\r\n        var _paysDt1997 = false;\r\n        if (window._viaPb1997Off !== true) {\r\n            if (typeof window._viaPaysDesktop1994 === 'function') {\r\n                if (window._viaPaysDesktop1994()) { _paysDt1997 = true; }\r\n            }\r\n        }\r\n        \/* ====================================================================\r\n         * pb1999 : LE DECALAGE PARTAIT DU MAUVAIS POINT.\r\n         *   Log JF, site pays desktop :\r\n         *     [pb1982] deltas -25\/-30 | mt -15->-40px | ml 0->-30px\r\n         *   Un seul ecrivain a touche ces deux marges, et il a ecrit ce qu'on\r\n         *   lui demandait. Ce qui a derape est le POINT DE DEPART, et le log le\r\n         *   donne : la base memorisee vaut -15 en haut, 0 a gauche.\r\n         *   Avant cette demande, le palier desktop pb1897 valait +15 \/ +30 :\r\n         *     haut   -15 + 15 = 0      gauche  0 + 30 = +30\r\n         *   c'est-a-dire l'etat que JF avait sous les yeux en formulant\r\n         *   \u00ab 25px vers le haut, 30px vers la gauche \u00bb. Un deplacement se lit\r\n         *   depuis ce qu'on voit. J'avais applique -25 et -30 comme des deltas\r\n         *   depuis l'ORIGINE \u2014 la convention des quatre paliers precedents \u2014\r\n         *   ce qui donne :\r\n         *     haut   -40 au lieu de -25   (15 de trop, exactement pb1897)\r\n         *     gauche -30 au lieu de 0     (30 de trop, exactement pb1897)\r\n         *   L'ecart vaut le palier precedent, dans les deux axes. La convention\r\n         *   \u00ab depuis l'origine \u00bb tenait tant que les demandes allaient dans le\r\n         *   MEME sens : chacune reformulait un total. Des que la demande change\r\n         *   de sens, les deux lectures divergent \u2014 et c'est la lecture humaine\r\n         *   qui a raison.\r\n         *   ON EXPRIME DONC LA CIBLE, PAS LE DELTA. Les valeurs ci-dessous sont\r\n         *   les marges FINALES voulues ; le delta a poser depuis la base est\r\n         *   calcule. Une demande future se traduit directement, sans avoir a\r\n         *   se souvenir de la base ni du palier en cours.\r\n         *     regie desktop \/ pays mobile : cible non exprimee, on garde le\r\n         *       delta historique pb1897 (+15 \/ +30) pour ne rien changer la ou\r\n         *       rien n'a ete demande \u2014 regle 5.3.\r\n         *     regie mobile   : idem, delta pb1978 (-25 \/ +40) inchange.\r\n         *     pays desktop   : cible -25 en haut, 0 a gauche.\r\n         *   Reglages : window._viaMt1896 \/ window._viaMl1896 restent des DELTAS\r\n         *   et forcent les trois contextes, comme avant.\r\n         * ==================================================================== *\/\r\n        \/* ====================================================================\r\n         * pb2001 : QUATRIEME CONTEXTE \u2014 REGIE DESKTOP.\r\n         *   Constat JF, capture HTML a l'appui :\r\n         *     id=\"ChampsObligatoiresNEW\" style=\"margin-top: 25px !important;\r\n         *     margin-left: 30px !important;\" data-mt1894=\"10\" data-ml1894=\"0\"\r\n         *   soit exactement 10 + 15 et 0 + 30 : le palier pb1897, celui d'avant\r\n         *   cette session. L'element n'avait pas bouge parce que rien ne lui\r\n         *   avait ete demande \u2014 les modifications de pb1997 a pb2000 sont\r\n         *   gardees par body.via-popup-achat, absente sur la regie (regle 5.3,\r\n         *   volontairement). \u00ab Il n'a pas bouge \u00bb etait donc le comportement\r\n         *   attendu, pas un symptome.\r\n         *   Demande : 25px vers le haut, 30px vers la gauche, depuis ce qui est\r\n         *   a l'ecran. L'ecran montre 25 et 30, donc les CIBLES valent 0 et 0.\r\n         *   Le delta a poser depuis la base (10 \/ 0) est calcule, comme pour\r\n         *   les sites pays depuis pb1999.\r\n         *   LA MARGE FONCTIONNE ICI, C'EST MESURE : le test a 200px a fait\r\n         *   descendre l'element franchement, et le releve d'ancetres donne\r\n         *   #ReferencesFormulaires en display:flex. Un flex item ne fusionne\r\n         *   jamais ses marges \u2014 le piege de pb1996 n'existe pas a cet endroit,\r\n         *   inutile de passer par un padding.\r\n         *   ECHELLE : le meme releve donne matrix(1.1, ...) sur\r\n         *   #ReferencesFormulaires. Les px demandes sont des px CSS ; a l'ecran\r\n         *   ils seront multiplies par cette echelle. Si le rendu parait un peu\r\n         *   court, c'est de la que viendra l'ecart, pas d'un ecrivain rival.\r\n         *   Le quatrieme contexte a son predicat nomme, comme les trois autres.\r\n         *   Aucune largeur relue a la main : _viaLargeur1263 est l'accesseur\r\n         *   garde, celui qu'emploient deja pb1179 et _viaPaysDesktop1994.\r\n         *   Reglages : window._viaPb2001Haut \/ window._viaPb2001Gauche, en CIBLE.\r\n         *   Revert : window._viaPb2001Off = true (retour au palier pb1897).\r\n         * ==================================================================== *\/\r\n        var _regieDt2001 = false;\r\n        if (window._viaPb2001Off !== true) {\r\n            if (_estRegie1988()) {\r\n                var _lg2001 = (typeof window._viaLargeur1263 === 'function')\r\n                    ? window._viaLargeur1263() : window.outerWidth;\r\n                if (_lg2001 >= 1000) { _regieDt2001 = true; }\r\n            }\r\n        }\r\n        var _dmt;\r\n        var _dml;\r\n        if (_paysDt1997) {\r\n            \/* pb2000 : 10px vers le BAS demandes depuis l'etat pb1999, soit une\r\n               cible qui passe de -25 a -15. Exprimee en CIBLE et non en delta,\r\n               c'est une soustraction de tete et non plus un calcul avec la base :\r\n               c'est tout l'interet de la forme adoptee au marqueur precedent.\r\n               Paliers sites pays desktop, en cible : pb1999 -25\/0, pb2000 -15\/0. *\/\r\n            var _cibleT1999 = (typeof window._viaPb1999Haut === 'number')\r\n                ? window._viaPb1999Haut : -15;\r\n            var _cibleL1999 = (typeof window._viaPb1999Gauche === 'number')\r\n                ? window._viaPb1999Gauche : 0;\r\n            _dmt = _cibleT1999 - parseFloat(_bmt);\r\n            _dml = _cibleL1999 - parseFloat(_bml);\r\n        } else if (_regieDt2001) {\r\n            \/* pb2001 : cibles regie desktop. Paliers, en cible : pb1897 25\/30\r\n               (etat d'avant, exprime ici pour memoire), pb2001 0\/0,\r\n               pb2001b -10\/0 \u2014 \u00ab 10px supplementaires vers le haut \u00bb.\r\n               \u00ab Supplementaires \u00bb se lit sur la cible et non sur un delta :\r\n               0 - 10 = -10, sans avoir a savoir que la base vaut 10. C'est\r\n               ce que la forme de pb1999 est venue chercher. *\/\r\n            var _cibleT2001 = (typeof window._viaPb2001Haut === 'number')\r\n                ? window._viaPb2001Haut : -10;\r\n            var _cibleL2001 = (typeof window._viaPb2001Gauche === 'number')\r\n                ? window._viaPb2001Gauche : 0;\r\n            _dmt = _cibleT2001 - parseFloat(_bmt);\r\n            _dml = _cibleL2001 - parseFloat(_bml);\r\n        } else if (_mob) {\r\n            \/* ================================================================\r\n             * pb2004 : REGIE MOBILE \u2014 LA BASE EST CONNUE, ON PASSE EN CIBLE.\r\n             *   Log JF :\r\n             *     [pb1982] REGIE-MOBILE regie=true outerW=430 | deltas -45\/65\r\n             *              | mt -18->-63px | ml 20->85px\r\n             *   La base de ce contexte vaut donc -18 en haut et 20 a gauche \u2014\r\n             *   ni celle de la regie desktop (10\/0) ni celle des sites pays\r\n             *   (-15\/0). Avoir refuse d'ecrire une cible avant de la mesurer\r\n             *   etait donc juste : les trois bases sont differentes.\r\n             *   Elle est mesuree, on convertit. Les quatre contextes parlent\r\n             *   desormais la meme langue, et la confusion delta\/cible qui a\r\n             *   coute pb1999 ne peut plus se reproduire.\r\n             *   CONVERSION VERIFIABLE, PAS DEVINEE :\r\n             *     etat pb2003   mt -63   ml 85\r\n             *     + 20 de margin-top demandes (erratum JF : top, pas bottom)\r\n             *     cible         mt -43   ml 85\r\n             *   controle : -43 - (-18) = -25 et 85 - 20 = 65, soit exactement\r\n             *   les deltas que le log affiche, aux 20px pres sur le haut.\r\n             *   Paliers regie mobile, desormais en cible : pb2004 -43\/85.\r\n             *   Reglages : window._viaPb2004Haut \/ window._viaPb2004Gauche, en\r\n             *   CIBLE. Les anciens _viaPb2002Haut \/ _viaPb2002Droite, qui\r\n             *   etaient en delta, disparaissent \u2014 garder deux knobs de sens\r\n             *   contraire sur la meme valeur serait le piege suivant.\r\n             *   Revert : window._viaPb2004Off = true (retour au delta pb1978).\r\n             * ================================================================ *\/\r\n            if (window._viaPb2004Off === true) {\r\n                _dmt = -25;\r\n                _dml = 40;\r\n            } else {\r\n                \/* Paliers regie mobile, en cible : pb2004 -43\/85, pb2004b -63\/85\r\n                   (20px de margin-top retires, partis sur DataFacturation),\r\n                   pb2004c -53\/85 (+10 de margin-top).\r\n                   \u00ab Ajouter du margin-top \u00bb descend l'element : la cible monte\r\n                   donc de -63 a -53. Le signe se lit une fois ici plutot qu'a\r\n                   chaque demande. *\/\r\n                var _cibleT2004 = (typeof window._viaPb2004Haut === 'number')\r\n                    ? window._viaPb2004Haut : -53;\r\n                var _cibleL2004 = (typeof window._viaPb2004Gauche === 'number')\r\n                    ? window._viaPb2004Gauche : 85;\r\n                _dmt = _cibleT2004 - parseFloat(_bmt);\r\n                _dml = _cibleL2004 - parseFloat(_bml);\r\n            }\r\n        } else {\r\n            \/* ================================================================\r\n             * pb2054 : CINQUIEME CONTEXTE SERVI \u2014 SITES PAYS MOBILE.\r\n             *   Demande JF : #ChampsObligatoiresNEW decale de 30px vers la\r\n             *   GAUCHE. C'est le seul des cinq contextes qui n'avait jamais rien\r\n             *   recu : il tenait encore le palier pb1897 (+15 bas \/ +30 droite).\r\n             *   LECTURE DEPUIS L'ECRAN, pas depuis l'origine \u2014 la lecon pb1999 :\r\n             *   \u00ab un deplacement se lit depuis ce qu'on voit \u00bb, et c'est la\r\n             *   lecture humaine qui a raison des que la demande change de sens.\r\n             *   A l'ecran l'element est a base + 30. Trente pixels vers la\r\n             *   gauche donnent base + 0, donc un delta de 0.\r\n             *   pb2054b : \u00ab encore 20px vers la gauche \u00bb, lus depuis l'etat\r\n             *   pb2054 qui vaut 0 -> delta -20. Le relatif s'enchaine sans\r\n             *   jamais avoir besoin de la base ; c'est tout l'interet de cette\r\n             *   forme tant qu'elle n'est pas mesuree.\r\n             *   Paliers sites pays mobile, en delta : pb1897 +30, pb2054 0,\r\n             *   pb2054b -20.\r\n             *   ENCORE UN DELTA, ET C'EST ASSUME : les quatre autres contextes\r\n             *   sont passes en CIBLE depuis pb1999, mais chacun l'a fait APRES\r\n             *   avoir mesure sa base \u2014 les trois mesurees valent 10\/0, -15\/0 et\r\n             *   -18\/20, toutes differentes. Celle-ci ne l'est toujours pas.\r\n             *   Un deplacement RELATIF n'a pas besoin de la base ; une cible si.\r\n             *   Le log de retour affiche \u00ab ml <base>-><pose> \u00bb : au premier\r\n             *   releve sur un site pays mobile, ce contexte pourra passer en\r\n             *   cible comme les autres, sans rien deviner.\r\n             *   Le haut n'est pas touche : rien n'a ete demande dessus (regle 5.3).\r\n             *   Reglage : window._viaPb2054Delta \u2014 un DELTA, comme cette branche,\r\n             *   et non une cible ; les knobs _viaPb1999\/2001\/2004Gauche sont des\r\n             *   cibles, celui-ci porte donc un nom qui ne s'y confond pas.\r\n             *   Revert : window._viaPb2054Off = true (palier pb1897, +30).\r\n             * ================================================================ *\/\r\n            _dmt = 15;\r\n            if (window._viaPb2054Off === true) {\r\n                _dml = 30;\r\n            } else {\r\n                _dml = (typeof window._viaPb2054Delta === 'number')\r\n                    ? window._viaPb2054Delta : -20;\r\n            }\r\n        }\r\n        if (typeof window._viaMt1896 === 'number') { _dmt = window._viaMt1896; }\r\n        if (typeof window._viaMl1896 === 'number') { _dml = window._viaMl1896; }\r\n        \/* pb1998 : L'ECRITURE DE LA POLICE EST PARTIE D'ICI.\r\n           Elle n'aurait jamais du y etre : pb1893b, quelques centaines de\r\n           lignes plus bas, est l'ecrivain de la police de cet element depuis\r\n           qu'il a ete ecrit, base memorisee dans data-fs1893 comprise. Voir\r\n           la note pb1998 a son emplacement. Ce writer-ci ne gouverne que les\r\n           marges, comme avant pb1997. *\/\r\n        var _cmt = (parseFloat(_bmt) + _dmt) + 'px';\r\n        var _cml = (parseFloat(_bml) + _dml) + 'px';\r\n        \/* idempotent : ce mecanisme est rejoue a chaque passe ET par le\r\n           veilleur ; reecrire a l'identique declencherait les observateurs\r\n           de style pour rien (lecon pb1971). *\/\r\n        if (_el.style.marginTop !== _cmt) {\r\n            _el.style.setProperty('margin-top', _cmt, 'important');\r\n        }\r\n        if (_el.style.marginLeft !== _cml) {\r\n            _el.style.setProperty('margin-left', _cml, 'important');\r\n        }\r\n        var _r = _el.getBoundingClientRect();\r\n        \/* pb2001 : le log nomme le contexte retenu. \u00ab desktop \u00bb ne distinguait\r\n           pas la regie des sites pays, et c'est precisement la question qui a\r\n           occupe les derniers tours. *\/\r\n        var _ctx2001 = 'pays-mobile';\r\n        if (_paysDt1997) { _ctx2001 = 'PAYS-DESKTOP'; }\r\n        else if (_regieDt2001) { _ctx2001 = 'REGIE-DESKTOP'; }\r\n        else if (_mob) { _ctx2001 = 'REGIE-MOBILE'; }\r\n        return '[pb1982] ' + _ctx2001\r\n            + ' regie=' + _estRegie1988()\r\n            + ' outerW=' + window.outerWidth\r\n            + ' | deltas ' + _dmt + '\/' + _dml\r\n            + ' | mt ' + _bmt + '->' + _cmt\r\n            + ' | ml ' + _bml + '->' + _cml\r\n            + ' | rendu ' + _r.width.toFixed(0) + 'x' + _r.height.toFixed(0);\r\n    };\r\n\r\n    \/* ====================================================================\r\n     * pb2045 : RESTAURATION \u2014 DEUX FONCTIONS EMPORTEES PAR UN NETTOYAGE.\r\n     *   Constat JF : \u00ab pb1989 ne fonctionne plus \u00bb.\r\n     *   Il n'y avait rien a reprocher a pb1989 : son bloc est intact et sa\r\n     *   valeur _mtF1989 arrive bien jusqu'a l'ecriture, l.15972. Ce qui\r\n     *   l'empechait de s'executer se trouvait QUARANTE LIGNES PLUS HAUT.\r\n     *   CE QUE J'AI FAIT : en retirant la sonde pb1993 (pb2041), j'ai supprime\r\n     *   une REGION delimitee par deux ancres. _viaPaysDesktop1994 et\r\n     *   _viaRecapAFaire1994 vivaient dedans, entre la sonde et l'ancre de fin.\r\n     *   Mes verifications ne pouvaient pas le voir : j'avais controle que la\r\n     *   sonde etait bien dans le bloc, que _viaCalageOblig1982 n'y etait pas,\r\n     *   et que les accolades s'equilibraient \u2014 or une definition de fonction\r\n     *   complete s'equilibre aussi. Je n'ai jamais verifie qu'aucune AUTRE\r\n     *   definition n'habitait la region.\r\n     *   C'est la faute que ce projet a deja payee une fois, avec var _st498 et\r\n     *   cinq iterations perdues. Elle porte un nom dans les regles : ne pas\r\n     *   reecrire par bornes d'index. Je l'ai refaite.\r\n     *   POURQUOI pb1989 EN MOURAIT : trois des cinq appels a\r\n     *   _viaPaysDesktop1994 ne sont pas gardes par un typeof \u2014 l.15929,\r\n     *   l.15959, l.19095. Le premier est dans pb1996, quarante lignes AVANT\r\n     *   l'ecriture de la marge. Fonction absente -> TypeError -> l'exception\r\n     *   traverse tout le reste du bloc -> setProperty('margin-top') jamais\r\n     *   atteint. pb1989 ne s'executait plus, sans un mot.\r\n     *   LE CODE EST RESTITUE A L'IDENTIQUE, depuis le transcript de la session\r\n     *   ou il a ete ecrit. Aucune reecriture de memoire : une fonction\r\n     *   reconstituee \u00ab de tete \u00bb aurait pu differer sur un seuil ou un\r\n     *   selecteur et donner un troisieme comportement.\r\n     * ==================================================================== *\/\r\n    window._viaPaysDesktop1994 = function () {\r\n        if (window._viaPb1994Off === true) { return false; }\r\n        var _pays1994 = document.body\r\n            ? document.body.classList.contains('via-popup-achat') : false;\r\n        if (!_pays1994) { return false; }\r\n        var _lg1994 = (typeof window._viaLargeur1263 === 'function')\r\n            ? window._viaLargeur1263() : window.outerWidth;\r\n        return _lg1994 >= 1000;\r\n    };\r\n    window._viaRecapAFaire1994 = function () {\r\n        if (window._viaPb1994Off === true) { return false; }\r\n        var _e1994 = document.querySelector('.RecapitulatifVosCommandestitre');\r\n        if (!_e1994) { return false; }\r\n        if (window._viaCibleProcess1091 === 'recapitulatif') { return false; }\r\n        if (_e1994.closest) {\r\n            if (_e1994.closest('.via-etape-grisee')) { return false; }\r\n        }\r\n        return true;\r\n    };\r\n\r\n    \/* ====================================================================\r\n     * pb2041 : NETTOYAGE \u2014 LA SONDE pb1993 EST RETIREE.\r\n     *   Elle a repondu a la question pour laquelle elle avait ete ecrite :\r\n     *   \u00ab TEXTE sous la classe titre ? false \u00bb. Le noeud qui porte \u00ab Vos\r\n     *   reservations \u00bb n'est pas sous le selecteur titre d'etapesConfig\r\n     *   (l.11751), et pb913 ne l'a donc jamais gouverne \u2014 ce qui explique que\r\n     *   six paliers de taille se soient regles si mal.\r\n     *   Ce constat n'a pas encore ete exploite : la correction, le jour ou JF\r\n     *   y reviendra, est dans etapesConfig et non dans un palier. Il est\r\n     *   consigne ici pour ne pas se reperdre.\r\n     *   Le reste de ce qu'elle avait vu, et qui a servi : Ele0A et Ele1A ne\r\n     *   sont jamais rendus en meme temps, le VLP n'ouvrant qu'un espace a la\r\n     *   fois \u2014 d'ou pb2011, la base de l'aplat qui suit son parent au lieu\r\n     *   d'etre gelee sur une mesure d'avant.\r\n     * ==================================================================== *\/\r\n    \/\/ \u2705 Override scale r\u00e9f\u00e9rences dans l'iframe mode=popup\r\n    \/\/ v4.9ds (fix) : depuis Entete.txt v4.9ds, les params iframe sont pass\u00e9s en HASH\r\n    \/\/   (#mode=popup&...) et non plus en search (?mode=popup&...). On lit donc le hash\r\n    \/\/   en priorit\u00e9, fallback sur search pour compatibilit\u00e9 descendante. Sans ce fix,\r\n    \/\/   le bloc CSS ci-dessous (et celui de spacing) ne s'ex\u00e9cutait JAMAIS en pratique.\r\n    var _modePopupCheck = new URLSearchParams(window.location.hash.substring(1) || window.location.search).get('mode') === 'popup';\r\n\r\n    if (_modePopupCheck) {\r\n        if (!document.getElementById('via-references-scale-style')) {\r\n            \/* ============================================================\r\n             * pb1612 : LES DEUX REGLAGES N'ETAIENT LUS QU'UNE FOIS.\r\n             *   Constat user : \u00ab window._viaPb1594Scale = 0.8 \u00bb et\r\n             *   \u00ab window._viaEchelleRef1611 = 0.95 \u00bb sans aucun effet.\r\n             *   Normal : le premier n'est relu que si l'observateur de\r\n             *   #ReferencesFormulaires se declenche, le second seulement au moment ou\r\n             *   cette feuille est CONSTRUITE, c'est-a-dire a l'initialisation. Poser la\r\n             *   variable ensuite ne relance ni l'un ni l'autre.\r\n             *   Un knob qu'on ne peut pas actionner n'est pas un knob. On expose donc\r\n             *   une fonction qui reconstruit la feuille ET repousse l'echelle du\r\n             *   conteneur, dans la foulee :\r\n             *     window._viaEchelleReferences1612(0.95)        \/\/ les 3 formulaires\r\n             *     window._viaEchelleReferences1612(0.95, 0.8)   \/\/ + le conteneur\r\n             *   Sans argument, elle relit les valeurs courantes et reapplique.\r\n             * ============================================================ *\/\r\n            window._viaEchelleReferences1612 = function (_forms, _conteneur) {\r\n                if (typeof _forms === 'number') { window._viaEchelleRef1611 = _forms; }\r\n                if (typeof _conteneur === 'number') { window._viaPb1594Scale = _conteneur; }\r\n                \/* ============================================================\r\n                 * pb1698 : LE BON ECRIVAIN ETAIT DEJA NOMME, DIX LIGNES PLUS BAS.\r\n                 *   pb1606 l ecrit noir sur blanc : \u00ab pb1594 et pb1605 agissaient sur\r\n                 *   #ReferencesFormulaires \u2014 le HTML montre mes styles bien poses\r\n                 *   dessus, sans le moindre effet. L echelle est appliquee a ses\r\n                 *   ENFANTS par cette feuille : .ReferencesConteneurScale. \u00bb\r\n                 *   J ai refait exactement la meme erreur sur trois tours, en reglant\r\n                 *   #ReferencesFormulaires \u2014 d abord par JS (pb1594\/pb1695\/pb1696, qui\r\n                 *   ne tourne pas sur tactile), puis par variable CSS (pb1697, posee\r\n                 *   sur le mauvais element). Le commentaire etait la depuis pb1606.\r\n                 *   Ici, et ici seulement, se decide l echelle des trois formulaires.\r\n                 *   Sous 1000 px elle compense les 18 px forces par pb1690 :\r\n                 *   18 x 0.61 = 11 px rendus, la taille de la regie. Le desktop garde 1.\r\n                 *   Reglage immediat, sans redeploiement :\r\n                 *     window._viaEchelleReferences1612(0.5, 0.5)\r\n                 *   Revert : window._viaPb1698Off = true.\r\n                 * ============================================================ *\/\r\n                var _def1698 = 1;\r\n                if (window._viaPb1698Off !== true) {\r\n                    if (window.outerWidth <= 1000) { _def1698 = 0.89; }   \/* pb1704 : 0.87 -> 0.89 (user) *\/\r\n                }\r\n                \/* ============================================================\r\n                 * pb1890 : LE RETRAIT DE 4px, ENFIN AU BON ENDROIT.\r\n                 *   Quatrieme tentative. Les trois precedentes ont echoue faute\r\n                 *   d avoir lu l avertissement ecrit vingt lignes plus haut :\r\n                 *     pb1886\/1887\/1888  yearbook-media.js, bloc qui SORT sur tactile\r\n                 *                       (pb211) \u2014 aucun log, aucun effet\r\n                 *     pb1889            bloc _d1700, jamais atteint : sa feuille\r\n                 *                       existe deja, la garde\r\n                 *                       if (!getElementById('via-references-scale-style'))\r\n                 *                       est fausse des que cette fonction-ci a tourne\r\n                 *   pb1698 le disait : \u00ab ici, et ici seulement, se decide l echelle\r\n                 *   des trois formulaires \u00bb, et signalait deja que le bloc de\r\n                 *   yearbook-media.js ne tourne pas sur tactile.\r\n                 *   font-size INCHANGEE a 18px : iOS decide sur la taille calculee\r\n                 *   et ignore transform:scale, donc pas de zoom a la saisie.\r\n                 *     rendu actuel   18 x 0.89 = 16.02 px CSS\r\n                 *     retrait 4px -> 12.02 px CSS, soit scale 0.668\r\n                 *   Le calcul part de _def1698 : si pb1704 change son 0.89, le\r\n                 *   retrait reste de 4px au lieu de deriver.\r\n                 *   Reglage a chaud : window._viaRetrait1889 = 2   (px CSS)\r\n                 *   Revert : window._viaPb1890Off = true\r\n                 * ============================================================ *\/\r\n                var _avant1890 = _def1698;\r\n                if (window._viaPb1890Off !== true) {\r\n                    if (window.outerWidth <= 1000) {\r\n                        var _ret1890 = (typeof window._viaRetrait1889 === 'number') ? window._viaRetrait1889 : 4;\r\n                        var _n1890 = Math.round(((_def1698 * 18 - _ret1890) \/ 18) * 1000) \/ 1000;\r\n                        if (_n1890 < 0.3) { _n1890 = 0.3; }\r\n                        _def1698 = _n1890;\r\n                        console.log('[pb1890] retrait ' + _ret1890 + 'px : scale ' + _avant1890\r\n                            + ' -> ' + _def1698 + ' | rendu ' + (18 * _def1698).toFixed(2)\r\n                            + 'px CSS (police forcee 18px, inchangee)');\r\n                    }\r\n                }\r\n                var _f = (typeof window._viaEchelleRef1611 === 'number') ? window._viaEchelleRef1611 : _def1698;   \/* pb1614, defaut pb1698 *\/\r\n                console.log('[pb1698] echelle des 3 formulaires = ' + _f\r\n                    + ' | outerWidth=' + window.outerWidth\r\n                    + ' | rendu attendu ' + (18 * _f).toFixed(1) + 'px');\r\n                var _anc = document.getElementById('via-references-scale-style');\r\n                if (_anc ? _anc.parentNode : false) { _anc.parentNode.removeChild(_anc); }\r\n                var _s = document.createElement('style');\r\n                _s.id = 'via-references-scale-style';\r\n                _s.textContent =\r\n                    '#ReferencesConteneurId, .ReferencesConteneurScale { transform: scale(' + _f + ') !important; transform-origin: top center !important; } '\r\n                    \/* pb1892a : \u00ab * champ obligatoire \u00bb ETAIT TROP A GAUCHE.\r\n                       pb1890b lui laissait l echelle d avant retrait (0.89) pendant que\r\n                       les formulaires passaient a 0.668. Avec transform-origin:top center\r\n                       et une largeur de 100%, plus l echelle est grande plus l element\r\n                       est large : il debordait des deux cotes, ce qui se voit a gauche.\r\n                       Il prend donc la MEME echelle que les formulaires \u2014 l alignement\r\n                       suit \u2014 et sa taille de texte est rendue par font-size, que le\r\n                       transform du parent ne touche pas.\r\n                       k = echelle_avant \/ echelle_apres. calc(1em * k) : le 1em designe\r\n                       la taille du parent, la valeur ne derive pas d elle-meme. *\/\r\n                    + '#ChampsObligatoiresNEW { transform: scale(' + _f + ') !important;'\r\n                        + ' transform-origin: top center !important;'\r\n                        \/* pb1893b : font-size en em retiree \u2014 posee sur le conteneur, que le\r\n                           <p> interne n herite pas. Elle est desormais calculee et posee en\r\n                           px sur le <p> lui-meme, dans la passe differee. *\/\r\n                        + ' } '\r\n                    + '#ChoixDataFacturationForm, #DataFacturationForm { transform: scale(' + _f + ') !important; transform-origin: top center !important; }'   \/* pb1614c *\/\r\n                    + ' #ReferencesFormulaires, #ReferencesConteneurId, #ChoixDataFacturationForm,'\r\n                    + ' #DataFacturationForm, .ReferencesConteneurScale {'\r\n                    + ' max-width: 100% !important; box-sizing: border-box !important;'\r\n                    + ' transform-origin: top center !important; }   \/* pb1700 : centre, le top left alignait a droite *\/'\r\n                    \/* pb1891a : LES DEUX FORMULAIRES DE FACTURATION RESTAIENT GRANDS.\r\n                       Capture user : le formulaire annonceur a bien retreci, les deux\r\n                       autres non. Ils sont pourtant nommes plus haut avec le meme _f.\r\n                       pb1700 explique pourquoi : _refStyle, construit a l initialisation,\r\n                       est appendu APRES cette feuille et repose scale(_sc1606) sur ces\r\n                       deux ids precis. A specificite egale, la derniere feuille gagne.\r\n                       On repose donc la valeur en fin de feuille avec html body devant :\r\n                       specificite (1,0,2) contre (1,0,0), l ordre des feuilles ne decide\r\n                       plus. Les trois formulaires sont enfin a la meme echelle. *\/\r\n                    + ' html body #ChoixDataFacturationForm, html body #DataFacturationForm {'\r\n                    + ' transform: scale(' + _f + ') !important; transform-origin: top center !important; }';\r\n                document.head.appendChild(_s);\r\n                \/* pb1893a : publier l echelle pour les ecrivains qui l appliquent\r\n                   ailleurs \u2014 _applyMobScale notamment, qui repasse toutes les 2s. *\/\r\n                window._viaEchelleRefCourante = parseFloat(_f);\r\n                \/* ============================================================\r\n                 * pb1891b : REMONTER CE QUI SUIT UN ELEMENT REDUIT.\r\n                 *   Capture user : un grand vide au-dessus de \u00ab * champ\r\n                 *   obligatoire \u00bb. transform:scale retrecit le RENDU mais ne touche\r\n                 *   pas a la boite de mise en page : offsetHeight reste celui de\r\n                 *   l element a taille pleine, et h x (1 - echelle) de vide subsiste\r\n                 *   sous chacun. pb1614 l avait note en sens inverse : \u00ab a l echelle\r\n                 *   1, la boite correspond au rendu, donc le vide disparait \u00bb.\r\n                 *   On mesure et on compense par un margin-bottom negatif.\r\n                 *   offsetHeight est INSENSIBLE au transform : la mesure ne depend\r\n                 *   donc pas de la compensation qu elle produit, et il n y a pas de\r\n                 *   boucle possible.\r\n                 *   #ChampsObligatoiresNEW est exclu : il garde son echelle d avant\r\n                 *   retrait (pb1890b), donc son vide n a pas change.\r\n                 *   Differe : la feuille vient d etre posee, le layout n est pas\r\n                 *   encore recalcule au moment de l appel.\r\n                 *   Revert : window._viaPb1891Off = true\r\n                 * ============================================================ *\/\r\n                if (window._viaPb1891Off !== true) {\r\n                    setTimeout(function () {\r\n                        try {\r\n                            \/* pb1892b : LE SCALE DES DEUX FORMULAIRES DE FACTURATION, EN INLINE.\r\n                               pb1891a avait renforce la specificite de la regle de feuille\r\n                               (html body + id, soit 1,0,2). Sans effet : ils restent grands\r\n                               sur la capture. Le fichier l a deja ecrit en pb1699 \u2014 \u00ab un\r\n                               inline bat toute feuille \u00bb \u2014 et c est ainsi que pb1594 impose\r\n                               deja le sien sur #ReferencesFormulaires.\r\n                               On cesse donc de se battre a coups de selecteurs : le scale\r\n                               est pose en inline, dans la meme passe que la compensation.\r\n                               #ChampsObligatoiresNEW rejoint la liste : depuis pb1892a il\r\n                               porte la meme echelle, donc le meme vide a compenser. *\/\r\n                            var _ids1891 = ['ReferencesConteneurId', 'ChampsObligatoiresNEW',\r\n                                'ChoixDataFacturationForm', 'DataFacturationForm'];\r\n                            var _res1891 = [];\r\n                            for (var _i1891 = 0; _i1891 < _ids1891.length; _i1891++) {\r\n                                var _e1891 = document.getElementById(_ids1891[_i1891]);\r\n                                if (!_e1891) { _res1891.push(_ids1891[_i1891] + '=absent'); continue; }\r\n                                \/* pb1892b : le scale d abord, la compensation ensuite \u2014\r\n                                   offsetHeight est insensible au transform, l ordre entre les\r\n                                   deux n a donc pas d importance pour la mesure elle-meme. *\/\r\n                                _e1891.style.setProperty('transform', 'scale(' + _f + ')', 'important');\r\n                                _e1891.style.setProperty('transform-origin', 'top center', 'important');\r\n                                var _h1891 = _e1891.offsetHeight;\r\n                                if (!(_h1891 > 0)) { _res1891.push(_ids1891[_i1891] + '=h0'); continue; }\r\n                                var _v1891 = Math.round(_h1891 * (1 - parseFloat(_f)));\r\n                                if (_v1891 < 0) { _v1891 = 0; }\r\n                                \/* pb2004 : LE TERME DE MARGE BASSE pb2003 EST RETIRE.\r\n                                   Erratum de JF : c'etait margin-TOP, pas bottom. Mais le\r\n                                   log dit autre chose, qu'il faut consigner : la ligne\r\n                                   [pb2003] n'est jamais apparue. Elle ne pouvait pas.\r\n                                   Ce bloc-ci appartient a _viaEchelleReferences1612, et\r\n                                   cette passe ne tourne que si #ReferencesFormulaires est\r\n                                   RENDU \u2014 la condition meme dont pb1982 avait du extraire\r\n                                   le calage parce qu'elle n'est jamais remplie sur la\r\n                                   regie mobile. J'ai donc pose un reglage \u00ab regie mobile \u00bb\r\n                                   dans le seul writer qui ne tourne pas la-bas : le code\r\n                                   etait inatteignable par construction, et son absence de\r\n                                   log en etait la preuve immediate.\r\n                                   La lecon vaut au-dela du cas : choisir le bon ECRIVAIN\r\n                                   ne suffit pas, il faut aussi verifier qu'il TOURNE dans\r\n                                   le contexte vise. Les deux questions sont distinctes.\r\n                                   La marge haute, elle, est portee par\r\n                                   _viaCalageOblig1982, que le veilleur rejoue toutes les\r\n                                   2s sur la regie \u2014 le log de JF le montre au passage 13.\r\n                                   La demande y est donc traitee, voir pb2004 la-bas. *\/\r\n                                _e1891.style.setProperty('margin-bottom', (-_v1891) + 'px', 'important');\r\n                                \/* ============================================================\r\n                                 * pb1893b : LE TEXTE \u00ab * champ obligatoire \u00bb ETAIT TROP PETIT.\r\n                                 *   pb1892a posait font-size:calc(1em * k) sur le CONTENEUR.\r\n                                 *   Sans effet utile : le <p> interne porte sa propre\r\n                                 *   font-size Elementor, il n herite donc pas du conteneur.\r\n                                 *   On la pose sur le <p> lui-meme, en px, apres mesure.\r\n                                 *   La base est memorisee dans un data-* : sans cela chaque\r\n                                 *   passage relirait une valeur deja multipliee et le texte\r\n                                 *   grossirait sans fin \u2014 cette passe est rejouee a chaque\r\n                                 *   appel de _viaEchelleReferences1612, et pb1621 en\r\n                                 *   declenche trois.\r\n                                 * ============================================================ *\/\r\n                                if (_ids1891[_i1891] === 'ChampsObligatoiresNEW') {\r\n                                    var _k1893 = (parseFloat(_f) > 0)\r\n                                        ? (Math.round((_avant1890 \/ parseFloat(_f)) * 1000) \/ 1000) : 1;\r\n                                    var _ps1893 = _e1891.querySelectorAll('p');\r\n                                    var _dit1998 = '';\r\n                                    for (var _j1893 = 0; _j1893 < _ps1893.length; _j1893++) {\r\n                                        var _pe1893 = _ps1893[_j1893];\r\n                                        var _b1893 = _pe1893.getAttribute('data-fs1893');\r\n                                        if (_b1893 === null) {\r\n                                            _b1893 = String(parseFloat(window.getComputedStyle(_pe1893).fontSize) || 0);\r\n                                            _pe1893.setAttribute('data-fs1893', _b1893);\r\n                                        }\r\n                                        \/* ============================================\r\n                                         * pb1998 : LA POLICE REVIENT DANS SON ECRIVAIN.\r\n                                         *   Question de JF : \u00ab il y avait deja un writer\r\n                                         *   pour ces modifs, tu l'as utilise ? \u00bb\r\n                                         *   Pour les marges, oui : la branche sites pays\r\n                                         *   desktop de pb1997 a ete ajoutee DANS\r\n                                         *   _viaCalageOblig1982, l'ecrivain unique des\r\n                                         *   marges depuis pb1982.\r\n                                         *   Pour la POLICE, non, et c'etait une erreur.\r\n                                         *   pb1893b est l'ecrivain de la police de cet\r\n                                         *   element depuis qu'il existe, avec sa base\r\n                                         *   memorisee dans data-fs1893. J'ai ecrit\r\n                                         *   ailleurs, puis ajoute ici une garde pour\r\n                                         *   faire taire l'ecrivain d'origine : deux\r\n                                         *   modifications, dans deux endroits eloignes,\r\n                                         *   couplees l'une a l'autre \u2014 une strate, exactement\r\n                                         *   ce que ce projet refuse. Et ma justification\r\n                                         *   etait fausse : je l'avais motivee par un veilleur\r\n                                         *   qui, hors regie, ne tourne pas (pb1988).\r\n                                         *   La forme juste est une BRANCHE dans le writer\r\n                                         *   existant : meme boucle, meme base, meme\r\n                                         *   ecriture, seule la valeur cible change selon le\r\n                                         *   contexte. Un writer, un endroit, aucune garde a\r\n                                         *   distance.\r\n                                         *   Reglage : window._viaPb1997Fs = 11\r\n                                         *   Revert  : window._viaPb1997Off = true (retour a\r\n                                         *   base x facteur + 2 partout).\r\n                                         * ============================================ *\/\r\n                                        var _paysDt1998 = false;\r\n                                        if (window._viaPb1997Off !== true) {\r\n                                            if (typeof window._viaPaysDesktop1994 === 'function') {\r\n                                                if (window._viaPaysDesktop1994()) { _paysDt1998 = true; }\r\n                                            }\r\n                                        }\r\n                                        if (parseFloat(_b1893) > 0) {\r\n                                            var _cfs1998;\r\n                                            if (_paysDt1998) {\r\n                                                \/* pb1997 : 10px demandes, valeur FINALE \u2014 ni\r\n                                                   facteur ni supplement, donc la base n'entre\r\n                                                   pas dans le calcul ici. *\/\r\n                                                _cfs1998 = ((typeof window._viaPb1997Fs === 'number')\r\n                                                    ? window._viaPb1997Fs : 10) + 'px';\r\n                                            } else {\r\n                                                \/* pb1894a : +2px demandes, ajoutes APRES le facteur \u2014 c est\r\n                                                   une taille finale, pas un facteur de plus. *\/\r\n                                                _cfs1998 = (Math.round((parseFloat(_b1893) * _k1893 + 2) * 10) \/ 10) + 'px';\r\n                                            }\r\n                                            _dit1998 = _cfs1998;\r\n                                            if (_pe1893.style.fontSize !== _cfs1998) {\r\n                                                _pe1893.style.setProperty('font-size', _cfs1998, 'important');\r\n                                                if (window._viaSig1998 !== _cfs1998) {\r\n                                                    window._viaSig1998 = _cfs1998;\r\n                                                    console.log('[pb1998] ChampsObligatoiresNEW police = '\r\n                                                        + _cfs1998 + ' | pays-desktop=' + _paysDt1998\r\n                                                        + ' | base ' + _b1893 + ' facteur ' + _k1893);\r\n                                                }\r\n                                            }\r\n                                        }\r\n                                    }\r\n                                    \/* ============================================================\r\n                                     * pb1894a : CALAGE DEMANDE PAR JF \u2014 +2px de police,\r\n                                     *   10px plus bas, 20px vers la droite, pour degager le\r\n                                     *   message d erreur rouge qui le chevauchait.\r\n                                     *   Les deux marges sont ADDITIVES sur une base memorisee\r\n                                     *   dans un data-* : une feuille pose deja margin-top:-15px\r\n                                     *   sur .ReferencesConteneur, et cette passe est rejouee\r\n                                     *   plusieurs fois. Sans base figee, les 10px et les 20px\r\n                                     *   s ajouteraient a chaque tour et l element partirait.\r\n                                     * ============================================================ *\/\r\n                                    \/* pb1982 : le calage est desormais UNE fonction,\r\n                                       appelee ici comme par le veilleur autonome. *\/\r\n                                    \/* pb1999 : ce resume annoncait \u00ab +2px \u00bb en dur. Depuis\r\n                                       pb1998 la valeur depend du contexte, et le log de JF\r\n                                       affichait donc \u00ab +2px \u00bb au moment meme ou 10px etaient\r\n                                       poses. Un journal qui ment coute un aller-retour : on\r\n                                       affiche la valeur reellement ecrite. *\/\r\n                                    _res1891.push('fsObl base=' + _b1893 + ' x' + _k1893\r\n                                        + ' -> ' + (_dit1998 || '(aucune ecriture)')\r\n                                        + ' sur ' + _ps1893.length + ' p | '\r\n                                        + window._viaCalageOblig1982(_e1891));\r\n                                }\r\n                                _res1891.push(_ids1891[_i1891] + ' h=' + _h1891 + ' -> mb=-' + _v1891);\r\n                            }\r\n                            \/* ============================================================\r\n                             * pb1894b : MARGE BASSE DE #ChoixDataFacturationForm SELON LA CASE.\r\n                             *   Demande JF : 25px si la case est decochee, 15px si cochee.\r\n                             *   Traite HORS de la boucle : le log montrait ce formulaire a\r\n                             *   \u00ab =h0 \u00bb au moment de la passe, donc le continue sautait son\r\n                             *   tour. La marge ne depend pas de sa hauteur, elle n a pas a\r\n                             *   attendre qu il soit mesurable.\r\n                             *   Expose en fonction et rebranche sur le change de la case :\r\n                             *   sans cela la valeur ne suivrait pas le clic de l utilisateur,\r\n                             *   cette passe n etant rejouee que par pb1621.\r\n                             *   Reglages : window._viaMbFact1894Decoche \/ ...Coche\r\n                             * ============================================================ *\/\r\n                            \/* pb1896b : DEUX CIBLES DIFFERENTES SELON L ETAT DE LA CASE.\r\n                               Precision JF : decochee, les 30px vont sur #ChoixDataFacturationForm ;\r\n                               cochee, les 15px vont sur #DataFacturationForm \u2014 l autre formulaire,\r\n                               celui qui apparait. pb1894b posait tout sur le premier.\r\n                               Chaque cible retrouve sa base quand elle n est pas visee : sans cela\r\n                               les 30px resteraient en place apres le cochage.\r\n                               Base memorisee dans data-mb1896 \u2014 cette fonction tourne a chaque\r\n                               passe ET a chaque clic, lire la valeur courante l ajouterait a\r\n                               elle-meme sans fin.\r\n                               Reglages : window._viaMbFact1894Decoche \/ ...Coche *\/\r\n                            window._viaMbFact1894 = function () {\r\n                                try {\r\n                                    var _cb = document.getElementById('form-field-DataFacturation-0');\r\n                                    var _on = _cb ? (_cb.checked === true) : false;\r\n                                    var _dec = (typeof window._viaMbFact1894Decoche === 'number') ? window._viaMbFact1894Decoche : 30;\r\n                                    var _coc = (typeof window._viaMbFact1894Coche === 'number') ? window._viaMbFact1894Coche : 15;\r\n                                    var _poser1896 = function (_id, _ajout) {\r\n                                        var _e = document.getElementById(_id);\r\n                                        if (!_e) { return _id.substring(0, 6) + '=absent'; }\r\n                                        var _b = _e.getAttribute('data-mb1896');\r\n                                        if (_b === null) {\r\n                                            _b = String(parseFloat(window.getComputedStyle(_e).marginBottom) || 0);\r\n                                            _e.setAttribute('data-mb1896', _b);\r\n                                        }\r\n                                        _e.style.setProperty('margin-bottom', (parseFloat(_b) + _ajout) + 'px', 'important');\r\n                                        return _id.substring(0, 6) + ' ' + _b + '+' + _ajout;\r\n                                    };\r\n                                    var _r1 = _poser1896('ChoixDataFacturationForm', _on ? 0 : _dec);\r\n                                    var _r2 = _poser1896('DataFacturationForm', _on ? _coc : 0);\r\n                                    return (_on ? 'cochee' : 'decochee') + ' | ' + _r1 + ' | ' + _r2;\r\n                                } catch (_e) { return 'erreur : ' + _e.message; }\r\n                            };\r\n                            _res1891.push('mbFact ' + window._viaMbFact1894());\r\n                            if (!window._viaEcoute1894) {\r\n                                window._viaEcoute1894 = true;\r\n                                document.addEventListener('change', function (_ev) {\r\n                                    var _t = _ev.target;\r\n                                    if (!_t) { return; }\r\n                                    if (_t.id !== 'form-field-DataFacturation-0') { return; }\r\n                                    console.log('[pb1894] case facturation -> ' + window._viaMbFact1894());\r\n                                }, true);\r\n                            }\r\n                            console.log('[pb1891] vide du transform compense (echelle ' + _f + ') | '\r\n                                + _res1891.join(' | '));\r\n                        } catch (_e1891x) { console.log('[pb1891] compensation impossible : ' + _e1891x.message); }\r\n                    }, 250);\r\n                }\r\n                \/* pousser l'echelle du conteneur : l'observateur la relira aussitot *\/\r\n                var _rf = document.getElementById('ReferencesFormulaires');\r\n                var _c = (typeof window._viaPb1594Scale === 'number') ? window._viaPb1594Scale : 1;   \/* pb1614 *\/\r\n                if (_rf) { _rf.style.setProperty('transform', 'scale(' + _c + ')', 'important'); }\r\n                console.log('[pb1612] echelles References | formulaires=' + _f\r\n                    + ' | conteneur=' + _c + ' | composee=' + Math.round(_f * _c * 1000) \/ 1000);\r\n                return 'formulaires=' + _f + ' conteneur=' + _c;\r\n            };\r\n            var _refStyle = document.createElement('style');\r\n            _refStyle.id = 'via-references-scale-style';\r\n            var _isMobRef = window.outerWidth < 1000;\r\n            \/\/ \u2705 v4.9ds+ : neutraliser le scale(0.9) de .ReferencesConteneurScale sur les forms facturation\r\n            \/\/   (ces forms ne b\u00e9n\u00e9ficient pas du container #ReferencesFormulaires scale(1.1))\r\n            \/* ============================================================\r\n             * pb1606 : L'ECHELLE DE REFERENCES EST ICI, PAS SUR LE CONTENEUR.\r\n             *   pb1594 et pb1605 agissaient sur #ReferencesFormulaires \u2014 le HTML montre\r\n             *   mes styles bien poses dessus, sans le moindre effet. La raison : l'echelle\r\n             *   est appliquee a ses ENFANTS par cette feuille, dans un AUTRE fichier \u2014\r\n             *   .ReferencesConteneurScale { transform: scale(0.9) }.\r\n             *   Ce 0.9 compensait le scale(1.1) du conteneur parent, regle pour la colonne\r\n             *   droite de la regie. Depuis pb1594 le conteneur est a l'echelle 1 dans le\r\n             *   popup : le 0.9 n'a plus rien a compenser et retrecit seul.\r\n             *   En mode popup, aucune echelle.\r\n             *   Revert : window._viaPb1606Off = true (0.9 partout).\r\n             * ============================================================ *\/\r\n            \/* pb1611b : pb1606 annule \u2014 l'echelle 0.9 fait partie de la mecanique de la\r\n               regie desktop, que l'utilisateur demande a reproduire. Elle se compose avec\r\n               le 0.75 de #ReferencesFormulaires (yearbook-media.js) : 0.675 pour le\r\n               formulaire principal, 0.75 pour ceux de facturation qui annulent le 0.9.\r\n               Reglage a chaud : window._viaEchelleRef1611 = 0.95 *\/\r\n            \/* ============================================================\r\n             * pb1614 : LES TROIS FORMULAIRES A LA MEME ECHELLE, ET PLEINE TAILLE.\r\n             *   Constat user : \u00ab pourquoi les 3 formulaires n'ont-ils pas la meme\r\n             *   taille ? \u00bb et \u00ab la taille des textes des champs de saisie est trop\r\n             *   petite \u00bb.\r\n             *   Les echelles se COMPOSENT, et divergeaient :\r\n             *     annonceur    0.75 x 0.9 = 0.675\r\n             *     facturation  0.75 x 1.0 = 0.75     (le 1.0 annulait le 0.9)\r\n             *   D'ou 11 % d'ecart entre les deux, visible sur la capture.\r\n             *   Ces reductions servaient a faire tenir les formulaires dans la colonne\r\n             *   droite de la regie. Depuis pb1610, les largeurs sont bornees au\r\n             *   conteneur : il n'y a plus rien a faire tenir de force, et reduire ne\r\n             *   fait que rendre les libelles illisibles.\r\n             *   On met donc TOUT a 1 : meme echelle pour les trois, texte a sa taille\r\n             *   naturelle. Effet secondaire bienvenu : a l'echelle 1, la boite de mise\r\n             *   en page correspond au rendu, donc le vide vertical laisse par le\r\n             *   transform disparait.\r\n             *   Reduction possible a chaud : window._viaEchelleReferences1612(0.9, 0.9)\r\n             *   Revert : window._viaEchelleRef1611 = 0.9 et window._viaPb1594Scale = 0.75.\r\n             * ============================================================ *\/\r\n            \/* ============================================================\r\n             * pb1700 : DEUX FEUILLES, ET LA SECONDE ANNULAIT LA PREMIERE.\r\n             *   Constat user : _viaEchelleReferences1612(0.65) ne modifie que le\r\n             *   PREMIER formulaire.\r\n             *   La fonction reconstruit via-references-scale-style, qui vise bien\r\n             *   les trois. Mais _refStyle, construit ici a l initialisation, est\r\n             *   appendu APRES et repose #ChoixDataFacturationForm et\r\n             *   #DataFacturationForm a scale(_sc1606) \u2014 soit 1. A specificite\r\n             *   egale, la derniere feuille gagne : les deux formulaires de\r\n             *   facturation revenaient a 1, le premier gardait 0.65.\r\n             *   pb1619 avait fait appeler la fonction par l initialisation, mais\r\n             *   sans supprimer cette feuille-ci : les deux coexistent encore.\r\n             *   On leur donne au moins le meme defaut, pour qu elles ne se\r\n             *   contredisent plus. La fusion des deux feuilles reste a faire.\r\n             * ============================================================ *\/\r\n            var _d1700 = 1;\r\n            if (window._viaPb1698Off !== true) {\r\n                if (window.outerWidth <= 1000) { _d1700 = 0.89; }   \/* pb1704 *\/\r\n            }\r\n            \/* ============================================================\r\n             * pb1889 : TEXTE DES CHAMPS References PLUS PETIT DE 4px, MOBILE.\r\n             *   C est ICI qu il fallait poser le retrait. Trois tentatives dans\r\n             *   yearbook-media.js (pb1886, pb1887, pb1888) sont restees sans\r\n             *   effet : leur bloc sort immediatement sur mobile tactile (pb211,\r\n             *   maxTouchPoints>0 et outerWidth<1000). Aucun de leurs logs\r\n             *   n apparaissait dans le releve, c est ce qui l a montre.\r\n             *   ON NE TOUCHE PAS A LA font-size : elle reste forcee a 18px par\r\n             *   une feuille statique, pour qu iOS ne zoome pas a la saisie \u2014 il\r\n             *   decide sur la taille CALCULEE et ignore transform:scale.\r\n             *   Le retrait passe donc par l echelle, exprime en px de rendu :\r\n             *     rendu actuel   18 x 0.89 = 16.02 px CSS\r\n             *     retrait 4px -> 12.02 px CSS, soit scale 0.668\r\n             *   Le calcul part de _d1700 et non d une constante : si pb1704\r\n             *   change son 0.89, le retrait reste de 4px au lieu de deriver.\r\n             *   Reglage a chaud : window._viaRetrait1889 = 2   (px CSS)\r\n             *   Revert : window._viaPb1889Off = true\r\n             * ============================================================ *\/\r\n            if (window._viaPb1889Off !== true) {\r\n                if (window.outerWidth <= 1000) {\r\n                    var _ret1889 = (typeof window._viaRetrait1889 === 'number') ? window._viaRetrait1889 : 4;\r\n                    var _base1889 = 18;\r\n                    var _av1889 = _d1700;\r\n                    var _n1889 = Math.round(((_d1700 * _base1889 - _ret1889) \/ _base1889) * 1000) \/ 1000;\r\n                    if (_n1889 < 0.3) { _n1889 = 0.3; }\r\n                    _d1700 = _n1889;\r\n                    if (window._viaSig1889 !== _d1700) {\r\n                        window._viaSig1889 = _d1700;\r\n                        console.log('[pb1889] retrait ' + _ret1889 + 'px : scale ' + _av1889\r\n                            + ' -> ' + _d1700 + ' | rendu ' + (_base1889 * _d1700).toFixed(2)\r\n                            + 'px CSS (police forcee ' + _base1889 + 'px, inchangee)');\r\n                    }\r\n                }\r\n            }\r\n            \/* pb1889b : echelle d avant retrait, pour les elements exclus. *\/\r\n            var _scAvant1889 = String((typeof window._viaEchelleRef1611 === 'number')\r\n                ? window._viaEchelleRef1611 : (typeof _av1889 === 'number' ? _av1889 : _d1700));\r\n            var _sc1606 = String((typeof window._viaEchelleRef1611 === 'number')\r\n                ? window._viaEchelleRef1611 : _d1700);\r\n            console.log('[pb1606] .ReferencesConteneurScale -> scale(' + _sc1606 + ')');\r\n            _refStyle.textContent =\r\n                '#ReferencesConteneurId, .ReferencesConteneurScale { transform: scale(' + _sc1606 + ') !important; transform-origin: top center !important; } ' +\r\n                \/* pb1889b : \u00ab * champ obligatoire \u00bb garde sa taille. Il porte\r\n                   .ReferencesConteneurScale et suivrait donc la reduction.\r\n                   Une regle d ID bat une regle de classe : pas besoin de le\r\n                   retirer du selecteur ci-dessus, ni de croiser deux facteurs.\r\n                   Il reprend l echelle d avant retrait, calculee au meme\r\n                   endroit \u2014 window._viaEchelleRef1611 continue de primer si\r\n                   elle est posee. *\/\r\n                '#ChampsObligatoiresNEW { transform: scale(' + _scAvant1889 + ') !important; transform-origin: top center !important; } ' +\r\n                \/\/ \u2705 v4.9ds+ : neutraliser scale(0.9) sur les forms facturation\r\n                \/\/   (hors #ReferencesFormulaires qui booste #ReferencesConteneurId \u00e0 ~1.0)\r\n                \/* pb1614b : la regle d'annulation disparait \u2014 elle existait pour rendre\r\n                   aux formulaires de facturation le 0.9 applique aux autres. A echelle\r\n                   commune, elle creerait justement l'ecart qu'on supprime. *\/\r\n                '#ChoixDataFacturationForm, #DataFacturationForm { transform: scale(' + _sc1606 + ') !important; transform-origin: top center !important; }' +\r\n                \/* pb1610 : la ligne de la case a cocher etait coupee A GAUCHE \u2014 signe d'un\r\n                   element plus large que son conteneur et centre. On borne les formulaires\r\n                   et on ancre la transformation en haut a gauche, pour que tout\r\n                   debordement residuel parte a droite (visible) plutot qu'a gauche\r\n                   (perdu hors du popup). *\/\r\n                ' #ReferencesFormulaires, #ReferencesConteneurId, #ChoixDataFacturationForm,'\r\n                + ' #DataFacturationForm, .ReferencesConteneurScale {'\r\n                + ' max-width: 100% !important; box-sizing: border-box !important;'\r\n                + ' transform-origin: top center !important; }   \/* pb1700 : centre, le top left alignait a droite *\/'\r\n                + ' #ReferencesFormulaires .elementor-form-fields-wrapper {'\r\n                + ' max-width: 100% !important; box-sizing: border-box !important; }';\r\n            document.head.appendChild(_refStyle);\r\n            \/* ============================================================\r\n             * pb1619 : L'INITIALISATION EMPRUNTE LE MEME CHEMIN QUE LA FONCTION.\r\n             *   Constat user : \u00ab par defaut les formulaires n'ont toujours pas la meme\r\n             *   taille, window._viaEchelleReferences1612(1, 1) resout le pb \u00bb.\r\n             *   Autrement dit, deux chemins produisaient deux resultats : la feuille\r\n             *   construite ici a l'initialisation, et celle que reconstruit la fonction.\r\n             *   Ils ne posaient donc pas exactement les memes regles \u2014 et j'ai ajuste les\r\n             *   defauts des deux separement (pb1614), en supposant qu'ils convergeraient.\r\n             *   On supprime la divergence a la source : l'initialisation APPELLE la\r\n             *   fonction. Un seul endroit decrit les echelles, et ce que tu obtiens en\r\n             *   console est exactement ce que tu obtiens au chargement.\r\n             *   Differe d'un tick : #ReferencesFormulaires peut ne pas etre encore rendu.\r\n             * ============================================================ *\/\r\n            \/* ============================================================\r\n             * pb1621 : ATTENDRE QUE LE FORMULAIRE SOIT RENDU.\r\n             *   Constat user : aucun log [pb1620]. Deux raisons cumulees :\r\n             *     - le bloc pb1620 est garde par \u00ab largeur > 0 \u00bb, or\r\n             *       #ReferencesFormulaires reste a zero tant que l'etape References\r\n             *       n'est pas ouverte \u2014 donc apres le clic Finaliser ;\r\n             *     - et _viaForcer100pc1578, qui le porte, n'est plus appelee que sur\r\n             *       resize ou a l'apparition du bouton Finaliser : j'ai retire sa veille\r\n             *       en pb1601. Rien ne la declenche a l'ouverture de References.\r\n             *   Un correctif place dans une fonction que personne n'appelle au bon\r\n             *   moment ne s'execute jamais \u2014 c'est la troisieme fois de la session.\r\n             *   On scrute donc ici, dans le fichier ou vit la fonction : des que le\r\n             *   formulaire a une largeur, on applique les echelles, puis deux fois de\r\n             *   plus a distance pour couvrir ce qui repasserait ensuite.\r\n             *   Revert : window._viaPb1621Off = true.\r\n             * ============================================================ *\/\r\n            if (window._viaPb1621Off !== true) {\r\n                var _n1621 = 0;\r\n                var _fait1621 = 0;\r\n                var _t1621 = setInterval(function () {\r\n                    _n1621++;\r\n                    \/* pb1630b : la scrutation pb1621 declenche aussi la fonction qui porte\r\n                       pb1613, pb1616, pb1617 et pb1630 \u2014 sans elle, ces correctifs ne sont\r\n                       appliques qu'au resize. *\/\r\n                    var _rf = document.getElementById('ReferencesFormulaires');\r\n                    var _vis = _rf ? (_rf.getBoundingClientRect().width > 0) : false;\r\n                    if (_vis ? (typeof window._viaForcer100pc1578 === 'function') : false) {\r\n                        window._viaForcer100pc1578('scrutation pb1630b');\r\n                    }\r\n                    if (_vis ? (typeof window._viaEchelleReferences1612 === 'function') : false) {\r\n                        _fait1621++;\r\n                        console.log('[pb1621] formulaire References rendu \u2014 application des echelles ('\r\n                            + _fait1621 + '\/3)');\r\n                        window._viaEchelleReferences1612();\r\n                        if (_fait1621 >= 3) { clearInterval(_t1621); return; }\r\n                    }\r\n                    if (_n1621 >= 240) {\r\n                        clearInterval(_t1621);\r\n                        if (_fait1621 === 0) {\r\n                            console.log('[pb1621] abandon : #ReferencesFormulaires jamais rendu en 2 min');\r\n                        }\r\n                    }\r\n                }, 500);\r\n            }\r\n        }\r\n\r\n        \/\/ \u2705 v4.9ds+ (suite 6) Pb 4 mobile device \u2014 fix par inline style JS forc\u00e9.\r\n        \/\/   La CSS de _sYBM (YBM L388, scale(1.3) !important sur #ChoixDataFacturationForm)\r\n        \/\/   bat la CSS PM ci-dessus \u00e0 cause de l'ordre d'injection (YBM inject\u00e9 APR\u00c8S PM\r\n        \/\/   dans le head, m\u00eame sp\u00e9cificit\u00e9 \u2192 YBM gagne). Le diag chain ancestor a confirm\u00e9 :\r\n        \/\/   #ChoixDataFacturationForm computed transform = matrix(1.3, 0, 0, 1.3, 0, 0).\r\n        \/\/   Solution : appliquer un style inline avec setProperty(..., 'important') \u2192\r\n        \/\/   bat toute CSS (y compris !important). Et re-appliquer toutes les 2s pour\r\n        \/\/   contrer les resets \u00e9ventuels par Elementor ResizeObserver\/MutationObserver.\r\n        \/\/   Cible : pointer:coarse uniquement (vrai mobile tactile, pas DVM ni desktop).\r\n        if (window.matchMedia('(pointer: coarse)').matches) {\r\n            function _applyMobScale() {\r\n                var _els = document.querySelectorAll('#ChoixDataFacturationForm, #DataFacturationForm');\r\n                for (var _i = 0; _i < _els.length; _i++) {\r\n                    \/\/ \u2705 Valeur tweakable : compound avec #ReferencesFormulaires (scale 0.75) \u2192\r\n                    \/\/   0.7 = compound 0.525 (trop petit), 0.9 = compound 0.675, 1.0 = compound 0.75\r\n                    \/* ============================================================\r\n                     * pb1893a : CE 0.9 EN DUR REPOSAIT L ECHELLE TOUTES LES 2 SECONDES.\r\n                     *   Constat JF : \u00ab les 2 formulaires prennent une taille correcte\r\n                     *   puis reviennent a leur taille initiale \u00bb. Le log le confirme :\r\n                     *   [pb1620] DataFacturationForm=1 quand la feuille dit 0.668.\r\n                     *   Cette fonction, armee sur pointer:coarse \u2014 donc sur le vrai\r\n                     *   mobile du user \u2014 repose scale(0.9) en inline important toutes\r\n                     *   les 2s. Elle bat tout : feuille, specificite renforcee (pb1891a)\r\n                     *   et l inline pose par pb1892b.\r\n                     *   Elle a sa raison d etre \u2014 contrer les resets d Elementor \u2014 et ce\r\n                     *   n est donc pas elle qu il faut desarmer, mais sa VALEUR EN DUR.\r\n                     *   Elle lit desormais l echelle courante publiee par\r\n                     *   _viaEchelleReferences1612, et retombe sur 0.9 si celle-ci n est\r\n                     *   pas encore connue. Un seul endroit decide, celui-ci applique.\r\n                     * ============================================================ *\/\r\n                    var _sc1893 = (typeof window._viaEchelleRefCourante === 'number')\r\n                        ? window._viaEchelleRefCourante : 0.9;\r\n                    _els[_i].style.setProperty('transform', 'scale(' + _sc1893 + ')', 'important');\r\n                    _els[_i].style.setProperty('transform-origin', 'top center', 'important');\r\n                }\r\n            }\r\n            \/\/ Application initiale apr\u00e8s 500ms (laisser le DOM se monter)\r\n            setTimeout(_applyMobScale, 500);\r\n            \/\/ Re-application p\u00e9riodique pour contrer Elementor resets\r\n            setInterval(_applyMobScale, 2000);\r\n        }\r\n\r\n        \/\/ v4.9ds : remonter les sections de ViaPopupProcessAchat (sites pays \/ mode=popup)\r\n        \/\/   pour resserrer la mise en page verticalement.\r\n        \/\/   Cumul : la valeur sur DatesDureeCampagneClass entra\u00eene aussi le d\u00e9placement\r\n        \/\/   des \u00e9l\u00e9ments suivants ; les valeurs n\u00e9gatives s'ajoutent donc visuellement.\r\n        \/\/   Updates v4.9ds (cumuls successifs) :\r\n        \/\/     DatesDuree                            : -15 (stable)\r\n        \/\/     Refs (.ReferencesConteneur)           : -15 (stable)\r\n        \/\/     ChoisirPaiementClass                  : -20 \u2192 0 (annul\u00e9)\r\n        \/\/     ModePaiementLisereBleu                : -10 (NOUVEAU, remonte 10)\r\n        \/\/     #ReferencesConteneurId                : +28 (stable)\r\n        \/\/     #ValidationsConteneur                 : RETIRE en pb1792\r\n        \/\/                                             (Elementor reprend la main)\r\n        \/\/     #FormatSubContainer    margin-bottom  : +10 (stable)\r\n        \/\/     .AssocierSecteurClass  margin-bottom  : -8 (stable)\r\n        \/\/   + masquage de 2 messages d'OK qui ne doivent jamais s'afficher\r\n        \/\/   + titre \u00e9tape \"Associer Secteur\" en gris par d\u00e9faut (override via-etape-en-cours)\r\n        if (!document.getElementById('via-popup-process-achat-spacing')) {\r\n            var _spacingStyle = document.createElement('style');\r\n            _spacingStyle.id = 'via-popup-process-achat-spacing';\r\n            _spacingStyle.textContent =\r\n                'html body .DatesDureeCampagneClass { margin-top: -15px !important; }' +\r\n                'html body .ReferencesConteneur     { margin-top: -15px !important; }' +\r\n                \/* ============================================================\r\n                 * pb1718 : CETTE REGLE ANNULAIT LES REMONTEES D ELEMENTOR.\r\n                 *   Probes compares, regie contre site pays :\r\n                 *     PayableParMsgConteneur   mt = -20px  |  mt = 0px\r\n                 *     ChoisirPaiement          mt = -10px  |  mt = 0px\r\n                 *     ModePaiementLisereBleu   h  =  211   |  h  = 279\r\n                 *   Les deux ecarts que tu entoures valent exactement 20 et 10 px.\r\n                 *   Elementor applique a ces conteneurs un --margin-top negatif\r\n                 *   (post-278591-css : --margin-top: -20px, -10px). La regle\r\n                 *   ci-dessous, en classe et en important, le remettait a zero sur\r\n                 *   TOUS les .ChoisirPaiementClass a la fois.\r\n                 *   Elle n existe que dans cette feuille, injectee en mode=popup\r\n                 *   seulement : d ou une regie intacte et des sites pays espaces.\r\n                 *   Son commentaire disait \u00ab decalage annule \u00bb \u2014 c etait exact, et\r\n                 *   c est justement ce qu il ne fallait plus faire. On la retire ;\r\n                 *   la mise en page d Elementor reprend la main, identique a la\r\n                 *   regie.\r\n                 *   La regle voisine sur #ModePaiementLisereBleu reste : elle pose\r\n                 *   -10px, soit exactement ce que la regie calcule deja. Elle est\r\n                 *   redondante, pas nuisible \u2014 je ne la touche pas dans le meme\r\n                 *   marqueur.\r\n                 *   Revert : window._viaPb1718Off = true.\r\n                 * ============================================================ *\/\r\n                (window._viaPb1718Off === true\r\n                    ? 'html body .ChoisirPaiementClass    { margin-top: 0px   !important; }'\r\n                    : '') +\r\n                \/\/ v4.9ds : ModePaiementLisereBleu (ID) \u2014 remonte de 10px (cumul depuis 0)\r\n                'html body #ModePaiementLisereBleu  { margin-top: -10px !important; }' +\r\n                'html body #ReferencesConteneurId   { margin-top:  28px !important; }' +\r\n                \/\/ pb1194 : contenu de l'etape Validations CENTRE (demande user).\r\n                \/\/   La regle rejoint celle qui gere deja la marge de ce conteneur :\r\n                \/\/   un seul endroit decide de sa mise en page.\r\n                \/\/   align-items centre les enfants d'un conteneur flex (le cas des\r\n                \/\/   blocs Elementor) ; margin auto et text-align couvrent le cas ou\r\n                \/\/   il retomberait en flux normal. Les trois ensemble valent pour\r\n                \/\/   les deux modes de mise en page, sans avoir a savoir lequel\r\n                \/\/   s'applique.\r\n                \/* ============================================================\r\n                 * pb1792 : LE -10px DE #ValidationsConteneur EST RETIRE (JF).\r\n                 *   La declaration margin-top disparait, le centrage reste.\r\n                 *   On ne la met pas a 0 : on la SUPPRIME, pour qu'Elementor\r\n                 *   reprenne la main et rende la meme valeur que sur la regie.\r\n                 *   Poser 0 aurait fige un troisieme comportement, different\r\n                 *   des deux contextes \u2014 c'est la lecon de pb1718, meme feuille,\r\n                 *   meme piege : une regle qui neutralise Elementor en popup\r\n                 *   seulement produit une regie intacte et des sites pays\r\n                 *   decales.\r\n                 *   Le centrage (align-items, justify-content, text-align,\r\n                 *   margin-left\/right auto) est conserve tel quel : pb1194 avait\r\n                 *   volontairement mis marge et centrage dans la MEME regle pour\r\n                 *   qu'un seul endroit decide de la mise en page de ce bloc.\r\n                 *   ATTENTION : cette feuille est construite UNE SEULE FOIS a\r\n                 *   l'initialisation, derriere !getElementById(...). Le knob doit\r\n                 *   donc etre pose AVANT, sinon il n'a aucun effet \u2014 silencieux.\r\n                 *   Revert : window._viaPb1792Off = true  (retablit -10px).\r\n                 * ============================================================ *\/\r\n                'html body #ValidationsConteneur    { '\r\n                    + (window._viaPb1792Off === true ? 'margin-top: -10px !important;' : '') +\r\n                '   align-items: center !important;' +\r\n                '   justify-content: center !important;' +\r\n                '   text-align: center !important;' +\r\n                '   margin-left: auto !important; margin-right: auto !important; }' +\r\n                'html body #ValidationsConteneur > * { margin-left: auto !important;' +\r\n                '   margin-right: auto !important; }' +\r\n                \/\/ marges verticales bottom\r\n                'html body #FormatSubContainer      { margin-bottom: 10px !important; }' +\r\n                'html body .AssocierSecteurClass    { margin-bottom: -8px !important; }' +\r\n                \/\/ pb1174 : REGLE SUPPRIMEE \u2014 elle for\u00e7ait le gris sur le titre\r\n                \/\/   \"Associer Secteur\", avec une specificite volontairement elevee\r\n                \/\/   \"pour battre .via-etape-en-cours *\". Elle contredisait donc par\r\n                \/\/   construction la regle des trois etats (pb1169).\r\n                \/\/   C'est l'un des writers concurrents que je compensais en rappelant\r\n                \/\/   la couleur apres coup (pb1172) : la bonne correction est de le\r\n                \/\/   retirer, pas de courir apres lui.\r\n                \/\/   La couleur de cette etape suit desormais son etat, comme toutes\r\n                \/\/   les autres.\r\n                \/* ============================================================\r\n                 * pb1719 : LES DEUX PHRASES VERTES DOIVENT S AFFICHER AUSSI EN POPUP.\r\n                 *   Constat user, HTML compare :\r\n                 *     regie      #MsgCompleterFormulaireOK  display: block !important\r\n                 *     site pays  #MsgCompleterFormulaireOK  display: none  !important\r\n                 *   Le texte est correct des deux cotes : seul l affichage differe.\r\n                 *   Deux mecanismes concourants, poses tous deux par v4.9ds :\r\n                 *     - cette regle-ci, \u00ab defense en profondeur \u00bb\r\n                 *     - la garde !_isPopupMsgUD dans _syncMessagesOK (l.15587, 15598)\r\n                 *   Le motif d origine est ecrit juste a cote : \u00ab sinon _showMsg pose\r\n                 *   un style inline display:block !important qui bat notre CSS \u00bb. Les\r\n                 *   deux se combattaient, et v4.9ds avait tranche en supprimant le\r\n                 *   message plutot qu en supprimant le conflit.\r\n                 *   On retire la cause : plus de regle de masquage ici, plus de garde\r\n                 *   la-bas. _showMsg redevient seul maitre de ces deux messages, et\r\n                 *   les sites pays se comportent comme la regie.\r\n                 *   Les autres conditions restent : etape fermee, etape complete, et\r\n                 *   clic Finaliser effectue (Pb 7). Rien ne s affichera plus tot.\r\n                 *   Revert : window._viaPb1719Off = true.\r\n                 * ============================================================ *\/\r\n                (window._viaPb1719Off === true\r\n                    ? 'html body #MsgCompleterFormulaireOKConteneur,'\r\n                      + 'html body #MsgCompleterFormulaireOK,'\r\n                      + 'html body #DeviseModedePaiementMsgConteneur,'\r\n                      + 'html body #DeviseModedePaiementMsg { display: none !important; }'\r\n                    : '');\r\n            document.head.appendChild(_spacingStyle);\r\n        }\r\n    }\r\n\r\n    \/\/ \u2705 v2.4.10 : Helper \u2014 restaure les accents sur les formats extraits depuis les classes CSS\r\n    function normaliseFormatAccents(fmt) {\r\n        var _map = { 'Banniere': 'Banni\u00e8re', 'Communique': 'Communiqu\u00e9', 'Video': 'Vid\u00e9o' };\r\n        return (fmt && _map[fmt]) ? _map[fmt] : (fmt || '');\r\n    }\r\n\r\n    \/* pb1513 : VALIDITE D'UN FORMAT \u2014 une seule verite.\r\n       Depuis pb1501, un format peut valoir la sentinelle 'a choisir' : l'espace est\r\n       reserve mais le format sera choisi plus tard dans le popup. Cette sentinelle est\r\n       une chaine NON VIDE, donc VRAIE : tout test de la forme `item.format && ...` la\r\n       laissait passer pour un format renseigne. Deux controles de completude le\r\n       faisaient (remplirFormulaireDepuisItem et recalculerTousLesTarifs) et partaient\r\n       appeler calculerTarifAPI('a choisir', ...) des que le pays et les dates etaient\r\n       saisis. Seul _isValidFmt, const locale utilisee a un seul endroit, connaissait la\r\n       sentinelle. On la remonte ici pour que tout controle de format passe par elle.\r\n       Revert : window._viaPb1513Off = true -> retour au simple test de verite. *\/\r\n    function _viaFormatValide1513(v) {\r\n        if (window._viaPb1513Off === true) { return !!v; }\r\n        if (!v) { return false; }\r\n        if (v === 'null') { return false; }\r\n        if (v === 'undefined') { return false; }\r\n        if (v === (window._viaFmtAChoisir1501 || '\u00e0 choisir')) { return false; }\r\n        return true;\r\n    }\r\n    window._viaFormatValide1513 = _viaFormatValide1513;\r\n\r\n    \/\/ ================================================================\r\n    \/\/ pb2099 : L'ETAPE FORMAT EST FAITE SI UN FORMAT VALIDE EXISTE **OU**\r\n    \/\/   SI LA CREATION D'ANNONCE EST ACTIVE.\r\n    \/\/   Constat user : vignette Creation selectionnee, l'etape Format reste\r\n    \/\/   ACTIVE au lieu de passer completee (et Dates ne devient pas l'etape\r\n    \/\/   courante). Log : \"[Pb 9.76] closeChoixFormat bloque \u2014 format non\r\n    \/\/   selectionne\". Cause : toute la chaine qui juge l'etape format\r\n    \/\/   (sequenceur pb1076, sonde pb1071, table pb1557, gardes) lit\r\n    \/\/   FormatSelect \/ item.format, que la Creation ne renseigne pas.\r\n    \/\/   L'equivalence pb858 (\"la Creation vaut un format\") n'existait que\r\n    \/\/   dans la garde pb857. On la centralise ici pour les COMPLETIONS\r\n    \/\/   d'etape uniquement \u2014 PAS dans _viaFormatValide1513, qui sert aussi\r\n    \/\/   aux tarifs ou la Creation n'est pas un format.\r\n    \/\/   Revert : window._viaPb2099Off = true.\r\n    \/\/ ================================================================\r\n    window._viaChoixFormatFait2099 = function(_fmt) {\r\n        if (_viaFormatValide1513(_fmt)) { return true; }\r\n        if (window._viaPb2099Off === true) { return false; }\r\n        if (sessionStorage.getItem('CreationFormatActive') === 'Yes') {\r\n            if (window._viaSig2099 !== '1') {\r\n                window._viaSig2099 = '1';\r\n                console.log('[pb2099] Creation active -> etape format consideree FAITE (sequenceur)');\r\n            }\r\n            return true;\r\n        }\r\n        window._viaSig2099 = '';\r\n        return false;\r\n    };\r\n\r\n    \/\/ \u2705 v1.7 : Initialisation du flag resize ET listener IMM\u00c9DIAT\r\n    window.VIA_Panier_ResizeEnCours = false;\r\n    let resizeTimeoutGlobal;\r\n    window.addEventListener('resize', function() {\r\n        window.VIA_Panier_ResizeEnCours = true;\r\n        clearTimeout(resizeTimeoutGlobal);\r\n        resizeTimeoutGlobal = setTimeout(function() {\r\n            window.VIA_Panier_ResizeEnCours = false;\r\n        }, 500);\r\n    });\r\n\r\n    \/\/ \u2705 v4.9ds+ (suite 6) Helper traduction FR \u2192 EN des labels format affich\u00e9s dans le panier.\r\n    \/\/   Le s\u00e9lecteur de format affiche les labels EN dans l'UI mais item.format stocke\r\n    \/\/   le nom canonique FR (Banni\u00e8re\/Communiqu\u00e9\/etc). Cet helper traduit pour l'affichage.\r\n    \/\/   G\u00e9r\u00e9 aussi le cas composite \"Pop-up X\" \u2192 \"Pop-up X_translated\".\r\n    function _translateFormatLabel(_lbl) {\r\n        if (!_lbl) { return _lbl; }\r\n        if (sessionStorage.getItem('SiteLangue') !== 'EN') { return _lbl; }\r\n        var _map = {\r\n            'Banni\u00e8re': 'Banner',\r\n            'Banniere': 'Banner',\r\n            'Communiqu\u00e9': 'Press release',\r\n            'Communique': 'Press release',\r\n            'Vid\u00e9o': 'Video',\r\n            'Video': 'Video',\r\n            'Interview': 'Interview',\r\n            'Parrainage': 'Sponsorship',\r\n            'Cr\u00e9ation': 'Creation',\r\n            'Creation': 'Creation',\r\n            'Pop-up': 'Pop-up'\r\n        };\r\n        if (_lbl.indexOf('Pop-up ') === 0) {\r\n            var _suffix = _lbl.substring(7);\r\n            return 'Pop-up ' + (_map[_suffix] || _suffix);\r\n        }\r\n        return _map[_lbl] || _lbl;\r\n    }\r\n    \/\/ Expos\u00e9 pour debug et usage externe \u00e9ventuel\r\n    window._viaTranslateFormatLabel = _translateFormatLabel;\r\n\r\n    window.VIA_Panier = {\r\n        \r\n        config: {\r\n            templateItem: '.CampagneTemplateClass',\r\n            conteneurParent: '.VosCampagnesConteneurClass',\r\n            etape1Container: '#Etape1Container',\r\n            syntheseConteneur: '#SyntheseConteneur',\r\n            boutonCommande: '.PasserCommandeBouton'\r\n        },\r\n        \r\n        state: {\r\n            items: [],\r\n            recapOuvert: false,\r\n            itemActif: null,\r\n            totalPanier: 0,\r\n            deviseAffichage: 'EUR',\r\n            scrollEnCours: false,  \/\/ \u2705 Flag pour \u00e9viter les scrolls simultan\u00e9s\r\n            syntheseEnCoursAffichage: false,  \/\/ \u2705 v1.7 : Anti-rebond afficherSynthese()\r\n            enVisualisationEtape: false  \/\/ \u2705 v1.10 : Flag pour permettre visualisation sans message\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 Scroll fluide vers une cible avec requestAnimationFrame\r\n         * @param {string|jQuery} target - S\u00e9lecteur ou \u00e9l\u00e9ment jQuery\r\n         * @param {number} offset - D\u00e9calage en pixels (d\u00e9faut: -30)\r\n         * @param {number} duration - Dur\u00e9e en ms (d\u00e9faut: 2000)\r\n         * @param {function} callback - Callback apr\u00e8s animation\r\n         *\/\r\n        scrollVers(target, offset = -30, duration = 2000, callback = null) {\r\n            \/\/ \u00c9viter les scrolls simultan\u00e9s\r\n            if (this.state.scrollEnCours) {\r\n                console.log('\ud83d\udd35 SCROLL: Animation d\u00e9j\u00e0 en cours, ignor\u00e9');\r\n                return;\r\n            }\r\n            \r\n            const $target = $(target);\r\n            if (!$target.length) {\r\n                console.warn('\ud83d\udd35 SCROLL: Cible non trouv\u00e9e', target);\r\n                return;\r\n            }\r\n            \r\n            const _offset = $target.offset();\r\n            if (!_offset) {\r\n                console.warn('\ud83d\udd35 SCROLL: offset() undefined (\u00e9l\u00e9ment non visible?)', target);\r\n                return;\r\n            }\r\n            const targetTop = _offset.top + offset;\r\n            const startTop = window.pageYOffset || document.documentElement.scrollTop;\r\n            const distance = targetTop - startTop;\r\n            \r\n            \/\/ Si la distance est tr\u00e8s faible, pas besoin d'animer\r\n            if (Math.abs(distance) < 10) {\r\n                console.log('\ud83d\udd35 SCROLL: Distance trop faible, ignor\u00e9');\r\n                return;\r\n            }\r\n            \r\n            console.log('\ud83d\udd35 SCROLL: Animation de', startTop, 'vers', targetTop, '(distance:', distance, ')');\r\n            \r\n            this.state.scrollEnCours = true;\r\n            const self = this;\r\n            const startTime = performance.now();\r\n            \r\n            \/\/ Fonction easing pour un mouvement plus naturel (easeInOutCubic)\r\n            function easeInOutCubic(t) {\r\n                return t < 0.5 \r\n                    ? 4 * t * t * t \r\n                    : 1 - Math.pow(-2 * t + 2, 3) \/ 2;\r\n            }\r\n            \r\n            function animateScroll(currentTime) {\r\n                const elapsed = currentTime - startTime;\r\n                const progress = Math.min(elapsed \/ duration, 1);\r\n                const easedProgress = easeInOutCubic(progress);\r\n                \r\n                const currentPosition = startTop + (distance * easedProgress);\r\n                window.scrollTo(0, currentPosition);\r\n                \r\n                if (progress < 1) {\r\n                    requestAnimationFrame(animateScroll);\r\n                } else {\r\n                    self.state.scrollEnCours = false;\r\n                    console.log('\ud83d\udd35 SCROLL: Animation termin\u00e9e');\r\n                    if (callback) callback();\r\n                }\r\n            }\r\n            \r\n            requestAnimationFrame(animateScroll);\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 Convertit le code position technique en libell\u00e9 utilisateur\r\n         *\/\r\n        convertirPositionEnLibelle: function(positionTechnique) {\r\n            if (!positionTechnique) return '-';\r\n            \r\n            \/\/ Si c'est d\u00e9j\u00e0 un libell\u00e9 utilisateur, le retourner tel quel\r\n            if (positionTechnique === 'Haut de page' || \r\n                positionTechnique === 'Corps de page' ||\r\n                positionTechnique === 'Pop-up') {\r\n                return positionTechnique;\r\n            }\r\n            \r\n            \/\/ Convertir les codes techniques\r\n            var positionLower = positionTechnique.toLowerCase();\r\n            \r\n            if (positionLower.indexOf('hdp') !== -1) {\r\n                return 'Haut de page';\r\n            }\r\n            \r\n            if (positionLower.indexOf('cdp') !== -1) {\r\n                return 'Corps de page';\r\n            }\r\n            \r\n            if (positionLower.indexOf('pop-up') !== -1 || positionLower.indexOf('popup') !== -1) {\r\n                return 'Pop-up';\r\n            }\r\n            \r\n            \/\/ Si aucun pattern reconnu, retourner tel quel\r\n            return positionTechnique;\r\n        },\r\n        \r\n        \/**\r\n         * MODIFICATION de creerNouvelItem pour g\u00e9rer la r\u00e9f\u00e9rence et donn\u00e9es iframe\r\n         *\/\r\n        async creerNouvelItem(donnees) {\r\n            console.log('\ud83d\udfe1 [creerNouvelItem] APPEL\u00c9');\r\n            console.log('\ud83c\udd95 Cr\u00e9ation nouvel item panier avec donn\u00e9es iframe:', donnees);\r\n            console.log('\ud83d\udd0d creerNouvelItem - Emplacement:', donnees.Commande_Emplacement_Page_Web);\r\n            console.log('\ud83d\udd0d creerNouvelItem - Items actuels:', this.state.items.map(i => ({id: i.id, statut: i.statut, emplacement: i.emplacementPageWeb})));\r\n            \r\n            \/\/ \u2705 v4.9ds : forceNew=true \u2192 bypass complet d\u00e9dup\/anti-doublon\/R1a, cr\u00e9ation\r\n            \/\/   directe d'une nouvelle r\u00e9servation. Utilis\u00e9 par yearbook-media.js:1884\r\n            \/\/   listener viaAddNouvelItem pour annonce d\u00e9pos\u00e9e dans un autre espace pub\r\n            \/\/   alors que le popup d'achat est d\u00e9j\u00e0 ouvert. Sans ce flag, la r\u00e9sa active\r\n            \/\/   est r\u00e9utilis\u00e9e \u00e0 tort (Pb 9.61 R1a). Demande user.\r\n            const _forceNewCNI = (donnees && donnees.forceNew === true);\r\n            if (_forceNewCNI) {\r\n                console.log('\ud83c\udd95 [creerNouvelItem] forceNew=true \u2192 bypass d\u00e9dup\/R1a, cr\u00e9ation nouvelle r\u00e9sa directe | rank:', donnees.Rank_Emplacement_Page_Web, '| empl:', donnees.Commande_Emplacement_Page_Web);\r\n            }\r\n            \r\n            \/\/ \u2705 v1.7 : Masquer le message \"aucune commande\" si pr\u00e9sent\r\n            $('#MsgAucuneCommande').hide();\r\n            \/\/ \u2705 v2.4.5 : Annuler le timer d'inactivit\u00e9 si une commande est cr\u00e9\u00e9e\r\n            if (window._viaNoCommandeTimer) {\r\n                clearTimeout(window._viaNoCommandeTimer);\r\n                window._viaNoCommandeTimer = null;\r\n            }\r\n            if (window._viaNoCommandeReset) {\r\n                document.removeEventListener('click',     window._viaNoCommandeReset);\r\n                document.removeEventListener('keydown',   window._viaNoCommandeReset);\r\n                document.removeEventListener('scroll',    window._viaNoCommandeReset);\r\n                document.removeEventListener('mousemove', window._viaNoCommandeReset);\r\n                window._viaNoCommandeReset = null;\r\n            }\r\n            \r\n            \/\/ \u2705 NOUVEAU : V\u00e9rifier si modification autoris\u00e9e (bon de commande cr\u00e9\u00e9 ?)\r\n            if (!this.gererModificationCommande('campagne')) {\r\n                console.log('\ud83d\udd12 Cr\u00e9ation annul\u00e9e - bon de commande d\u00e9j\u00e0 cr\u00e9\u00e9');\r\n                return null;\r\n            }\r\n            \r\n            \/\/ \u2705 ANTI-REBOND + ANTI-DOUBLON : \u00c9viter les appels multiples et les doublons\r\n            const emplacementActuel = donnees.Commande_Emplacement_Page_Web;\r\n            \/\/ pb116 : l'anti-rebond (timing) doit s'appliquer M\u00caME en forceNew. Sur mobile, un\r\n            \/\/   tap d\u00e9clenche une rafale (touchend\/click\/change) ; apr\u00e8s SUPPRESSION de la r\u00e9sa,\r\n            \/\/   le d\u00e9p\u00f4t passe par forceNew (plus de r\u00e9sa active \u00e0 r\u00e9utiliser) qui bypassait\r\n            \/\/   l'anti-rebond \u2192 3 r\u00e9sa du M\u00caME emplacement. On sort le timing du gate forceNew.\r\n            \/\/   L'anti-DOUBLON (r\u00e9utiliser un item existant) reste hors forceNew (forceNew cr\u00e9e\r\n            \/\/   d\u00e9lib\u00e9r\u00e9ment une nouvelle r\u00e9sa hors rafale). pb111 intact (item r\u00e9gie empl=null).\r\n            if (emplacementActuel) {\r\n                \/\/ 1. Anti-rebond (timing) \u2014 appliqu\u00e9 Y COMPRIS en forceNew (pb116)\r\n                const maintenant = Date.now();\r\n                if (!this.state.derniersTraitements) {\r\n                    this.state.derniersTraitements = {};\r\n                }\r\n                const dernierTraitement = this.state.derniersTraitements[emplacementActuel];\r\n                \r\n                if (dernierTraitement && (maintenant - dernierTraitement) < 2000) {\r\n                    console.log('\u26a0\ufe0f ANTI-REBOND (pb116, incl. forceNew) - emplacement trait\u00e9 il y a < 2s:', emplacementActuel, '| forceNew:', _forceNewCNI);\r\n                    return null;\r\n                }\r\n                \r\n                \/\/ Enregistrer le timestamp\r\n                this.state.derniersTraitements[emplacementActuel] = maintenant;\r\n                \r\n                \/\/ 2. Anti-doublon (r\u00e9utiliser l'existant) \u2014 UNIQUEMENT hors forceNew\r\n                if (!_forceNewCNI) {\r\n                    const commandeExistantePourEmplacement = this.state.items.find(i => \r\n                        i.emplacementPageWeb === emplacementActuel\r\n                    );\r\n                    \r\n                    if (commandeExistantePourEmplacement) {\r\n                        console.log('\u26a0\ufe0f [creerNouvelItem] DOUBLON \u00c9VIT\u00c9 - return anticip\u00e9, emplacement:', emplacementActuel, '| item:', commandeExistantePourEmplacement.id);\r\n                        this.setItemActif(commandeExistantePourEmplacement.id);\r\n                        return commandeExistantePourEmplacement;\r\n                    }\r\n                }\r\n            }\r\n\r\n            \/\/ v4.9ds : anti-doublon par rank+URL quand emplacement non pass\u00e9.\r\n            \/\/   Cas Ele0A en mode popup site pays : yearbook-media.js:1290 ne passe pas\r\n            \/\/   Commande_Emplacement_Page_Web (commentaire v2.7 : \"evite que remplirItemComplet\r\n            \/\/   affiche 'reserve' avant clic Reserver\"). Du coup l'anti-doublon ci-dessus\r\n            \/\/   est bypass\u00e9 \u2192 un NOUVEL item est cr\u00e9\u00e9 m\u00eame quand un item d'une session\r\n            \/\/   pr\u00e9c\u00e9dente a \u00e9t\u00e9 restaur\u00e9 via OptionA postMessage (yearbook-media.js:11476)\r\n            \/\/   pour le m\u00eame rank\/URL \u2192 DOUBLON dans le panier.\r\n            \/\/   Fix : matcher sur (donneesIframe.Rank_Emplacement_Page_Web + LoadedPageUrl)\r\n            \/\/   quand emplacementActuel est vide.\r\n            if (!emplacementActuel && donnees.Rank_Emplacement_Page_Web && !_forceNewCNI) {\r\n                const _rankADup = donnees.Rank_Emplacement_Page_Web;\r\n                const _urlADup = donnees.LoadedPageUrl || '';\r\n                const _normUrlADup = (u) => (u || '').split('?')[0].split('#')[0].replace(\/\\\/+$\/, '').toLowerCase();\r\n                const _urlNormADup = _normUrlADup(_urlADup);\r\n                const commandeRankUrl = this.state.items.find(i => {\r\n                    const _itRank = i.donneesIframe ? i.donneesIframe.Rank_Emplacement_Page_Web : null;\r\n                    if (_itRank !== _rankADup) return false;\r\n                    const _itUrl = (i.donneesIframe ? i.donneesIframe.LoadedPageUrl : null) || i.linkSecteurPage || '';\r\n                    return _normUrlADup(_itUrl) === _urlNormADup;\r\n                });\r\n                if (commandeRankUrl) {\r\n                    console.log('\u26a0\ufe0f [creerNouvelItem] DOUBLON \u00c9VIT\u00c9 par rank+URL \u2014 rank:', _rankADup, '| url:', _urlNormADup, '| item existant:', commandeRankUrl.id, '| statut:', commandeRankUrl.statut);\r\n                    this.setItemActif(commandeRankUrl.id);\r\n                    return commandeRankUrl;\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 R\u00c9INITIALISER le formulaire IMM\u00c9DIATEMENT pour \u00e9viter h\u00e9ritage\r\n            this.reinitialiserFormulaire();\r\n            \r\n            console.log('\ud83d\udd0d LOG 5 - creerNouvelItem D\u00c9BUT - donn\u00e9es re\u00e7ues:', {\r\n                EspPubLienAnnonce: donnees.EspPubLienAnnonce,\r\n                lienEspacePub: donnees.lienEspacePub\r\n            });\r\n            \r\n            \/\/ \u2705 R\u00c9INITIALISER le dernier r\u00e9sultat de calcul pour le nouvel item\r\n            if (window.VIA_App && window.VIA_App.state) {\r\n                window.VIA_App.state.dernierResultatCalcul = null;\r\n                console.log('\ud83d\udd04 Dernier r\u00e9sultat de calcul r\u00e9initialis\u00e9');\r\n            }\r\n            \r\n            \/\/ \u2705 R\u00c9INITIALISER l'affichage du tarif\r\n            $('#Tariftobedisplayed').html('-');\r\n\r\n            \/\/ \u2705 V\u00c9RIFIER si une commande partielle existe pour CETTE page\r\n            const linkSecteurPage = donnees.LoadedPageUrl || sessionStorage.getItem('LinkSecteurPage');\r\n            console.log('\ud83d\udd0d [creerNouvelItem] linkSecteurPage r\u00e9solu:', linkSecteurPage);\r\n            console.log('\ud83d\udd0d [creerNouvelItem] Items actuels:', this.state.items.map(i => ({\r\n                id: i.id, statut: i.statut,\r\n                linkSecteurPage: i.linkSecteurPage,\r\n                emplacementPageWeb: i.emplacementPageWeb\r\n            })));\r\n            \/\/ \u2705 Ne pas r\u00e9utiliser un item qui a d\u00e9j\u00e0 une annonce sur un rank diff\u00e9rent\r\n            \/\/ \u2705 v4.9ds : si forceNew=true, bypass complet du filter (cr\u00e9ation nouvelle r\u00e9sa)\r\n            const _rankCourantCNI = donnees.Rank_Emplacement_Page_Web || '';\r\n            const _normUrlCNI = (u) => (u || '').split('?')[0].split('#')[0].replace(\/\\\/+$\/, '').toLowerCase();\r\n            const _linkNormCNI = _normUrlCNI(linkSecteurPage);\r\n            const commandePartielle = _forceNewCNI ? null : this.state.items.find(i => {\r\n                if (i.statut !== 'partielle') return false;\r\n                \/\/ \u2705 Si l'item a donneesIframe.LoadedPageUrl (fiable), l'utiliser pour comparer l'URL\r\n                \/\/ Sinon fallback sur linkSecteurPage (qui peut \u00eatre stale)\r\n                const _itUrlCNI = (i.donneesIframe && i.donneesIframe.LoadedPageUrl)\r\n                    ? i.donneesIframe.LoadedPageUrl\r\n                    : i.linkSecteurPage;\r\n                if (_normUrlCNI(_itUrlCNI) !== _linkNormCNI) return false;\r\n                \/\/ \u2705 Si l'item a un rank ET une URL fiable (donneesIframe.LoadedPageUrl), v\u00e9rifier la coh\u00e9rence\r\n                if (i.donneesIframe && i.donneesIframe.Rank_Emplacement_Page_Web && i.donneesIframe.LoadedPageUrl) {\r\n                    if (_normUrlCNI(i.donneesIframe.LoadedPageUrl) !== _linkNormCNI) return false;\r\n                }\r\n                \/\/ \u2705 Si l'item a d\u00e9j\u00e0 un espace occup\u00e9 (annonce d\u00e9pos\u00e9e OU envoi diff\u00e9r\u00e9) avec un rank diff\u00e9rent \u2192 ne pas r\u00e9utiliser\r\n                var _itRankCNI = i.donneesIframe && i.donneesIframe.Rank_Emplacement_Page_Web;\r\n                var _itOccupied = i.donneesIframe && (\r\n                    i.donneesIframe.FileReceived === 'Yes'\r\n                    || i.donneesIframe.EnvoiUlterieur === 'true'\r\n                    || i.donneesIframe.EnvoiUlterieur === true\r\n                );\r\n                if (_itOccupied && _itRankCNI && _rankCourantCNI && _itRankCNI !== _rankCourantCNI) {\r\n                    return false;\r\n                }\r\n                \/\/ \u2705 Si l'item a d\u00e9j\u00e0 un emplacementPageWeb pour un rank diff\u00e9rent \u2192 cr\u00e9er un nouvel item\r\n                var _itEmplacement = i.emplacementPageWeb || (i.donneesIframe && i.donneesIframe.Commande_Emplacement_Page_Web);\r\n                var _newEmplacement = donnees.Commande_Emplacement_Page_Web || '';\r\n                if (_itEmplacement && _newEmplacement && _itEmplacement !== _newEmplacement) {\r\n                    console.log('[creerNouvelItem] item', i.id, 'emplacement', _itEmplacement, '!= nouveau', _newEmplacement, '\u2192 skip');\r\n                    return false;\r\n                }\r\n                return true;\r\n            });\r\n            console.log('\ud83d\udd0d [creerNouvelItem] commandePartielle trouv\u00e9e?', commandePartielle ? commandePartielle.id : 'NON');\r\n            \r\n            \/\/ \u2705 v4.9ds : garde finale forceNew \u2014 m\u00eame si R1a (logique non visible dans cette\r\n            \/\/   version upload\u00e9e) a trouv\u00e9 une commandePartielle, on l'ignore pour forcer\r\n            \/\/   cr\u00e9ation nouvelle r\u00e9sa. Robuste contre les variantes de Panier_manager d\u00e9ploy\u00e9.\r\n            if (_forceNewCNI && commandePartielle) {\r\n                console.log('\ud83c\udd95 [creerNouvelItem] forceNew=true \u2192 ignorer commandePartielle trouv\u00e9e:', commandePartielle.id, '\u2014 cr\u00e9ation nouvelle r\u00e9sa');\r\n            }\r\n            \r\n            if (commandePartielle && !_forceNewCNI) {\r\n                console.log('\ud83d\udd0d LOG 6 - Appel completerCommandePartielle avec:', {\r\n                    EspPubLienAnnonce: donnees.EspPubLienAnnonce,\r\n                    lienEspacePub: donnees.lienEspacePub\r\n                });\r\n                \r\n                const result = await this.completerCommandePartielle(commandePartielle, donnees);\r\n                \r\n                console.log('\ud83d\udd0d LOG 7 - Retour completerCommandePartielle:', {\r\n                    reference: result?.reference,\r\n                    lien: result?.lienEspacePub\r\n                });\r\n                \r\n                return result;\r\n            }\r\n            \r\n            const $template = $('#CampagneTemplate');\r\n            \r\n            if ($template.length === 0) {\r\n                console.error('\u274c Template introuvable');\r\n                return null;\r\n            }\r\n            \r\n            \/\/ \u2705 G\u00e9n\u00e9rer la r\u00e9f\u00e9rence AVANT de cr\u00e9er l'item\r\n            const reference = await this.construireReferenceCommande(donnees);\r\n            \r\n            $template.find('#Etape1Container').remove();\r\n            \r\n            const $newItem = $template.clone();\r\n            const itemId = `CampagneTemplate_${Date.now()}`;\r\n            \r\n            $template.css('display', 'none');\r\n            $template.hide();\r\n            \r\n            $newItem.removeAttr('data-is-template');\r\n            $newItem.attr('id', itemId);\r\n            $newItem.attr('data-reference', reference);\r\n            \r\n            \/\/ \u2705 Nettoyer TOUTES les donn\u00e9es h\u00e9rit\u00e9es du template\r\n            $newItem.find('.CampagneTarifClass').html('').hide();\r\n            $newItem.find('.CampagnePaysSocieteClass').html('');\r\n            $newItem.find('.CampagneDatesClass').html('');\r\n            $newItem.find('.CampagneNbJours').html('');\r\n            \r\n            $newItem.css('display', 'block');\r\n            $newItem.show();\r\n            \/\/ \u2705 v2.4.3 : Reset bordure du clone (h\u00e9rit\u00e9e du template)\r\n            $newItem[0].style.removeProperty('border');\r\n            \r\n            \/\/ \u2705 CAPTURER les donn\u00e9es de page AU MOMENT DE LA CR\u00c9ATION\r\n            let selectedPageType = sessionStorage.getItem('SelectedPageType'); \/\/ pb255 : let -> reassignable\r\n            let selectedPageSecteur = sessionStorage.getItem('SelectedPageSecteur');\r\n            let selectedPageSecteurDisplayed = sessionStorage.getItem('SelectedPageSecteurDisplayed');\r\n            \r\n            \/\/ \u2705 R\u00e9cup\u00e9rer le type de page\r\n            let commandePage = sessionStorage.getItem('Commande_Page') || 'Homepage';\r\n            \r\n            \/\/ pb76 : si la page VLP a envoy\u00e9 son contexte r\u00e9el (LoadedPageSecteur\/Type),\r\n            \/\/   \u00e9craser les valeurs sessionStorage (contexte r\u00e9gie stale \"Homepage\").\r\n            \/\/   Ex: banque\/?vlp=1 \u2192 LoadedPageSecteur=\"Banque\", LoadedPageType=\"HPType\"\r\n            \/\/       \u2192 commandePage=\"Homepage\", selectedPageSecteurDisplayed=\"Banque\"\r\n            if (donnees.LoadedPageSecteur) {\r\n                selectedPageSecteurDisplayed = donnees.LoadedPageSecteur;\r\n                selectedPageSecteur = donnees.LoadedPageSecteur;\r\n                if (donnees.LoadedPageType === 'ArtType') {\r\n                    commandePage = 'Article';\r\n                } else if (donnees.LoadedPageType === 'PTType') {\r\n                    commandePage = 'Page sectorielle';\r\n                } else {\r\n                    commandePage = 'Homepage';\r\n                }\r\n                console.log('[pb76] Contexte page VLP utilis\u00e9 | secteur:', donnees.LoadedPageSecteur, '| type:', donnees.LoadedPageType, '\u2192 commandePage:', commandePage);\r\n            }\r\n            \r\n            \/\/ pb255 : si LoadedPageSecteur absent (ex: forceNew depuis r\u00e9gie) mais\r\n            \/\/   LoadedPageUrl fourni, d\u00e9river commandePage\/selectedPageType\/Secteur depuis l'URL.\r\n            \/\/   R\u00e8gle : \/ ou \/en\/ ou \/fr\/ = Homepage (secteur vide) ;\r\n            \/\/           slug unique = Page sectorielle ; slug multiple = Article.\r\n            \/\/   Evite de lire un sessionStorage pollu\u00e9 par la r\u00e9sa pr\u00e9c\u00e9dente.\r\n            if (!donnees.LoadedPageSecteur && donnees.LoadedPageUrl) {\r\n                var _lu255 = donnees.LoadedPageUrl || '';\r\n                try {\r\n                    var _u255 = new URL(_lu255);\r\n                    var _path255 = _u255.pathname.replace(\/\\\/+$\/, '');\r\n                    var _segs255 = _path255.split('\/').filter(function(s) { return s.length > 0; });\r\n                    if (_segs255.length === 0) {\r\n                        commandePage = 'Homepage'; selectedPageType = 'HPType';\r\n                        selectedPageSecteur = ''; selectedPageSecteurDisplayed = '';\r\n                    } else if (_segs255.length === 1) {\r\n                        var _s255 = _segs255[0].toLowerCase();\r\n                        if (_s255 === 'en' || _s255 === 'fr') {\r\n                            commandePage = 'Homepage'; selectedPageType = 'HPType';\r\n                            selectedPageSecteur = ''; selectedPageSecteurDisplayed = '';\r\n                        } else {\r\n                            commandePage = 'Page sectorielle'; selectedPageType = 'PTType';\r\n                        }\r\n                    } else {\r\n                        commandePage = 'Article'; selectedPageType = 'ArtType';\r\n                    }\r\n                    console.log('[pb255] derive depuis URL:', _lu255, '->', commandePage, '\/', selectedPageType, '\/ secteur:', selectedPageSecteur || '(vide)');\r\n                } catch (_e255) {}\r\n            }\r\n\r\n            \/\/ pb111 : deux r\u00e9servations sur la M\u00caME page doivent afficher la m\u00eame\r\n            \/\/   d\u00e9nomination. Cas : page secteur \u00e0 article unique \u2192 l'URL secteur redirige\r\n            \/\/   vers l'article (pb84). L'item r\u00e9gie capture le contexte secteur (\"Assurances\",\r\n            \/\/   Page sectorielle) ; l'item VLP capture le contexte article (\"Art. La r\u00e9forme\u2026\",\r\n            \/\/   Article). M\u00eame page physique, d\u00e9nominations divergentes. \u2192 Si un item existe\r\n            \/\/   d\u00e9j\u00e0 pour la m\u00eame page (URL normalis\u00e9e, ?vlp=1 \/ slash final ignor\u00e9s), le\r\n            \/\/   nouvel item h\u00e9rite de SA d\u00e9nomination (1er item = r\u00e9f\u00e9rence).\r\n            \/\/   Revert : supprimer ce bloc.\r\n            (function() {\r\n                var _normPg111 = function(u) { return (u || '').split('?')[0].split('#')[0].replace(\/\\\/+$\/, '').toLowerCase(); };\r\n                var _newUrl111 = _normPg111(donnees.LoadedPageUrl || donnees.linkSecteurPage || '');\r\n                if (!_newUrl111) { return; }\r\n                var _items111 = this.state.items || [];\r\n                for (var _i111 = 0; _i111 < _items111.length; _i111++) {\r\n                    var _ex111 = _items111[_i111];\r\n                    if (_normPg111(_ex111.linkSecteurPage) !== _newUrl111) { continue; }\r\n                    if (!_ex111.selectedPageSecteurDisplayed) { continue; }\r\n                    selectedPageSecteurDisplayed = _ex111.selectedPageSecteurDisplayed;\r\n                    if (_ex111.selectedPageSecteur) { selectedPageSecteur = _ex111.selectedPageSecteur; }\r\n                    if (_ex111.commandePage) { commandePage = _ex111.commandePage; }\r\n                    console.log('[pb111] d\u00e9nomination h\u00e9rit\u00e9e d\\'un item existant sur la m\u00eame page \u2192 secteur:', selectedPageSecteurDisplayed, '| commandePage:', commandePage);\r\n                    break;\r\n                }\r\n            }).call(this);\r\n            \r\n            \/\/ \u2705 Calculer la position dynamiquement (valeur TECHNIQUE pour calculs)\r\n            const position = this.calculerPosition(\r\n                donnees.Rank_Emplacement_Page_Web,\r\n                commandePage\r\n            );\r\n            \r\n            console.log('\ud83d\udccb Donn\u00e9es page captur\u00e9es:', {\r\n                selectedPageType,\r\n                commandePage,\r\n                position,\r\n                selectedPageSecteur,\r\n                selectedPageSecteurDisplayed\r\n            });\r\n            \r\n            \/\/ \u2705 Cr\u00e9er l'objet item avec commandePage et position calcul\u00e9e\r\n            \/\/ pb669 : pays annonceur deja saisi sur une resa existante (commun a toutes).\r\n            var _paysAnn669 = this._paysAnnonceurCommun669();\r\n            if (_paysAnn669) { console.log('[pb669] pays annonceur herite (creerNouvelItem) : ' + _paysAnn669); }\r\n            const item = {\r\n                id: itemId,\r\n                reference: reference,\r\n                espacepubId: donnees.espacepubId || donnees.espacepub_id,\r\n                format: normaliseFormatAccents(donnees.format || donnees.Commande_Format_Transmis),\r\n                position: position,\r\n                emplacementPageWeb: donnees.emplacementPageWeb || donnees.Commande_Emplacement_Page_Web,\r\n                \r\n                selectedPageType: selectedPageType,\r\n                commandePage: commandePage,\r\n                selectedPageSecteur: selectedPageSecteur,\r\n                selectedPageSecteurDisplayed: selectedPageSecteurDisplayed,\r\n                \/\/ \u2705 linkSecteurPage indispensable pour commandeSansEspace filter dans Formulaire\r\n                linkSecteurPage: donnees.LoadedPageUrl || donnees.linkSecteurPage || null,\r\n                \r\n                lienEspacePub: donnees.lienEspacePub || donnees.EspPubLienAnnonce || null,\r\n                \r\n                \/\/ v4.9ds : cheminFichierAnnonce pos\u00e9 sur l'item (lu en priorit\u00e9 par\r\n                \/\/   Validations.txt:487 \u2192 creer_commande POST). Sans \u00e7a, fallback sur\r\n                \/\/   donneesIframe.FullPathAdFile qui peut \u00eatre vide en cas de bug de\r\n                \/\/   propagation (ex: clic R\u00e9server Ele1A apr\u00e8s Ele0A \u2192 StateManager\r\n                \/\/   global pas synchro). Triple fallback : donnees.cheminFichierAnnonce\r\n                \/\/   (pass\u00e9 par Formulaire.txt:2578) \u2192 donnees.FullPathAdFile (StateManager)\r\n                \/\/   \u2192 null.\r\n                cheminFichierAnnonce: donnees.cheminFichierAnnonce || donnees.FullPathAdFile || null,\r\n                \r\n                donneesIframe: {\r\n                    AddNewRefInVosCampagnes: donnees.AddNewRefInVosCampagnes,\r\n                    Commande_Emplacement_Page_Web: donnees.Commande_Emplacement_Page_Web,\r\n                    Commande_Format_Transmis: donnees.Commande_Format_Transmis,\r\n                    EnvoiUlterieur: donnees.EnvoiUlterieur,\r\n                    FileReceived: donnees.FileReceived,\r\n                    codePage: donnees.codePage,\r\n                    LoadedPageUrl: donnees.LoadedPageUrl,\r\n                    Rank_Emplacement_Page_Web: donnees.Rank_Emplacement_Page_Web,\r\n                    FullPathAdFile: donnees.FullPathAdFile || null,\r\n                    EspPubLienAnnonce: donnees.EspPubLienAnnonce || null\r\n                },\r\n                \r\n                \/\/ \u2705 v4.9ds Pb 7 : item.pays correspond s\u00e9mantiquement au pays de l'ANNONCEUR\r\n                \/\/   (champ form_fields[Nationalite_Societe], mapp\u00e9 NationaliteDataVosCampagnes\r\n                \/\/   dans sessionStorage). \u00c0 la cr\u00e9ation de l'item, ce pays est INCONNU \u2014\r\n                \/\/   c'est l'utilisateur qui le saisira plus tard, propag\u00e9 \u00e0 tous les items\r\n                \/\/   via mettreAJourPaysGlobal().\r\n                \/\/   Avant : on initialisait item.pays avec le pays de la PAGE WEB extrait\r\n                \/\/   de l'URL iframe (ex: \"Congo\" pour congo.yearbook-media.com). Faux \u2014\r\n                \/\/   le pays annonceur peut \u00eatre France, Allemagne, etc., sans rapport\r\n                \/\/   avec la page s\u00e9lectionn\u00e9e. Le bug ne se voyait pas avant car\r\n                \/\/   remplirFormulaireDepuisItem vidait toujours le champ ; mais maintenant\r\n                \/\/   qu'on pr\u00e9-remplit depuis item.pays (Pb 7), il faut item.pays correct.\r\n                \/\/   \u2192 Initialisation \u00e0 null. mettreAJourPaysGlobal mettra la bonne valeur\r\n                \/\/   quand l'user saisira son pays annonceur.\r\n                \/\/ pb669 : le pays de l'ANNONCEUR est commun a toutes les resas -> une\r\n                \/\/   nouvelle resa herite de celui deja saisi. Avant : null, en comptant\r\n                \/\/   sur mettreAJourPaysGlobal, qui ne se declenche qu'a une SAISIE de\r\n                \/\/   l'utilisateur : la resa 2 restait donc sans pays (et sans tarif).\r\n                pays: _paysAnn669,\r\n                paysAnnonceur: _paysAnn669,\r\n                dateDebut: null,\r\n                dateFin: null,\r\n                duree: null,\r\n                tarifHT: null,\r\n                tarifTTC: null,\r\n                devise: 'EUR',\r\n                \/\/ \u2705 'en_cours' si espace r\u00e9serv\u00e9 (Commande_Emplacement_Page_Web fourni), 'partielle' sinon (pendingAd \/ envoi diff\u00e9r\u00e9 avant r\u00e9servation)\r\n                statut: donnees.Commande_Emplacement_Page_Web ? 'en_cours' : 'partielle',\r\n                \/\/ v4.9ds (estReserveEffective) : flag explicite \u00e0 la cr\u00e9ation.\r\n                \/\/   Pour Ele1A+ (handleEspacePubData via dataFromIframeEspacePub) : reste\r\n                \/\/   false ici, mis \u00e0 true plus tard par yearbook-media.js:11624 \/ fallback\r\n                \/\/   11672 \/ Formulaire.txt:2230 lors du clic R\u00e9server effectif.\r\n                \/\/   Pour Ele0A en mode popup (clic R\u00e9server ouvre popup ProcessAchat\r\n                \/\/   directement \u2192 handleEspacePubData n'est jamais appel\u00e9e pour ce flow) :\r\n                \/\/   pos\u00e9 \u00e0 true ici si donnees._fromReserver===true (propag\u00e9 via\r\n                \/\/   popupLateParams Entete.txt:2960 \/ hash fromReserver=Yes Entete.txt:2861).\r\n                \/\/   Initialisation explicite garantit que le flag ne reste pas undefined\r\n                \/\/   ni h\u00e9rit\u00e9 d'un item restaur\u00e9.\r\n                estReserveEffective: donnees._fromReserver === true\r\n            };\r\n            \r\n            \/\/ pb1515 : POINT UNIQUE. Tous les chemins de creation passent ici \u2014 l'ouverture\r\n            \/\/   du popup (yearbook-media.js popupLateParams, l'espace reserve ET les\r\n            \/\/   otherDeposedAds) comme la creation du process classique (Formulaire.txt\r\n            \/\/   \"CAS 3\"). Un seul test evite d'aller neutraliser chaque appelant, et\r\n            \/\/   garantit qu'aucun nouveau chemin n'echappera a la regle.\r\n            \/\/   Le statut du literal ci-dessus ('en_cours'\/'partielle') n'est conserve que\r\n            \/\/   si les cinq donnees sont deja reunies \u2014 ce qui est le cas du process\r\n            \/\/   classique arrive au bout de ses etapes.\r\n            if (window._viaPb1515Off !== true) {\r\n                var _c1515 = this._cinqDonnees1515(item);\r\n                if (!_c1515.ok) {\r\n                    item.statut = 'attente';\r\n                    console.log('[pb1515] espace EN ATTENTE | ' + (item.emplacementPageWeb || item.reference)\r\n                        + ' | manque : ' + _c1515.manquantes.join(', '));\r\n                }\r\n            }\r\n\r\n            this.state.items.push(item);\r\n            \/\/ v4.9ds : DIAG temporaire pour tracer le flag estReserveEffective\r\n\r\n            console.log('\ud83d\udd17 Item cr\u00e9\u00e9 avec lien:', item.lienEspacePub);\r\n            \r\n            \/\/ \u2705 Remplir l'item avec TOUTES les donn\u00e9es (r\u00e9f\u00e9rence + iframe)\r\n            await this.remplirItemComplet($newItem, item, item.donneesIframe);\r\n            \r\n            \/\/ \u2705 .first() : \u00e9vite les doublons DOM si plusieurs VosCampagnesConteneurClass\r\n            const $conteneur = $(this.config.conteneurParent).first();\r\n            if ($conteneur.length === 0) {\r\n                console.error('\u274c Conteneur parent introuvable');\r\n                return null;\r\n            }\r\n            \r\n            \/\/ pb1516 : PAS DE CARTE pour un espace en attente. Tant que les cinq donnees\r\n            \/\/   ne sont pas reunies, rien ne s'affiche dans \u00ab Vos reservations \u00bb : l'objet\r\n            \/\/   existe, il est actif, il recoit les saisies \u2014 mais il n'est pas encore une\r\n            \/\/   reservation et ne doit pas se presenter comme telle.\r\n            \/\/   $newItem reste construit (remplirItemComplet a tourne) : la promotion\r\n            \/\/   pb1517 n'a plus qu'a l'inserer, sans le reconstruire.\r\n            \/\/   Le recap et le total n'ont besoin d'aucune exclusion : ils filtrent deja\r\n            \/\/   sur tarifHT, qu'un item en attente n'a pas.\r\n            \/\/   Revert : window._viaPb1516Off = true.\r\n            var _cache1516 = (window._viaPb1516Off === true) ? false : (item.statut === 'attente');\r\n            if (_cache1516) {\r\n                item._vueEnAttente1516 = $newItem;\r\n                console.log('[pb1516] carte NON rendue (espace en attente) | ' + (item.emplacementPageWeb || item.reference));\r\n            } else {\r\n                $conteneur.append($newItem);\r\n            }\r\n            \r\n            this.setItemActif(itemId);\r\n            this.reinitialiserFormulaire();\r\n            this.afficherEtape1DansItem(itemId);\r\n            \r\n            \/\/ \u2705 v1.8 : Afficher #ProcessCommande apr\u00e8s s\u00e9lection espace publicitaire\r\n            $('#ProcessCommande').show();\r\n            console.log('\ud83d\udcc2 #ProcessCommande affich\u00e9 (espace pub s\u00e9lectionn\u00e9)');\r\n            \r\n            \/\/ \u2705 v1.10 : Fermer PageWeb SEULEMENT si annonce d\u00e9pos\u00e9e OU envoi diff\u00e9r\u00e9\r\n            \/\/ \u2705 sujet 8 : Envoi diff\u00e9r\u00e9 seul ne doit PAS fermer la PageWeb \u2014 seul un d\u00e9p\u00f4t d'annonce\r\n            \/\/             ou un clic R\u00e9server (qui pose FileReceived=Yes) la ferme.\r\n            \/\/             Sans \u00e7a, s\u00e9lectionner Envoi diff\u00e9r\u00e9 sur un 2e espace referme l'\u00e9tape.\r\n            const hasAnnonceDeposee = item.donneesIframe?.FileReceived === 'Yes';\r\n            const hasEnvoiDiffere = item.donneesIframe?.EnvoiUlterieur === 'true' || item.donneesIframe?.EnvoiUlterieur === true || item.donneesIframe?.EnvoiUlterieur === 'Yes';\r\n            if (hasAnnonceDeposee) {\r\n                this.fermerPageWeb(true);\r\n            } else if (hasEnvoiDiffere) {\r\n                console.log('\u2139\ufe0f [sujet 8] Envoi diff\u00e9r\u00e9 seul \u2014 PageWeb reste ouvert (pas de fermeture auto)');\r\n            } else {\r\n                console.log('\u2139\ufe0f PageWeb reste ouvert (format s\u00e9lectionn\u00e9 uniquement)');\r\n            }\r\n            \r\n            \/\/ \u2705 Garder le r\u00e9capitulatif ouvert si en mode 3 colonnes OU si d\u00e9j\u00e0 ouvert (2e espace)\r\n            if (sessionStorage.getItem('PageWebColonneOpenclose') !== 'Open' && !this.state.recapOuvert) {\r\n                this.fermerRecapitulatif(false);\r\n            }\r\n            \r\n            console.log('\u2705 Item cr\u00e9\u00e9 avec r\u00e9f\u00e9rence:', reference);\r\n            \r\n            return item;\r\n        },\r\n        \r\n        \/**\r\n         * Compl\u00e8te une commande partielle avec les donn\u00e9es iframe\r\n         *\/\r\n        async completerCommandePartielle(commandePartielle, donnees) {\r\n            console.log('\ud83d\udd04 Compl\u00e9tion commande partielle avec donn\u00e9es iframe');\r\n            \r\n            \/\/ pb1527 : INSERER LA CARTE AVANT DE LA CHERCHER. pb1526e la posait bien, mais\r\n            \/\/   trente lignes trop bas : $item etait resolu ICI, alors que la carte etait\r\n            \/\/   encore dans _vueEnAttente1516. $item restait donc un ensemble VIDE pour tout\r\n            \/\/   le reste de la fonction \u2014 et jQuery ne bronche pas sur un ensemble vide.\r\n            \/\/   Deux consequences en chaine :\r\n            \/\/     - $item.attr('data-reference', referenceComplete) sans effet : la carte\r\n            \/\/       gardait la reference PARTIELLE ;\r\n            \/\/     - remplirItemComplet remplissait le vide.\r\n            \/\/   Puis updateRecapitulatif cherche l'item par data-reference, ne trouve rien\r\n            \/\/   avec la reference partielle, et MASQUE la carte. D'ou le constat : le log\r\n            \/\/   annonce \"[pb1526] carte inseree\" et l'ecran ne montre rien.\r\n            \/\/   Revert : window._viaPb1527Off = true.\r\n            if (window._viaPb1527Off !== true) {\r\n                this._insererCarteEnAttente1526(commandePartielle);\r\n            }\r\n            const $item = $(`#${commandePartielle.id}`);\r\n            \r\n            \/\/ \u2705 Reconstruire r\u00e9f\u00e9rence COMPL\u00c8TE avec le vrai codePage\r\n            const emplacementWeb = donnees.Commande_Emplacement_Page_Web || '';\r\n            const codePage = donnees.codePage || '';\r\n            \r\n            const indexCodePage = emplacementWeb.indexOf(codePage);\r\n            const suffixeEspace = indexCodePage >= 0 ? \r\n                emplacementWeb.substring(indexCodePage + codePage.length) : '';\r\n            \r\n            \/\/ Extraire le code unique existant (ORZ)\r\n            const partiesRef = commandePartielle.reference.split('-');\r\n            const codeUnique = partiesRef[0];\r\n            const codeSite = partiesRef[1];\r\n            \r\n            \/\/ \u2705 NOUVELLE r\u00e9f\u00e9rence avec le VRAI codePage\r\n            const referenceComplete = `${codeUnique}-${codeSite}-${codePage}-${suffixeEspace}`;\r\n            \r\n            \/\/ \u2705 Recalculer la position avec le type de page stock\u00e9 (valeur TECHNIQUE)\r\n            const nouvellePosition = this.calculerPosition(\r\n                donnees.Rank_Emplacement_Page_Web,\r\n                commandePartielle.commandePage || 'Homepage'\r\n            );\r\n            \r\n            \/\/ \u2705 Mettre \u00e0 jour l'item\r\n            commandePartielle.reference = referenceComplete;\r\n            commandePartielle.espacepubId = donnees.espacepubId || donnees.espacepub_id;\r\n            commandePartielle.emplacementPageWeb = donnees.Commande_Emplacement_Page_Web;\r\n            commandePartielle.position = nouvellePosition;\r\n            commandePartielle.format = normaliseFormatAccents(donnees.Commande_Format_Transmis);\r\n            commandePartielle.lienEspacePub = donnees.lienEspacePub || donnees.EspPubLienAnnonce || null;\r\n            commandePartielle.cheminFichierAnnonce = donnees.cheminFichierAnnonce || donnees.FullPathAdFile || null;\r\n            commandePartielle.statut = 'en_cours';\r\n            \/\/ pb1527b : l'insertion faite ici par pb1526e a ete remontee en tete de\r\n            \/\/   fonction. Elle arrivait apres la resolution de $item, donc trop tard.\r\n            \/\/ \u2705 D\u00e9bloquer #ProcessAchatInside si pr\u00e9c\u00e9demment bloqu\u00e9 (item \u00e9tait partielle)\r\n            $('#ProcessAchatInside').css('pointer-events', '').css('opacity', '');\r\n            $('#MsgBlockDates').hide();\r\n\r\n\r\n            \r\n            \/\/ Donn\u00e9es iframe\r\n            commandePartielle.donneesIframe = {\r\n                AddNewRefInVosCampagnes: donnees.AddNewRefInVosCampagnes,\r\n                Commande_Emplacement_Page_Web: donnees.Commande_Emplacement_Page_Web,\r\n                Commande_Format_Transmis: donnees.Commande_Format_Transmis,\r\n                EnvoiUlterieur: donnees.EnvoiUlterieur,\r\n                FileReceived: donnees.FileReceived,\r\n                codePage: donnees.codePage,\r\n                LoadedPageUrl: donnees.LoadedPageUrl,\r\n                Rank_Emplacement_Page_Web: donnees.Rank_Emplacement_Page_Web,\r\n                FullPathAdFile: donnees.FullPathAdFile || null,\r\n                Upload_File_Name: donnees.Upload_File_Name,\r\n                EspPubLienAnnonce: donnees.EspPubLienAnnonce || null,\r\n                \/\/ \u2705 v2.3.4 : Propager PopUpChoice depuis l'item ou sessionStorage\r\n                PopUpChoice: commandePartielle.popUpChoice || sessionStorage.getItem('PopUpChoice') || 'No',\r\n                \/\/ \u2705 v2.6 : Propager commandePage et secteur pour remplirItemComplet\r\n                \/\/ pb76 : si la page VLP a envoy\u00e9 son contexte r\u00e9el (LoadedPageSecteur\/Type),\r\n                \/\/   l'utiliser \u00e0 la place du sessionStorage de la r\u00e9gie (qui peut \u00eatre stale).\r\n                \/\/   Ex: HPType \"banque\" \u2192 \"Banque\" ; ArtType \u2192 \"Art. Secteur\".\r\n                commandePage: (donnees.LoadedPageSecteur ? (donnees.LoadedPageType === 'HPType' ? 'Homepage' : (donnees.LoadedPageType === 'ArtType' ? 'Article' : 'Page sectorielle')) : null) || commandePartielle.commandePage || sessionStorage.getItem('Commande_Page') || 'Homepage',\r\n                selectedPageSecteurDisplayed: donnees.LoadedPageSecteur || commandePartielle.selectedPageSecteurDisplayed || sessionStorage.getItem('SelectedPageSecteurDisplayed') || sessionStorage.getItem('SelectedPageSecteur') || ''\r\n            };\r\n            \r\n            $item.attr('data-reference', referenceComplete);\r\n            \r\n            \/\/ \u2705 Remplir l'affichage COMPLET\r\n            console.log('\ud83d\udd0d [completerCP] avant remplirItemComplet \u2014 emplacementPageWeb:', commandePartielle.emplacementPageWeb, '| reference:', commandePartielle.reference);\r\n            await this.remplirItemComplet($item, commandePartielle, commandePartielle.donneesIframe);\r\n            console.log('\u2705 [completerCP] remplirItemComplet termin\u00e9 \u2014 CampagneNoClass actuel:', $item.find('.CampagneNoClass').text());\r\n            console.log('\u2705 [completerCP] CampagneInfoEspaceMessage visible?', $item.find('.CampagneInfoEspaceMessage').is(':visible'));\r\n            \r\n            \/\/ \u2705 R\u00c9INITIALISER le dernier r\u00e9sultat de calcul et l'affichage du tarif\r\n            if (window.VIA_App && window.VIA_App.state) {\r\n                window.VIA_App.state.dernierResultatCalcul = null;\r\n            }\r\n            $('#Tariftobedisplayed').html('-');\r\n            \r\n            this.setItemActif(commandePartielle.id);\r\n            this.afficherEtape1DansItem(commandePartielle.id);\r\n            \r\n            \/\/ \u2705 v1.8 : Afficher #ProcessCommande apr\u00e8s s\u00e9lection espace publicitaire\r\n            $('#ProcessCommande').show();\r\n            console.log('\ud83d\udcc2 #ProcessCommande affich\u00e9 (espace pub s\u00e9lectionn\u00e9)');\r\n            \r\n            \/\/ \u2705 v1.10 : Fermer PageWeb SEULEMENT si annonce d\u00e9pos\u00e9e OU envoi diff\u00e9r\u00e9\r\n            \/\/ \u2705 sujet 8 : Envoi diff\u00e9r\u00e9 seul ne doit PAS fermer la PageWeb\r\n            const hasAnnonceDeposee = donnees.FileReceived === 'Yes';\r\n            const hasEnvoiDiffere = donnees.EnvoiUlterieur === 'true' || donnees.EnvoiUlterieur === true || donnees.EnvoiUlterieur === 'Yes';\r\n            if (hasAnnonceDeposee) {\r\n                this.fermerPageWeb(true);\r\n                console.log('\ud83d\udcc1 PageWeb ferm\u00e9 (annonce d\u00e9pos\u00e9e)');\r\n            } else if (hasEnvoiDiffere) {\r\n                console.log('\u2139\ufe0f [sujet 8] Envoi diff\u00e9r\u00e9 seul \u2014 PageWeb reste ouvert');\r\n            } else {\r\n                console.log('\u2139\ufe0f PageWeb reste ouvert (format s\u00e9lectionn\u00e9 uniquement)');\r\n            }\r\n            \r\n            \/\/ \u2705 Garder le r\u00e9capitulatif ouvert si en mode 3 colonnes OU si d\u00e9j\u00e0 ouvert (2e espace)\r\n            if (sessionStorage.getItem('PageWebColonneOpenclose') !== 'Open' && !this.state.recapOuvert) {\r\n                this.fermerRecapitulatif(false);\r\n            }\r\n            \r\n            console.log('\u2705 Commande partielle compl\u00e9t\u00e9e:', referenceComplete);\r\n            \r\n            \/\/ \u2705 Mettre \u00e0 jour message global r\u00e9cap (espace maintenant r\u00e9serv\u00e9 \u2192 masquer)\r\n            if (typeof window.updateRecapInfoMessage === 'function') {\r\n                const _urlComplete = commandePartielle.linkSecteurPage || (commandePartielle.donneesIframe && commandePartielle.donneesIframe.LoadedPageUrl) || '';\r\n                window.updateRecapInfoMessage(_urlComplete);\r\n            }\r\n            \r\n            console.log('\ud83d\udd0d LOG 10 - completerCommandePartielle FIN avant return:', {\r\n                reference: commandePartielle.reference,\r\n                lien: commandePartielle.lienEspacePub\r\n            });\r\n            \r\n            return commandePartielle;\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 D\u00e9termine commandePage de mani\u00e8re fiable\r\n         *\/\r\n        \/\/ pb255 : d\u00e9tection homepage par URL (source de v\u00e9rit\u00e9 immune \u00e0 la pollution des\r\n        \/\/   globales sessionStorage en multi-r\u00e9sa). Homepage = path racine, \/en\/ ou \/fr\/.\r\n        _isHomepageUrl255: function(url) {\r\n            try {\r\n                var _p = new URL(url).pathname.replace(\/\\\/+$\/, '');\r\n                var _s = _p.split('\/').filter(function(x) { return x.length > 0; });\r\n                if (_s.length === 0) { return true; }\r\n                if (_s.length === 1) { var _l = _s[0].toLowerCase(); return _l === 'en' ? true : (_l === 'fr'); }\r\n                return false;\r\n            } catch (_e) { return false; }\r\n        },\r\n        \r\n        determinerCommandePage: function() {\r\n            \/\/ 1. D'abord essayer Commande_Page\r\n            const commandePageSession = sessionStorage.getItem('Commande_Page');\r\n            if (commandePageSession) {\r\n                return commandePageSession;\r\n            }\r\n            \r\n            \/\/ 2. Sinon, d\u00e9duire depuis SelectedPageType\r\n            const selectedPageType = sessionStorage.getItem('SelectedPageType');\r\n            \r\n            if (selectedPageType) {\r\n                switch (selectedPageType) {\r\n                    case 'HPType':\r\n                        return 'Homepage';\r\n                    case 'PTType':\r\n                        return 'Page sectorielle';\r\n                    case 'ArtType':\r\n                        return 'Article';\r\n                    default:\r\n                        return 'Homepage';\r\n                }\r\n            }\r\n            \r\n            return 'Homepage';\r\n        },\r\n        \r\n        \/**\r\n         * Cr\u00e9e une commande partielle (avant s\u00e9lection espace pub)\r\n         *\/\r\n        async creerCommandePartielle(forcedLinkSecteurPage) {\r\n            console.log('\ud83d\udcdd Cr\u00e9ation commande partielle...');\r\n            \r\n            \/\/ \u2705 v1.7 : Masquer le message \"aucune commande\" si pr\u00e9sent\r\n            $('#MsgAucuneCommande').hide();\r\n            \r\n            \/\/ \u2705 v1.7 : M\u00e9moriser la vue (desktop\/mobile) lors de la premi\u00e8re s\u00e9lection de page\r\n            if (this.state.items.length === 0 && !sessionStorage.getItem('ProcessStartedInView')) {\r\n                const LimitMobileOrdi = parseInt(sessionStorage.getItem('LimitMobileOrdi')) || 1015;\r\n                const currentView = window.outerWidth > LimitMobileOrdi ? 'desktop' : 'mobile';\r\n                sessionStorage.setItem('ProcessStartedInView', currentView);\r\n                console.log('\ud83d\udcf1\ud83d\udda5\ufe0f Process d\u00e9marr\u00e9 en mode:', currentView);\r\n            }\r\n            \r\n            \/\/ \u2705 Utiliser l'URL pass\u00e9e en param\u00e8tre pour \u00e9viter les URLs stale (sessionStorage pas encore \u00e0 jour)\r\n            const linkSecteurPage = forcedLinkSecteurPage || sessionStorage.getItem('LinkSecteurPage');\r\n            console.log('\ud83d\udd0d LinkSecteurPage actuel:', linkSecteurPage, '| forced:', !!forcedLinkSecteurPage);\r\n            \r\n            \/\/ V\u00c9RIFIER : Commande partielle pour cette page\r\n            \/\/ \u2705 Ne pas r\u00e9utiliser un item qui a d\u00e9j\u00e0 une annonce sur un rank diff\u00e9rent\r\n            \/\/ creerCommandePartielle n'a pas de param\u00e8tre donnees \u2192 pas de filtre rank ici\r\n            const _rankCourant = '';\r\n            \/\/ \u2705 Normaliser l'URL pour la comparaison (ignorer trailing slash)\r\n            const _normalizeUrlCP = (u) => u ? u.replace(\/\\\/+$\/, '').toLowerCase() : '';\r\n            const _linkNorm = _normalizeUrlCP(linkSecteurPage);\r\n            console.log('\ud83d\udd0d [creerCommandePartielle] Recherche commandePartiellePage pour URL:', linkSecteurPage, '| normalized:', _linkNorm);\r\n            console.log('\ud83d\udd0d [creerCommandePartielle] Items actuels:', this.state.items.map(i => ({id: i.id, statut: i.statut, linkSecteurPage: i.linkSecteurPage, secteur: i.selectedPageSecteurDisplayed})));\r\n            \/\/ \u2705 v4.9ds R0 : R\u00c9GIE \u2014 si une r\u00e9servation active non-anticip\u00e9e existe,\r\n            \/\/   la r\u00e9utiliser pour la mise \u00e0 jour au lieu d'en cr\u00e9er une nouvelle.\r\n            \/\/   R\u00e9gression user : changement pays\/secteur\/format sur une r\u00e9sa active\r\n            \/\/   cr\u00e9ait une 2e r\u00e9servation au lieu de mettre \u00e0 jour l'active.\r\n            \/\/   R\u00e8gle m\u00e9tier : sur le process d'achat, toutes modifications impactent\r\n            \/\/   la r\u00e9sa active ; pas de cr\u00e9ation hors clic #AutreCommandeBouton.\r\n            \/\/   Anticip\u00e9e exclue \u2192 laiss\u00e9e \u00e0 FB4 (upgrade 'anticipee' \u2192 'partielle').\r\n            \/\/   'complete' exclue \u2192 r\u00e9sa finalis\u00e9e, pas modifiable par ce flow.\r\n            let commandePartiellePage = null;\r\n            if (this.state.itemActif) {\r\n                var _actifR0 = this.state.items.find(function(_i) {\r\n                    if (_i.id !== this.state.itemActif) { return false; }\r\n                    if (_i.statut === 'partielle') { return true; }\r\n                    if (_i.statut === 'en_cours')  { return true; }\r\n                    if (_i.statut === 'valide')    { return true; }\r\n                    return false;\r\n                }.bind(this));\r\n                \/\/ pb174 : ne PAS reutiliser l'item actif s'il est deja engage sur une AUTRE page\r\n                \/\/   AVEC un format -> chaque page engagee = une resa distincte. Sinon (meme page,\r\n                \/\/   ou item sans format encore) -> reutilisation normale (mise a jour resa active).\r\n                if (_actifR0) {\r\n                    var _normCP174 = function(u) { return (u || '').split('?')[0].split('#')[0].replace(\/\\\/+$\/, '').toLowerCase(); };\r\n                    var _actifUrl174 = (_actifR0.donneesIframe && _actifR0.donneesIframe.LoadedPageUrl) || _actifR0.linkSecteurPage || '';\r\n                    \/\/ pb775 : \"engage sur une autre page\" ne suffit plus a justifier une\r\n                    \/\/   seconde reservation. Depuis pb743, changer de pays ou de secteur MET\r\n                    \/\/   A JOUR la resa active au lieu d'en creer une : l'item porte donc\r\n                    \/\/   legitimement une ancienne URL, le temps que la nouvelle page soit\r\n                    \/\/   ouverte. Le clic FORMAT passe ensuite par DisplayPageWeb ->\r\n                    \/\/   creerCommandePartielle, et pb174 y voyait un changement de page :\r\n                    \/\/   une 2e resa naissait a l'insu de l'utilisateur (log : \"item actif\r\n                    \/\/   engage sur congo.yearbook-media.com != nouvelle page\r\n                    \/\/   congo...\/congo-elevage-...\").\r\n                    \/\/   Le critere devient l'ENGAGEMENT REEL : un espace publicitaire\r\n                    \/\/   effectivement reserve sur l'ancienne page (emplacementPageWeb).\r\n                    \/\/   Un format seul n'engage rien \u2014 il se change d'un clic.\r\n                    \/\/   Le bouton \"Ajouter une reservation\" reste le seul moyen explicite\r\n                    \/\/   d'en creer une nouvelle.\r\n                    \/\/   Revert : window._viaPb775Off = true.\r\n                    var _engage775 = (window._viaPb775Off === true)\r\n                        ? !!_actifR0.format\r\n                        : !!_actifR0.emplacementPageWeb;\r\n                    if (_normCP174(_actifUrl174) && _normCP174(_actifUrl174) !== _normCP174(linkSecteurPage) && _engage775) {\r\n                        console.log('\ud83c\udd95 [creerCommandePartielle pb174\/pb775] item actif ' + _actifR0.id + ' ENGAGE (emplacement ' + _actifR0.emplacementPageWeb + ') sur ' + _normCP174(_actifUrl174) + ' != nouvelle page ' + _normCP174(linkSecteurPage) + ' -> creer une NOUVELLE resa');\r\n                        _actifR0 = null;\r\n                    } else if (_normCP174(_actifUrl174) !== _normCP174(linkSecteurPage)) {\r\n                        console.log('[pb775] item actif ' + _actifR0.id + ' reutilise (page ' + _normCP174(_actifUrl174) + ' -> ' + _normCP174(linkSecteurPage) + ') \u2014 aucun espace reserve, pas de duplication');\r\n                    }\r\n                }\r\n                if (_actifR0) {\r\n                    commandePartiellePage = _actifR0;\r\n                    \/\/ Mettre \u00e0 jour TOUS les champs avec les nouvelles valeurs sessionStorage\r\n                    \/\/   pour que setItemActif \u2192 syncItemToSessionStorage propage les\r\n                    \/\/   nouvelles donn\u00e9es au lieu d'\u00e9craser avec l'ancien \u00e9tat (Pb r\u00e9gie).\r\n                    commandePartiellePage.linkSecteurPage = linkSecteurPage;\r\n                    commandePartiellePage.linkSecteurPageDisplayed = sessionStorage.getItem('LinkSecteurPageDisplayed') || linkSecteurPage;\r\n                    commandePartiellePage.selectedPageType = sessionStorage.getItem('SelectedPageType') || commandePartiellePage.selectedPageType;\r\n                    commandePartiellePage.selectedPageSecteur = sessionStorage.getItem('SelectedPageSecteur') || commandePartiellePage.selectedPageSecteur;\r\n                    \/\/ \u2705 v4.9ds+ Pb 1 multi-achat : SelectedPageSecteurDisplayed globale peut \u00eatre\r\n                    \/\/   contamin\u00e9e par le contexte d'un autre item (ex: Gabon\/Investissement \u00e9crase\r\n                    \/\/   Madagascar\/Croissance). Priorit\u00e9 : valeur propre de l'item > SelectedPageSecteur\r\n                    \/\/   (d\u00e9j\u00e0 correct pour cette URL) > globale (risque de porosit\u00e9).\r\n                    commandePartiellePage.selectedPageSecteurDisplayed = commandePartiellePage.selectedPageSecteurDisplayed\r\n                        || sessionStorage.getItem('SelectedPageSecteur')\r\n                        || sessionStorage.getItem('SelectedPageSecteurDisplayed');\r\n                    commandePartiellePage.commandePage = this.determinerCommandePage() || commandePartiellePage.commandePage;\r\n                    \/\/ pb255 : l'URL de l'item prime sur les globales SelectedPageType\/Secteur\r\n                    \/\/   pollu\u00e9es (multi-r\u00e9sa : restent ArtType\/Plan de la r\u00e9sa pr\u00e9c\u00e9dente).\r\n                    \/\/   Homepage (path \/ ou \/en\/ \/fr\/) -> Homepage + secteur vide.\r\n                    if (this._isHomepageUrl255(linkSecteurPage)) {\r\n                        commandePartiellePage.commandePage = 'Homepage';\r\n                        commandePartiellePage.selectedPageType = 'HPType';\r\n                        commandePartiellePage.selectedPageSecteur = '';\r\n                        commandePartiellePage.selectedPageSecteurDisplayed = '';\r\n                    }\r\n                    commandePartiellePage.pays = sessionStorage.getItem('ContinentPaysTitre') || commandePartiellePage.pays;\r\n                    commandePartiellePage.paysDisplayed = sessionStorage.getItem('ContinentPaysTitreDisplayed') || sessionStorage.getItem('ContinentPaysTitre') || commandePartiellePage.paysDisplayed;\r\n                    var _newFmtR0 = sessionStorage.getItem('FormatSelect');\r\n                    \/\/ \u2705 v4.9ds+ (suite 8) Pb 2 multi-r\u00e9sa : NE PAS \u00e9craser le format existant\r\n                    \/\/   de l'item avec FormatSelect global. FormatSelect peut \u00eatre pollu\u00e9 par\r\n                    \/\/   le format d'un autre item r\u00e9cemment actif (cas multi-r\u00e9servations :\r\n                    \/\/   user sur Gabon\/Vid\u00e9o \u2192 switch Madagascar\/Banni\u00e8re \u2192 FormatSelect=Vid\u00e9o\r\n                    \/\/   \u00e9crasait Madagascar.format=Banni\u00e8re). Le format de l'item ne doit\r\n                    \/\/   changer que via une s\u00e9lection explicite (handler format), pas via la\r\n                    \/\/   r\u00e9utilisation R0. Si l'item n'a pas encore de format, on peut le poser\r\n                    \/\/   depuis FormatSelect (cr\u00e9ation initiale).\r\n                    if (_newFmtR0 ? !commandePartiellePage.format : false) {\r\n                        commandePartiellePage.format = _newFmtR0;\r\n                    }\r\n                    var _newCodeSiteR0 = sessionStorage.getItem('CodeSite');\r\n                    if (_newCodeSiteR0) { commandePartiellePage.codeSite = _newCodeSiteR0; }\r\n                    var _newCodePageR0 = sessionStorage.getItem('CodePage');\r\n                    if (_newCodePageR0) { commandePartiellePage.codePage = _newCodePageR0; }\r\n                    \/\/ Si la nouvelle URL diff\u00e8re de l'ancienne, l'espace pub r\u00e9serv\u00e9 n'est\r\n                    \/\/   plus valide (autre page) \u2192 r\u00e9initialiser emplacement + rank +\r\n                    \/\/   FullPathAdFile, et redescendre en 'partielle' si on \u00e9tait 'en_cours'.\r\n                    var _oldUrlR0 = (commandePartiellePage.donneesIframe ? commandePartiellePage.donneesIframe.LoadedPageUrl : '') || '';\r\n                    var _normR0 = function(u) { return (u || '').split('?')[0].split('#')[0].replace(\/\\\/+$\/, '').toLowerCase(); };\r\n                    if (_normR0(_oldUrlR0) && _normR0(_oldUrlR0) !== _normR0(linkSecteurPage)) {\r\n                        commandePartiellePage.emplacementPageWeb = null;\r\n                        commandePartiellePage.position = null;\r\n                        commandePartiellePage.statut = 'partielle';\r\n                        \/\/ reservationEnAttente effac\u00e9 + estReserveEffective=false :\r\n                        \/\/   L'emplacement est r\u00e9initialis\u00e9 (null). \"Espace r\u00e9serv\u00e9 \" (vide)\r\n                        \/\/   serait incoh\u00e9rent. \"\u00e0 r\u00e9server\" est la bonne indication \u2014\r\n                        \/\/   l'utilisateur doit s\u00e9lectionner un nouvel espace pub.\r\n                        \/\/   Flux complet :\r\n                        \/\/   1. click pays \u2192 resetDonneesCampagne \u2192 reservationEnAttente=true\r\n                        \/\/      \u2192 remplirItemPartiel affiche \"Espace publicitaire MDG44766L1A\"\r\n                        \/\/   2. R0 (nouvelle page) \u2192 emplacementPageWeb=null + estReserveEffective=false\r\n                        \/\/      \u2192 remplirItemPartiel affiche \"Espace publicitaire  \u00e0 r\u00e9server [cb]\"\r\n                        commandePartiellePage.reservationEnAttente = false;\r\n                        commandePartiellePage.estReserveEffective  = false;\r\n                        if (commandePartiellePage.donneesIframe) {\r\n                            commandePartiellePage.donneesIframe.LoadedPageUrl = linkSecteurPage;\r\n                            commandePartiellePage.donneesIframe.Commande_Emplacement_Page_Web = '';\r\n                            commandePartiellePage.donneesIframe.Rank_Emplacement_Page_Web = '';\r\n                            commandePartiellePage.donneesIframe.FullPathAdFile = null;\r\n                            commandePartiellePage.donneesIframe.FullPathAdFileOnly = null;\r\n                            commandePartiellePage.donneesIframe.FileReceived = 'No';\r\n                            commandePartiellePage.donneesIframe.EnvoiUlterieur = 'false';\r\n                            if (_newCodeSiteR0) { commandePartiellePage.donneesIframe.codeSite = _newCodeSiteR0; }\r\n                            if (_newCodePageR0) { commandePartiellePage.donneesIframe.codePage = _newCodePageR0; }\r\n                        }\r\n                    } else if (commandePartiellePage.donneesIframe) {\r\n                        commandePartiellePage.donneesIframe.LoadedPageUrl = linkSecteurPage;\r\n                    }\r\n                    console.log('\ud83c\udfaf [creerCommandePartielle R0] itemActif r\u00e9utilis\u00e9:', _actifR0.id, '| statut:', _actifR0.statut, '\u2192', commandePartiellePage.statut, '| nouvelle URL:', linkSecteurPage, '| pays:', commandePartiellePage.pays, '| secteur:', commandePartiellePage.selectedPageSecteurDisplayed);\r\n                    \r\n                    \/\/ \u2705 v4.9ds R0 : rafra\u00eechir le DOM de la carte r\u00e9capitulative pour\r\n                    \/\/   refl\u00e9ter les nouvelles donn\u00e9es (sinon CampagnePaysTexte \/ CampagnePageText \/\r\n                    \/\/   CampagneFormatClass \/ CampagneNoClass gardent les anciennes valeurs).\r\n                    var $_itemR0 = $('#' + commandePartiellePage.id);\r\n                    if ($_itemR0.length && typeof this.remplirItemPartiel === 'function') {\r\n                        this.remplirItemPartiel($_itemR0, commandePartiellePage);\r\n                    }\r\n                    \/\/ pb73 : synchroniser les champs cl\u00e9s de commandePartiellePage sur _actifR0\r\n                    \/\/ (r\u00e9f\u00e9rence directe dans state.items). Sans \u00e7a, les refreshes ult\u00e9rieurs de\r\n                    \/\/ remplirItemPartiel lisent l'objet _actifR0 (anticip\u00e9e) avec pays: null \u2192\r\n                    \/\/ fallback sur ContinentPaysTitre global \u2192 affiche le dernier pays s\u00e9lectionn\u00e9\r\n                    \/\/ (ex: Gabon) m\u00eame pour une r\u00e9sa Madagascar.\r\n                    if (_actifR0) {\r\n                        if (commandePartiellePage.pays) { _actifR0.pays = commandePartiellePage.pays; }\r\n                        if (commandePartiellePage.linkSecteurPage) { _actifR0.linkSecteurPage = commandePartiellePage.linkSecteurPage; }\r\n                        if (commandePartiellePage.statut) { _actifR0.statut = commandePartiellePage.statut; }\r\n                        if (commandePartiellePage.format) { _actifR0.format = commandePartiellePage.format; }\r\n                        if (commandePartiellePage.selectedPageSecteurDisplayed) { _actifR0.selectedPageSecteurDisplayed = commandePartiellePage.selectedPageSecteurDisplayed; }\r\n                        if (commandePartiellePage.donneesIframe) {\r\n                            if (!_actifR0.donneesIframe) { _actifR0.donneesIframe = {}; }\r\n                            if (commandePartiellePage.donneesIframe.LoadedPageUrl) { _actifR0.donneesIframe.LoadedPageUrl = commandePartiellePage.donneesIframe.LoadedPageUrl; }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            \r\n            \/\/ Recherche par URL \u2014 uniquement si R0 n'a pas match\u00e9\r\n            if (!commandePartiellePage) {\r\n                commandePartiellePage = this.state.items.find(i => {\r\n                if (i.statut !== 'partielle') return false;\r\n                \/\/ \u2705 Comparaison normalis\u00e9e (trailing slash insensible)\r\n                if (_normalizeUrlCP(i.linkSecteurPage) !== _linkNorm) return false;\r\n                \/\/ Si l'item a d\u00e9j\u00e0 une annonce d\u00e9pos\u00e9e avec un rank diff\u00e9rent \u2192 ne pas r\u00e9utiliser\r\n                \/\/ \u2705 Si l'item a d\u00e9j\u00e0 un espace occup\u00e9 (annonce OU envoi diff\u00e9r\u00e9) avec un rank diff\u00e9rent \u2192 ne pas r\u00e9utiliser\r\n                var _itRankCP = i.donneesIframe && i.donneesIframe.Rank_Emplacement_Page_Web;\r\n                var _itOccupiedCP = i.donneesIframe && (\r\n                    i.donneesIframe.FileReceived === 'Yes'\r\n                    || i.donneesIframe.EnvoiUlterieur === 'true'\r\n                    || i.donneesIframe.EnvoiUlterieur === true\r\n                );\r\n                if (_itOccupiedCP && _itRankCP && _rankCourant && _itRankCP !== _rankCourant) {\r\n                    return false;\r\n                }\r\n                return true;\r\n            });\r\n            }\r\n\r\n            \/\/ \u2705 v2.3.2 : Fallback \u2014 chercher via LinkSecteurPageDisplayed (page article \u2192 secteur)\r\n            \/\/ Cas : item cr\u00e9\u00e9 avec l'URL article, puis creerCommandePartielle appel\u00e9 avec l'URL secteur courte\r\n            \/\/ Condition : m\u00eame domaine (pays) ET urls ne correspondent pas d\u00e9j\u00e0\r\n            if (!commandePartiellePage) {\r\n                const _displayedUrl = sessionStorage.getItem('LinkSecteurPageDisplayed') || '';\r\n                const _displayedNorm = _normalizeUrlCP(_displayedUrl);\r\n                const _getDomain = (u) => { try { return new URL(u).hostname; } catch(e) { return ''; } };\r\n                const _newDomain = _getDomain(linkSecteurPage);\r\n                const _displayedDomain = _getDomain(_displayedUrl);\r\n                const _currentSecteur = (sessionStorage.getItem('SelectedPageSecteur') || '').toLowerCase();\r\n                if (_displayedNorm && _newDomain && _newDomain === _displayedDomain) {\r\n                    commandePartiellePage = this.state.items.find(i => {\r\n                        if (i.statut !== 'partielle') return false;\r\n                        if (_normalizeUrlCP(i.linkSecteurPage) !== _displayedNorm) return false;\r\n                        \/\/ \u2705 v2.3.2 : V\u00e9rifier que le secteur correspond \u2014 \u00e9vite de recycler\r\n                        \/\/ un item Croissance quand l'utilisateur a s\u00e9lectionn\u00e9 International\r\n                        const _itemSecteur = (i.selectedPageSecteur || '').toLowerCase();\r\n                        if (_currentSecteur && _itemSecteur && _itemSecteur !== _currentSecteur) {\r\n                            console.log('\u23ed\ufe0f [creerCommandePartielle] fallback ignor\u00e9 \u2014 secteurs diff\u00e9rents:', _itemSecteur, '\u2260', _currentSecteur);\r\n                            return false;\r\n                        }\r\n                        return true;\r\n                    });\r\n                    if (commandePartiellePage) {\r\n                        console.log('\u2705 [creerCommandePartielle] match via LinkSecteurPageDisplayed:', commandePartiellePage.id, '| displayed:', _displayedUrl);\r\n                        \/\/ Mettre \u00e0 jour linkSecteurPage avec l'URL secteur courte pour coh\u00e9rence future\r\n                        commandePartiellePage.linkSecteurPage = linkSecteurPage;\r\n                    }\r\n                } else if (_displayedNorm) {\r\n                    console.log('\u23ed\ufe0f [creerCommandePartielle] fallback ignor\u00e9 \u2014 domaines diff\u00e9rents:', _newDomain, '\u2260', _displayedDomain);\r\n                }\r\n            }\r\n\r\n\r\n            \/\/ \u2705 v2.3.3 : Fallback FB3 \u2014 domain+secteur identiques (couvre le cas categoryChanged\r\n            \/\/             qui efface LinkSecteurPageDisplayed avant d'appeler creerCommandePartielle)\r\n            if (!commandePartiellePage) {\r\n                const _getDomainFB3 = (u) => { try { return new URL(u).hostname; } catch(e) { return ''; } };\r\n                const _domainFB3 = _getDomainFB3(linkSecteurPage);\r\n                const _secteurFB3 = (sessionStorage.getItem('SelectedPageSecteur') || '').toLowerCase();\r\n                if (_domainFB3 && _secteurFB3) {\r\n                    commandePartiellePage = this.state.items.find(i => {\r\n                        if (i.statut !== 'partielle') return false;\r\n                        if (_getDomainFB3(i.linkSecteurPage) !== _domainFB3) return false;\r\n                        if ((i.selectedPageSecteur || '').toLowerCase() !== _secteurFB3) return false;\r\n                        return true;\r\n                    });\r\n                    if (commandePartiellePage) {\r\n                        console.log('\u2705 [creerCommandePartielle] match via domain+secteur (FB3):', commandePartiellePage.id);\r\n                        commandePartiellePage.linkSecteurPage = linkSecteurPage;\r\n                    }\r\n                }\r\n            }\r\n\r\n            \/\/ \u2705 FB4 \u2014 item anticipee (cr\u00e9\u00e9 lors du changement pays\/secteur avant URL disponible)\r\n            if (!commandePartiellePage) {\r\n                commandePartiellePage = this.state.items.find(i => i.statut === 'anticipee');\r\n                if (commandePartiellePage) {\r\n                    console.log('\u2705 [creerCommandePartielle] FB4 \u2014 item anticipee upgrad\u00e9 en partielle:', commandePartiellePage.id);\r\n                    commandePartiellePage.linkSecteurPage = linkSecteurPage;\r\n                    commandePartiellePage.statut = 'partielle';\r\n                    commandePartiellePage.selectedPageType     = sessionStorage.getItem('SelectedPageType');\r\n                    commandePartiellePage.selectedPageSecteur  = sessionStorage.getItem('SelectedPageSecteur');\r\n                    \/\/ \u2705 v4.9ds+ Pb 1 multi-achat : m\u00eame anti-contamination que R0\r\n                    commandePartiellePage.selectedPageSecteurDisplayed = sessionStorage.getItem('SelectedPageSecteur')\r\n                        || sessionStorage.getItem('SelectedPageSecteurDisplayed');\r\n                    commandePartiellePage.commandePage = this.determinerCommandePage();\r\n                    if (!commandePartiellePage.format) {\r\n                        \/\/ \u2705 v2.4.10 : Utiliser _viaFormatForPartielle sauvegard\u00e9 par CheckSteps123 avant de vider FormatSelect\r\n                        commandePartiellePage.format = normaliseFormatAccents(\r\n                            sessionStorage.getItem('FormatSelect') ||\r\n                            sessionStorage.getItem('_viaFormatForPartielle') || null\r\n                        );\r\n                        sessionStorage.removeItem('_viaFormatForPartielle');\r\n                    }\r\n                    \/\/ \u2705 v1.11 : Rafra\u00eechir le DOM du clone (\u00e9tat anticip\u00e9 \u2192 \u00e9tat partiel)\r\n                    var $_fb4Item = $('#' + commandePartiellePage.id);\r\n                    if ($_fb4Item.length) {\r\n                        \/\/ Supprimer le message d'invitation anticip\u00e9\r\n                        $_fb4Item.find('.CampagneMsgAccompagnement').remove();\r\n                        \/\/ R\u00e9afficher CampagnePageText et CampagnePaysTexte masqu\u00e9s en \u00e9tat anticip\u00e9\r\n                        $_fb4Item.find('.CampagnePageTextClass, #CampagnePageText').show();\r\n                        $_fb4Item.find('[id=\"CampagnePaysTexte\"], .CampagnePaysClass').show();\r\n                        \/\/ Relancer le rendu partiel complet\r\n                        this.remplirItemPartiel($_fb4Item, commandePartiellePage);\r\n                    }\r\n                }\r\n            }\r\n\r\n            console.log('\ud83d\udd0d [creerCommandePartielle] commandePartiellePage trouv\u00e9:', commandePartiellePage ? commandePartiellePage.id + ' (' + commandePartiellePage.selectedPageSecteurDisplayed + ')' : 'AUCUN');\r\n            \r\n            if (commandePartiellePage) {\r\n                console.log('\u26a0\ufe0f Commande partielle d\u00e9j\u00e0 existante pour cette page:', commandePartiellePage.id);\r\n                \/\/ \u2705 v2.4.9f : Si l'item actif appartient d\u00e9j\u00e0 \u00e0 cette page \u2192 ne pas switcher\r\n                \/\/ (l'utilisateur a cliqu\u00e9 explicitement sur un autre item de la m\u00eame page)\r\n                if (this.state.itemActif && this.state.itemActif !== commandePartiellePage.id) {\r\n                    const _activeItem = this.state.items.find(i => i.id === this.state.itemActif);\r\n                    if (_activeItem) {\r\n                        const _activeUrl = (_activeItem.donneesIframe && _activeItem.donneesIframe.LoadedPageUrl) || _activeItem.linkSecteurPage || '';\r\n                        const _normalizeU = (u) => (u || '').replace(\/\\\/?$\/, '').toLowerCase();\r\n                        if (_normalizeU(_activeUrl) === _normalizeU(linkSecteurPage)) {\r\n                            console.log('\u2705 [creerCommandePartielle] item actif d\u00e9j\u00e0 sur cette page \u2192 pas de switch:', this.state.itemActif);\r\n                            return commandePartiellePage;\r\n                        }\r\n                    }\r\n                }\r\n                \/\/ \u2705 CORRECTION : Mettre \u00e0 jour commandePage si elle a chang\u00e9\r\n                \/\/ pb255 : homepage par URL prime sur determinerCommandePage (globales pollu\u00e9es)\r\n                var _isHomeCP255 = this._isHomepageUrl255(linkSecteurPage);\r\n                if (_isHomeCP255) {\r\n                    commandePartiellePage.selectedPageSecteur = '';\r\n                    commandePartiellePage.selectedPageSecteurDisplayed = '';\r\n                }\r\n                const commandePageActuel = _isHomeCP255 ? 'Homepage' : this.determinerCommandePage();\r\n                if (commandePageActuel && commandePartiellePage.commandePage !== commandePageActuel) {\r\n                    console.log(`\ud83d\udd04 Mise \u00e0 jour commandePage: ${commandePartiellePage.commandePage} \u2192 ${commandePageActuel}`);\r\n                    commandePartiellePage.commandePage = commandePageActuel;\r\n                    \r\n                    \/\/ Mettre \u00e0 jour l'affichage\r\n                    const $item = $(`#${commandePartiellePage.id}`);\r\n                    const selectedPageSecteurDisplayed = commandePartiellePage.selectedPageSecteurDisplayed || '';\r\n                    let titrePage;\r\n                    \r\n                    switch (commandePageActuel) {\r\n                        case 'Homepage':\r\n                            titrePage = 'Homepage';\r\n                            break;\r\n                        case 'Page sectorielle':\r\n                            \/\/ \u2705 v2.4.6 : Supprimer \"Page\" devant le secteur\r\n                            titrePage = selectedPageSecteurDisplayed;\r\n                            break;\r\n                        case 'Article':\r\n                            titrePage = 'Article ' + selectedPageSecteurDisplayed;\r\n                            break;\r\n                        default:\r\n                            titrePage = commandePageActuel;\r\n                    }\r\n                    \r\n                    \/\/ \u2705 v2.4.5 : Conserver la position d\u00e9j\u00e0 affich\u00e9e dans #CampagnePageText\r\n                    var $_ptPartiel2 = $item.find('#CampagnePageText, .CampagnePageTextClass').first();\r\n                    var _existingText2 = $_ptPartiel2.text() || '';\r\n                    var _nbspIdx2 = _existingText2.indexOf('\u00a0\u00a0\u00a0\u00a0');\r\n                    var _posPartiel2 = _nbspIdx2 !== -1 ? _existingText2.substring(_nbspIdx2 + 2).trim() : '';\r\n                    if (!_posPartiel2 && item.position) { _posPartiel2 = this.convertirPositionEnLibelle(item.position); }\r\n                    $_ptPartiel2.html(_posPartiel2 ? titrePage + '\u00a0\u00a0\u00a0\u00a0' + _posPartiel2 : titrePage);\r\n                }\r\n                \/\/ \u2705 v2.3.2 : Si 3 colonnes ouvertes ET pas de format explicite \u2192 reset format + DOM\r\n                \/\/ \u2705 v4.9ds+ (suite 8) Pb 2 multi-r\u00e9sa : \u00e9tendre _fmtExpliciteEarlyCheck pour\r\n                \/\/   prendre en compte commandePartiellePage.format (source de v\u00e9rit\u00e9 du panier).\r\n                \/\/   Sans cette extension, item.format propre (ex: Banni\u00e8re) \u00e9tait reset \u00e0 null\r\n                \/\/   d\u00e8s que Commande_Format_Transmis<idx> et global \u00e9taient absents\/d\u00e9synchros\r\n                \/\/   en multi-r\u00e9sa, \u00e9crasant le format r\u00e9el de l'item.\r\n                const _activeIdxEarlyReset = sessionStorage.getItem('VIA_ActiveCampagneIndex');\r\n                const _fmtExpliciteEarlyCheck = (_activeIdxEarlyReset && sessionStorage.getItem('Commande_Format_Transmis' + _activeIdxEarlyReset))\r\n                    || sessionStorage.getItem('Commande_Format_Transmis')\r\n                    || commandePartiellePage.format;\r\n                if (sessionStorage.getItem('PageWebColonneOpenclose') === 'Open' && !_fmtExpliciteEarlyCheck) {\r\n                    commandePartiellePage.format = null;\r\n                    if (commandePartiellePage.donneesIframe) {\r\n                        commandePartiellePage.donneesIframe.Commande_Format_Transmis = null;\r\n                    }\r\n                    \/\/ \u2705 Mettre \u00e0 jour le DOM : masquer le tag format affich\u00e9\r\n                    const $_itemReset = $(`#${commandePartiellePage.id}`);\r\n                    $_itemReset.find('.CampagneFormatClass').hide();\r\n                }\r\n                this.setItemActif(commandePartiellePage.id);\r\n                return commandePartiellePage;\r\n            }\r\n            \r\n            \/\/ \u2705 CORRECTION : V\u00e9rifier 'valide' OU 'en_cours'\r\n            const _normalizeUrlCC = (u) => (u || '').replace(\/\\\/?$\/, '').toLowerCase();\r\n            const _linkNormCC = _normalizeUrlCC(linkSecteurPage);\r\n            const commandeComplete = this.state.items.find(i => {\r\n                if (i.statut !== 'en_cours' && i.statut !== 'valide') return false;\r\n                const _itUrl = (i.donneesIframe && i.donneesIframe.LoadedPageUrl) || i.linkSecteurPage || '';\r\n                return _normalizeUrlCC(_itUrl) === _linkNormCC;\r\n            });\r\n            \r\n            if (commandeComplete) {\r\n                \/* ============================================================\r\n                 * pb1730 : UN APPEL AUTOMATIQUE NE DOIT PAS OUVRIR UNE MODALE.\r\n                 *   Pile nommee par pb1729, de bas en haut :\r\n                 *     marquerEtapeEnCours -> _sequenceurOuverture1073\r\n                 *       -> DisplayPageWeb -> creerCommandePartielle\r\n                 *       -> setItemActif -> message\r\n                 *   Aucun clic la-dedans : c est la boucle de synchronisation des\r\n                 *   etapes qui rouvre la page web, laquelle recree une commande\r\n                 *   partielle, laquelle redesigne l item actif. setItemActif refuse\r\n                 *   \u2014 a juste titre, la commande est verrouillee \u2014 mais il refuse\r\n                 *   en ouvrant une MODALE, qui recouvre l acces aux bons de\r\n                 *   commande.\r\n                 *   Le message s adresse a un utilisateur qui tente une\r\n                 *   modification. Ici personne ne tente rien.\r\n                 *   Une fois le bon de commande cree, l item actif ne change plus :\r\n                 *   redesigner celui qui l est deja n a aucun effet utile. On\r\n                 *   s abstient, et on rend l item trouve \u2014 le contrat de la\r\n                 *   fonction est respecte.\r\n                 *   Les huit autres appelants du message restent intacts : ils\r\n                 *   partent tous d une action utilisateur.\r\n                 *   Revert : window._viaPb1730Off = true.\r\n                 * ============================================================ *\/\r\n                var _verrou1730 = false;\r\n                if (window._viaPb1730Off !== true) {\r\n                    try { _verrou1730 = (sessionStorage.getItem('BonCommandeCree') === 'Yes'); }\r\n                    catch (_e1730) { _verrou1730 = false; }\r\n                }\r\n                if (_verrou1730) {\r\n                    if (window._viaSig1730 !== commandeComplete.id) {\r\n                        window._viaSig1730 = commandeComplete.id;\r\n                        console.log('[pb1730] bon de commande cree -> setItemActif automatique ignore'\r\n                            + ' | item=' + commandeComplete.id + ' (pas de modale)');\r\n                    }\r\n                    return commandeComplete;\r\n                }\r\n                console.log('\u26a0\ufe0f Commande en_cours\/valide d\u00e9j\u00e0 existante pour cette page:', commandeComplete.id, '\u2192 setItemActif');\r\n                this.setItemActif(commandeComplete.id);\r\n                return commandeComplete;\r\n            }\r\n            \r\n            \/\/ V\u00c9RIFIER : S\u00e9lection commande existante\r\n            const selectedIndex = sessionStorage.getItem('SelectedCampagneIndex');\r\n            \r\n            if (selectedIndex && selectedIndex !== '0') {\r\n                const commandeExistante = this.state.items.find(i => \r\n                    i.sessionStorageIndex === parseInt(selectedIndex)\r\n                );\r\n                \r\n                \/\/ \u2705 CORRECTION : V\u00e9rifier 'valide' OU 'en_cours'\r\n                if (commandeExistante && (commandeExistante.statut === 'en_cours' || commandeExistante.statut === 'valide')) {\r\n                    console.log('\u26a0\ufe0f S\u00e9lection d\\'une commande existante, pas de cr\u00e9ation partielle');\r\n                    return null;\r\n                }\r\n            }\r\n            \r\n            console.log('\u2705 Conditions OK pour cr\u00e9er commande partielle');\r\n            \r\n            \/\/ \u2705 v1.7 : R\u00e9initialiser le tarif pr\u00e9c\u00e9dent pour \u00e9viter qu'il soit r\u00e9utilis\u00e9\r\n            if (window.VIA_App && window.VIA_App.state) {\r\n                window.VIA_App.state.dernierResultatCalcul = null;\r\n            }\r\n            $('#Tariftobedisplayed').html('-');\r\n            \r\n            \/\/ \u2705 v1.7 : R\u00e9initialiser le formulaire (dates, STATE.emplacementPageWeb, etc.)\r\n            if (typeof window.reinitialiserFormulaireDatesTarif === 'function') {\r\n                window.reinitialiserFormulaireDatesTarif();\r\n                console.log('\u2705 Formulaire r\u00e9initialis\u00e9 via reinitialiserFormulaireDatesTarif');\r\n            }\r\n            \r\n            const $template = $('#CampagneTemplate');\r\n            \r\n            if ($template.length === 0) {\r\n                console.error('\u274c Template introuvable');\r\n                return null;\r\n            }\r\n            \r\n            \/\/ G\u00e9n\u00e9rer r\u00e9f\u00e9rence PARTIELLE\r\n            const codeUnique = await this.genererCodeUnique();\r\n            const codeSite = sessionStorage.getItem('codeSite') || 'XXX';\r\n            const codePage = sessionStorage.getItem('IdPage') || '00000';\r\n            const referencePartielle = `${codeUnique}-${codeSite}-${codePage}`;\r\n            \r\n            $template.find('#Etape1Container').remove();\r\n            \r\n            const $newItem = $template.clone();\r\n            const itemId = `CampagneTemplate_${Date.now()}`;\r\n            \r\n            $template.css('display', 'none').hide();\r\n            \r\n            $newItem.removeAttr('data-is-template');\r\n            $newItem.attr('id', itemId);\r\n            $newItem.attr('data-reference', referencePartielle);\r\n            $newItem.css('display', 'block').show();\r\n            \r\n            \/\/ Capturer les donn\u00e9es actuelles\r\n            const selectedPageType = sessionStorage.getItem('SelectedPageType');\r\n            const selectedPageSecteur = sessionStorage.getItem('SelectedPageSecteur');\r\n            \/\/ \u2705 SelectedPageSecteurDisplayed peut \u00eatre stale si setItemActif n'a pas encore mis \u00e0 jour le sessionStorage global\r\n            \/\/ \u2192 pr\u00e9f\u00e9rer la valeur index\u00e9e de l'item actif (syncItemToSessionStorage l'a \u00e9crite avec l'index correct)\r\n            const _activeIndex = sessionStorage.getItem('SelectedCampagneIndex');\r\n            const selectedPageSecteurDisplayed = _secteurFromUrl\r\n                || ((_activeIndex && _activeIndex !== '0')\r\n                    ? (sessionStorage.getItem('SelectedPageSecteurDisplayed' + _activeIndex) || sessionStorage.getItem('SelectedPageSecteurDisplayed'))\r\n                    : sessionStorage.getItem('SelectedPageSecteurDisplayed'))\r\n                || '';\r\n            const continentPaysTitre = (_activeIndex && _activeIndex !== '0')\r\n                ? (sessionStorage.getItem('ContinentPaysTitre' + _activeIndex) || sessionStorage.getItem('ContinentPaysTitre'))\r\n                : sessionStorage.getItem('ContinentPaysTitre');\r\n            \/\/ \u2705 v2.3.2 : Format \u2014 depuis Commande_Format_Transmis en priorit\u00e9.\r\n            \/\/ FormatSelect utilis\u00e9 UNIQUEMENT si Formatchoisi='Yes' ET pays+secteur pr\u00e9sents\r\n            \/\/ (cas : format cliqu\u00e9 avant ouverture des 3 colonnes = s\u00e9lection volontaire courante).\r\n            \/\/ FormatSelect r\u00e9siduel (Formatchoisi='No' ou absent) est ignor\u00e9.\r\n            const _idxFmt = _activeIndex && _activeIndex !== '0' ? _activeIndex : null;\r\n            const _fmtExplicite = (_idxFmt && sessionStorage.getItem('Commande_Format_Transmis' + _idxFmt))\r\n                || sessionStorage.getItem('Commande_Format_Transmis');\r\n            \r\n            const popUpChoice = sessionStorage.getItem('PopUpChoice');\r\n            \/\/ \u2705 v2.4.10 : Aussi lire _viaFormatForPartielle sauvegard\u00e9 par CheckSteps123\r\n            const formatSelect = sessionStorage.getItem('FormatSelect') || sessionStorage.getItem('_viaFormatForPartielle') || '';\r\n            if (!sessionStorage.getItem('FormatSelect') && formatSelect) { sessionStorage.removeItem('_viaFormatForPartielle'); }\r\n            const formatChoisi = sessionStorage.getItem('Formatchoisi') === 'Yes';\r\n            const _hasPays = sessionStorage.getItem('ContinentPaysTitre') !== null;\r\n            const _hasSecteur = sessionStorage.getItem('SelectedPageSecteur') !== null;\r\n            \r\n            let formatTransmis = _fmtExplicite || null;\r\n            \/\/ \u2705 v2.3.2 : FormatSelect utilis\u00e9 uniquement si 3 colonnes PAS encore ouvertes\r\n            \/\/ Quand 3 colonnes d\u00e9j\u00e0 ouvertes \u2192 seul Commande_Format_Transmis (iframe) est valide\r\n            \/\/ \u2705 v2.3.2 : FormatSelect utilis\u00e9 si pays+secteur pr\u00e9sents\r\n            \/\/ Guard : les handlers pays\/secteur effacent FormatSelect \u2192 pas de r\u00e9siduel possible\r\n            \/\/ \u2705 v2.3.3c : PopUpChoice='Yes' suffit m\u00eame si FormatSelect est vide (cas FormatPopup sans format sous-jacent)\r\n            if (!formatTransmis && _hasPays && _hasSecteur) {\r\n                if (formatSelect || popUpChoice === 'Yes') {\r\n                    formatTransmis = popUpChoice === 'Yes' ? 'Pop-Up' : formatSelect;\r\n                    console.log('\ud83d\udccb Format d\u00e9duit (FormatSelect\/PopUp + pays+secteur OK):', formatTransmis);\r\n                } else if (formatTransmis) {\r\n                    console.log('\ud83d\udccb Format r\u00e9cup\u00e9r\u00e9 depuis Commande_Format_Transmis:', formatTransmis);\r\n                } else {\r\n                    console.log('\ud83d\udccb Format ignor\u00e9 \u2014 pas de s\u00e9lection explicite pour cet item');\r\n                }\r\n            } else if (formatTransmis) {\r\n                console.log('\ud83d\udccb Format r\u00e9cup\u00e9r\u00e9 depuis Commande_Format_Transmis:', formatTransmis);\r\n            } else {\r\n                console.log('\ud83d\udccb Format ignor\u00e9 \u2014 pas de s\u00e9lection explicite pour cet item');\r\n            }\r\n            \r\n            \/\/ \u2705 v2.6 : D\u00e9duire commandePage depuis LoadedPageUrl si disponible\r\n            \/\/ (sessionStorage peut \u00eatre \u00e9crit en race condition apr\u00e8s creerNouvelItem)\r\n            var _loadedUrl = linkSecteurPage || '';\r\n            var _commandePageFromUrl = '';\r\n            var _secteurFromUrl = '';\r\n            if (_loadedUrl) {\r\n                var _urlPath = _loadedUrl.replace(\/#.*$\/, '').replace(\/^https?:\\\/\\\/[^\/]+\/, '').replace(\/\\\/$\/, ''); \/\/ strip hash + origin + trailing slash\r\n                if (_urlPath && _urlPath !== '' && _urlPath !== '\/') {\r\n                    _commandePageFromUrl = 'Page sectorielle';\r\n                    var _parts = _urlPath.split('\/').filter(function(p) { return p.length > 0; });\r\n                    if (_parts.length > 0) {\r\n                        var _rawSect = _parts[_parts.length - 1];\r\n                        _secteurFromUrl = _rawSect.charAt(0).toUpperCase() + _rawSect.slice(1).replace(\/-\/g, ' ');\r\n                    }\r\n                } else {\r\n                    _commandePageFromUrl = 'Homepage';\r\n                }\r\n            }\r\n            \/\/ \u2705 R\u00e9cup\u00e9rer le type de page\r\n            const commandePage = _commandePageFromUrl || this.determinerCommandePage();\r\n\r\n            console.log('\ud83d\udccb Donn\u00e9es page captur\u00e9es:', {\r\n                selectedPageType,\r\n                commandePage,\r\n                selectedPageSecteur,\r\n                selectedPageSecteurDisplayed,\r\n                linkSecteurPage,\r\n                formatTransmis\r\n            });\r\n            \r\n            \/\/ \u2705 Cr\u00e9er l'item partiel avec le format\r\n            const item = {\r\n                id: itemId,\r\n                reference: referencePartielle,\r\n                espacepubId: null,\r\n                format: formatTransmis,\r\n                position: null,\r\n                emplacementPageWeb: null,\r\n                \r\n                selectedPageType: selectedPageType,\r\n                commandePage: commandePage,\r\n                selectedPageSecteur: selectedPageSecteur,\r\n                selectedPageSecteurDisplayed: selectedPageSecteurDisplayed,\r\n                linkSecteurPage: linkSecteurPage,\r\n                \r\n                donneesIframe: null,\r\n                \/\/ \u2705 v2.3.4 : PopUpChoice persist\u00e9 d\u00e8s la cr\u00e9ation de l'item\r\n                popUpChoice: sessionStorage.getItem('PopUpChoice') === 'Yes' ? 'Yes' : 'No',\r\n                \r\n                pays: null,\r\n                dateDebut: null,\r\n                dateFin: null,\r\n                duree: null,\r\n                tarifHT: null,\r\n                tarifTTC: null,\r\n                devise: 'EUR',\r\n                statut: 'partielle'\r\n            };\r\n            \r\n            this.state.items.push(item);\r\n            \r\n            \/\/ pb1520 : LE PARTIEL DE PAGE SUIT LA MEME REGLE QUE pb1515\/pb1516.\r\n            \/\/   creerCommandePartielle est le SECOND chemin de creation : il naissait avec\r\n            \/\/   sa propre carte et prenait le focus. Observe dans le log : l'espace reserve\r\n            \/\/   (porteur de emplacementPageWeb, mis en attente donc sans carte) devenait\r\n            \/\/   invisible ET inactif, tandis que ce partiel \u2014 qui n'a ni espace ni position\r\n            \/\/   \u2014 recuperait la carte et toutes les saisies. D'ou la carte reclamant un\r\n            \/\/   espace publicitaire deja choisi, et les dates a saisir deux fois.\r\n            \/\/   Un partiel de page a moins que les cinq donnees par construction : c'est\r\n            \/\/   donc lui aussi un espace en attente.\r\n            \/\/   Revert : window._viaPb1520Off = true.\r\n            if (window._viaPb1520Off !== true) {\r\n                item.statut = 'attente';\r\n                console.log('[pb1520] partiel de page EN ATTENTE (pas de carte) | ' + (item.reference || item.id));\r\n            }\r\n\r\n            \/\/ Remplir l'affichage PARTIEL\r\n            this.remplirItemPartiel($newItem, item);\r\n            \r\n            \/\/ \u2705 .first() : \u00e9vite les doublons DOM si plusieurs VosCampagnesConteneurClass\r\n            const $conteneur = $(this.config.conteneurParent).first();\r\n            if ($conteneur.length === 0) {\r\n                console.error('\u274c Conteneur parent introuvable');\r\n                return null;\r\n            }\r\n            \r\n            \/\/ pb1520b : carte gardee de cote tant que le partiel est en attente ; pb1517\r\n            \/\/   l'inserera telle quelle a la promotion, sans la reconstruire.\r\n            if (item.statut === 'attente') { item._vueEnAttente1516 = $newItem; }\r\n            else { $conteneur.append($newItem); }\r\n            \r\n            $('#CampagneTemplate').hide();\r\n            \r\n            \/\/ pb1520c : PRIORITE A L'ESPACE RESERVE. Choisir une page ne doit jamais\r\n            \/\/   deplacer le focus hors d'un espace qui porte deja un emplacementPageWeb et\r\n            \/\/   attend d'etre complete : c'est lui que les saisies doivent renseigner.\r\n            \/\/   Sans cette garde, le setItemActif ci-dessous ecrasait itemActif avec un\r\n            \/\/   partiel vide et pays \/ dates \/ format partaient au mauvais endroit.\r\n            var _resa1520 = null;\r\n            if (window._viaPb1520Off !== true) {\r\n                _resa1520 = (this.state.items || []).find(function (i) {\r\n                    if (i.id === itemId) { return false; }\r\n                    if (i.statut !== 'attente') { return false; }\r\n                    if (!i.emplacementPageWeb) { return false; }\r\n                    return true;\r\n                }) || null;\r\n            }\r\n            if (_resa1520) {\r\n                console.log('[pb1520] focus CONSERVE sur l\\'espace reserve ' + _resa1520.emplacementPageWeb\r\n                    + ' | partiel ' + (item.reference || itemId) + ' cree sans prendre la main');\r\n                this.setItemActif(_resa1520.id);\r\n            } else {\r\n                this.setItemActif(itemId);\r\n            }\r\n            \r\n            \/\/ \u2705 Ouvrir PageWeb quand nouvelle page s\u00e9lectionn\u00e9e\r\n            this.ouvrirPageWeb();\r\n            \r\n            \/\/ \u2705 v1.7 : Afficher le message \"Merci de s\u00e9lectionner un espace publicitaire\"\r\n            $('[data-id=\"656f02e0\"]').show();\r\n            \r\n            console.log('\u2705 Commande partielle cr\u00e9\u00e9e pour:', linkSecteurPage);\r\n            \r\n            return item;\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 NOUVEAU : Cr\u00e9e une r\u00e9servation anticip\u00e9e (pays OU secteur seul, avant URL disponible)\r\n         * Appel\u00e9e lors du changement de pays (secteur reset) ou de secteur (pays reset)\r\n         * @param {Object} options\r\n         *   - type: 'pays' | 'secteur'\r\n         *   - pays, paysDisplay, hpUrl  (si type='pays')\r\n         *   - secteur, secteurDisplay, secteurType  (si type='secteur')\r\n         *\/\r\n        async creerReservationAnticipee(options) {\r\n            console.log('\ud83d\udd50 [creerReservationAnticipee] APPEL\u00c9 | type:', options.type);\r\n\r\n            \/\/ \u2705 Guard : bon de commande d\u00e9j\u00e0 cr\u00e9\u00e9 \u2192 bloquer\r\n            if (sessionStorage.getItem('BonCommandeCree') === 'Yes') {\r\n                console.log('\ud83d\udd12 [creerReservationAnticipee] bloqu\u00e9 - bon de commande cr\u00e9\u00e9');\r\n                return null;\r\n            }\r\n\r\n            \/\/ 1. Supprimer les items 'anticipee' existants (non encore compl\u00e9t\u00e9s)\r\n            \/\/ \u2705 v2.6 : Si type='pays' et qu'un item anticipee pr\u00e9c\u00e9dent a un secteur,\r\n            \/\/           r\u00e9cup\u00e9rer ce secteur pour le transf\u00e9rer au nouvel item\r\n            \/\/ ====================================================================\r\n            \/\/ pb1023 : NE PAS PURGER LES ANTICIPEES QUAND LA CREATION EST EXPLICITE.\r\n            \/\/   Constat user (regie) : Homepage -> resa 1 OK ; lien vers Numerique ->\r\n            \/\/   resa 2 OK ; lien vers un article DANS Numerique -> la resa 2 DISPARAIT\r\n            \/\/   et remplacee par la resa 3. Resultat : 3 VLP pour 2 resas.\r\n            \/\/   Cause, montree par le log : creerReservationAnticipee supprime en tete\r\n            \/\/   TOUS les items de statut 'anticipee' (\"item anticipee precedent\r\n            \/\/   supprime: ...330762\"). Ce nettoyage date de v1.11 et vise le flux\r\n            \/\/   clic pays \/ clic secteur, ou l'anticipee precedente n'est qu'un\r\n            \/\/   BROUILLON qu'on remplace. Mais _viaCreateNouvelleReservation (bouton\r\n            \/\/   Ajouter, et clic sur un lien depuis un VLP via pb989) demande au\r\n            \/\/   contraire une resa SUPPLEMENTAIRE : il passe deja forceNew:true \u2014\r\n            \/\/   ce drapeau n'etait simplement jamais lu ici.\r\n            \/\/   Une resa creee depuis un VLP reste 'anticipee' tant qu'aucun espace\r\n            \/\/   pub n'est choisi : les resas 2 et 3 tombaient donc toutes deux dans\r\n            \/\/   le filtre, et la 3e effacait la 2e.\r\n            \/\/   Meme motif que pb1013 : un mecanisme ecrit pour un monde a une seule\r\n            \/\/   resa, devenu faux depuis la coexistence desktop.\r\n            \/\/   L'heritage de secteur (_prevSecteur) est desactive en meme temps : il\r\n            \/\/   lit l'anticipee precedente, qu'on ne considere plus comme un brouillon\r\n            \/\/   a reprendre. Le log montrait la resa 3 recuperant \"Numerique\", le\r\n            \/\/   secteur de la resa 2 \u2014 donnee etrangere a la page cliquee.\r\n            \/\/   Revert : window._viaPb1023Off = true.\r\n            \/\/ ====================================================================\r\n            var _forceNew1023 = (window._viaPb1023Off !== true)\r\n                ? (options.forceNew === true)\r\n                : false;\r\n            var _itemsAnticipes = _forceNew1023\r\n                ? []\r\n                : this.state.items.filter(function(i) { return i.statut === 'anticipee'; });\r\n            if (_forceNew1023) {\r\n                console.log('[pb1023] forceNew -> les r\u00e9sas anticip\u00e9es existantes sont CONSERV\u00c9ES ('\r\n                    + this.state.items.filter(function(i) { return i.statut === 'anticipee'; }).length\r\n                    + ' pr\u00e9serv\u00e9e(s))');\r\n            }\r\n            var _prevSecteur = null, _prevSecteurDisplay = null, _prevSecteurType = null;\r\n            if (options.type === 'pays') {\r\n                _itemsAnticipes.forEach(function(i) {\r\n                    if (i._anticipeSecteur || i.selectedPageSecteur) {\r\n                        _prevSecteur = i._anticipeSecteur || i.selectedPageSecteur;\r\n                        _prevSecteurDisplay = i._anticipeSecteurDisplay || i.selectedPageSecteurDisplayed || _prevSecteur;\r\n                        _prevSecteurType = i.selectedPageType || null;\r\n                    }\r\n                });\r\n                if (_prevSecteur) { console.log('\u2705 [creerReservationAnticipee] secteur r\u00e9cup\u00e9r\u00e9 de l\\'anticip\u00e9e pr\u00e9c\u00e9dente:', _prevSecteur); }\r\n            }\r\n            var self = this;\r\n            _itemsAnticipes.forEach(function(i) {\r\n                $('#' + i.id).remove();\r\n                self.state.items = self.state.items.filter(function(x) { return x.id !== i.id; });\r\n                console.log('\ud83d\uddd1\ufe0f [creerReservationAnticipee] item anticipee pr\u00e9c\u00e9dent supprim\u00e9:', i.id);\r\n            });\r\n\r\n            \/\/ 2. Masquer \"aucune commande\"\r\n            $('#MsgAucuneCommande').hide();\r\n\r\n            \/\/ \u2705 v2.6 : Pousser un placeholder dans state.items AVANT le await\r\n            \/\/ \u2192 creerCommandePartielle (d\u00e9clench\u00e9 par clic secteur rapide) trouve l'item via FB4\r\n            \/\/ et l'upgrade en 'partielle' avant que genererCodeUnique() soit r\u00e9solu\r\n            var _phId = 'anticipee_placeholder_' + Date.now();\r\n            this.state.items.push({ statut: 'anticipee', id: _phId });\r\n\r\n            \/\/ 3. G\u00e9n\u00e9rer r\u00e9f\u00e9rence partielle (sans codeSite\/codePage encore inconnus)\r\n            const codeUnique = await this.genererCodeUnique();\r\n            const referenceAnticipee = codeUnique + '-???-?????';\r\n\r\n            \/\/ \u2705 Retirer le placeholder par son ID sp\u00e9cifique\r\n            \/\/ Si FB4 l'a upgrad\u00e9 en 'partielle' entre-temps, il ne sera plus dans la liste\r\n            \/\/ (FB4 modifie l'objet in-place, mais il garde son id \u2192 on le retire uniquement\r\n            \/\/  si son statut est toujours 'anticipee', i.e. FB4 ne l'a pas encore upgrad\u00e9)\r\n            var _phItem = this.state.items.find(function(i) { return i.id === _phId; });\r\n            if (_phItem) {\r\n                if (_phItem.statut === 'partielle') {\r\n                    \/\/ FB4 l'a upgrad\u00e9 \u2014 ne pas supprimer, juste mettre \u00e0 jour l'id et la ref\r\n                    console.log('\u2705 [creerReservationAnticipee] placeholder upgrad\u00e9 par FB4 \u2014 poursuite avec item existant');\r\n                    return _phItem;\r\n                } else {\r\n                    \/\/ Pas encore upgrad\u00e9 \u2014 remplacer par le vrai item\r\n                    this.state.items = this.state.items.filter(function(i) { return i.id !== _phId; });\r\n                }\r\n            }\r\n\r\n            \/\/ 4. Cloner le template\r\n            const $template = $('#CampagneTemplate');\r\n            if ($template.length === 0) {\r\n                console.error('\u274c [creerReservationAnticipee] Template introuvable');\r\n                return null;\r\n            }\r\n\r\n            $template.find('#Etape1Container').remove();\r\n            const $newItem = $template.clone();\r\n            const itemId = 'CampagneTemplate_' + Date.now();\r\n\r\n            $template.css('display', 'none').hide();\r\n            $newItem.removeAttr('data-is-template');\r\n            $newItem.attr('id', itemId);\r\n            $newItem.attr('data-reference', referenceAnticipee);\r\n            $newItem.css('display', 'block').show();\r\n            $newItem[0].style.removeProperty('border');\r\n\r\n            \/\/ Nettoyer donn\u00e9es h\u00e9rit\u00e9es du template\r\n            $newItem.find('.CampagneTarifClass').html('').hide();\r\n            $newItem.find('.CampagnePaysSocieteClass').html('');\r\n            $newItem.find('.CampagneDatesClass').html('');\r\n            $newItem.find('.CampagneNbJours').html('');\r\n\r\n            \/\/ 5. Construire l'objet item minimal\r\n            \/\/ \u2705 v1.11 : format=null (secteur non confirm\u00e9, format sera re-s\u00e9lectionn\u00e9)\r\n            \/\/           linkSecteurPage=null (pas de page \u00e0 charger tant que pays+secteur incomplets)\r\n            var _fmt = null;\r\n            var _commandePage, _linkSecteurPage, _selectedPageSecteur, _selectedPageType;\r\n\r\n            if (options.type === 'pays') {\r\n                \/\/ \u2705 v2.6 : Si un secteur pr\u00e9c\u00e9dent existait (s\u00e9lection secteur\u2192pays), le conserver\r\n                _commandePage     = _prevSecteur ? (_prevSecteurType === 'HPType' ? 'Homepage' : 'Page sectorielle') : null;\r\n                _linkSecteurPage  = null;\r\n                _selectedPageSecteur = _prevSecteur || null;\r\n                _selectedPageType = _prevSecteurType || null;\r\n            } else {\r\n                \/\/ secteur s\u00e9lectionn\u00e9, pays inconnu\r\n                _commandePage     = options.secteurType === 'HPType' ? 'Homepage' : 'Page sectorielle';\r\n                _linkSecteurPage  = null;\r\n                _selectedPageSecteur = options.secteur || null;\r\n                _selectedPageType    = options.secteurType || null;\r\n            }\r\n\r\n            \/\/ pb669 (2e fabrique) : creerReservationAnticipee construit son PROPRE item.\r\n            \/\/   C'est CE chemin qui cree la resa 2 au clic pays\/secteur -> l'heritage\r\n            \/\/   pose dans creerNouvelItem ne s'y appliquait pas.\r\n            var _paysAnn669 = this._paysAnnonceurCommun669();\r\n            if (_paysAnn669) { console.log('[pb669] pays annonceur herite (anticipee) : ' + _paysAnn669); }\r\n\r\n            const item = {\r\n                id: itemId,\r\n                reference: referenceAnticipee,\r\n                espacepubId: null,\r\n                format: _fmt,\r\n                position: null,\r\n                emplacementPageWeb: null,\r\n                selectedPageType: _selectedPageType,\r\n                commandePage: _commandePage,\r\n                selectedPageSecteur: _selectedPageSecteur,\r\n                selectedPageSecteurDisplayed: options.secteurDisplay || _prevSecteurDisplay || null,\r\n                linkSecteurPage: _linkSecteurPage,\r\n                donneesIframe: null,\r\n                popUpChoice: sessionStorage.getItem('PopUpChoice') === 'Yes' ? 'Yes' : 'No',\r\n                \/\/ ============================================================\r\n                \/\/ pb1272 : item.pays NE DOIT PAS heriter du pays de l'ANNONCEUR.\r\n                \/\/   Constat user (capture) : la nouvelle reservation affiche\r\n                \/\/   \u00ab Communication associee au site France \u00bb \u2014 France est le pays\r\n                \/\/   de l'annonceur, pas un site pays. L'etape \u00ab Associer votre\r\n                \/\/   communication a des pays \u00bb se croit donc faite.\r\n                \/\/   Les deux champs ne designent pas la meme chose, et ce fichier\r\n                \/\/   le dit trente lignes plus bas : \u00ab .CampagnePaysClass [...] porte\r\n                \/\/   le pays du SITE \u00bb, a ne pas confondre avec\r\n                \/\/   .CampagnePaysSocieteClass. pb773 le confirme cote\r\n                \/\/   yearbook-media : \u00ab item.pays porte legitimement le pays du SITE ;\r\n                \/\/   le champ annonceur, lui, lit paysAnnonceur \u00bb.\r\n                \/\/   pb669 voulait heriter l'ANNONCEUR \u2014 il ecrivait les deux. Seul\r\n                \/\/   paysAnnonceur garde l'heritage ; le site repart vide, comme le\r\n                \/\/   secteur et le format.\r\n                \/\/   Revert : window._viaPb1272Off = true.\r\n                \/\/ ============================================================\r\n                pays: (window._viaPb1272Off === true) ? _paysAnn669 : null,\r\n                paysAnnonceur: _paysAnn669,\r\n                dateDebut: null, dateFin: null, duree: null,\r\n                tarifHT: null, tarifTTC: null, devise: 'EUR',\r\n                statut: 'anticipee',\r\n                \/\/ Contexte m\u00e9moris\u00e9 pour compl\u00e9tion ult\u00e9rieure\r\n                _anticipePays:         options.type === 'pays' ? (options.pays || null) : null,\r\n                _anticipePaysDisplay:  options.type === 'pays' ? (options.paysDisplay || null) : null,\r\n                _anticipeSecteur:      options.type === 'secteur' ? (options.secteur || null) : (_prevSecteur || null),\r\n                _anticipeSecteurDisplay: options.type === 'secteur' ? (options.secteurDisplay || null) : (_prevSecteurDisplay || null)\r\n            };\r\n\r\n            this.state.items.push(item);\r\n\r\n            \/\/ 6. Affichage minimal dans le clone DOM\r\n\r\n            \/\/ Pays affich\u00e9 (extrait du pays si type='pays', sinon '-' en attente)\r\n            var _paysRaw = options.type === 'pays' ? (options.pays || '-') : '-';\r\n            var _paysLabel = typeof formatPaysDisplay === 'function'\r\n                ? formatPaysDisplay(_paysRaw)\r\n                : _paysRaw.replace('-en', ' english');\r\n            $newItem.find('[id=\"CampagnePaysTexte\"], .CampagnePaysClass').html(_paysLabel);\r\n\r\n            \/\/ pb669 : reafficher le pays ANNONCEUR herite (le nettoyage du clone,\r\n            \/\/   plus haut, vide .CampagnePaysSocieteClass). A ne pas confondre avec\r\n            \/\/   .CampagnePaysClass juste au-dessus, qui porte le pays du SITE.\r\n            if (_paysAnn669) { $newItem.find('.CampagnePaysSocieteClass').html(_paysAnn669); }\r\n\r\n            \/\/ Page \/ secteur\r\n            var $_pt = $newItem.find('#CampagnePageText, .CampagnePageTextClass').first();\r\n            if (options.type === 'pays') {\r\n                $_pt.html('<em style=\"color:#aaa;font-size:11px;\">\u2014 s\u00e9lectionner un secteur \u2014<\/em>');\r\n            } else {\r\n                $_pt.html(options.secteurDisplay || options.secteur || '...');\r\n            }\r\n\r\n            \/\/ Format si d\u00e9j\u00e0 s\u00e9lectionn\u00e9\r\n            var $_fmtEl = $newItem.find('.CampagneFormatClass');\r\n            if (_fmt) {\r\n                $_fmtEl.find('p').text(_translateFormatLabel(_fmt));\r\n                \/\/ \u2705 v4.9ds+ (suite 6) Pb format mal positionn\u00e9 en popup achat sites pays :\r\n                \/\/   outerWidth refl\u00e8te la taille \u00e9cran physique (pas le viewport iframe),\r\n                \/\/   donc order=5 s'applique \u00e0 tort dans le popup \u00e9troit. Force order=0\r\n                \/\/   en popup achat \u2192 format reprend sa position DOM naturelle.\r\n                var _isPopupAchatN = document.body.classList.contains('via-popup-achat');\r\n                var _orderValN = _isPopupAchatN ? '0' : (window.outerWidth >= 1000 ? '5' : '0');\r\n                $_fmtEl.show(); if ($_fmtEl[0]) { $_fmtEl[0].style.setProperty('order', _orderValN, 'important'); $_fmtEl[0].style.setProperty('width','auto','important'); }\r\n            } else {\r\n                $_fmtEl.hide();\r\n            }\r\n\r\n            \/\/ Masquer les champs non disponibles\r\n            $newItem.find('.CampagneNoClass').hide();\r\n            $newItem.find('.CampagnePositionClass').hide();\r\n            $newItem.find('.CampagneReferenceClass').hide();\r\n            $newItem.find('.CampagneEnvoiUlterieurClass').hide();\r\n            $newItem.find('.CampagneAnnonceDeposeClass').hide();\r\n            $newItem.find('.CampagneDatesClass').html('-');\r\n            $newItem.find('.CampagneNbJours').html('-');\r\n            $newItem.find('.CampagnePaysSocieteClass').html('-');\r\n            $newItem.find('.CampagneTarifClass').html('-').hide();\r\n            \/\/ \u2705 v1.11 \/ v2.6 : .CampagnePageText \u2014 masqu\u00e9 si pays-only sans secteur, affich\u00e9 si secteur connu\r\n            if (options.type === 'pays' && !_prevSecteur) {\r\n                $newItem.find('.CampagnePageTextClass, #CampagnePageText').hide();\r\n            } else {\r\n                \/\/ type='secteur' OU type='pays' avec secteur r\u00e9cup\u00e9r\u00e9\r\n                var $_ptAnticipe = $newItem.find('#CampagnePageText, .CampagnePageTextClass').first();\r\n                var _secteurLabel = options.type === 'secteur'\r\n                    ? (options.secteurDisplay || options.secteur || '')\r\n                    : (_prevSecteurDisplay || _prevSecteur || '');\r\n                $_ptAnticipe.html(_secteurLabel).show();\r\n            }\r\n            \/\/ \u2705 v1.11 : Pour type='secteur', pays inconnu \u2192 masquer le pays (\"-\" inesth\u00e9tique)\r\n            if (options.type === 'secteur') {\r\n                $newItem.find('[id=\"CampagnePaysTexte\"], .CampagnePaysClass').html('').hide();\r\n            }\r\n\r\n            \/\/ 7. Ins\u00e9rer dans le conteneur\r\n            const $conteneur = $(this.config.conteneurParent).first();\r\n            if ($conteneur.length === 0) {\r\n                console.error('\u274c [creerReservationAnticipee] Conteneur parent introuvable');\r\n                return null;\r\n            }\r\n            $conteneur.append($newItem);\r\n            $('#CampagneTemplate').hide();\r\n\r\n            \/\/ \u2705 v4.9ds+ (suite 8) Pb 1 : injecter la croix Supprimer .CampagneCloseButton\r\n            \/\/   d\u00e8s la cr\u00e9ation de l'item anticip\u00e9 (Nouvelle r\u00e9servation). M\u00eame logique que\r\n            \/\/   remplirItemPartiel (lignes ~2834+) \u2014 le user veut pouvoir supprimer une r\u00e9sa\r\n            \/\/   non encore finalis\u00e9e. Le handler click '.CampagneCloseButton' (ligne 5773) est\r\n            \/\/   d\u00e9l\u00e9gu\u00e9 via $(document).on, donc op\u00e9rationnel sur ce bouton dynamique.\r\n            if (!$newItem.find('.CampagneCloseButton').length) {\r\n                var _svgCloseA = '<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><line x1=\"2\" y1=\"2\" x2=\"10\" y2=\"10\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"\/><line x1=\"10\" y1=\"2\" x2=\"2\" y2=\"10\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"\/><\/svg>';\r\n                var $btnCloseA = $('<button type=\"button\" class=\"CampagneCloseButton\" aria-label=\"Supprimer\" title=\"Supprimer\">' + _svgCloseA + '<\/button>');\r\n                $newItem.append($btnCloseA);\r\n            }\r\n            \/\/ pb206 : injecter aussi le picto \"S\u00e9lectionner\" d\u00e8s la cr\u00e9ation de l'item\r\n            \/\/   (anticip\u00e9\/nouvelle r\u00e9servation). Sans \u00e7a il n'apparaissait qu'apr\u00e8s le choix\r\n            \/\/   d'un format (via remplirItemPartiel\/Complet) \u2192 absent sur une r\u00e9sa toute\r\n            \/\/   neuve (cf capture).\r\n            if ((window._viaPb931Off === true) && !$newItem.find('.via-selectionner-btn').length) {\r\n                var _svgSelectA = '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><rect x=\"2.5\" y=\"2.5\" width=\"19\" height=\"19\" rx=\"3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.83\"\/><path d=\"M7 12.5 L10.5 16 L17 8.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.83\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg>';\r\n                var $btnSelectA = $('<button type=\"button\" class=\"via-selectionner-btn\" aria-label=\"S\u00e9lectionner\" title=\"S\u00e9lectionner\">' + _svgSelectA + '<\/button>');\r\n                var $closeRefA = $newItem.find('.CampagneCloseButton').first();\r\n                if ($closeRefA.length) { $closeRefA.before($btnSelectA); } else { $newItem.prepend($btnSelectA); }\r\n            }\r\n            \/\/ pb222 : injecter aussi le picto \"R\u00e9duire\" d\u00e8s la cr\u00e9ation de l'item anticip\u00e9.\r\n            \/\/   Il n'\u00e9tait jamais inject\u00e9 ici (seulement remplirItemPartiel\/Complet) \u2192 absent\r\n            \/\/   au clic AutreCommandeBouton. Plac\u00e9 entre S\u00e9lectionner et la Croix.\r\n            if (!$newItem.find('.via-reduire-btn').length) {\r\n                var _svgReduireA = '<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><line x1=\"2\" y1=\"10.5\" x2=\"12\" y2=\"10.5\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"\/><\/svg>';\r\n                var _svgAgrandirA = '<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><rect x=\"1.5\" y=\"1.5\" width=\"9\" height=\"9\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg>';\r\n                var $btnReducerA = $('<button type=\"button\" class=\"via-reduire-btn\" aria-label=\"R\u00e9duire\" title=\"R\u00e9duire\" data-via-svg-reduire=\"' + encodeURIComponent(_svgReduireA) + '\" data-via-svg-agrandir=\"' + encodeURIComponent(_svgAgrandirA) + '\">' + _svgReduireA + '<\/button>');\r\n                var $closeRefA2 = $newItem.find('.CampagneCloseButton').first();\r\n                if ($closeRefA2.length) { $closeRefA2.before($btnReducerA); } else { $newItem.prepend($btnReducerA); }\r\n            }\r\n\r\n            \/\/ 8. Message d'accompagnement anticip\u00e9\r\n            this.ajouterMsgAccompagnement($newItem, {\r\n                statut: 'anticipee',\r\n                anticipeeType: options.type\r\n            });\r\n\r\n            \/\/ 9. Activer l'item + afficher ProcessCommande\r\n            this.setItemActif(itemId);\r\n            $('#ProcessCommande').show();\r\n\r\n            console.log('\u2705 [creerReservationAnticipee] item cr\u00e9\u00e9:', itemId, '| type:', options.type, '| statut: anticipee');\r\n            return item;\r\n        },\r\n\r\n        \/**\r\n         * Remplit l'affichage d'une commande partielle\r\n         *\/\r\n        \/\/ \u2705 v2.4.3 : Message d'accompagnement dans les items du r\u00e9capitulatif\r\n        \/\/ \u2705 v4.9ds : R\u00c9ACTIV\u00c9E \u2014 l'utilisateur veut les messages d'accompagnement\r\n        \/\/   (\"Merci de faire un choix d'espace publicitaire dans la page s\u00e9lectionn\u00e9e\"\r\n        \/\/   notamment) qui ne s'affichaient plus. D\u00e9sactivation ant\u00e9rieure (Pb 5)\r\n        \/\/   annul\u00e9e. Demande user.\r\n        ajouterMsgAccompagnement($item, opts) {\r\n            \/\/ pb1488 : annonce deposee -> plus de message d'accompagnement.\r\n            \/\/   Le remove() ci-dessous existe deja dans la fonction ; on le fait\r\n            \/\/   ici AVANT de sortir, sinon un message pose a la passe precedente\r\n            \/\/   resterait affiche indefiniment.\r\n            try {\r\n                var _it1488 = (opts ? opts.item : null);\r\n                if (!_it1488) {\r\n                    if ($item ? $item.length : false) {\r\n                        var _id1488 = $item.attr('data-item-id') || $item.attr('id') || '';\r\n                        if (_id1488) {\r\n                            if (this.state ? this.state.items : null) {\r\n                                for (var _k1488 = 0; _k1488 < this.state.items.length; _k1488++) {\r\n                                    if (this.state.items[_k1488].id === _id1488) { _it1488 = this.state.items[_k1488]; }\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n                if (_it1488) {\r\n                    if (this._annonceDeposee1488(_it1488)) {\r\n                        if ($item ? $item.length : false) {\r\n                            var $m1488 = $item.find('.CampagneMsgAccompagnement');\r\n                            if ($m1488.length) {\r\n                                $m1488.remove();\r\n                                console.log('[pb1488] message d\\'accompagnement retire (annonce deposee)');\r\n                            }\r\n                        }\r\n                        return;\r\n                    }\r\n                }\r\n            } catch (_e1488) {\r\n                console.warn('[pb1488] garde msg accompagnement : ' + _e1488.message);\r\n            }\r\n            \/\/ Supprimer un \u00e9ventuel message pr\u00e9c\u00e9dent\r\n            $item.find('.CampagneMsgAccompagnement').remove();\r\n\r\n            \/\/ \u2705 v1.11 : Item anticip\u00e9 \u2192 message d'invitation sp\u00e9cifique (bypass du guard espace)\r\n            \/\/ \u2705 v4.9ds : message dynamique selon ce qui est d\u00e9j\u00e0 s\u00e9lectionn\u00e9 en sessionStorage.\r\n            \/\/   Composer la liste des \u00e9l\u00e9ments manquants parmi : pays, secteur, format.\r\n            \/\/   Toutes les combinaisons :\r\n            \/\/   - aucun s\u00e9lectionn\u00e9  \u2192 \"Merci de s\u00e9lectionner un pays, un secteur et un format\"\r\n            \/\/   - pays seul          \u2192 \"Merci de s\u00e9lectionner un secteur et un format\"\r\n            \/\/   - secteur seul       \u2192 \"Merci de s\u00e9lectionner un pays et un format\"\r\n            \/\/   - format seul        \u2192 \"Merci de s\u00e9lectionner un pays et un secteur\"\r\n            \/\/   - pays + secteur     \u2192 \"Merci de s\u00e9lectionner un format\"\r\n            \/\/   - pays + format      \u2192 \"Merci de s\u00e9lectionner un secteur\"\r\n            \/\/   - secteur + format   \u2192 \"Merci de s\u00e9lectionner un pays\"\r\n            \/\/   - tous s\u00e9lectionn\u00e9s  \u2192 pas de message (return)\r\n            \/\/   Demande user.\r\n            if (opts.statut === 'anticipee') {\r\n                var _isEN_A = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                var _hasPaysA = !!sessionStorage.getItem('ContinentPaysTitre');\r\n                \/\/ pb843 : un ARTICLE est un choix de page valide, au meme titre qu'un\r\n                \/\/   secteur \u2014 la cle SelectedPageSecteur reste vide dans ce cas, et le\r\n                \/\/   message reclamait \"un secteur\" alors qu'un article etait choisi.\r\n                \/\/   Memes marqueurs que pb792, qui traitait le meme oubli sur l'aplat.\r\n                \/\/   Revert : window._viaPb843Off = true.\r\n                var _hasSecteurA = !!sessionStorage.getItem('SelectedPageSecteur');\r\n                if (!_hasSecteurA ? (window._viaPb843Off !== true) : false) {\r\n                    if (sessionStorage.getItem('Commande_Article')) { _hasSecteurA = true; }\r\n                    else if (sessionStorage.getItem('SelectedPageType') === 'ArtType') { _hasSecteurA = true; }\r\n                    if (_hasSecteurA) {\r\n                        console.log('[pb843] page = ARTICLE -> le critere secteur est satisfait');\r\n                    }\r\n                }\r\n                var _hasFormatA = !!sessionStorage.getItem('FormatSelect');\r\n                var _missingA = [];\r\n                if (!_hasPaysA)    { _missingA.push(_isEN_A ? 'a country' : 'un pays'); }\r\n                if (!_hasSecteurA) { _missingA.push(_isEN_A ? 'a sector'  : 'un secteur'); }\r\n                if (!_hasFormatA)  { _missingA.push(_isEN_A ? 'a format'  : 'un format'); }\r\n                if (_missingA.length === 0) {\r\n                    \/\/ Tout s\u00e9lectionn\u00e9 \u2014 pas de message anticip\u00e9e. Sera remplac\u00e9 par\r\n                    \/\/ \"Merci de faire un choix d'espace publicitaire...\" quand la\r\n                    \/\/ r\u00e9sa passe en 'partielle' avec PageWeb charg\u00e9e.\r\n                    return;\r\n                }\r\n                var _msgAnticipe;\r\n                if (_missingA.length === 1) {\r\n                    _msgAnticipe = (_isEN_A ? 'Please select ' : 'Merci de s\u00e9lectionner ') + _missingA[0];\r\n                } else if (_missingA.length === 2) {\r\n                    _msgAnticipe = (_isEN_A ? 'Please select ' : 'Merci de s\u00e9lectionner ') + _missingA[0] + (_isEN_A ? ' and ' : ' et ') + _missingA[1];\r\n                } else {\r\n                    \/\/ 3 manquants\r\n                    _msgAnticipe = (_isEN_A ? 'Please select ' : 'Merci de s\u00e9lectionner ') + _missingA[0] + ', ' + _missingA[1] + (_isEN_A ? ' and ' : ' et ') + _missingA[2];\r\n                }\r\n                \/\/ \u2705 Pb 1 : titre \"Nouvelle r\u00e9servation\" inject\u00e9 au-dessus du message d'accompagnement\r\n                \/\/   uniquement quand AUCUN champ n'est encore s\u00e9lectionn\u00e9 (_missingA.length === 3).\r\n                \/\/   D\u00e8s qu'un pays, secteur ou format est choisi \u2192 titre supprim\u00e9.\r\n                \/\/   Rouge, 14px\/700, d\u00e9cal\u00e9 5px vers le bas. FR + EN selon SiteLangue.\r\n                \/\/ \u2705 v4.9ds+ (suite 8) Pb 1 : margin-top conditionnel selon le mode colonnes :\r\n                \/\/   - 3 cols (PageWeb ouverte, sessionStorage PageWebColonneOpenclose==='Open') :\r\n                \/\/     0px (compact) pour que le bloc ne chevauche pas le liser\u00e9 inf\u00e9rieur quand\r\n                \/\/     l'item est r\u00e9duit.\r\n                \/\/   - 2 cols (PageWeb ferm\u00e9e) : 9px (valeur originale, espace normal).\r\n                var _is3ColNR = sessionStorage.getItem('PageWebColonneOpenclose') === 'Open';\r\n                var _mtTitleNR = _is3ColNR ? '0px' : '9px';\r\n                var _titreNR = (_missingA.length === 3)\r\n                    ? '<div class=\"via-nouvelle-resa-titre\" style=\"font-size:12px;font-weight:700;margin-top:' + _mtTitleNR + ';margin-bottom:3px;\">'  \/* pb224 : 14px -> 12px + classe marqueur *\/\r\n                        + (_isEN_A ? 'New reservation' : 'Nouvelle r\u00e9servation')\r\n                        + '<\/div>'\r\n                    : '';\r\n                var _mtMsgAnticipe = (window.outerWidth < 1000) ? '7px' : '9px';\r\n                var $msgAnticipe = $('<div class=\"CampagneMsgAccompagnement\" style=\"color:#FB5E2A;font-size:11px;font-weight:600;text-align:center;margin-top:' + _mtMsgAnticipe + ';padding:2px 6px;line-height:1.4;max-width:100%;margin-left:auto;margin-right:auto;\">'\r\n                    + _titreNR\r\n                    + _msgAnticipe\r\n                    + '<\/div>');\r\n                var $anchorA = $item.find('.CampagnePageRefClass');\r\n                if ($anchorA.length) { $anchorA.after($msgAnticipe); } else { $item.append($msgAnticipe); }\r\n                \/\/ pb77 : le CSS [data-via-reduit=\"true\"] .CampagneMsgAccompagnement { margin:4px auto 0 !important }\r\n                \/\/   \u00e9crase l'inline sans !important. On force via setProperty apr\u00e8s stabilisation.\r\n                var _msgAnticipeEl = $msgAnticipe[0];\r\n                if (_msgAnticipeEl) {\r\n                    [0, 150, 400].forEach(function(_t) {\r\n                        setTimeout(function() {\r\n                            if (_msgAnticipeEl) { _msgAnticipeEl.style.setProperty('margin-top', _mtMsgAnticipe, 'important'); }\r\n                        }, _t);\r\n                    });\r\n                }\r\n                return;\r\n            }\r\n\r\n            var _msg = '';\r\n            \/\/ \u2705 v2.4.7 : Pas d'espace s\u00e9lectionn\u00e9 \u2192 message d'invitation dans l'item (remplace #RecapInfoEspaceMessage global)\r\n            if (!opts.espace) {\r\n                \/\/ ============================================================\r\n                \/\/ pb1374 : DOUBLON avec l'invite de pb1262 (demande user).\r\n                \/\/   La carte affichait deux fois la meme consigne : \u00ab Choisir les\r\n                \/\/   espaces publicitaires dans la page selectionnee \u00bb en tete\r\n                \/\/   (.via-invite-haut-1262, pb1262) et \u00ab Merci de choisir des\r\n                \/\/   espaces publicitaires dans la page selectionnee \u00bb en bas (ici).\r\n                \/\/   pb1262 est posterieur et mieux place \u2014 en tete de carte, la ou\r\n                \/\/   l'utilisateur regarde. On retire celui-ci plutot que l'autre.\r\n                \/\/   On sort AVANT de construire le message : rien n'est ajoute au\r\n                \/\/   DOM, donc rien a retirer ensuite.\r\n                \/\/   Revert : window._viaPb1374Off = true.\r\n                \/\/ ============================================================\r\n                if (window._viaPb1374Off !== true) {\r\n                    if (window._viaSig1374 !== true) {\r\n                        window._viaSig1374 = true;\r\n                        console.log('[pb1374] message d\\'accompagnement \u00ab choisir des espaces \u00bb'\r\n                            + ' non pos\u00e9 \u2014 doublon de l\\'invite pb1262');\r\n                    }\r\n                    return;\r\n                }\r\n                var _langNE = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                var _msgNE = _langNE === 'EN'\r\n                    ? 'Please select an advertising space on the displayed page'\r\n                    \/\/ pb956 : nouveau libelle (demande user).\r\n                    : \"Merci de choisir des espaces publicitaires dans la page s\u00e9lectionn\u00e9e\";\r\n                var $msgNE = $('<div class=\"CampagneMsgAccompagnement\" style=\"color:#FB5E2A;font-size:11px;font-weight:600;text-align:center;margin-top:4px;padding:2px 6px;line-height:1.4;max-width:100%;margin-left:auto;margin-right:auto;\">' + _msgNE + '<\/div>');\r\n                var $anchorNE = $item.find('.CampagnePageRefClass');\r\n                if ($anchorNE.length) { $anchorNE.after($msgNE); } else { $item.append($msgNE); }\r\n                return;\r\n            }\r\n            if (!opts.estReserve) {\r\n                \/\/ \u2705 v4.9ds Fix 24 : sur les sites pays (= popup achat, pas r\u00e9gie),\r\n                \/\/   l'item \"\u00c0 r\u00e9server\" ne doit PAS afficher le message d'accompagnement\r\n                \/\/   \"Merci de r\u00e9server l'espace publicitaire\" \u2014 la checkbox cliquable\r\n                \/\/   ajout\u00e9e dans .CampagneNoClass (Fix 19) remplit ce r\u00f4le de guidage.\r\n                \/\/   Sur la r\u00e9gie (via-from-regie), comportement inchang\u00e9.\r\n                \/\/   IMPORTANT : ce skip s'applique UNIQUEMENT \u00e0 l'\u00e9tat \"\u00e0 r\u00e9server\"\r\n                \/\/   (aReserver=true). Quand la r\u00e9servation devient effective\r\n                \/\/   (estReserve=true), on n'entre plus dans cette branche du if et le\r\n                \/\/   message s'affiche normalement (cf else if ligne 1996+ : message\r\n                \/\/   \"Merci de choisir dates...\" si tarif absent, ou pas de message si\r\n                \/\/   tarif pr\u00e9sent \u2014 comportement standard non modifi\u00e9).\r\n                var _isRegieF24 = document.documentElement.classList.contains('via-from-regie');\r\n                if (opts.aReserver === true ? !_isRegieF24 : false) {\r\n                    return;\r\n                }\r\n                \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction : message \"Merci de r\u00e9server\" en EN\r\n                var _isEN_RES = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                _msg = _isEN_RES\r\n                    ? 'Please reserve the advertising space'\r\n                    : 'Merci de r\u00e9server l\\'espace publicitaire';\r\n            } else if (!opts.tarifHT) {\r\n                \/\/ v4.9ds : si l'item est en mode \"\u00c0 r\u00e9server\" (anticip\u00e9e\/partielle non\r\n                \/\/   encore r\u00e9serv\u00e9e effectivement), ne PAS afficher le message tarif\r\n                \/\/   manquant \u2014 demande user. Le titre indique d\u00e9j\u00e0 \"A r\u00e9server\" en orange,\r\n                \/\/   ce qui suffit comme feedback. Le message reste affich\u00e9 pour les\r\n                \/\/   r\u00e9servations effectives qui n'ont pas encore de tarif (cas o\u00f9 user\r\n                \/\/   doit saisir dates+pays).\r\n                if (opts.aReserver === true) {\r\n                    return;\r\n                }\r\n                \/\/ v4.9ds : message tarif manquant raccourci pour gain de place\r\n                \/\/ \u2705 v4.9ds+ Pb 3 (EN) : traduction du message tarif manquant\r\n                var _isEN_MSG = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                _msg = _isEN_MSG\r\n                    ? 'Please select campaign dates to get a price'\r\n                    : 'Merci de choisir les dates de campagne pour un tarif';\r\n            }\r\n\r\n            if (!_msg) {\r\n                \/\/ Tarif pr\u00e9sent \u2192 s'assurer que tout message r\u00e9siduel est masqu\u00e9\r\n                $item.find('.CampagneMsgAccompagnement').hide();\r\n                return;\r\n            }\r\n\r\n            \/\/ pb122 : marquer le div message avec via-msg-dates UNIQUEMENT si le texte est le\r\n            \/\/   message dates (FR ou EN) \u2192 le chevron ::before ne s'affiche que pour ce message.\r\n            var _isDateMsg122 = (_msg === 'Merci de choisir les dates de campagne pour un tarif')\r\n                ? true\r\n                : (_msg === 'Please select campaign dates to get a price');\r\n\r\n            var $msg = $('<div class=\"CampagneMsgAccompagnement' + (_isDateMsg122 ? ' via-msg-dates' : '') + '\" style=\"color:#FB5E2A;font-size:11px;font-weight:600;text-align:center;margin-top:4px;padding:2px 6px;line-height:1.4;max-width:100%;margin-left:auto;margin-right:auto;\">' + _msg + '<\/div>');\r\n            var $anchor = $item.find('.CampagnePageRefClass');\r\n            if ($anchor.length) {\r\n                $anchor.after($msg);\r\n            } else {\r\n                $item.append($msg);\r\n            }\r\n        },\r\n\r\n        remplirItemPartiel($item, item) {\r\n            console.log('\ud83d\udd04 Remplissage item partiel...');\r\n            \r\n            \/\/ \u2705 v4.9ds : restaurer .CampagnePageRefClass masqu\u00e9 par #AutreCommandeBouton.\r\n            \/\/   Le clic AutreCommandeBouton (yearbook-media.js:18195) masque CampagnePageRefClass\r\n            \/\/   pour afficher le placeholder \"Vous pouvez choisir un autre espace pub...\".\r\n            \/\/   Une fois l'item rempli (pays\/secteur\/format\/espace s\u00e9lectionn\u00e9s), il faut\r\n            \/\/   le r\u00e9afficher pour montrer les donn\u00e9es. Demande user.\r\n            $item.find('.CampagnePageRefClass').each(function() {\r\n                if (this.style.display === 'none') {\r\n                    this.style.removeProperty('display');\r\n                }\r\n            });\r\n            \/\/ Restaurer aussi min-height + position du conteneur item (pos\u00e9s par AutreCommandeBouton)\r\n            if ($item.length && $item[0].style) {\r\n                $item[0].style.removeProperty('min-height');\r\n                $item[0].style.removeProperty('position');\r\n            }\r\n            \r\n            \/\/ 1. CampagneNoClass \u2014 r\u00e8gles :\r\n            \/\/    - Option cr\u00e9\u00e9e sans espace \u2192 cach\u00e9\r\n            \/\/    - Annonce d\u00e9pos\u00e9e OU envoi diff\u00e9r\u00e9 \u2192 \"Espace publicitaire ESPACE\"\r\n            \/\/    - R\u00e9serv\u00e9 \u2192 g\u00e9r\u00e9 dans remplirItemComplet\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const _espacePartiel = (item.donneesIframe && item.donneesIframe.Commande_Emplacement_Page_Web)\r\n                ? item.donneesIframe.Commande_Emplacement_Page_Web\r\n                : (item.emplacementPageWeb || '');\r\n            const _hasAnnoncePartiel = item.donneesIframe\r\n                && (item.donneesIframe.FileReceived === 'Yes'\r\n                    || item.donneesIframe.EnvoiUlterieur === 'true'\r\n                    || item.donneesIframe.EnvoiUlterieur === true)\r\n                && _espacePartiel;\r\n            \/\/ v4.9ds (estReserveEffective) : \"r\u00e9serv\u00e9\" UNIQUEMENT si flag explicite pos\u00e9\r\n            \/\/   \u00e0 la r\u00e9servation effective (clic R\u00e9server) ou statut === 'complete'.\r\n            \/\/   AVANT : `!!emplacementPageWeb || statut==='complete'` \u2192 faux positif\r\n            \/\/   car emplacementPageWeb est pos\u00e9 \u00e0 tort d\u00e8s qu'un emplacement est connu\r\n            \/\/   (yearbook-media.js:1311), m\u00eame sans clic R\u00e9server.\r\n            const _isReservedPartiel = item.estReserveEffective === true || item.statut === 'complete';\r\n            \/\/ \u2705 v4.9ds Fix 26 : poser data-via-areserver sur l'item \u2014 utilis\u00e9 en CSS pour\r\n            \/\/   ajouter un padding-bottom de 3px \u00e0 .CampagneEnvoiUlterieurClass uniquement\r\n            \/\/   sur les items \"\u00e0 r\u00e9server\" sites pays (cf CSS ligne ~340). Retir\u00e9\r\n            \/\/   automatiquement quand la r\u00e9sa devient effective (data-via-areserver=\"false\").\r\n            $item.attr('data-via-areserver', _isReservedPartiel ? 'false' : 'true');\r\n            \/\/ \u2705 pb220 T3 : desktop, popup achat site pays, item \u00c0 R\u00c9SERVER, \u00e0 sa 1re prise\r\n            \/\/   en compte \u2192 d\u00e9caler les textes bleus de 5px vers le bas (classe\r\n            \/\/   via-blue-shift-220 + r\u00e8gle CSS). Pos\u00e9 ICI (et non dans setItemActif) car\r\n            \/\/   remplirItemPartiel est le dernier maillon du flux : data-via-areserver n'est\r\n            \/\/   pos\u00e9 qu'ici, apr\u00e8s les setItemActif. Flag data-via-first-active-done \u2192 1 fois.\r\n            (function() {\r\n                if (_isReservedPartiel) { return; }\r\n                if (window.outerWidth < 1000) { return; }\r\n                if (!document.body.classList.contains('via-popup-achat')) { return; }\r\n                if ($item[0].getAttribute('data-via-first-active-done') === '1') { return; }\r\n                $item[0].setAttribute('data-via-first-active-done', '1');\r\n                $item[0].classList.add('via-blue-shift-220');\r\n                \/\/ Diag : lister la structure r\u00e9elle des lignes bleues de l'item.\r\n                var _refEl = $item[0].querySelector('.CampagnePageRefClass');\r\n                console.log('[pb220 T3 diag2] CampagnePageRefClass pr\u00e9sent:', !!_refEl,\r\n                    '| son HTML (200c):', _refEl ? _refEl.outerHTML.substring(0,200) : 'N\/A');\r\n                var _allBlue = $item[0].querySelectorAll('.CampagnePageRefClass, .CampagnePaysClass, .CampagneFormatClass, .CampagnePageTextClass, .CampagneSecteurClass');\r\n                console.log('[pb220 T3 diag2] elements bleus:', _allBlue.length);\r\n                _allBlue.forEach(function(_b, _i) {\r\n                    var _cs = window.getComputedStyle(_b);\r\n                    console.log('  [' + _i + '] class=' + _b.className.substring(0,60) + ' | transform=' + _cs.transform + ' | inlineTransform=' + (_b.style.transform || '(none)'));\r\n                });\r\n            })();\r\n            \/\/ v4.9ds : .CampagneNoClass \u2014 texte FR \"Espace r\u00e9serv\u00e9\" (au lieu de \"Espace publicitaire r\u00e9serv\u00e9\")\r\n            \/\/   + retrait du span font-size:12px sur la ref \u2192 la ref h\u00e9rite de la taille du parent.\r\n            \/\/   EN inchang\u00e9. Cas non-r\u00e9serv\u00e9 conserv\u00e9 tel quel (\"Espace publicitaire \").\r\n            \/\/   \u2705 reservationEnAttente : pos\u00e9 par resetDonneesCampagne (changement pays\/secteur\/format)\r\n            \/\/   \u2192 l'item est \"r\u00e9serv\u00e9\" mais en cours de modification \u2192 montrer \"Espace publicitaire\"\r\n            \/\/   (plus \"r\u00e9serv\u00e9\") jusqu'\u00e0 ce qu'un nouvel espace pub soit s\u00e9lectionn\u00e9.\r\n            var _reservationEnAttente = (item.reservationEnAttente === true);\r\n            \/\/ \u2705 reservationEnAttente = \u00e9tat transitoire (pays\/secteur\/format chang\u00e9, pas encore re-r\u00e9serv\u00e9).\r\n            \/\/   Quand l'item est effectivement r\u00e9serv\u00e9 (_isReservedPartiel=true), le flag est ignor\u00e9 :\r\n            \/\/   label \"r\u00e9serv\u00e9\" + emplacement doivent toujours s'afficher.\r\n            const _labelEspacePartiel = _isReservedPartiel\r\n                ? (lang === 'EN' ? 'Reserved advertising space ' : 'Espace r\u00e9serv\u00e9 ')\r\n                : (lang === 'EN' ? 'Advertising space ' : 'Espace publicitaire ');\r\n            const $_noClass1 = $item.find('.CampagneNoClass');\r\n            \/\/ v4.9ds : afficher le label aussi si l'item est r\u00e9serv\u00e9 (clic R\u00e9server direct\r\n            \/\/   sur Ele1A+ sans upload effectif ni envoi diff\u00e9r\u00e9). Sans \u00e7a, le sc\u00e9nario\r\n            \/\/   \"drag image dans Ele1A + clic R\u00e9server\" laissait CampagneNoClass masqu\u00e9 :\r\n            \/\/   _hasAnnoncePartiel=false (FileReceived=No, EnvoiUlterieur=null) \u2192 hide alors\r\n            \/\/   que l'item est bien estReserveEffective=true.\r\n            \/\/ v4.9ds : pour Ele0A (emplacement se terminant par \"L0A\"), ins\u00e9rer \" Pop-up \"\r\n            \/\/   avant l'emplacement \u2192 \"Espace r\u00e9serv\u00e9 Pop-up MDG48442L0A\"\r\n            \/\/   v4.9ds : si non r\u00e9serv\u00e9, ajouter \" A r\u00e9server\" en #fb5e2a apr\u00e8s la r\u00e9f\u00e9rence\r\n            const _isEle0APartiel = \/L0A$\/.test(_espacePartiel);\r\n            const _emplAvecPopupP = _isEle0APartiel ? ('Pop-up ' + _espacePartiel) : _espacePartiel;\r\n            \/\/ \u2705 reservationEnAttente : l'ancienne r\u00e9f\u00e9rence est effac\u00e9e \u2014 ne pas l'afficher.\r\n            \/\/   L'emplacement sera remplac\u00e9 par le nouvel espace pub choisi par l'utilisateur.\r\n            \/\/ Masquer l'emplacement uniquement dans l'\u00e9tat transitoire (avant nouvelle r\u00e9servation)\r\n            const _emplToShowP = (_reservationEnAttente && !_isReservedPartiel) ? '' : _emplAvecPopupP;\r\n            \/\/ \u2705 v4.9ds Fix 19 (Pb 14) : ajouter une checkbox cliquable juste apr\u00e8s \"A r\u00e9server\"\r\n            \/\/   pour permettre \u00e0 l'utilisateur de r\u00e9server directement depuis le r\u00e9cap sans\r\n            \/\/   avoir \u00e0 retourner sur l'espace pub. Au change \u2192 postMessage qui cible la\r\n            \/\/   vraie checkbox dans la page pays (cf handler change global ci-dessous +\r\n            \/\/   listener c\u00f4t\u00e9 Entete.txt).\r\n            const _rankPartielFix19 = item.donneesIframe ? (item.donneesIframe.Rank_Emplacement_Page_Web || '') : '';\r\n            \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction : \"\u00e0 r\u00e9server\" + tooltip en EN\r\n            \/\/   margin-left:3px en EN car \"to be reserved\" commence par 't' (coll\u00e9 visuellement\r\n            \/\/   \u00e0 la ref) alors que \"\u00e0 r\u00e9server\" a l'accent qui cr\u00e9e un blanc naturel.\r\n            var _isEN_P = lang === 'EN';\r\n            var _spanAReserverP = _isEN_P\r\n                ? ' <span style=\"color:#fb5e2a;margin-left:3px;\">to be reserved<\/span>'\r\n                : ' <span style=\"color:#fb5e2a\">\u00e0 r\u00e9server<\/span>';\r\n            var _titleCbP = _isEN_P ? 'Reserve this advertising space' : 'R\u00e9server cet espace publicitaire';\r\n            const _aReserverP = _isReservedPartiel\r\n                ? ''\r\n                : _spanAReserverP\r\n                  + ' <input type=\"checkbox\" class=\"via-recap-reserver-cb\"'\r\n                  + ' data-rank=\"' + _rankPartielFix19 + '\"'\r\n                  + ' data-empl=\"' + _espacePartiel + '\"'\r\n                  + ' data-item-id=\"' + item.id + '\"'\r\n                  + ' title=\"' + _titleCbP + '\"'\r\n                  + ' style=\"margin-left:1px;cursor:pointer;width:10px;height:10px;z-index:110;position:relative;top:-2px;\">';\r\n            if (_hasAnnoncePartiel || _isReservedPartiel) {\r\n                $_noClass1.html(_labelEspacePartiel + _emplToShowP + _aReserverP);\r\n                $_noClass1.show();\r\n            } else {\r\n                $_noClass1.hide();\r\n            }\r\n            \/\/ v4.9ds : sync data-via-no-ref selon visibilit\u00e9 CampagneNoClass\r\n            \/\/   directement apr\u00e8s le show\/hide. Le calcul est aussi fait dans\r\n            \/\/   setItemActif mais ce dernier ne s'ex\u00e9cute qu'au changement d'item\r\n            \/\/   actif \u2014 pas quand l'utilisateur coche \"Envoi diff\u00e9r\u00e9\" ou d\u00e9pose une\r\n            \/\/   annonce, ce qui re-rend l'item via remplirItemPartiel sans changer\r\n            \/\/   d'item actif. Sans cette sync, le bouton R\u00e9duire\/Agrandir reste masqu\u00e9\r\n            \/\/   alors que CampagneNoClass est devenue visible.\r\n            if (_hasAnnoncePartiel || _isReservedPartiel) {\r\n                $item[0].removeAttribute('data-via-no-ref');\r\n            } else {\r\n                $item[0].setAttribute('data-via-no-ref', 'true');\r\n            }\r\n            \/\/ pb77 : re-forcer margin-top inline ici aussi (ResizeObserver peut avoir tourn\u00e9)\r\n            (function() {\r\n                var _cp77p = $item.find('#CampagnePage')[0];\r\n                if (_cp77p) { _cp77p.style.setProperty('margin-top', window.VIA_Panier._mt801('12px'), 'important'); }   \/\/ pb801\r\n            })();\r\n            \/\/ \u2699\ufe0f [COMMENT\u00c9] CampagneInfoEspaceMessage par item \u2014 remplac\u00e9 par message global #RecapitulatifVosCommandestitreContainer\r\n            \/\/ var $msgInfo = $item.find('.CampagneInfoEspaceMessage');\r\n            \/\/ if (!$msgInfo.length) {\r\n            \/\/     $msgInfo = $('<div class=\"CampagneInfoEspaceMessage\" style=\"color:#FB5E2A;font-size:11px;font-weight:bold;text-align:center;margin-top:-21px;margin-bottom:5px;padding:2px 0;\"><\/div>');\r\n            \/\/     $item.find('.CampagnePageRefClass').before($msgInfo);\r\n            \/\/ }\r\n            \/\/ $msgInfo.text(\"Merci de faire un choix d'espace publicitaire dans la page s\u00e9lectionn\u00e9e\").show();\r\n            \/\/ console.log('\u2705 [remplirItemPartiel] CampagneInfoEspaceMessage affich\u00e9 sur item:', $item.attr('id'));\r\n            console.log('\u2705 [remplirItemPartiel] CampagneNoClass =', $item.find('.CampagneNoClass').text());\r\n            \/\/ \u2705 v4.9ds : injecter bouton R\u00e9duire\/Agrandir si absent (\u00e0 c\u00f4t\u00e9 de la croix close)\r\n            \/\/   SVG repris de kit.js (popup Cr\u00e9ation) :\r\n            \/\/     - R\u00e9duire = trait horizontal (line)\r\n            \/\/     - Agrandir = carr\u00e9 vide (rect non rempli)\r\n            \/\/   data-via-reduit-state initialis\u00e9 \u00e0 \"false\" \u2014 sera ajust\u00e9 par setItemActif()\r\n            if (!$item.find('.via-reduire-btn').length) {\r\n                var _svgReduire = '<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><line x1=\"2\" y1=\"10.5\" x2=\"12\" y2=\"10.5\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"\/><\/svg>';\r\n                var _svgAgrandir = '<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><rect x=\"1.5\" y=\"1.5\" width=\"9\" height=\"9\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg>';\r\n                var $btnReducer = $('<button type=\"button\" class=\"via-reduire-btn\" aria-label=\"R\u00e9duire\" title=\"R\u00e9duire\" data-via-svg-reduire=\"' + encodeURIComponent(_svgReduire) + '\" data-via-svg-agrandir=\"' + encodeURIComponent(_svgAgrandir) + '\">' + _svgReduire + '<\/button>');\r\n                var $closeBtn = $item.find('.CampagneCloseButton').first();\r\n                if ($closeBtn.length) {\r\n                    $closeBtn.before($btnReducer);\r\n                } else {\r\n                    $item.prepend($btnReducer);\r\n                }\r\n            }\r\n            \/\/ pb206 : picto \"S\u00e9lectionner\" (case \u00e0 cocher) \u00e0 c\u00f4t\u00e9 des autres pictos.\r\n            \/\/   Vert #01f41a quand la r\u00e9servation est active (data-via-reduit=\"false\"),\r\n            \/\/   gris #bbbbbb sinon \u2014 pilot\u00e9 en CSS via la couleur currentColor + le\r\n            \/\/   s\u00e9lecteur [data-via-reduit]. Plac\u00e9 juste avant le bouton R\u00e9duire.\r\n            if ((window._viaPb931Off === true) && !$item.find('.via-selectionner-btn').length) {\r\n                var _svgSelect = '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><rect x=\"2.5\" y=\"2.5\" width=\"19\" height=\"19\" rx=\"3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.83\"\/><path d=\"M7 12.5 L10.5 16 L17 8.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.83\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg>';\r\n                var $btnSelect = $('<button type=\"button\" class=\"via-selectionner-btn\" aria-label=\"S\u00e9lectionner\" title=\"S\u00e9lectionner\">' + _svgSelect + '<\/button>');\r\n                var $reducerRef = $item.find('.via-reduire-btn').first();\r\n                if ($reducerRef.length) {\r\n                    $reducerRef.before($btnSelect);\r\n                } else {\r\n                    var $closeRef = $item.find('.CampagneCloseButton').first();\r\n                    if ($closeRef.length) { $closeRef.before($btnSelect); } else { $item.prepend($btnSelect); }\r\n                }\r\n            }\r\n            \/\/ \u2705 v4.9ds Fix 19 v6 (Pb 14) : injecter programmatiquement la croix Supprimer\r\n            \/\/   (.CampagneCloseButton) puisque le user a simplifi\u00e9 le template Elementor\r\n            \/\/   en supprimant ce bloc. La croix doit \u00eatre \u00e0 droite du bouton R\u00e9duire et\r\n            \/\/   op\u00e9rationnelle (handler click '.CampagneCloseButton' d\u00e9j\u00e0 attach\u00e9 ligne 4584).\r\n            \/\/   Position : right:5px (cf CSS inject\u00e9 ligne 280 \u2014 \u00e0 droite de via-reduire-btn\r\n            \/\/   qui est \u00e0 right:20px).\r\n            if (!$item.find('.CampagneCloseButton').length) {\r\n                var _svgClose = '<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><line x1=\"2\" y1=\"2\" x2=\"10\" y2=\"10\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"\/><line x1=\"10\" y1=\"2\" x2=\"2\" y2=\"10\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"\/><\/svg>';\r\n                var $btnClose = $('<button type=\"button\" class=\"CampagneCloseButton\" aria-label=\"Supprimer\" title=\"Supprimer\">' + _svgClose + '<\/button>');\r\n                $item.append($btnClose);\r\n            }\r\n            \r\n            \/\/ 2. Pays - extraire depuis l'URL de l'item (source fiable)\r\n            var _linkP1 = (item.donneesIframe && item.donneesIframe.LoadedPageUrl) || item.linkSecteurPage || '';\r\n            var _matchP1 = _linkP1.match(\/https?:\\\/\\\/([^.]+)\\.yearbook-media\\.com\/);\r\n            var _paysP1 = _matchP1 ? (_matchP1[1].charAt(0).toUpperCase() + _matchP1[1].slice(1)) : null;\r\n            var _rawP1 = _paysP1 || item.pays || sessionStorage.getItem('ContinentPaysTitre') || '-';\r\n            var paysSite = typeof formatPaysDisplay === 'function' ? formatPaysDisplay(_rawP1) : _rawP1.replace('-en', ' english');\r\n            var $_paysEl = $item.find('[id=\"CampagnePaysTexte\"], .CampagnePaysClass');\r\n            $_paysEl.html(paysSite);\r\n            \/\/ \u2705 MutationObserver d\u00e9fensif : si Elementor ou tout code asynchrone r\u00e9initialise\r\n            \/\/   le widget text-editor et remet \"R\u00e9servation\" (valeur template), on corrige\r\n            \/\/   imm\u00e9diatement. Auto-d\u00e9connect\u00e9 apr\u00e8s 2s pour \u00e9viter les fuites m\u00e9moire.\r\n            (function($_pEl, _pSite) {\r\n                if (!window.MutationObserver) { return; }\r\n                var _elP = $_pEl[0];\r\n                if (!_elP) { return; }\r\n                var _obsP = new MutationObserver(function() {\r\n                    var _cur = $_pEl.html() || '';\r\n                    if (_cur !== _pSite) {\r\n                        _obsP.disconnect();\r\n                        $_pEl.html(_pSite);\r\n                        \/\/ R\u00e9installer l'observer au cas o\u00f9 un 2e reset surviendrait\r\n                        var _obsP2 = new MutationObserver(function() {\r\n                            _obsP2.disconnect();\r\n                            if (($_pEl.html() || '') !== _pSite) { $_pEl.html(_pSite); }\r\n                        });\r\n                        _obsP2.observe(_elP, { childList: true, subtree: true, characterData: true });\r\n                        setTimeout(function() { _obsP2.disconnect(); }, 1500);\r\n                    }\r\n                });\r\n                _obsP.observe(_elP, { childList: true, subtree: true, characterData: true });\r\n                setTimeout(function() { _obsP.disconnect(); }, 2000);\r\n            })($_paysEl, paysSite);\r\n            \r\n            \/\/ 3. Page\r\n            let titrePage;\r\n            const commandePage = item.commandePage || 'Homepage';\r\n            const selectedPageSecteurDisplayed = item.selectedPageSecteurDisplayed || '';\r\n            \r\n            \/\/ \u2705 v1.11 : Item anticip\u00e9 sans commandePage \u2192 placeholder\r\n            if (item.statut === 'anticipee' && !item.commandePage) {\r\n                titrePage = '<em style=\"color:#aaa;font-size:11px;\">\u2014 s\u00e9lectionner un secteur \u2014<\/em>';\r\n            } else {\r\n                switch (commandePage) {\r\n                    case 'Homepage':\r\n                        \/\/ pb82\/pb83 : pour HPType secteur (ex: \/btp\/), utiliser selectedPageSecteurDisplayed\r\n                        if (selectedPageSecteurDisplayed) {\r\n                            if (selectedPageSecteurDisplayed !== 'Homepage') {\r\n                                titrePage = selectedPageSecteurDisplayed;\r\n                            } else {\r\n                                titrePage = 'Homepage';\r\n                            }\r\n                        } else {\r\n                            titrePage = 'Homepage';\r\n                        }\r\n                        break;\r\n                    case 'Page sectorielle':\r\n                        titrePage = selectedPageSecteurDisplayed;\r\n                        break;\r\n                    case 'Article':\r\n                        titrePage = 'Article ' + selectedPageSecteurDisplayed;\r\n                        break;\r\n                    default:\r\n                        titrePage = commandePage;\r\n                }\r\n                \/\/ pb82 : tronquer \u00e0 3 mots max + \"\u2026\" (titres d'articles longs)\r\n                var _prefixTp83 = '';\r\n                var _restTp83 = titrePage.replace(\/\\bArt\\.\\s*\/g, '').replace(\/\\s{2,}\/g, ' ').trim();\r\n                if (\/^Article\\b\/.test(_restTp83)) {\r\n                    _prefixTp83 = 'Article';\r\n                    _restTp83 = _restTp83.slice('Article'.length).replace(\/^\\s+\/, '');\r\n                }\r\n                var _wTp83 = _restTp83.split(\/\\s+\/).filter(function(w) { return w.length > 0; });\r\n                if (_wTp83.length > 3) { _restTp83 = _wTp83.slice(0, 3).join(' ') + '\\u2026'; }\r\n                titrePage = _prefixTp83 ? (_prefixTp83 + (_restTp83 ? ' ' + _restTp83 : '')) : _restTp83;\r\n            }\r\n\r\n            \/\/ \u2705 v2.4.5 : Conserver la position d\u00e9j\u00e0 affich\u00e9e dans #CampagnePageText\r\n            var $_ptPartiel = $item.find('#CampagnePageText, .CampagnePageTextClass').first();\r\n            var _existingText = $_ptPartiel.text() || '';\r\n            var _nbspIdx = _existingText.indexOf('\u00a0\u00a0\u00a0\u00a0');\r\n            var _posPartiel = _nbspIdx !== -1 ? _existingText.substring(_nbspIdx + 2).trim() : '';\r\n            \/\/ \u2705 v2.4.5 : Calculer depuis donneesIframe.Rank d\u00e8s l'envoi diff\u00e9r\u00e9 \/ d\u00e9p\u00f4t annonce\r\n            if (!_posPartiel) {\r\n                var _rankPartiel = (item.donneesIframe && item.donneesIframe.Rank_Emplacement_Page_Web) || '';\r\n                if (_rankPartiel) {\r\n                    _posPartiel = this.convertirPositionEnLibelle(this.calculerPosition(_rankPartiel, commandePage));\r\n                } else if (item.position) {\r\n                    _posPartiel = this.convertirPositionEnLibelle(item.position);\r\n                }\r\n            }\r\n            \/\/ v4.9ds : pour Ele0A, NE JAMAIS ajouter \"    Pop-up\" dans CampagnePageText\r\n            \/\/   (la mention Pop-up est portee par CampagneNoClass uniquement)\r\n            $_ptPartiel.html((_posPartiel ? !_isEle0APartiel : false) ? titrePage + '\u00a0\u00a0\u00a0\u00a0' + _posPartiel : titrePage);\r\n            \r\n            \/\/ 4. Format \u2014 afficher si d\u00e9fini sur l'item OU dans sessionStorage (index actif)\r\n            \/\/ \u2705 Format : cascade de fallbacks pour garantir la r\u00e9solution\r\n            \/\/    1. item.format (d\u00e9fini lors de la cr\u00e9ation de l'item)\r\n            \/\/    2. Commande_Format_Transmis{itemIndex} (\u00e9crit par syncItemToSessionStorage)\r\n            \/\/    3. Commande_Format_Transmis global\r\n            \/\/    4. FormatSelect (dernier recours \u2014 format s\u00e9lectionn\u00e9 par l'utilisateur)\r\n            \/\/ pb73 : utiliser item.sessionStorageIndex (index propre de l'item) plut\u00f4t que\r\n            \/\/   SelectedCampagneIndex global (qui pointe vers l'item ACTIF, pas l'item en cours\r\n            \/\/   de rendu). Sans \u00e7a, quand item2 est actif (index 2), remplirItemPartiel pour\r\n            \/\/   item1 lirait Commande_Format_Transmis2 (null) au lieu de Commande_Format_Transmis1.\r\n            const _activeIdxFmt = item.sessionStorageIndex || sessionStorage.getItem('SelectedCampagneIndex');\r\n            const _fmtFromIndex = (_activeIdxFmt && _activeIdxFmt !== '0')\r\n                ? sessionStorage.getItem('Commande_Format_Transmis' + _activeIdxFmt)\r\n                : null;\r\n            const _fmtGlobal = sessionStorage.getItem('Commande_Format_Transmis');\r\n            \/\/ \u2705 v2.3.2 : Exclure les valeurs string invalides : 'null', 'undefined', '\u00e0 choisir'\r\n            \/\/ pb1513 : delegue au helper partage (meme regle, un seul endroit).\r\n            const _isValidFmt = _viaFormatValide1513;\r\n            \/\/ FormatSelect utilis\u00e9 uniquement si Formatchoisi='Yes' (s\u00e9lection volontaire courante)\r\n            const _fmtFormatSelect = sessionStorage.getItem('FormatSelect');\r\n            const _fmtFormatchoisi = sessionStorage.getItem('Formatchoisi') === 'Yes';\r\n            \/\/ \u2705 v2.3.2 : FormatSelect utilis\u00e9 si Formatchoisi='Yes' (c\u00f4t\u00e9 iframe) OU si pays+secteur pr\u00e9sents\r\n            \/\/ Formatchoisi n'est pas fiable c\u00f4t\u00e9 parent \u2192 fallback sur pr\u00e9sence pays+secteur\r\n            const _hasPaysRM = sessionStorage.getItem('ContinentPaysTitre') !== null;\r\n            const _hasSecteurRM = sessionStorage.getItem('SelectedPageSecteur') !== null;\r\n            \/\/ \u2705 v2.3.2 : FormatSelect valide si pays+secteur pr\u00e9sents (guard : handlers effacent FormatSelect au reset)\r\n            const _fmtFromFormatSelect = (_isValidFmt(_fmtFormatSelect) && (_fmtFormatchoisi || (_hasPaysRM && _hasSecteurRM))) ? _fmtFormatSelect : null;\r\n            const _formatPartiel = (_isValidFmt(item.format) ? item.format : null)\r\n                || (_isValidFmt(_fmtFromIndex) ? _fmtFromIndex : null)\r\n                || (_isValidFmt(_fmtGlobal) ? _fmtGlobal : null)\r\n                || (_isValidFmt(_fmtFromFormatSelect) ? _fmtFromFormatSelect : null)\r\n                || '';\r\n            console.log('\ud83d\udccb [remplirItemPartiel] format r\u00e9solu:', _formatPartiel,\r\n                '| item.format:', item.format,\r\n                '| idx:', _fmtFromIndex,\r\n                '| global:', _fmtGlobal);\r\n            \/\/ \u2705 v2.3.4 : Label popup = \"Pop-up Vid\u00e9o\" \/ \"Pop-up Banni\u00e8re\" etc.\r\n            var _formatLabel = _formatPartiel;\r\n            if (_formatPartiel === 'PopUp' || _formatPartiel === 'Pop-up') {\r\n                var _underlying = (item.donneesIframe && item.donneesIframe.PopUpFormatSelect) || '';\r\n                _formatLabel = _underlying ? ('Pop-up ' + _underlying) : 'Pop-up';\r\n            }\r\n            const $_fmt1 = $item.find('.CampagneFormatClass');\r\n            if (_formatLabel) {\r\n                $_fmt1.find('p').text(_translateFormatLabel(_formatLabel));\r\n                \/\/ \u2705 Forcer display via setProperty pour passer les \u00e9ventuels !important Elementor\r\n                \/\/ \u2705 v4.9ds+ (suite 6) order=0 en popup achat (cf creerNouvelItem)\r\n                var _isPopupAchatP = document.body.classList.contains('via-popup-achat');\r\n                var _orderValP = _isPopupAchatP ? '0' : (window.outerWidth >= 1000 ? '5' : '0');\r\n                $_fmt1.show(); if ($_fmt1[0]) { $_fmt1[0].style.setProperty('order', _orderValP, 'important'); $_fmt1[0].style.setProperty('width','auto','important'); }\r\n            } else {\r\n                $_fmt1.hide();\r\n            }\r\n            \r\n            \/\/ ================================================================\r\n            \/\/ pb1247 : MEME GABARIT pour la carte PARTIELLE que pour la complete\r\n            \/\/   (demande user).\r\n            \/\/   Constat : avant reservation d'un espace, le contenu chevauche le\r\n            \/\/   titre, les libelles ne sont pas alignes et les interlignes varient.\r\n            \/\/   Tout rentre dans l'ordre des que l'espace est reserve.\r\n            \/\/   Cause : ces quatre lignes MASQUENT les zones non encore renseignees.\r\n            \/\/   La carte perd donc quatre lignes, sa hauteur se contracte, et la\r\n            \/\/   mise en page se decale \u2014 ce n'etait ni un probleme de rendu (pb1245)\r\n            \/\/   ni d'empilement (pb1243b), mais de lignes absentes.\r\n            \/\/   On garde donc les zones VISIBLES avec un tiret, comme le fait deja la\r\n            \/\/   ligne suivante pour les dates, la duree et le tarif. La carte\r\n            \/\/   conserve sa hauteur et son alignement quel que soit son avancement.\r\n            \/\/   Revert : window._viaPb1247Off = true (masquage d'origine).\r\n            \/\/ ================================================================\r\n            \/\/ pb1252 : pb1248 RETIRE (demande user) \u2014 plus d'invite en tete de carte.\r\n\r\n            \/\/ pb1252 : pb1247 RETIRE (demande user) \u2014 retour au masquage d'origine.\r\n            \/\/ Cacher les \u00e9l\u00e9ments non disponibles\r\n            $item.find('.CampagnePositionClass').hide();\r\n            $item.find('.CampagneReferenceClass').hide();\r\n            $item.find('.CampagneEnvoiUlterieurClass').hide();\r\n            $item.find('.CampagneAnnonceDeposeClass').hide();\r\n            \/\/ \u2705 Pb 2 : ne pas \u00e9craser les dates\/pays si l'item les a d\u00e9j\u00e0 \u2014 ils\r\n            \/\/   seraient perdus car remplirItemPartiel n'appelle pas rafraichirItemHTML.\r\n            if (!item.dateDebut) { $item.find('.CampagneDatesClass').html('-'); }\r\n            if (!item.duree)     { $item.find('.CampagneNbJours').html('-'); }\r\n            if (!item.paysAnnonceur) { $item.find('.CampagnePaysSocieteClass').html('-'); }\r\n            \/\/ ================================================================\r\n            \/\/ pb1373 : LE TARIF AUSSI \u2014 il avait ete oublie par \u00ab Pb 2 \u00bb.\r\n            \/\/   Constat user : en 3 colonnes, le tarif disparait de la carte alors\r\n            \/\/   qu'il est affiche dans le popup et present dans l'item.\r\n            \/\/   Les trois lignes au-dessus testent \u00ab si l'item n'a pas la valeur \u00bb\r\n            \/\/   avant d'ecrire un tiret \u2014 leur commentaire dit pourquoi : \u00ab ne pas\r\n            \/\/   ecraser les dates\/pays si l'item les a deja, ils seraient perdus car\r\n            \/\/   remplirItemPartiel n'appelle pas rafraichirItemHTML \u00bb. Le raisonnement\r\n            \/\/   valait pour le tarif ; la ligne, elle, etait restee inconditionnelle.\r\n            \/\/   Meme formatage que remplirItemComplet (~l.5596), pour que la carte\r\n            \/\/   affiche la meme chose quel que soit le chemin qui la remplit.\r\n            \/\/   Revert : window._viaPb1373Off = true (effacement inconditionnel).\r\n            \/\/ ================================================================\r\n            if (window._viaPb1373Off === true) {\r\n                $item.find('.CampagneTarifClass').html('-');\r\n            } else if (!item.tarifHT) {\r\n                $item.find('.CampagneTarifClass').html('-');\r\n            } else {\r\n                \/\/ ============================================================\r\n                \/\/ pb1375 : ECRIRE NE SUFFIT PAS \u2014 IL FAUT AUSSI REVELER.\r\n                \/\/   Le HTML fourni est sans appel :\r\n                \/\/     class=\"... CampagneTarifClass elementor-hidden-desktop\r\n                \/\/            elementor-hidden-tablet elementor-hidden-mobile ...\"\r\n                \/\/     style=\"display: none;\"   et le contenu VIDE\r\n                \/\/   Trois masquages se cumulent : les classes Elementor (qui posent\r\n                \/\/   display:none !important en feuille), un display inline pose par\r\n                \/\/   un .hide() anterieur, et un contenu vide. pb1373 n'agissait que\r\n                \/\/   sur le contenu, et son .show() \u2014 qui ecrit display:block SANS\r\n                \/\/   !important \u2014 ne pouvait pas battre les classes.\r\n                \/\/   On applique donc l'idiome deja etabli ici pour ce cas precis\r\n                \/\/   (~l.6695, .ArticleTitre) : ecrire dans .elementor-widget-container\r\n                \/\/   quand il existe, retirer les trois classes, puis poser le display\r\n                \/\/   en !important. Meme geste que pb1256 pour la zone Annonceur.\r\n                \/\/   Le log dit ce qui a ete ecrit : si le tarif manque encore apres\r\n                \/\/   ca, c'est qu'un writer repasse APRES \u2014 et non que la valeur\r\n                \/\/   n'existait pas.\r\n                \/\/   Revert : window._viaPb1375Off = true (ecriture seule, sans r\u00e9v\u00e9ler).\r\n                \/\/ ============================================================\r\n                var _lblT1373 = (lang === 'EN') ? 'Price excl. VAT' : 'Tarif H.T.';\r\n                var _txtT1373 = _lblT1373 + ' ' + item.tarifHT;\r\n                try {\r\n                    if (window.VIA_App\r\n                        ? (typeof window.VIA_App.formaterMontant === 'function') : false) {\r\n                        _txtT1373 = _lblT1373 + ' '\r\n                            + window.VIA_App.formaterMontant(item.tarifHT, item.devise || 'EUR', 2);\r\n                    }\r\n                } catch (_eT1373) {\r\n                    console.warn('[pb1373] formatage du tarif : ' + _eT1373.message);\r\n                }\r\n                var $tar1375 = $item.find('.CampagneTarifClass');\r\n                if ($tar1375.length) {\r\n                    \/\/ pb2121 : resa active d'un commercial -> libelle seul.\r\n                    _txtT1373 = window._viaLibelleTarif2121($item.length ? $item.attr('id') : '', _txtT1373);\r\n                    var $cib1375 = $tar1375.find('.elementor-widget-container').first();\r\n                    ($cib1375.length ? $cib1375 : $tar1375).html(_txtT1373);\r\n                    if (window._viaPb1375Off !== true) {\r\n                        $tar1375.removeClass('elementor-hidden-desktop'\r\n                            + ' elementor-hidden-tablet elementor-hidden-mobile');\r\n                        $tar1375[0].style.setProperty('display', 'block', 'important');\r\n                    } else {\r\n                        $tar1375.show();\r\n                    }\r\n                    if (window._viaSig1375 !== _txtT1373) {\r\n                        window._viaSig1375 = _txtT1373;\r\n                        console.log('[pb1375] tarif pos\u00e9 sur la carte : \"' + _txtT1373\r\n                            + '\" | conteneur Elementor=' + ($cib1375.length ? 'oui' : 'non')\r\n                            + ' | calcul\u00e9=' + window.getComputedStyle($tar1375[0]).display);\r\n                    }\r\n                } else {\r\n                    console.warn('[pb1375] .CampagneTarifClass introuvable dans la carte');\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 CampagneEnvoiUlterieurClass \u2014 r\u00e8gles :\r\n            \/\/    - Option cr\u00e9\u00e9e \u2192 cach\u00e9\r\n            \/\/    - Annonce d\u00e9pos\u00e9e \u2192 \"Annonce ins\u00e9r\u00e9e\"\r\n            \/\/    - Envoi diff\u00e9r\u00e9 sans fichier \u2192 texte envoi diff\u00e9r\u00e9\r\n            \/\/    - R\u00e9serv\u00e9 \u2192 ne change pas (g\u00e9r\u00e9 dans remplirItemComplet)\r\n            \/\/ v4.9ds : HasAdLoadedDom='Yes' suffit pour consid\u00e9rer l'annonce d\u00e9pos\u00e9e\r\n            \/\/   visuellement (drop miniature dans Ele1A+ \u2192 image en DOM, FileReceived\r\n            \/\/   reste 'No' tant qu'il n'y a pas d'upload serveur effectif).\r\n            \/\/ \u2705 v4.9ds Pb 6 : quand l'annonce est d\u00e9pos\u00e9e (fichier re\u00e7u), afficher\r\n            \/\/   \"Annonce ins\u00e9r\u00e9e\" M\u00caME SI envoi diff\u00e9r\u00e9 coch\u00e9. Avant, le test\r\n            \/\/   _hasFilePartiel ? !_isEnvoiDifferePartiel : false gardait le texte\r\n            \/\/   \"\u00e0 transmettre\" si envoi diff\u00e9r\u00e9+fichier \u2192 l'utilisateur ne savait pas\r\n            \/\/   que son annonce avait \u00e9t\u00e9 prise en compte. Demande user.\r\n            if (item.donneesIframe) {\r\n                var $_envoiUlt1 = $item.find('.CampagneEnvoiUlterieurClass');\r\n                const _isEnvoiDifferePartiel = item.donneesIframe.EnvoiUlterieur === 'true' || item.donneesIframe.EnvoiUlterieur === true;\r\n                const _hasFilePartiel = item.donneesIframe.FileReceived === 'Yes'\r\n                                     || item.donneesIframe.HasAdLoadedDom === 'Yes';\r\n                var $_annonceDepose1 = $item.find('.CampagneAnnonceDeposeClass');\r\n                if (_hasFilePartiel) {\r\n                    \/\/ Fichier d\u00e9pos\u00e9 \u2192 afficher .CampagneAnnonceDeposeClass, cacher .CampagneEnvoiUlterieurClass\r\n                    $_envoiUlt1.hide();\r\n                    $_annonceDepose1.show();\r\n                    console.log('\u2705 [remplirItemPartiel] CampagneAnnonceDeposeClass affich\u00e9');\r\n                } else if (_isEnvoiDifferePartiel) {\r\n                    \/\/ Envoi diff\u00e9r\u00e9 coch\u00e9 mais pas de fichier \u2192 texte d'attente dans CampagneEnvoiUlterieurClass\r\n                    const _txtDiffere = lang === 'EN' ? 'Ad to be sent within 8 days of payment' : \"Annonce \u00e0 transmettre jusqu'\u00e0 8 jours apr\u00e8s paiement, un lien vous sera adress\u00e9 par contact@via-agency.media\";\r\n                    $_envoiUlt1.find('p').text(_txtDiffere);\r\n                    $_envoiUlt1.show();\r\n                    $_annonceDepose1.hide();\r\n                    console.log('\u2705 [remplirItemPartiel] Envoi diff\u00e9r\u00e9 affich\u00e9');\r\n                } else {\r\n                    $_envoiUlt1.hide();\r\n                    $_annonceDepose1.hide();\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 reservationEnAttente : r\u00e9servation en cours de modification (pays\/secteur\/format chang\u00e9).\r\n            \/\/   M\u00eames combinaisons de messages que la cr\u00e9ation initiale.\r\n            if (_reservationEnAttente) {\r\n                (function(_self2) {\r\n                    var _rHasPays = !!sessionStorage.getItem('ContinentPaysTitre');\r\n                    var _rHasSect = !!sessionStorage.getItem('SelectedPageSecteur');\r\n                    var _rHasFmt  = !!sessionStorage.getItem('FormatSelect');\r\n                    if (_rHasPays) { if (_rHasSect) { if (_rHasFmt) {\r\n                        _self2.ajouterMsgAccompagnement($item, {\r\n                            statut: 'partielle', espace: '', estReserve: false,\r\n                            tarifHT: null, aReserver: false, anticipeeType: null\r\n                        });\r\n                        return;\r\n                    }}}\r\n                    _self2.ajouterMsgAccompagnement($item, { statut: 'anticipee', tarifHT: null });\r\n                })(this);\r\n            } else {\r\n                this.ajouterMsgAccompagnement($item, {\r\n                    espace: _espacePartiel,\r\n                    estReserve: _isReservedPartiel,\r\n                    tarifHT: item.tarifHT || null,\r\n                    statut: item.statut,\r\n                    anticipeeType: item._anticipePaysDisplay ? 'pays' : (item._anticipeSecteurDisplay ? 'secteur' : null),\r\n                    aReserver: !_isReservedPartiel\r\n                });\r\n            }\r\n            \r\n            \/\/ \u2705 Pays \u2014 extraire depuis item.pays ou linkSecteurPage (absent de remplirItemComplet pour ces items)\r\n            (function() {\r\n                var _paysRaw = item.pays || null;\r\n                if (!_paysRaw) {\r\n                    var _urlP = item.linkSecteurPage || (item.donneesIframe && item.donneesIframe.LoadedPageUrl) || '';\r\n                    var _mP = _urlP.match(\/https?:\\\/\\\/([^.]+)\\.yearbook-media\\.com\/);\r\n                    if (_mP && _mP[1]) { _paysRaw = _mP[1].charAt(0).toUpperCase() + _mP[1].slice(1); }\r\n                }\r\n                if (_paysRaw) {\r\n                    var _displayPays = typeof formatPaysDisplay === 'function' ? formatPaysDisplay(_paysRaw) : _paysRaw;\r\n                    $item.find('[id=\"CampagnePaysTexte\"], .CampagnePaysClass').html(_displayPays);\r\n                }\r\n            })();\r\n            this._majArticleTitre694($item, item, 'remplirItemPartiel');   \/\/ pb694\r\n            this._majRecap793($item, item);   \/\/ pb793 : writer unique des libelles\r\n            console.log('\u2705 Item partiel rempli');\r\n            \/\/ pb77 : forcer margin-top 12px en inline style sur #CampagnePage pour r\u00e9sister\r\n            \/\/   au ResizeObserver d'Elementor qui \u00e9crase le CSS stylesheet.\r\n            (function() {\r\n                var _cp77 = $item.find('#CampagnePage')[0];\r\n                if (_cp77) { _cp77.style.setProperty('margin-top', window.VIA_Panier._mt801('12px'), 'important'); }   \/\/ pb801\r\n            })();\r\n            \/\/ \u2705 v4.9ds+ Pb5\/6 : Elementor ResizeObserver impose width:100% et order:0 sur CampagneFormatClass\r\n            \/\/   apr\u00e8s remplirItemPartiel. On re-fixe via setProperty 200ms apr\u00e8s pour gagner.\r\n            setTimeout(function() {\r\n                var _fmtLate = $item.find('.CampagneFormatClass')[0];\r\n                if (_fmtLate) {\r\n                    \/\/ \u2705 v4.9ds+ (suite 6) order=0 en popup achat (cf creerNouvelItem)\r\n                    var _isPopupAchatL = document.body.classList.contains('via-popup-achat');\r\n                    var _orderValL = _isPopupAchatL ? '0' : (window.outerWidth >= 1000 ? '5' : '0');\r\n                    _fmtLate.style.setProperty('order', _orderValL, 'important');\r\n                    _fmtLate.style.setProperty('width', 'auto', 'important');\r\n                }\r\n            }, 200);\r\n        },\r\n        \r\n        \/**\r\n         * Remplit le HTML d'un item clon\u00e9 avec les donn\u00e9es\r\n         *\/\r\n        remplirItemHTML($item, donnees) {\r\n            \/\/ \u2705 CampagneNoClass \u2014 r\u00e8gles align\u00e9es avec remplirItemComplet\r\n            const langH = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const $_noClassH = $item.find('.CampagneNoClass');\r\n            \/\/ v4.9ds (estReserveEffective) : texte \"r\u00e9serv\u00e9\" UNIQUEMENT si flag pos\u00e9\r\n            \/\/   \u00e0 la r\u00e9servation effective. Sinon \"Espace publicitaire\" (juste d\u00e9pos\u00e9).\r\n            const _isReservedH = donnees.estReserveEffective === true || donnees.statut === 'complete';\r\n            if (donnees.emplacementPageWeb) {\r\n                const lblHReserve = _isReservedH\r\n                    ? (langH === 'EN' ? 'Reserved advertising space ' : 'Espace r\u00e9serv\u00e9 ')\r\n                    : (langH === 'EN' ? 'Advertising space ' : 'Espace publicitaire ');\r\n                $_noClassH.html(lblHReserve + donnees.emplacementPageWeb);\r\n                $_noClassH.show();\r\n                \/\/ $item.find('.CampagneInfoEspaceMessage').hide(); \/\/ \u2699\ufe0f [COMMENT\u00c9] g\u00e9r\u00e9 par message global\r\n            } else {\r\n                $_noClassH.hide();\r\n            }\r\n            \r\n            if (donnees.format) {\r\n                const $_fmt2 = $item.find('.CampagneFormatClass');\r\n                if (donnees.format) {\r\n                    $_fmt2.find('p').text(_translateFormatLabel(donnees.format));\r\n                    $_fmt2.show();\r\n                } else {\r\n                    $_fmt2.hide();\r\n                }\r\n            }\r\n            \r\n\r\n            \r\n            if (donnees.emplacementPageWeb) {\r\n                $item.find('.CampagnePageTextClass').html(donnees.emplacementPageWeb);\r\n            }\r\n            \r\n            $item.find('.CampagnePaysClass').html('-');\r\n            $item.find('.CampagneDatesClass').html('-');\r\n            $item.find('.CampagneTarifClass').html('-');\r\n            this._majArticleTitre694($item, donnees, 'remplirItemHTML');   \/\/ pb694\r\n        },\r\n        \r\n        \/**\r\n         * G\u00e9n\u00e8re un code unique via AJAX\r\n         *\/\r\n        \/**\r\n         * \u2705 R\u00e9initialise dates, pays et tarif de la r\u00e9servation active.\r\n         *    Appel\u00e9e quand le pays, le secteur ou le format est modifi\u00e9 par l'utilisateur.\r\n         *    Sauvegarde les valeurs dans sessionStorage avant de les effacer,\r\n         *    pour restauration \u00e0 la prochaine ouverture de ProcessAchatInside.\r\n         *    \"estReserveEffective\" est r\u00e9initialis\u00e9 \u2192 affiche \"\u00e0 r\u00e9server\" au prochain\r\n         *    d\u00e9p\u00f4t d'annonce ou clic Envoi diff\u00e9r\u00e9 sur un nouvel espace pub.\r\n         *\/\r\n        \/\/ pb746 : recalcul du tarif d'UN item, apres un changement de format\/position.\r\n        \/\/   Reprend exactement la voie eprouvee de mettreAJourPaysGlobal (L6037) :\r\n        \/\/   _viaProxyCalculerTarif en priorite, calculerTarifAPI en repli.\r\n        \/\/   Toutes les branches loguent : un tarif absent doit dire POURQUOI.\r\n        async _recalculerTarifItem746(item, _origine746) {\r\n            if (window._viaPb746Off === true) { return; }\r\n            try {\r\n                if (!item) { return; }\r\n                var _fmt746 = item.format;\r\n                var _pos746 = item.position;\r\n                var _dur746 = item.duree;\r\n                var _pays746 = item.paysAnnonceur || item.pays || '';\r\n                \/\/ pb746b : le code pays s'obtient par VIA_Countries.getCountryByLabel \u2014 la\r\n                \/\/   voie utilisee partout ailleurs dans ce fichier (L4835, L6040, L6519,\r\n                \/\/   L8603). VIA_App.getCountryByName, que j'avais suppose, n'existe pas :\r\n                \/\/   d'ou le 'code=(inconnu)' du log pb746 alors que tout le reste etait la.\r\n                \/\/   Repli sur STATE.selectedCountry (deja resolu par viaSetSelectedCountry,\r\n                \/\/   qui logue 'France (FR)' juste avant notre appel).\r\n                var _code746 = '';\r\n                if (window.VIA_Countries ? typeof window.VIA_Countries.getCountryByLabel === 'function' : false) {\r\n                    var _c746 = window.VIA_Countries.getCountryByLabel(_pays746);\r\n                    _code746 = _c746 ? (_c746.code || '') : '';\r\n                }\r\n                if (!_code746) {\r\n                    var _st746 = window.VIA_Elementor ? (window.VIA_Elementor.state || null) : null;\r\n                    var _sel746 = _st746 ? _st746.selectedCountry : null;\r\n                    if (_sel746) { _code746 = _sel746.code || _sel746 || ''; }\r\n                }\r\n                var _pret746 = item.dateDebut ? (item.dateFin ? (_dur746 ? (_fmt746 ? (_pos746 ? !!_code746 : false) : false) : false) : false) : false;\r\n                if (!_pret746) {\r\n                    console.log('[pb746] recalcul ignore (' + _origine746 + ') | fmt=' + _fmt746\r\n                        + ' pos=' + _pos746 + ' duree=' + _dur746 + ' pays=' + _pays746\r\n                        + ' code=' + (_code746 || '(inconnu)')\r\n                        + ' dates=' + item.dateDebut + '->' + item.dateFin);\r\n                    return;\r\n                }\r\n                if (!window.VIA_App) { console.warn('[pb746] VIA_App absent'); return; }\r\n                var _api746 = window._viaProxyCalculerTarif || window.VIA_App.calculerTarifAPI;\r\n                if (typeof _api746 !== 'function') { console.warn('[pb746] aucune fonction de calcul'); return; }\r\n                console.log('[pb746] recalcul (' + _origine746 + ') | fmt=' + _fmt746 + ' pos=' + _pos746\r\n                    + ' duree=' + _dur746 + ' code=' + _code746 + ' | proxy=' + (!!window._viaProxyCalculerTarif));\r\n                var _res746 = await _api746(_fmt746, _pos746, _dur746, _code746);\r\n                if (_res746 ? _res746.success : false) {\r\n                    var _avant746 = item.tarifHT;\r\n                    item.tarifHT = _res746.tarif_ht;\r\n                    item.tarifTTC = _res746.tarif_ttc;\r\n                    item.statut = 'valide';\r\n                    console.log('[pb746] tarif ' + (_avant746 === null ? '(vide)' : _avant746) + ' -> ' + item.tarifHT);\r\n                    if (typeof this.rafraichirItemHTML === 'function') { this.rafraichirItemHTML(item.id); }\r\n                    if (typeof this.remplirFormulaireDepuisItem === 'function') { this.remplirFormulaireDepuisItem(item); }\r\n                    if (typeof this.calculerTotalPanier === 'function') { this.calculerTotalPanier(); }\r\n                } else {\r\n                    console.warn('[pb746] API en echec \u2014 tarif inchange', _res746);\r\n                }\r\n            } catch (_e746) { console.warn('[pb746]', _e746 ? _e746.message : _e746); }\r\n        },\r\n\r\n        resetDonneesCampagne(opts) {\r\n            \/\/ opts.clearSecteur : true uniquement lors d'un clic PAYS (le secteur n'est\r\n            \/\/   plus valide car li\u00e9 au pays). Sur clic FORMAT ou SECTEUR : false \u2192\r\n            \/\/   SelectedPageSecteur conserv\u00e9, CampagnePageTextClass non vid\u00e9.\r\n            var _clearSecteur = false;\r\n            if (opts) { if (opts.clearSecteur) { _clearSecteur = true; } }\r\n\r\n            var _itemId = this.state.itemActif;\r\n            if (!_itemId) { return; }\r\n            var _item = (this.state.items || []).find(function(i) { return i.id === _itemId; });\r\n            if (!_item) { return; }\r\n            \/\/ Guard : ne s'ex\u00e9cute que si l'item a des donn\u00e9es utilisateur \u00e0 r\u00e9initialiser.\r\n            \/\/   item.pays (pays publicitaire) est intentionnellement absent : il est aliment\u00e9\r\n            \/\/   automatiquement par creerCommandePartielle\/R0 pour TOUS les items, y compris\r\n            \/\/   les nouvelles r\u00e9servations sans dates ni tarif \u2014 son inclusion d\u00e9clencherait\r\n            \/\/   un reset intempestif (reservationEnAttente=true) sur des items frais.\r\n            if (!_item.dateDebut && !_item.dateFin && !_item.tarifHT) {\r\n                return;\r\n            }\r\n            console.log('\ud83d\udd04 [resetDonneesCampagne] r\u00e9initialisation pour item:', _itemId, '| dateDebut:', _item.dateDebut, '| pays:', _item.pays, '| tarifHT:', _item.tarifHT);\r\n            \/\/ 1. Sauvegarder avant reset \u2014 UNE SEULE FOIS (cl\u00e9 absente = jamais sauv\u00e9).\r\n            \/\/    Le 2\u00e8me appel redondant (double handler pays) ne doit pas \u00e9craser\r\n            \/\/    le 1er save avec les valeurs d\u00e9j\u00e0 nullifi\u00e9es par le 1er appel.\r\n            if (!sessionStorage.getItem('_via_saved_dateDebut')) {\r\n                sessionStorage.setItem('_via_saved_dateDebut', _item.dateDebut || '');\r\n                sessionStorage.setItem('_via_saved_dateFin',   _item.dateFin   || '');\r\n                sessionStorage.setItem('_via_saved_duree',     _item.duree     ? (_item.duree + '') : '');\r\n                sessionStorage.setItem('_via_saved_pays',      _item.paysAnnonceur || '');\r\n                \/\/ pb959 : memoriser l'item PROPRIETAIRE de ces dates. Sans lui, la\r\n                \/\/   restauration plus bas les reposait sur n'importe quel item affiche\r\n                \/\/   ensuite \u2014 typiquement une NOUVELLE reservation, qui heritait alors\r\n                \/\/   des dates de la precedente (constat user).\r\n                sessionStorage.setItem('_via_saved_itemId', _itemId || '');\r\n            }\r\n            \/\/ 2. Reset mod\u00e8le item \u2014 dates\/pays\/tarif\r\n            _item.dateDebut          = null;\r\n            _item.dateFin            = null;\r\n            _item.duree              = null;\r\n            _item.pays               = null;\r\n            _item.paysAnnonceur      = null;\r\n            _item.tarifHT            = null;\r\n            _item.tarifTTC           = null;\r\n            \/\/ Envoi diff\u00e9r\u00e9 \u2014 invalide sur un nouvel espace pub (quel que soit le trigger)\r\n            _item.envoiUlterieur = false;\r\n            if (_item.donneesIframe) {\r\n                _item.donneesIframe.EnvoiUlterieur = 'false';\r\n                \/\/ Rank vide \u2192 remplirItemPartiel ne recalcule pas la position (Haut de page, etc.)\r\n                _item.donneesIframe.Rank_Emplacement_Page_Web = '';\r\n            }\r\n            \/\/ Secteur \/ position \u2014 invalides UNIQUEMENT si le pays a chang\u00e9\r\n            if (_clearSecteur) {\r\n                _item.selectedPageSecteur          = null;\r\n                _item.selectedPageSecteurDisplayed = null;\r\n                _item.position                     = null;\r\n                _item.linkSecteurPage              = null;\r\n                _item.linkSecteurPageDisplayed     = null;\r\n            }\r\n            \/\/ estReserveEffective : NE PAS r\u00e9initialiser ici.\r\n            \/\/   \"\u00e0 r\u00e9server\" doit appara\u00eetre uniquement quand un NOUVEL espace pub est\r\n            \/\/   s\u00e9lectionn\u00e9 (d\u00e9p\u00f4t d'annonce ou Envoi diff\u00e9r\u00e9), pas d\u00e8s le click pays.\r\n            \/\/   La valeur sera mise \u00e0 false par R0\/creerCommandePartielle au moment du\r\n            \/\/   chargement de la page web du nouveau pays.\r\n            \/\/ reservationEnAttente : flag qui change le label CampagneNoClass de\r\n            \/\/   \"Espace r\u00e9serv\u00e9\" \u2192 \"Espace publicitaire\" jusqu'\u00e0 la s\u00e9lection du nouvel\r\n            \/\/   espace pub. Effac\u00e9 par R0 quand emplacementPageWeb est r\u00e9initialis\u00e9.\r\n            _item.reservationEnAttente = true;\r\n            \/\/ 3. Reset affichage r\u00e9capitulatif carte item\r\n            var $item = $('#' + _itemId);\r\n            $item.find('.CampagneDatesClass').html('-');\r\n            $item.find('.CampagneNbJours').html('-');\r\n            $item.find('.CampagnePaysSocieteClass').html('-').hide();\r\n            $item.find('.CampagneTarifClass').html('-').hide();\r\n            $item.find('.CampagneDatesContainer').hide();\r\n            $item.find('.CampagneFormatClass').html(_translateFormatLabel(_item.format || '') || '');\r\n            \/\/ CampagneNoClass : \"Espace r\u00e9serv\u00e9\" \u2192 \"Espace publicitaire\" (ref conserv\u00e9e).\r\n            \/\/   Le flag reservationEnAttente g\u00e8re remplirItemPartiel. Cette ligne DOM directe\r\n            \/\/   est un filet de s\u00e9curit\u00e9 pour les appels remplirItemPartiel ant\u00e9rieurs au flag.\r\n            (function() {\r\n                var _langRDC = sessionStorage.getItem('SiteLangue') === 'EN' ? 'EN' : 'FR';\r\n                var _labelRDC = (_langRDC === 'EN') ? 'Advertising space' : 'Espace publicitaire';\r\n                \/\/ L'ancienne r\u00e9f\u00e9rence (ex: MDG44766L1A) est effac\u00e9e imm\u00e9diatement.\r\n                \/\/ remplirItemPartiel la supprimera aussi via reservationEnAttente.\r\n                $item.find('.CampagneNoClass').html(_labelRDC);\r\n            })();\r\n            \/\/ Vider secteur + position (Croissance \/ Haut de page) \u2014 uniquement si pays chang\u00e9\r\n            if (_clearSecteur) {\r\n                $item.find('.CampagnePageTextClass').html('');\r\n            }\r\n            \/\/ Masquer le message envoi diff\u00e9r\u00e9 \u2014 ne s'applique plus au nouvel espace pub\r\n            $item.find('.CampagneEnvoiUlterieurClass').hide();\r\n            \/\/ 4. Vider les cl\u00e9s sessionStorage secteur \u2014 uniquement si pays chang\u00e9\r\n            if (_clearSecteur) {\r\n                sessionStorage.removeItem('SelectedPageSecteur');\r\n                sessionStorage.removeItem('SelectedPageSecteurDisplayed');\r\n                sessionStorage.removeItem('LinkSecteurPage');\r\n                sessionStorage.removeItem('LinkSecteurPageDisplayed');\r\n            }\r\n            \/\/ 5. Mettre \u00e0 jour CampagneMsgAccompagnement selon ce qui est disponible.\r\n            \/\/    M\u00eame logique que pour la cr\u00e9ation de r\u00e9servation :\r\n            \/\/    - pays + secteur + format tous pr\u00e9sents \u2192 espace pub \u00e0 choisir\r\n            \/\/    - un ou plusieurs manquants \u2192 message \"Merci de s\u00e9lectionner X [et Y]\"\r\n            (function(_self) {\r\n                var _mHasPays = !!sessionStorage.getItem('ContinentPaysTitre');\r\n                var _mHasSect = !!sessionStorage.getItem('SelectedPageSecteur');\r\n                var _mHasFmt  = !!sessionStorage.getItem('FormatSelect');\r\n                if (_mHasPays && _mHasSect && _mHasFmt) {\r\n                    _self.ajouterMsgAccompagnement($item, {\r\n                        statut: 'partielle', espace: '', estReserve: false,\r\n                        tarifHT: null, aReserver: false, anticipeeType: null\r\n                    });\r\n                } else {\r\n                    _self.ajouterMsgAccompagnement($item, { statut: 'anticipee', tarifHT: null });\r\n                }\r\n            })(this);\r\n            \/\/ 6. Reset champs formulaire ProcessAchatInside (client seulement, pas d'appel serveur)\r\n            this.remplirFormulaireDepuisItem(_item);\r\n            console.log('\u2705 [resetDonneesCampagne] r\u00e9initialisation termin\u00e9e \u2014 valeurs sauv\u00e9es pour restauration');\r\n        },\r\n\r\n        async genererCodeUnique() {\r\n            try {\r\n                const response = await $.ajax({\r\n                    url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                    type: 'POST',\r\n                    xhrFields: { withCredentials: true },\r\n                    data: {\r\n                        action: 'generer_code_unique_commande'\r\n                    }\r\n                });\r\n                \r\n                if (response.success) {\r\n                    console.log('\u2705 Code unique g\u00e9n\u00e9r\u00e9:', response.data.code);\r\n                    return response.data.code;\r\n                } else {\r\n                    console.error('\u274c Erreur g\u00e9n\u00e9ration code:', response.data.message);\r\n                    return 'TMP';\r\n                }\r\n            } catch (error) {\r\n                console.error('\u274c Erreur AJAX g\u00e9n\u00e9ration code:', error);\r\n                return 'TMP';\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * Construit la r\u00e9f\u00e9rence compl\u00e8te de commande\r\n         *\/\r\n        async construireReferenceCommande(donnees) {\r\n            const codeUnique = await this.genererCodeUnique();\r\n            \r\n            \/\/ Extraire les parties de Commande_Emplacement_Page_Web\r\n            const emplacementWeb = donnees.Commande_Emplacement_Page_Web || '';\r\n            const codePage = donnees.codePage || '';\r\n            \r\n            \/\/ 3 premiers chars (ex: \"MDG\")\r\n            const prefixePays = emplacementWeb.substring(0, 3).toUpperCase();\r\n            \r\n            \/\/ Chars apr\u00e8s codePage (ex: \"L1A\" de \"MDG48442L1A\")\r\n            const indexCodePage = emplacementWeb.indexOf(codePage);\r\n            const suffixeEspace = indexCodePage >= 0 ? \r\n                emplacementWeb.substring(indexCodePage + codePage.length) : \r\n                '';\r\n            \r\n            \/\/ Format final : JWC-MDG-48442-L1A\r\n            const reference = `${codeUnique}-${prefixePays}-${codePage}-${suffixeEspace}`;\r\n            \r\n            console.log('\ud83d\udccb R\u00e9f\u00e9rence construite:', reference);\r\n            \r\n            return reference;\r\n        },\r\n        \r\n        \/\/ ================================================================\r\n        \/\/ pb793 : LIBELLES du recapitulatif de reservation, writer UNIQUE.\r\n        \/\/   Ligne 1 : \"Site Cameroun\"            -> .CampagnePaysClass\r\n        \/\/             \"Homepage\" \/ \"Sect. Banque\" -> .CampagnePageTextClass\r\n        \/\/             \"Art. <titre>\"              -> .ArticleTitre (articles)\r\n        \/\/   Ligne 2 : \"Position Haut de page 1\"   -> .CampagnePositionClass\r\n        \/\/             \"Format Banniere\"           -> .CampagneFormatClass\r\n        \/\/   Ligne 3 : \"Ref. Espace pub MDG\u2026L1A\"   -> .CampagneNoClass\r\n        \/\/   Ligne 5 : \"Annonceur France\"          -> .CampagnePaysSocieteClass\r\n        \/\/   Dates et tarif inchanges.\r\n        \/\/   Ces zones avaient jusqu'a SIX writers chacune : tout passe desormais par\r\n        \/\/   _majRecap793, appele en fin de rendu. Sans writer unique, un rendu partiel\r\n        \/\/   ecraserait les libelles (motif pb735, pb726, pb738).\r\n        \/\/   Revert : window._viaPb793Off = true.\r\n        \/\/ ================================================================\r\n        \/\/ ================================================================\r\n        \/\/ pb801 : REMONTEE de 25px du recapitulatif, MOBILE uniquement.\r\n        \/\/   Le decalage vertical est porte par le margin-top de #CampagnePage. Il a\r\n        \/\/   DEUX sources qui se superposent :\r\n        \/\/     - le CSS pb77   : 16px mobile de base, 30px avec le bouton Modifier\r\n        \/\/     - des writers INLINE !important (item actif 22px, inactif 16px)\r\n        \/\/   L'inline prime sur la feuille : agir sur le seul CSS n'aurait rien change\r\n        \/\/   sur les items rendus. Les deux sont donc traites, par un decalage unique.\r\n        \/\/   pb801b : le decalage se fait vers le BAS (+25px). Knob unique\r\n        \/\/   window._viaDecale801 \u2014 une seule valeur a changer pour reajuster,\r\n        \/\/   plutot que six constantes dispersees. Positif = vers le bas.\r\n        \/\/   Revert : window._viaPb801Off = true.\r\n        \/\/ ================================================================\r\n        _mt801(valeurPx) {\r\n            var _v = parseFloat(valeurPx);\r\n            if (!(_v === _v)) { return valeurPx; }            \/\/ NaN : on ne touche pas\r\n            if (window._viaPb801Off === true) { return _v + 'px'; }\r\n            \/\/ pb803 : le desktop a lui aussi remonte d'environ 5px. Il n'etait pourtant\r\n            \/\/   pas touche par pb801\/pb802 \u2014 la cause est ailleurs (pb793b a rendu\r\n            \/\/   .CampagnePositionClass visible et recrute deux separateurs de ligne,\r\n            \/\/   ce qui a redistribue les hauteurs du conteneur flex).\r\n            \/\/   On lui donne donc son PROPRE decalage, independant du mobile, plutot\r\n            \/\/   que de faire porter au knob mobile une correction qui ne le concerne pas.\r\n            \/\/   Knob : window._viaDecaleDesk803 (5 par defaut, positif = vers le bas).\r\n            if (window.outerWidth >= 1000) {\r\n                var _dk = (typeof window._viaDecaleDesk803 === 'number') ? window._viaDecaleDesk803 : 5;\r\n                return (_v + _dk) + 'px';\r\n            }\r\n            var _d = (typeof window._viaDecale801 === 'number') ? window._viaDecale801 : -15;   \/\/ pb867 : 10 - 25 (remontee mobile)\r\n            return (_v + _d) + 'px';\r\n        },\r\n\r\n        _lib793(fr, en) {\r\n            return (sessionStorage.getItem('SiteLangue') === 'EN') ? en : fr;\r\n        },\r\n\r\n        \/\/   Titre d'article : retirer le prefixe \"Pays \u2013 Secteur \u2013 \", puis tronquer.\r\n        \/\/   ATTENTION : le separateur est un tiret DEMI-CADRATIN ENTOURE D'ESPACES.\r\n        \/\/   Un decoupage sur le simple trait d'union casserait \"Agro-industries\",\r\n        \/\/   \"Sud-Africain\", \"Pointe-Noire\"\u2026 On n'accepte donc que \" \u2013 \" \/ \" \u2014 \" \/ \" - \",\r\n        \/\/   espaces obligatoires des deux cotes.\r\n        _titreArticle793(titre) {\r\n            var _t = String(titre || '').trim();\r\n            if (!_t) { return ''; }\r\n            var _parts = _t.split(\/\\s+[\\u2013\\u2014-]\\s+\/);\r\n            if (_parts.length > 1) { _t = _parts[_parts.length - 1].trim(); }\r\n            var _max = (typeof window._viaMaxTitre793 === 'number') ? window._viaMaxTitre793 : 60;\r\n            if (_t.length <= _max) { return _t; }\r\n            \/\/ troncature a la frontiere de MOT, jamais au milieu\r\n            var _coupe = _t.slice(0, _max);\r\n            var _esp = _coupe.lastIndexOf(' ');\r\n            if (_esp > 20) { _coupe = _coupe.slice(0, _esp); }\r\n            return _coupe.replace(\/[\\s,;:.]+$\/, '') + '\\u2026';\r\n        },\r\n\r\n        \/\/   Rang de l'espace : Ele1A -> 1, sinon le chiffre apres \"L\" de la reference.\r\n        _rangEspace793(item) {\r\n            var _r = (item.donneesIframe ? item.donneesIframe.Rank_Emplacement_Page_Web : '') || '';\r\n            var _m = String(_r).match(\/Ele(\\d+)\/i);\r\n            if (_m) { return _m[1]; }\r\n            _m = String(item.emplacementPageWeb || '').match(\/L(\\d+)\/);\r\n            return _m ? _m[1] : '';\r\n        },\r\n\r\n        \/\/ ================================================================\r\n        \/\/ pb794 : les prefixes disparaissaient apres coup \u2014 \"Gabon\" au lieu de\r\n        \/\/   \"Site Gabon\", \"Banniere\" au lieu de \"Format Banniere\". pb793 n'etait\r\n        \/\/   accroche qu'a remplirItemPartiel et rafraichirItemHTML ; or ces zones\r\n        \/\/   comptent CINQ autres writers (L2835, 3527, 4269 pour le pays ; L3732,\r\n        \/\/   5602\/5606\/5609\/5612 pour le format) qui s'executent ensuite.\r\n        \/\/   Plutot que de courir apres chacun \u2014 et d'en manquer un au prochain\r\n        \/\/   ticket \u2014 le prefixe devient une PROJECTION IDEMPOTENTE : on l'ajoute si\r\n        \/\/   la zone ne le porte pas deja, on ne touche a rien sinon. Rejoue\r\n        \/\/   periodiquement, il repare toute reecriture concurrente.\r\n        \/\/   L'idempotence est la condition de suret\u00e9 : sans elle, chaque passe\r\n        \/\/   empilerait \"Site Site Site Gabon\".\r\n        \/\/   Revert : window._viaPb794Off = true.\r\n        \/\/ ================================================================\r\n        _prefixer794($zone, prefixe) {\r\n            if (window._viaPb794Off === true) { return; }\r\n            if (!$zone ? true : !$zone.length) { return; }\r\n            $zone.each(function () {\r\n                var _txt = (this.textContent || '').trim();\r\n                if (!_txt) { return; }                                   \/\/ vide : rien a prefixer\r\n                if (_txt.indexOf(prefixe) === 0) { return; }             \/\/ deja prefixe\r\n                \/\/ on prefixe le HTML pour preserver le tarif mode reduit (<span>)\r\n                this.innerHTML = prefixe + this.innerHTML.replace(\/^\\s+\/, '');\r\n            });\r\n        },\r\n\r\n        \/\/   pb795 : rejeu de TOUT le recapitulatif, plus seulement des prefixes.\r\n        \/\/   Le HTML montrait \"&nbsp;&nbsp;Haut de page\" dans .CampagnePageTextClass :\r\n        \/\/   un writer concurrent ([position] mettreAJour) y accole la position, dans\r\n        \/\/   la zone de la PAGE. Reprefixer ne corrigeait rien \u2014 le contenu lui-meme\r\n        \/\/   etait faux, et le prefixe \"Position \" attendait dans une autre zone.\r\n        \/\/   On re-projette donc _majRecap793 depuis l'etat du panier : chaque zone\r\n        \/\/   retrouve sa valeur, quel que soit ce qui est passe avant. La projection\r\n        \/\/   est idempotente, une passe a vide reecrit les memes chaines.\r\n        majPrefixes794() {\r\n            if (window._viaPb793Off === true) { return; }\r\n            if (window._viaPb794Off === true) { return; }\r\n            try {\r\n                var _self = this;\r\n                if (window._viaPb795Off !== true) {\r\n                    var _st795 = _self.state ? (_self.state.items || []) : [];\r\n                    _st795.forEach(function (_it795) {\r\n                        var $i795 = $('#' + _it795.id);\r\n                        if ($i795.length) { _self._majRecap793($i795, _it795); }\r\n                    });\r\n                }\r\n                var _site = _self._lib793('Site ', 'Site ');\r\n                var _fmt  = _self._lib793('Format ', 'Format ');\r\n                var _ann  = _self._lib793('Annonceur ', 'Advertiser ');\r\n                var _pos  = _self._lib793('Position ', 'Position ');\r\n                $('.CampagneTemplateClass').each(function () {\r\n                    var $it = $(this);\r\n                    if ($it.attr('id') === 'CampagneTemplate') { return; }   \/\/ le template nu\r\n                    _self._prefixer794($it.find('[id=\"CampagnePaysTexte\"], .CampagnePaysClass'), _site);\r\n                    _self._prefixer794($it.find('.CampagneFormatClass'), _fmt);\r\n                    \/\/ pb797 : PAS de prefixage aveugle sur .CampagneNoClass \u2014 un writer\r\n                    \/\/   concurrent y ecrit un libelle complet (\"Espace publicitaire\r\n                    \/\/   Pop-up \u2026\") devant lequel le prefixe se collait. La zone est\r\n                    \/\/   entierement reconstruite par _majRecap793, qui sait extraire la\r\n                    \/\/   reference et preserver la case a cocher.\r\n                    _self._prefixer794($it.find('.CampagnePaysSocieteClass'), _ann);\r\n                    _self._prefixer794($it.find('.CampagnePositionClass'), _pos);\r\n                });\r\n            } catch (_e794) { console.warn('[pb794]', _e794.message); }\r\n        },\r\n\r\n        \/\/ ================================================================\r\n        \/\/ pb815 : DESACTIVER une reservation depuis son picto .via-selectionner-btn.\r\n        \/\/   Etat inedit : state.itemActif = null. Jusqu'ici, seul setItemActif\r\n        \/\/   existait \u2014 on pouvait changer de resa active, jamais n'en avoir aucune.\r\n        \/\/   Effets demandes :\r\n        \/\/     - aucune autre resa ne devient active\r\n        \/\/     - pays \/ secteur \/ format deselectionnes\r\n        \/\/     - VLP laisse OUVERT, resa laissee DEPLIEE (choix utilisateur)\r\n        \/\/     - popup Tarifs vide entierement\r\n        \/\/   Le clic suivant sur un pays ou un secteur creera une nouvelle resa sans\r\n        \/\/   rien ajouter : _viaResaActive743 renvoie deja false sans item actif.\r\n        \/\/   Revert : window._viaPb815Off = true.\r\n        \/\/ ================================================================\r\n        _deselectionnerTrois815() {\r\n            \/\/ ================================================================\r\n            \/\/ pb815b : s'appuyer sur la MECANIQUE EXISTANTE de \"Ajouter une\r\n            \/\/   reservation\" (demande utilisateur). Ma version artisanale purgeait les\r\n            \/\/   cles et masquait les sous-titres, mais ne retablissait pas la mise en\r\n            \/\/   page des bandeaux : les hauteurs restaient calees sur des sous-titres\r\n            \/\/   visibles, et les vignettes chevauchaient leurs titres.\r\n            \/\/   _viaHideColonneCentre fait les deux \u2014 c'est la routine que le bouton\r\n            \/\/   Ajouter appelle. Les trois accordeons sont ensuite rouverts comme le\r\n            \/\/   fait ce meme bouton (openAssocierPays\/Secteur\/ChoixFormat), qui\r\n            \/\/   reaffichent chacun leur SousTitre seulement si la cle correspondante\r\n            \/\/   existe : apres purge, ils restent donc masques, et les hauteurs sont\r\n            \/\/   recalculees correctement.\r\n            \/\/   Le bloc manuel ci-dessous n'est conserve qu'en REPLI, si la routine\r\n            \/\/   canonique n'est pas exposee (contexte iframe ou chargement partiel).\r\n            \/\/ ================================================================\r\n            if (window._viaPb815bOff !== true) {\r\n                var _fait815b = false;\r\n                if (typeof window._viaHideColonneCentre === 'function') {\r\n                    try {\r\n                        window._viaHideColonneCentre();\r\n                        _fait815b = true;\r\n                        console.log('[pb815b] deselection par _viaHideColonneCentre (voie Ajouter une reservation)');\r\n                    } catch (_eH815) { console.warn('[pb815b] _viaHideColonneCentre:', _eH815.message); }\r\n                }\r\n                if (_fait815b) {\r\n                    ['openAssocierPays', 'openAssocierSecteur', 'openChoixFormat'].forEach(function (_fn) {\r\n                        try { if (typeof window[_fn] === 'function') { window[_fn](); } } catch (_eO815) {}\r\n                    });\r\n                    return;\r\n                }\r\n                console.warn('[pb815b] _viaHideColonneCentre indisponible -> repli manuel');\r\n            }\r\n            \/\/ memes cles que _viaHideColonneCentre (yearbook-media.js), sans masquer\r\n            \/\/ #ColonneCentre : on deselectionne, on ne change pas la mise en page.\r\n            ['ContinentPaysTitre', 'SitePays', 'ContinentPaysTitreDisplayed', 'SelectedSiteElementId',\r\n             'SelectedPageSecteur', 'SelectedPageType', 'SelectedPageSecteurDisplayed',\r\n             'LinkSecteurPage', 'LinkSecteurPageDisplayed', 'commandePage', 'SelectedSecteurElementId',\r\n             'FormatSelect', 'PopUpChoice', 'Formatchoisi', 'Commande_Format_Transmis',\r\n             '_FormatSelectApplied'].forEach(function (_k) { sessionStorage.removeItem(_k); });\r\n            try {\r\n                $('#ListeSitesConteneurScroll .SiteContinentPaysTitre').css('border', 'none');\r\n                $('.HPContinentPays').css('border', 'none');\r\n                $('.HPType, .PTType').css('border', 'none');\r\n                $('.CartoucheArticles').css('border', 'none');\r\n                $('.FormatClassique, .FormatPopup').css({ 'border': 'none', 'box-shadow': 'none' });\r\n                $('.AssocierPaysClass .SousTitre, .AssocierSecteurClass .SousTitre, .ChoixFormatClass .SousTitre').hide();\r\n                if (typeof FormatState !== 'undefined') { FormatState.set('', 'No'); }\r\n            } catch (_eD815) { console.warn('[pb815] deselection visuelle:', _eD815.message); }\r\n        },\r\n\r\n        desactiverResa815(itemId) {\r\n            if (window._viaPb815Off === true) { return false; }\r\n            try {\r\n                if (this.state.itemActif !== itemId) { return false; }   \/\/ pas l'active\r\n                console.log('[pb815] desactivation de ' + itemId + ' \u2014 plus aucune resa active');\r\n                this.state.itemActif = null;\r\n                var $it = $('#' + itemId);\r\n                if ($it.length) {\r\n                    \/\/ resa laissee DEPLIEE, seul le marqueur d'activite tombe\r\n                    $it.attr('data-via-item-actif', 'false');\r\n                    \/\/ pb816 : liser\u00e9 GRIS inactif, la meme valeur que celle posee par\r\n                    \/\/   setItemActif aux items non actifs (L6227) : 3px solid #BBBBBB,\r\n                    \/\/   en inline !important pour passer devant Elementor.\r\n                    \/\/   removeProperty seul rendait la main au CSS Elementor, sans\r\n                    \/\/   garantie \u2014 l'item gardait donc son liser\u00e9 vert (lecon pb668).\r\n                    \/\/   Le fond suit la meme regle (#F8F8F8), sinon un item desactive\r\n                    \/\/   resterait sur le fond de l'etat actif.\r\n                    \/\/   data-via-reduit n'est PAS touche : la resa reste DEPLIEE\r\n                    \/\/   (choix utilisateur pb815), contrairement au chemin setItemActif\r\n                    \/\/   qui replie les items non actifs.\r\n                    $it[0].style.removeProperty('border');\r\n                    $it[0].style.setProperty('border', '3px solid #BBBBBB', 'important');\r\n                    $it.css('background', '#F8F8F8');\r\n                    console.log('[pb816] lisere gris pose sur ' + itemId + ' (resa desactivee)');\r\n                }\r\n                this._deselectionnerTrois815();\r\n                \/\/ popup Tarifs : remise a zero par sa propre routine (pb710), seule a\r\n                \/\/   connaitre l'ensemble de ses champs et de ses etapes.\r\n                var _g815 = window.VIA_GrilleTarifaire;\r\n                if (_g815 ? typeof _g815.reinitialiserPopup710 === 'function' : false) {\r\n                    _g815.reinitialiserPopup710();\r\n                    console.log('[pb815] popup Tarifs reinitialise');\r\n                }\r\n                if (typeof this.rafraichirItemHTML === 'function') { this.rafraichirItemHTML(itemId); }\r\n                return true;\r\n            } catch (_e815) { console.warn('[pb815]', _e815.message); return false; }\r\n        },\r\n\r\n        \/\/ ================================================================\r\n        \/\/ pb885 : DESKTOP \u2014 a la creation de la PREMIERE reservation, refermer les\r\n        \/\/   trois etapes pays \/ secteurs \/ formats dans #via-col-ColonneDroite.\r\n        \/\/   L'equivalent mobile existe deja via _viaFermerBandeaux841, appele par les\r\n        \/\/   chemins achat express (pb838\/pb841). Le process desktop ne l'avait pas.\r\n        \/\/   Declencheur : passage de 0 a 1 item. Memorise pour ne se produire qu'une\r\n        \/\/   fois \u2014 une fermeture repetee empecherait l'utilisateur de rouvrir une\r\n        \/\/   etape (le drapeau _manualClosed308 la maintiendrait fermee).\r\n        \/\/   Revert : window._viaPb885Off = true.\r\n        \/\/ ================================================================\r\n        _fermerEtapesPremiereResa885() {\r\n            if (window._viaPb885Off === true) { return; }\r\n            if (window.outerWidth < 1000) { return; }        \/\/ desktop uniquement\r\n            if (window._viaFait885 === true) { return; }     \/\/ une seule fois\r\n            try {\r\n                var _nb885 = (this.state ? (this.state.items || []).length : 0);\r\n                if (_nb885 !== 1) { return; }\r\n                window._viaFait885 = true;\r\n                if (typeof window._viaFermerBandeaux841 === 'function') {\r\n                    console.log('[pb885] 1re reservation creee (desktop) -> fermeture des 3 etapes');\r\n                    window._viaFermerBandeaux841('1re resa desktop');\r\n                } else {\r\n                    console.warn('[pb885] _viaFermerBandeaux841 indisponible');\r\n                }\r\n            } catch (_e885) { console.warn('[pb885]', _e885.message); }\r\n        },\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb1262 : INVITE EN TETE DE CARTE pour la reservation ACTIVE non reservee\r\n        \/\/   (demande user) : \u00ab Choisir les espaces publicitaires dans la page\r\n        \/\/   selectionnee \u00bb, en rouge, au-dessus du bloc de la carte.\r\n        \/\/   A savoir avant de lire : une invite en tete de carte a deja existe\r\n        \/\/   (pb1248) et TU L'AS FAIT RETIRER en pb1252. Celle-ci en differe par le\r\n        \/\/   libelle, par la condition d'affichage et par le contexte \u2014 le\r\n        \/\/   recapitulatif est desormais l'etape active en 3 colonnes (pb1253), ce\r\n        \/\/   qui n'etait pas le cas alors. Si ce n'est pas ce que tu attends, c'est\r\n        \/\/   ici qu'il faut revenir.\r\n        \/\/   Le libelle est celui du bandeau VLP sur desktop (pb1114) : les deux\r\n        \/\/   endroits disent la meme chose, mot pour mot, comme pb1114 le faisait\r\n        \/\/   deja avec le titre de l'etape.\r\n        \/\/   Le message existant de ajouterMsgAccompagnement ne couvrait pas ce cas :\r\n        \/\/   quand pays, secteur et format sont tous choisis, sa branche 'anticipee'\r\n        \/\/   sort sans rien ecrire (\u00ab sera remplace quand la resa passe en partielle\r\n        \/\/   avec PageWeb chargee \u00bb) \u2014 et en 3 colonnes cette bascule n'a pas lieu.\r\n        \/\/   Conditions, reprises de _viaTexteInvite786 pour dire la meme chose que\r\n        \/\/   le bandeau : la carte est celle de l'item ACTIF, et l'espace n'est pas\r\n        \/\/   reserve (estReserveEffective, ou statut 'complete').\r\n        \/\/   Classe propre (.via-invite-haut-1262) : ajouterMsgAccompagnement fait un\r\n        \/\/   remove() sur .CampagneMsgAccompagnement a chaque passage, les deux ne\r\n        \/\/   doivent pas se marcher dessus.\r\n        \/\/   Revert : window._viaPb1262Off = true.\r\n        \/\/ ====================================================================\r\n        \/\/ ====================================================================\r\n        \/\/ pb1488 : PREDICAT UNIQUE \u00ab UNE ANNONCE EST DEPOSEE \u00bb.\r\n        \/\/   Trois affichages doivent basculer ensemble quand l'annonceur a\r\n        \/\/   depose son annonce : l'invite du haut, le message d'accompagnement,\r\n        \/\/   et le libelle de la ligne de reference. Un seul predicat pour les\r\n        \/\/   trois, sinon ils divergeront a la premiere retouche.\r\n        \/\/   Source : les memes champs que remplirItemPartiel utilise deja pour\r\n        \/\/   afficher .CampagneAnnonceDeposeClass (FileReceived \/ HasAdLoadedDom)\r\n        \/\/   \u2014 on ne cree pas une deuxieme verite.\r\n        \/\/   Revert global : window._viaPb1488Off = true.\r\n        \/\/ ====================================================================\r\n        \/\/ ====================================================================\r\n        \/\/ pb1491 : \u00ab A RESERVER \u00bb EST LE SIGNAL LE PLUS SUR (proposition user).\r\n        \/\/   Trois tentatives ont echoue parce qu'elles interrogeaient l'objet\r\n        \/\/   item, ecrit trop tard : au depot, FileReceived n'est pas encore\r\n        \/\/   pose, il ne l'est qu'a la reservation.\r\n        \/\/   La carte, elle, sait tout de suite : des le depot elle affiche\r\n        \/\/   \u00ab \u2026 a reserver \u00bb et sa case a cocher .via-recap-reserver-cb. Ce\r\n        \/\/   balisage n'existe QUE dans ce cas \u2014 annonce deposee, pas encore\r\n        \/\/   reservee \u2014 c'est donc exactement le signal recherche.\r\n        \/\/   La carte devient un second argument, optionnel : la ou l'appelant\r\n        \/\/   l'a sous la main, le predicat repond juste immediatement.\r\n        \/\/   Revert : window._viaPb1491Off = true (retour aux seuls champs item).\r\n        \/\/ ====================================================================\r\n        _annonceDeposee1488(item, $carte) {\r\n            if (window._viaPb1488Off === true) { return false; }\r\n            var _d1488 = item ? item.donneesIframe : null;\r\n            if (_d1488) {\r\n                if (_d1488.FileReceived === 'Yes') { return true; }\r\n                if (_d1488.HasAdLoadedDom === 'Yes') { return true; }\r\n            }\r\n            if (window._viaPb1491Off === true) { return false; }\r\n            try {\r\n                var _el1491 = null;\r\n                if ($carte) {\r\n                    _el1491 = $carte.nodeType ? $carte : ($carte.length ? $carte[0] : null);\r\n                }\r\n                if (!_el1491) { return false; }\r\n                \/\/ signal 1 : la case a cocher de reservation du recapitulatif\r\n                if (_el1491.querySelector('.via-recap-reserver-cb')) { return true; }\r\n                \/\/ signal 2 : la mention texte, dans la ligne de reference\r\n                var _no1491 = _el1491.querySelector('.CampagneNoClass');\r\n                if (_no1491) {\r\n                    var _t1491 = _no1491.textContent || '';\r\n                    if (_t1491.indexOf('\u00e0 r\u00e9server') !== -1) { return true; }\r\n                    if (_t1491.indexOf('to be booked') !== -1) { return true; }\r\n                }\r\n                \/\/ signal 3 : \u00ab Annonce inseree \u00bb effectivement visible\r\n                if (this._depotVisibleCarte1490 ? this._depotVisibleCarte1490(_el1491) : false) { return true; }\r\n                return false;\r\n            } catch (_e1491) { return false; }\r\n        },\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb1490 : LE DEPOT SE LIT AUSSI DANS LA CARTE.\r\n        \/\/   Constat user : le log pb1489 ne sort qu'a la RESERVATION, pas au\r\n        \/\/   depot. L'etat de l'objet item n'est donc pas encore a jour au\r\n        \/\/   moment ou l'annonce est deposee \u2014 alors que la carte, elle,\r\n        \/\/   affiche deja \u00ab Annonce inseree \u00bb (.CampagneAnnonceDeposeClass), ce\r\n        \/\/   que la capture montre noir sur blanc.\r\n        \/\/   On ajoute donc une lecture du DOM de la carte, en repli de l'etat.\r\n        \/\/   L'etat semantique reste la source preferee ; ce repli ne sert que\r\n        \/\/   pendant la fenetre ou il n'est pas encore ecrit.\r\n        \/\/   Revert : window._viaPb1490Off = true.\r\n        \/\/ ====================================================================\r\n        _depotVisibleCarte1490(carte) {\r\n            if (window._viaPb1490Off === true) { return false; }\r\n            if (!carte) { return false; }\r\n            try {\r\n                var _n1490 = carte.querySelector('.CampagneAnnonceDeposeClass');\r\n                if (!_n1490) { return false; }\r\n                var _cs1490 = getComputedStyle(_n1490);\r\n                if (_cs1490.display === 'none') { return false; }\r\n                if (_cs1490.visibility === 'hidden') { return false; }\r\n                if (_n1490.getBoundingClientRect().height > 0) { return true; }\r\n                return false;\r\n            } catch (_e1490) { return false; }\r\n        },\r\n\r\n        _inviteEspace1262($item, item) {\r\n            if (window._viaPb1262Off === true) { return; }\r\n            \/\/ pb1488 : annonce deposee -> l'invite \u00ab Choisir les espaces\r\n            \/\/   publicitaires dans la page selectionnee \u00bb n'a plus lieu d'etre :\r\n            \/\/   le choix est fait. On la RETIRE si elle est la, on ne se contente\r\n            \/\/   pas de ne plus la creer.\r\n            \/\/ pb1491 : la GARDE recoit la carte. C'est elle qui empeche la\r\n            \/\/   RECREATION de l'invite au battement suivant ; sans la carte, son\r\n            \/\/   predicat repondait faux au depot et l'invite renaissait aussitot\r\n            \/\/   apres avoir ete retiree par le balayage \u2014 d'ou l'impression\r\n            \/\/   qu'elle n'etait jamais masquee.\r\n            \/\/ ================================================================\r\n            \/\/ pb1492 : LA GARDE DIT CE QU'ELLE DECIDE.\r\n            \/\/   Trois livraisons sans effet et aucun log : impossible de savoir si\r\n            \/\/   la garde tourne, ni pourquoi elle repond faux. On journalise donc\r\n            \/\/   la decision ET les signaux, une fois par carte et par resultat.\r\n            \/\/   Les quatre signaux sont ceux de pb1491 ; les voir un par un dira\r\n            \/\/   lequel manque au moment du depot.\r\n            \/\/ ================================================================\r\n            var _dep1492 = this._annonceDeposee1488(item, $item);\r\n            try {\r\n                var _el1492 = $item ? ($item.length ? $item[0] : null) : null;\r\n                var _idc1492 = _el1492 ? (_el1492.id || '(sans-id)') : '(pas de carte)';\r\n                var _sig1492 = _idc1492 + '|' + (_dep1492 ? '1' : '0');\r\n                if (!window._viaVus1492) { window._viaVus1492 = {}; }\r\n                if (window._viaVus1492[_sig1492] ? false : true) {\r\n                    window._viaVus1492[_sig1492] = true;\r\n                    var _d1492 = item ? item.donneesIframe : null;\r\n                    var _no1492 = _el1492 ? _el1492.querySelector('.CampagneNoClass') : null;\r\n                    console.log('[pb1492] garde invite | carte=' + _idc1492\r\n                        + ' | deposee=' + _dep1492\r\n                        + ' | FileReceived=' + (_d1492 ? _d1492.FileReceived : '(pas de donneesIframe)')\r\n                        + ' | HasAdLoadedDom=' + (_d1492 ? _d1492.HasAdLoadedDom : '-')\r\n                        + ' | case a cocher=' + (_el1492 ? !!_el1492.querySelector('.via-recap-reserver-cb') : '-')\r\n                        + ' | texte NoClass=\"' + (_no1492 ? (_no1492.textContent || '').slice(0, 60) : '(absent)') + '\"');\r\n                }\r\n            } catch (_e1492) { console.warn('[pb1492] journal garde : ' + _e1492.message); }\r\n            if (_dep1492) {\r\n                if ($item ? $item.length : false) {\r\n                    var $inv1488 = $item.find('.via-invite-haut-1262');\r\n                    if ($inv1488.length) {\r\n                        $inv1488.remove();\r\n                        console.log('[pb1488] invite du haut retiree (annonce deposee)');\r\n                    }\r\n                }\r\n                return;\r\n            }\r\n            if (!$item ? true : !$item.length) { return; }\r\n            if (!item) { return; }\r\n            try {\r\n                var _actif1262 = this.state ? (this.state.itemActif === item.id) : false;\r\n                var _res1262 = (item.estReserveEffective === true)\r\n                    ? true\r\n                    : (item.statut === 'complete');\r\n                \/\/ ============================================================\r\n                \/\/ pb1272 : L'INVITE ATTEND QUE LA PAGE WEB SOIT LA (demande user).\r\n                \/\/   \u00ab Choisir les espaces publicitaires dans la page selectionnee \u00bb\r\n                \/\/   n'a aucun sens tant qu'aucune page n'est affichee : sur une\r\n                \/\/   reservation qui vient d'etre creee, elle demande de choisir\r\n                \/\/   dans une page qui n'existe pas encore.\r\n                \/\/   Critere : l'URL de la page de la reservation. C'est la meme\r\n                \/\/   donnee que le VLP consomme pour s'ouvrir \u2014 si elle est la, la\r\n                \/\/   page est affichee ou sur le point de l'etre ; si elle manque,\r\n                \/\/   il n'y a rien a montrer.\r\n                \/\/   Revert : window._viaPb1272Off = true.\r\n                \/\/ ============================================================\r\n                var _page1262 = (window._viaPb1272Off === true)\r\n                    ? true\r\n                    : !!(item.linkSecteurPage\r\n                        || (item.donneesIframe ? item.donneesIframe.LoadedPageUrl : ''));\r\n                var _voir1262 = _actif1262 ? (_res1262 ? false : _page1262) : false;\r\n                var $inv1262 = $item.find('.via-invite-haut-1262');\r\n                var _cle1262 = item.id || '(sans-id)';\r\n                if (!window._viaSigs1262) { window._viaSigs1262 = {}; }\r\n                if (!_voir1262) {\r\n                    if ($inv1262.length) {\r\n                        $inv1262.remove();\r\n                        window._viaSigs1262[_cle1262] = 'off';\r\n                        console.log('[pb1262] invite retir\u00e9e ('\r\n                            + (!_actif1262\r\n                                ? 'r\u00e9servation non active'\r\n                                : (_res1262 ? 'espace r\u00e9serv\u00e9' : 'pas encore de page web'))\r\n                            + ')');\r\n                    }\r\n                    return;\r\n                }\r\n                var _en1262 = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                var _txt1262 = _en1262\r\n                    ? 'Select advertising spaces on the selected page'\r\n                    : 'Choisir les espaces publicitaires dans la page s\\u00e9lectionn\\u00e9e';\r\n                var _neuf1262 = false;\r\n                if (!$inv1262.length) {\r\n                    $inv1262 = $('<div class=\"via-invite-haut-1262\"><\/div>');\r\n                    var $anc1262 = $item.find('.CampagnePageRefClass').first();\r\n                    if ($anc1262.length) { $anc1262.before($inv1262); }\r\n                    else { $item.prepend($inv1262); }\r\n                    _neuf1262 = true;\r\n                }\r\n                if ($inv1262[0].textContent !== _txt1262) { $inv1262[0].textContent = _txt1262; }\r\n                \/\/ ============================================================\r\n                \/\/ pb1262b : LA PHRASE REMONTE DE 20px (demande user).\r\n                \/\/   Constat : elle se superposait a la premiere ligne de la carte.\r\n                \/\/   Explication : le calage de pb1259c pose un margin-top negatif sur\r\n                \/\/   les zones de la ligne 1. Elles remontent donc AU-DESSUS du bord\r\n                \/\/   haut de .CampagnePageRefClass, qui ne les contient plus tout a\r\n                \/\/   fait \u2014 et l'invite, posee juste avant, se retrouve dessous. Tant\r\n                \/\/   qu'il n'y avait rien a cet endroit, ce debord ne se voyait pas.\r\n                \/\/   La valeur est exposee en variable : c'est un reglage visuel, il\r\n                \/\/   se retouche en console sans redeploiement.\r\n                \/\/   Les proprietes sont reappliquees a chaque passe mais ecrites\r\n                \/\/   seulement si elles ont change \u2014 cette methode tourne au rythme du\r\n                \/\/   sequenceur, et reecrire un style identique invaliderait la mise en\r\n                \/\/   page pour rien.\r\n                \/\/   Revert : window._viaInvite1262Haut = 0.\r\n                \/\/ ============================================================\r\n                var _haut1262 = (typeof window._viaInvite1262Haut === 'number')\r\n                    ? window._viaInvite1262Haut\r\n                    : -20;\r\n                \/\/ pb1262c : marge basse portee a 30px (demande user), reglable de la\r\n                \/\/   meme facon que la marge haute \u2014 les deux vont par paire.\r\n                \/\/   Revert : window._viaInvite1262Bas = 4.\r\n                var _bas1262 = (typeof window._viaInvite1262Bas === 'number')\r\n                    ? window._viaInvite1262Bas\r\n                    : 30;\r\n                \/\/ memes valeurs que les messages d'accompagnement de la carte, pour\r\n                \/\/   que les deux se ressemblent ; inline !important, seule ecriture\r\n                \/\/   qui tienne face aux regles Elementor.\r\n                \/\/ pb1395 : taille portee a 12px (demande user), reglable comme les\r\n                \/\/   deux marges au-dessus \u2014 cet element n'a que des valeurs de calage,\r\n                \/\/   autant qu'elles se retouchent toutes de la meme facon.\r\n                \/\/   Revert : window._viaInvite1262Taille = 11.\r\n                var _taille1395 = (typeof window._viaInvite1262Taille === 'number')\r\n                    ? window._viaInvite1262Taille : 12;\r\n                var _st1262 = {\r\n                    'color': '#FB5E2A',\r\n                    'font-size': _taille1395 + 'px',\r\n                    'font-weight': '600',\r\n                    'text-align': 'center',\r\n                    'margin-top': _haut1262 + 'px',\r\n                    'margin-bottom': _bas1262 + 'px',\r\n                    'margin-left': '0px',\r\n                    'margin-right': '0px'\r\n                };\r\n                var _s1262 = $inv1262[0].style;\r\n                Object.keys(_st1262).forEach(function (_p1262) {\r\n                    if (_s1262.getPropertyValue(_p1262) !== _st1262[_p1262]) {\r\n                        _s1262.setProperty(_p1262, _st1262[_p1262], 'important');\r\n                    }\r\n                });\r\n                var _sg1262 = _txt1262 + '|' + _haut1262 + '|' + _bas1262\r\n                    + '|' + _taille1395;   \/\/ pb1395 : la taille entre dans la signature\r\n                if (window._viaSigs1262[_cle1262] !== _sg1262) {\r\n                    window._viaSigs1262[_cle1262] = _sg1262;\r\n                    console.log('[pb1262] invite ' + (_neuf1262 ? 'pos\u00e9e' : 'ajust\u00e9e')\r\n                        + ' en t\u00eate de carte | remont\u00e9e de ' + (-_haut1262) + 'px'\r\n                        + ' | marge basse ' + _bas1262 + 'px'\r\n                        + ' | taille ' + _taille1395 + 'px'\r\n                        + ' | \"' + _txt1262 + '\"');\r\n                }\r\n            } catch (_e1262) { console.warn('[pb1262]', _e1262.message); }\r\n        },\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb1259 : LA NORMALISATION LARGE EST RETIREE \u2014 elle creait plus de\r\n        \/\/   defauts qu'elle n'en corrigeait.\r\n        \/\/   La preuve est dans les logs. En PM-pb1255b le recensement etait vide\r\n        \/\/   (un dedoublonnage par ascendance ecartait toutes les zones) : rien\r\n        \/\/   n'etait normalise. Or c'est justement la version ou l'utilisateur a\r\n        \/\/   ecrit \u00ab il reste un seul point a corriger : l'alignement de\r\n        \/\/   l'annonceur \u00bb. L'espace au-dessus des dates et le chevauchement de\r\n        \/\/   l'envoi differe, signales aux versions ou le recensement fonctionnait,\r\n        \/\/   etaient donc MES ecritures \u2014 pas des defauts d'origine.\r\n        \/\/   Une carte partielle n'a pas besoin d'etre reconstruite : elle a besoin\r\n        \/\/   qu'on corrige la seule zone qui sort du rang.\r\n        \/\/   Ne subsistent que trois ecritures, chacune avec sa preuve :\r\n        \/\/     - pb1256 : la zone Annonceur redevient un element de flux normal ;\r\n        \/\/     - pb1259 : elle s'aligne verticalement sur .CampagnePaysClass, sa\r\n        \/\/       voisine de ligne, qui porte le calage du bloc (-10px) ;\r\n        \/\/     - pb1254f : .CampagnePageRefClass peut grandir \u2014 c'est ce qui a fait\r\n        \/\/       disparaitre le chevauchement de l'envoi differe, et cette\r\n        \/\/       ecriture-la est restee active en PM-pb1255b.\r\n        \/\/   Tout le reste \u2014 recensement, regroupement en lignes, remise a zero des\r\n        \/\/   marges, traitement des enveloppes \u2014 est supprime.\r\n        \/\/   Revert : window._viaPb1254Off = true.\r\n        \/\/ ====================================================================\r\n        _normaliserCarte1254($item, item) {\r\n            if (window._viaPb1254Off === true) { return; }\r\n            if (!$item ? true : !$item.length) { return; }\r\n            if (!item) { return; }\r\n            try {\r\n                \/\/ meme critere que pb1126 : une carte est partielle tant que\r\n                \/\/   l'espace n'est pas reserve.\r\n                var _partiel1254 = (item.estReserveEffective === true)\r\n                    ? false\r\n                    : (item.statut !== 'complete');\r\n\r\n                if (!_partiel1254) {\r\n                    \/\/ --- NETTOYAGE : on ne retire que ce que l'on a ecrit.\r\n                    var _sales1254 = $item.find('[data-via1254]');\r\n                    if (_sales1254.length) {\r\n                        _sales1254.each(function () {\r\n                            this.style.removeProperty('line-height');\r\n                            this.style.removeProperty('margin-top');\r\n                            this.style.removeProperty('margin-bottom');\r\n                            this.removeAttribute('data-via1254');\r\n                            \/\/ pb1259b : la base memorisee part avec l'ecriture qu'elle\r\n                            \/\/   servait a calculer \u2014 sinon une carte revenue a l'etat\r\n                            \/\/   partiel repartirait d'une base perimee.\r\n                            this.removeAttribute('data-viamt1259');\r\n                            this.removeAttribute('data-viamb1259');\r\n                        });\r\n                        console.log('[pb1254] carte compl\u00e9t\u00e9e -> alignement retir\u00e9 ('\r\n                            + _sales1254.length + ' zone(s))');\r\n                    }\r\n                    \/\/ pb1254f : en mode reduit, pb869 libere aussi ce conteneur et\r\n                    \/\/   pour ses propres raisons \u2014 on ne lui retire rien.\r\n                    if ($item.attr('data-via-reduit') !== 'true') {\r\n                        $item.find('[data-via1254c]').each(function () {\r\n                            this.style.removeProperty('flex-wrap');\r\n                            this.style.removeProperty('height');\r\n                            this.style.removeProperty('overflow');\r\n                            this.style.removeProperty('padding-top');   \/\/ pb1316\r\n                            this.removeAttribute('data-via1254c');\r\n                        });\r\n                    }\r\n                    return;\r\n                }\r\n\r\n                \/\/ ============================================================\r\n                \/\/ pb1256 : LA ZONE ANNONCEUR REDEVIENT UN ELEMENT DE FLUX NORMAL.\r\n                \/\/   De toutes les zones de la carte, elle est la seule a porter\r\n                \/\/   elementor-hidden-desktop \/ -tablet \/ -mobile, et la seule dont\r\n                \/\/   l'affichage repose sur un display:block INLINE SANS !important \u2014\r\n                \/\/   la signature d'un .show() jQuery. _saut793, pb871 et _showMsg\r\n                \/\/   retirent tous les trois ces memes classes AVANT de forcer\r\n                \/\/   l'affichage, parce qu'une regle de classe en !important bat une\r\n                \/\/   valeur inline qui ne l'est pas.\r\n                \/\/   Rien n'est force quand la zone est VIDE : ce serait afficher un\r\n                \/\/   bloc sans contenu.\r\n                \/\/   Revert : window._viaPb1256Off = true.\r\n                \/\/ ============================================================\r\n                if (window._viaPb1256Off !== true) {\r\n                    $item.find('.CampagnePaysSocieteClass').each(function () {\r\n                        if (!((this.textContent || '').trim())) { return; }\r\n                        this.classList.remove('elementor-hidden-desktop',\r\n                            'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n                }\r\n\r\n                \/\/ ============================================================\r\n                \/\/ pb1259c : ALIGNER LA LIGNE SANS DEPLACER CE QUI SUIT.\r\n                \/\/   Deux tentatives, le meme symptome : l'interligne avec \u00ab Format\r\n                \/\/   Parrainage \u00bb trop petit. Aligner vers le haut (pb1259, -10px)\r\n                \/\/   retrecissait la boite de la ligne et faisait remonter la ligne 2 ;\r\n                \/\/   aligner vers le bas (pb1259b, 0px) laissait la ligne 2 en place\r\n                \/\/   mais faisait DESCENDRE le texte de 10px. Dans les deux cas l'ecart\r\n                \/\/   perdait 10px.\r\n                \/\/   Ce que je n'avais pas vu : ces 10px n'etaient pas un ecart, c'etait\r\n                \/\/   le DEBORD de l'annonceur sous ses voisines. Site et Secteur sont\r\n                \/\/   remontes de 10px par un calage (margin-top negatif), l'annonceur\r\n                \/\/   non ; c'est lui qui donnait sa hauteur a la ligne. Aligner les trois\r\n                \/\/   supprime forcement ce debord \u2014 d'un cote ou de l'autre.\r\n                \/\/   La regle juste enonce les deux choses separement :\r\n                \/\/     - POSITION : tout le monde au calage, c'est-a-dire a la marge la\r\n                \/\/       plus PETITE \u2014 celle voulue par le theme pour cette ligne ;\r\n                \/\/     - EMPREINTE : la boite recupere en marge basse l'ecart qu'elle\r\n                \/\/       vient de perdre en haut, pour que la ligne 2 ne bouge pas d'un\r\n                \/\/       pixel.\r\n                \/\/   Ce n'est pas une compensation apres coup : deplacer un bloc sans\r\n                \/\/   toucher a ce qui le suit demande les deux ecritures, elles sont le\r\n                \/\/   meme geste.\r\n                \/\/   Bases memorisees en data-* et toujours relues depuis la : une fois\r\n                \/\/   nos marges posees, la valeur calculee n'est plus celle du theme et\r\n                \/\/   l'ecart se cumulerait a chaque passe (lecon pb913\/pb1031).\r\n                \/\/ ============================================================\r\n                var _L1_1259 = '.CampagnePaysSocieteClass, .CampagnePaysClass,'\r\n                    + ' .CampagnePageTextClass';\r\n                var _zones1259 = [];\r\n                var _min1259 = null;\r\n                var _max1259 = null;\r\n                $item.find(_L1_1259).each(function () {\r\n                    if (window.getComputedStyle(this).display === 'none') { return; }\r\n                    if (!((this.textContent || '').trim())) { return; }\r\n                    var _bt1259 = this.getAttribute('data-viamt1259');\r\n                    var _bb1259 = this.getAttribute('data-viamb1259');\r\n                    if (_bt1259 === null) {\r\n                        var _cb1259 = window.getComputedStyle(this);\r\n                        _bt1259 = String(parseFloat(_cb1259.marginTop) || 0);\r\n                        _bb1259 = String(parseFloat(_cb1259.marginBottom) || 0);\r\n                        this.setAttribute('data-viamt1259', _bt1259);\r\n                        this.setAttribute('data-viamb1259', _bb1259);\r\n                    }\r\n                    var _v1259 = parseFloat(_bt1259) || 0;\r\n                    if (_min1259 === null ? true : (_v1259 < _min1259)) { _min1259 = _v1259; }\r\n                    if (_max1259 === null ? true : (_v1259 > _max1259)) { _max1259 = _v1259; }\r\n                    _zones1259.push(this);\r\n                });\r\n                if (_zones1259.length ? (_min1259 !== null) : false) {\r\n                    var _delta1259 = _max1259 - _min1259;   \/\/ le debord a rendre en bas\r\n                    var _refLh1259 = $item.find('.CampagnePaysClass')[0];\r\n                    var _lh1259 = _refLh1259\r\n                        ? window.getComputedStyle(_refLh1259).lineHeight : '';\r\n                    for (var _i1259 = 0; _i1259 < _zones1259.length; _i1259++) {\r\n                        var _e1259 = _zones1259[_i1259];\r\n                        var _mb1259 = parseFloat(_e1259.getAttribute('data-viamb1259')) || 0;\r\n                        _e1259.setAttribute('data-via1254', '1');\r\n                        _e1259.style.setProperty('margin-top', _min1259 + 'px', 'important');\r\n                        _e1259.style.setProperty('margin-bottom',\r\n                            (_mb1259 + _delta1259) + 'px', 'important');\r\n                        if (_lh1259) {\r\n                            _e1259.style.setProperty('line-height', _lh1259, 'important');\r\n                        }\r\n                    }\r\n                    \/\/ signature PAR CARTE (pb968 : une signature globale ne bloque\r\n                    \/\/   plus rien des qu'il y a plusieurs cartes).\r\n                    var _cle1259 = item.id || '(sans-id)';\r\n                    var _sg1259 = _min1259 + '|' + _delta1259 + '|' + _lh1259\r\n                        + '|' + _zones1259.length;\r\n                    if (!window._viaSigs1254) { window._viaSigs1254 = {}; }\r\n                    if (window._viaSigs1254[_cle1259] !== _sg1259) {\r\n                        window._viaSigs1254[_cle1259] = _sg1259;\r\n                        console.log('[pb1259] 1re ligne align\u00e9e | ' + _zones1259.length\r\n                            + ' zone(s) | calage ' + _min1259 + 'px'\r\n                            + ' | d\u00e9bord rendu en bas ' + _delta1259 + 'px'\r\n                            + ' | interligne ' + _lh1259);\r\n                    }\r\n                }\r\n\r\n                \/\/ ============================================================\r\n                \/\/ pb1254f : LE CONTENEUR DOIT POUVOIR GRANDIR.\r\n                \/\/   Un recouvrement ne vient pas des marges mais d'un contenu plus\r\n                \/\/   haut que son conteneur, qui deborde au lieu de le repousser.\r\n                \/\/   pb869 a rencontre et resolu exactement cela en mode reduit : \u00ab le\r\n                \/\/   conteneur doit pouvoir passer a la ligne naturellement et grandir,\r\n                \/\/   sinon les zones rendues visibles resteraient rognees \u00bb. Meme cause,\r\n                \/\/   meme remede, applique a la carte partielle \u2014 dont le nombre de\r\n                \/\/   lignes varie au fil du remplissage.\r\n                \/\/ ============================================================\r\n                \/\/ ================================================================\r\n                \/\/ pb1316 : LE CALAGE NE DOIT PAS DEBORDER DE LA CARTE.\r\n                \/\/   Constat user : le contenu chevauche le lisere vert du haut.\r\n                \/\/   Cause : pb1259c remonte la premiere ligne de |calage| px. Elle\r\n                \/\/   passe au-dessus du bord haut de .CampagnePageRefClass et,\r\n                \/\/   comme pb1254f met overflow visible, elle sort de la carte.\r\n                \/\/   Tant qu'une invite occupait cet espace (pb1262), le debord se\r\n                \/\/   voyait sur elle et non sur la bordure \u2014 d'ou ton intuition,\r\n                \/\/   juste sur le symptome.\r\n                \/\/   Le pendant du calage est un retrait haut de meme valeur sur le\r\n                \/\/   conteneur : la ligne remonte toujours, mais dans un conteneur\r\n                \/\/   qui a pris cette avance. Alignement conserve, debord supprime \u2014\r\n                \/\/   meme raisonnement qu'en pb1259c, ou la marge basse rendait a la\r\n                \/\/   ligne l'empreinte perdue en haut.\r\n                \/\/   La valeur vient de la mesure, jamais d'une constante.\r\n                \/\/   Revert : window._viaPb1316Off = true.\r\n                \/\/ ================================================================\r\n                var _pad1316 = 0;\r\n                if (window._viaPb1316Off !== true) {\r\n                    if (typeof _min1259 === 'number') {\r\n                        if (_min1259 < 0) { _pad1316 = -_min1259; }\r\n                    }\r\n                }\r\n                $item.find('.CampagnePageRefClass').each(function () {\r\n                    this.setAttribute('data-via1254c', '1');\r\n                    this.style.setProperty('flex-wrap', 'wrap', 'important');\r\n                    this.style.setProperty('height', 'auto', 'important');\r\n                    this.style.setProperty('overflow', 'visible', 'important');\r\n                    if (_pad1316 > 0) {\r\n                        if (this.style.paddingTop !== (_pad1316 + 'px')) {\r\n                            this.style.setProperty('padding-top', _pad1316 + 'px', 'important');\r\n                            console.log('[pb1316] carte : ' + _pad1316\r\n                                + 'px de retrait haut pour absorber le calage');\r\n                        }\r\n                    } else { this.style.removeProperty('padding-top'); }\r\n                });\r\n            } catch (_e1254b) { console.warn('[pb1254]', _e1254b.message); }\r\n        },\r\n\r\n        _majRecap793($item, item) {\r\n            this._fermerEtapesPremiereResa885();   \/\/ pb885\r\n            if (window._viaPb793Off === true) { return; }\r\n            if (!$item ? true : !$item.length) { return; }\r\n            if (!item) { return; }\r\n            \/\/ pb815 : libelle du picto selon l'etat. Pose ici plutot qu'aux trois\r\n            \/\/   endroits de creation du bouton : la projection est deja rejouee a\r\n            \/\/   chaque rendu et apres chaque changement d'item actif.\r\n            if (window._viaPb815Off !== true) {\r\n                try {\r\n                    var _actifBtn815 = (this.state ? this.state.itemActif === item.id : false);\r\n                    var _lbl815 = _actifBtn815\r\n                        ? this._lib793('D\\u00e9s\\u00e9lectionner', 'Deselect')\r\n                        : this._lib793('S\\u00e9lectionner', 'Select');\r\n                    $item.find('.via-selectionner-btn').each(function () {\r\n                        if (this.getAttribute('title') !== _lbl815) {\r\n                            this.setAttribute('title', _lbl815);\r\n                            this.setAttribute('aria-label', _lbl815);\r\n                        }\r\n                    });\r\n                } catch (_eT815) { console.warn('[pb815] title:', _eT815.message); }\r\n            }\r\n            try {\r\n                var _self = this;\r\n                \/\/ ---- Ligne 1 : site pays ----\r\n                var _pays = item.paysDisplayed || '';\r\n                if (!_pays) {\r\n                    var _u = (item.donneesIframe ? item.donneesIframe.LoadedPageUrl : '') || item.linkSecteurPage || '';\r\n                    var _sub = String(_u).match(\/https?:\\\/\\\/([^.]+)\\.yearbook-media\\.com\/);\r\n                    if (_sub) { _pays = _sub[1].charAt(0).toUpperCase() + _sub[1].slice(1); }\r\n                }\r\n                \/\/ pb820 : REAFFICHER la zone en meme temps qu'on l'ecrit. La creation\r\n                \/\/   d'un item anticipe fait '.html(\"\").hide()' sur la zone pays\r\n                \/\/   (L2888) : elle reste en display:none, et le texte qu'on y depose\r\n                \/\/   n'apparait jamais. Le log pb819 le montrait \u2014 paysDisplayed=Gabon\r\n                \/\/   ecrit sur l'item, mais rien a l'ecran.\r\n                \/\/   removeProperty('display') plutot qu'un show() : on rend la main a\r\n                \/\/   la feuille de style au lieu d'imposer un display arbitraire, la\r\n                \/\/   zone pouvant etre block, flex ou inline selon le modele.\r\n                \/\/   Symetrie : zone vide -> on la remasque, pour ne pas laisser un\r\n                \/\/   espace vide dans la mise en page.\r\n                \/\/   Revert : window._viaPb820Off = true.\r\n                var $zPays820 = $item.find('.CampagnePaysClass, [id=\"CampagnePaysTexte\"]');\r\n                if (_pays) {\r\n                    $zPays820.html(_self._lib793('Site ', 'Site ') + _pays);\r\n                    if (window._viaPb820Off !== true) {\r\n                        $zPays820.each(function () {\r\n                            if (getComputedStyle(this).display === 'none') {\r\n                                this.style.removeProperty('display');\r\n                                if (getComputedStyle(this).display === 'none') {\r\n                                    this.style.setProperty('display', 'block', 'important');\r\n                                }\r\n                                console.log('[pb820] zone pays reaffichee sur ' + item.id);\r\n                            }\r\n                        });\r\n                    }\r\n                }\r\n\r\n                \/\/ ---- Ligne 1 : page ----\r\n                var _type = item.selectedPageType || sessionStorage.getItem('SelectedPageType') || '';\r\n                var _sect = item.selectedPageSecteurDisplayed || item.selectedPageSecteur || '';\r\n                var _art  = item.articleTitre || sessionStorage.getItem('Commande_Article') || '';\r\n                var $page = $item.find('.CampagnePageTextClass');\r\n                var $artZ = $item.find('.ArticleTitre');\r\n                var _estArticle = _art ? true : (_type === 'PATType');\r\n                var _estHome = _estArticle ? false : (_type === 'HPType' ? true : _sect === 'Homepage');\r\n                if (_estArticle) {\r\n                    var _titre = _self._titreArticle793(_art);\r\n                    $artZ.each(function () {\r\n                        this.classList.remove('elementor-hidden-desktop', 'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                        \/\/ pb866 : hauteur et debordement liberes \u2014 en mode reduit, un\r\n                        \/\/   height:0 herite du template tronquait le titre d'article.\r\n                        this.style.setProperty('height', 'auto', 'important');\r\n                        this.style.setProperty('overflow', 'visible', 'important');\r\n                        this.innerHTML = _self._lib793('Art. ', 'Art. ') + _titre;\r\n                    });\r\n                    $page.html('');\r\n                } else {\r\n                    $artZ.each(function () { this.style.setProperty('display', 'none', 'important'); });\r\n                    \/\/ pb795 : ecriture INCONDITIONNELLE de la zone page. Un writer\r\n                    \/\/   concurrent y accole la position (\"Assurances&nbsp;&nbsp;Haut de\r\n                    \/\/   page\") ; ne rien ecrire quand _sect est vide laisserait cette\r\n                    \/\/   pollution en place. La position a sa propre zone.\r\n                    if (_estHome) { $page.html(_self._lib793('Homepage', 'Homepage')); }\r\n                    else if (_sect) { $page.html(_self._lib793('Sect. ', 'Sect. ') + _sect); }\r\n                    else { $page.html(''); }\r\n                    \/\/ pb820 : meme reaffichage que la zone pays \u2014 meme cause.\r\n                    if (window._viaPb820Off !== true ? (_estHome ? true : !!_sect) : false) {\r\n                        $page.each(function () {\r\n                            if (getComputedStyle(this).display === 'none') {\r\n                                this.style.removeProperty('display');\r\n                                if (getComputedStyle(this).display === 'none') {\r\n                                    this.style.setProperty('display', 'block', 'important');\r\n                                }\r\n                                console.log('[pb820] zone page reaffichee sur ' + item.id);\r\n                            }\r\n                        });\r\n                    }\r\n                }\r\n\r\n                \/\/ ---- Ligne 2 : position ----\r\n                var $pos = $item.find('.CampagnePositionClass');\r\n                var _posTxt = String(item.position || '');\r\n                var _posLib = (_posTxt.indexOf('hdp') === 0) ? _self._lib793('Haut de page', 'Top of page')\r\n                            : (_posTxt.indexOf('cdp') === 0) ? _self._lib793('Corps de page', 'Body of page') : '';\r\n                var _rang = _self._rangEspace793(item);\r\n                $pos.each(function () {\r\n                    \/\/ pb793 : cette zone servait de separateur flex invisible (height 0,\r\n                    \/\/   overflow hidden). On leve le masquage pour y ecrire la position.\r\n                    \/\/   Le retour a la ligne reste assure par flex-basis:100%.\r\n                    \/\/ pb866 : en mode REDUIT, la position manquait \u2014 pb820 ne\r\n                    \/\/   reaffichait que les zones pays et page. On retire ici aussi les\r\n                    \/\/   classes elementor-hidden-*, qui survivent au display inline.\r\n                    this.classList.remove('elementor-hidden-desktop', 'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                    this.style.setProperty('height', 'auto', 'important');\r\n                    this.style.setProperty('overflow', 'visible', 'important');\r\n                    this.style.setProperty('display', _posLib ? 'block' : 'none', 'important');\r\n                    \/\/ ====================================================================\r\n                    \/\/ pb1030 : LIBELLE DE POSITION avec niveau (demande user).\r\n                    \/\/   Regle, par rang d'espace :\r\n                    \/\/     Ele0A (rang 0, pop-up) -> INCHANGE (pas de niveau)\r\n                    \/\/     Ele1A -> \"Haut de page niveau 1\/2\"\r\n                    \/\/     Ele2A -> \"Haut de page niveau 2\/2\"\r\n                    \/\/     Ele3A -> \"Corps de page niveau 3\"\r\n                    \/\/     Ele4A -> \"Corps de page niveau 4\", etc.\r\n                    \/\/   Le haut de page compte DEUX emplacements, d'ou le \"\/2\" qui situe\r\n                    \/\/   l'espace dans ce sous-ensemble ; le corps de page n'est pas borne,\r\n                    \/\/   son niveau est donc le rang seul.\r\n                    \/\/   Le libelle est deduit du RANG et non de item.position : les deux\r\n                    \/\/   disent la meme chose (calculerPosition : rang 1-2 -> hdp, au-dela\r\n                    \/\/   -> cdp), mais le rang porte en plus le numero a afficher. Utiliser\r\n                    \/\/   deux sources pour un seul libelle les exposerait a diverger.\r\n                    \/\/   Repli sur _posLib quand le rang est inconnu : mieux vaut\r\n                    \/\/   \"Haut de page\" sans niveau qu'une zone vide.\r\n                    \/\/   AUCUN impact sur le calcul du tarif, qui lit item.position\r\n                    \/\/   ('hdp Home P.' \/ 'cdp Autres P.') et n'est pas touche ici.\r\n                    \/\/   Revert : window._viaPb1030Off = true.\r\n                    \/\/ ====================================================================\r\n                    var _txt1030 = _posLib ? (_posLib + (_rang ? ' ' + _rang : '')) : '';\r\n                    if ((window._viaPb1030Off !== true) ? _rang : false) {\r\n                        var _n1030 = parseInt(_rang, 10);\r\n                        if (_n1030 === _n1030) {\r\n                            if (_n1030 === 1 || _n1030 === 2) {\r\n                                _txt1030 = _self._lib793('Haut de page niveau ', 'Top of page level ')\r\n                                    + _n1030 + '\/2';\r\n                            } else if (_n1030 >= 3) {\r\n                                _txt1030 = _self._lib793('Corps de page niveau ', 'Body of page level ')\r\n                                    + _n1030;\r\n                            }\r\n                            \/\/ rang 0 (Ele0A, pop-up) : _txt1030 reste le libelle d'origine\r\n                        }\r\n                    }\r\n                    this.innerHTML = _posLib ? (_self._lib793('Position ', 'Position ') + _txt1030) : '';\r\n                });\r\n\r\n                \/\/ ---- Ligne 2 : format (le tarif mode reduit reste accole) ----\r\n                \/\/ pb796 : Ele0A est l'espace POP-UP. Son rang vaut 0 et sa reference se\r\n                \/\/   termine par L0A \u2014 deux marqueurs, on accepte l'un ou l'autre selon\r\n                \/\/   ce qui est renseigne a cet instant.\r\n                var _popup796 = (_rang === '0');\r\n                if (!_popup796) { _popup796 = \/L0A$\/i.test(String(item.emplacementPageWeb || '')); }\r\n                var $fmt = $item.find('.CampagneFormatClass');\r\n                if (item.format) {\r\n                    var _tarifReduit = $fmt.find('.CampagneTarifModeReduit');\r\n                    var _htmlReduit = _tarifReduit.length ? _tarifReduit[0].outerHTML : '';\r\n                    var _fmtLib796 = (_popup796 ? _self._lib793('Pop-up ', 'Pop-up ') : '') + item.format;\r\n                    $fmt.html(_self._lib793('Format ', 'Format ') + _fmtLib796 + _htmlReduit);\r\n                }\r\n\r\n                \/\/ ---- Ligne 3 : reference de l'espace ----\r\n                \/\/ pb796 : un writer concurrent remplace le contenu par\r\n                \/\/   \"Espace publicitaire Pop-up MDG33476L0A <span>a reserver<\/span>\r\n                \/\/   <input type=checkbox \u2026>\" \u2014 et mon prefixage collait \"Ref. Espace pub\"\r\n                \/\/   devant l'ensemble. On reconstruit donc la zone : libelle + reference,\r\n                \/\/   puis on RECOLLE le balisage de fin (mention + case a cocher), qui\r\n                \/\/   porte la logique de reservation et ne doit surtout pas disparaitre.\r\n                \/\/   Le suffixe commence au premier '<' : tout ce qui precede est du\r\n                \/\/   texte de libelle, tout ce qui suit est fonctionnel.\r\n                \/\/ pb797 : la reconstruction etait gardee par item.emplacementPageWeb.\r\n                \/\/   Or sur un espace PAS ENCORE RESERVE (mention \"a reserver\") ce champ\r\n                \/\/   est vide : le bloc etait saute et seul le prefixage aveugle agissait,\r\n                \/\/   d'ou \"Ref. Espace pub Espace publicitaire Pop-up MDG48442L0A\".\r\n                \/\/   La reference est pourtant dans le DOM, portee par la case a cocher\r\n                \/\/   (data-empl). Trois sources, dans l'ordre de fiabilite :\r\n                \/\/     1. item.emplacementPageWeb (espace reserve)\r\n                \/\/     2. data-empl de la case a cocher (espace propose)\r\n                \/\/     3. motif de reference dans le texte, en dernier recours\r\n                var $no796 = $item.find('.CampagneNoClass');\r\n                $no796.each(function () {\r\n                    var _h796 = this.innerHTML || '';\r\n                    var _empl797 = item.emplacementPageWeb || '';\r\n                    if (!_empl797) {\r\n                        var _cb797 = this.querySelector('.via-recap-reserver-cb');\r\n                        if (_cb797) { _empl797 = _cb797.getAttribute('data-empl') || ''; }\r\n                    }\r\n                    if (!_empl797) {\r\n                        var _m797 = (this.textContent || '').match(\/\\b[A-Z]{2,4}\\d{3,}L\\d+[A-Z]\\b\/);\r\n                        if (_m797) { _empl797 = _m797[0]; }\r\n                    }\r\n                    if (!_empl797) { return; }   \/\/ rien d'identifiable : on ne touche pas\r\n                    var _i796 = _h796.indexOf('<');\r\n                    var _suf796 = (_i796 >= 0) ? _h796.slice(_i796) : '';\r\n                    \/\/ ============================================================\r\n                    \/\/ pb1488 : LIBELLE ET COULEUR QUAND L'ANNONCE EST DEPOSEE.\r\n                    \/\/   Demande : \u00ab Ref. Espace pub XXX \u00bb devient \u00ab Espace\r\n                    \/\/   publicitaire XXX \u00bb, en rouge tant que la mention\r\n                    \/\/   \u00ab a reserver \u00bb est presente. La couleur suit donc la\r\n                    \/\/   MENTION, pas le depot : une fois l'espace reserve, la\r\n                    \/\/   mention dispara\u00eet et le libelle reprend sa couleur.\r\n                    \/\/   On lit la presence de la mention dans le suffixe qu'on\r\n                    \/\/   vient d'isoler \u2014 c'est lui qui la porte.\r\n                    \/\/ ============================================================\r\n                    var _dep1488 = _self._annonceDeposee1488(item);\r\n                    var _lib1488 = _dep1488\r\n                        ? _self._lib793('Espace publicitaire ', 'Advertising space ')\r\n                        : _self._lib793('Ref. Espace pub ', 'Ref. Ad space ');\r\n                    this.innerHTML = _lib1488\r\n                        + _empl797\r\n                        + (_suf796 ? ' ' + _suf796 : '');\r\n                    var _aRes1488 = false;\r\n                    if (_dep1488) {\r\n                        if (_suf796) {\r\n                            if (_suf796.indexOf('\u00e0 r\u00e9server') !== -1) { _aRes1488 = true; }\r\n                            if (_suf796.indexOf('to be booked') !== -1) { _aRes1488 = true; }\r\n                        }\r\n                    }\r\n                    if (_aRes1488) {\r\n                        this.style.setProperty('color', '#FB5E2A', 'important');\r\n                    } else {\r\n                        this.style.removeProperty('color');\r\n                    }\r\n                });\r\n\r\n                \/\/ ---- Ligne 5 : annonceur ----\r\n                \/\/ pb863 : NE PAS EFFACER sur une valeur transitoirement vide.\r\n                \/\/   item.paysAnnonceur passe par un RESET intermediaire (L3754,\r\n                \/\/   sauvegarde puis mise a null avant restauration) pendant le\r\n                \/\/   recalcul de format\/pays. La projection periodique de pb794\r\n                \/\/   (600ms) capturait cette fenetre : \"France\" -> \"-\" -> \"France\" en\r\n                \/\/   boucle, alors que la donnee finale est stable.\r\n                \/\/   On ne REECRIT que si une valeur non vide est presente ; le champ\r\n                \/\/   garde sa derniere valeur connue le temps que la restauration\r\n                \/\/   ait lieu, au lieu de clignoter.\r\n                \/\/   Revert : window._viaPb863Off = true.\r\n                \/\/ pb865 : MEMORISER la derniere valeur non vide. pb863 avait corrige\r\n                \/\/   l'affichage mais pas la signature : elle alternait entre 'France'\r\n                \/\/   et un substitut, donc le log continuait de sortir a chaque passe.\r\n                \/\/   L'etat REEL affiche est la derniere valeur connue \u2014 c'est elle qui\r\n                \/\/   doit servir de reference, sans quoi on compare une chose et on en\r\n                \/\/   affiche une autre.\r\n                var _ann = item.paysAnnonceur || '';\r\n                if (_ann) {\r\n                    item._annVu865 = _ann;\r\n                    $item.find('.CampagnePaysSocieteClass')\r\n                         .html(_self._lib793('Annonceur ', 'Advertiser ') + _ann);\r\n                } else if (window._viaPb863Off === true) {\r\n                    item._annVu865 = '';\r\n                    $item.find('.CampagnePaysSocieteClass').html('');\r\n                }\r\n                \/\/ valeur reellement a l'ecran : la courante, sinon la derniere connue\r\n                var _annEcran865 = _ann || item._annVu865 || '';\r\n\r\n                \/\/ ================================================================\r\n                \/\/ pb793b : ORDRE des zones. Le conteneur est un flex avec wrap ; la\r\n                \/\/   disposition depend de 'order', pas de l'ordre DOM. Le saut de ligne\r\n                \/\/   etait assure par CampagnePositionClass (flex-basis 100%, height 0) \u2014\r\n                \/\/   role que pb793 lui a retire en la transformant en zone de texte.\r\n                \/\/   On reaffecte donc les rangs, et on recrute DEUX elements masques,\r\n                \/\/   inutilises et deja presents, comme separateurs de ligne :\r\n                \/\/   .TarifClosedClass et .CampagneReferenceClass (hidden sur les trois\r\n                \/\/   breakpoints, aucun writer). Un separateur = largeur 100%, hauteur 0.\r\n                \/\/   Rien n'est ajoute au DOM : Elementor regenere le template, un noeud\r\n                \/\/   injecte disparaitrait au prochain rendu.\r\n                \/\/   Ecrit en inline !important : .CampagneFormatClass porte deja un\r\n                \/\/   'order: 5 !important' d'origine qu'il faut depasser.\r\n                \/\/   Revert : window._viaPb793OrdreOff = true.\r\n                \/\/ ================================================================\r\n                if (window._viaPb793OrdreOff !== true) {\r\n                    var _rang793 = function(sel, ordre) {\r\n                        $item.find(sel).each(function () {\r\n                            this.style.setProperty('order', String(ordre), 'important');\r\n                        });\r\n                    };\r\n                    \/\/ ================================================================\r\n                    \/\/ pb869 : en mode REDUIT, PAS de saut de ligne force.\r\n                    \/\/   pb793b intercale deux separateurs pleine largeur pour repartir\r\n                    \/\/   le recap sur trois lignes. En mode reduit la hauteur de l'item\r\n                    \/\/   est contrainte : les lignes 2 et 3 existent mais sortent du\r\n                    \/\/   cadre \u2014 c'est la que se trouvent le secteur\/article et la\r\n                    \/\/   position, d'ou leur absence apparente.\r\n                    \/\/   Replier tout sur un flux continu laisse le wrap naturel operer\r\n                    \/\/   et rend les zones visibles, sans toucher a leur contenu ni a\r\n                    \/\/   la hauteur de l'item.\r\n                    \/\/   Revert : window._viaPb869Off = true.\r\n                    \/\/ ================================================================\r\n                    var _reduit869 = ($item.attr('data-via-reduit') === 'true');\r\n                    var _saut793 = function(sel, ordre) {\r\n                        \/\/ ================================================================\r\n                        \/\/ pb870 : en mode reduit, CONSERVER le saut de ligne apres le\r\n                        \/\/   secteur (ordre 3) et ne neutraliser que le second (ordre 7).\r\n                        \/\/   pb869 supprimait les deux : tout se retrouvait sur une seule\r\n                        \/\/   ligne et la position, pourtant presente et en display:block\r\n                        \/\/   (HTML fourni), etait poussee hors du cadre par ses voisines.\r\n                        \/\/   Disposition voulue en mode reduit :\r\n                        \/\/     ligne 1 : Site Cameroun   Sect. Hydrocarbures\r\n                        \/\/     ligne 2 : Position Haut de page 1   Format Parrainage\r\n                        \/\/   Le saut d'ordre 3 la produit exactement ; celui d'ordre 7\r\n                        \/\/   n'ajouterait qu'une troisieme ligne inutile ici.\r\n                        \/\/   Revert : window._viaPb870Off = true (retour a pb869).\r\n                        \/\/ ================================================================\r\n                        var _neutraliser870 = _reduit869;\r\n                        if (_neutraliser870 ? (window._viaPb870Off !== true) : false) {\r\n                            if (ordre === 3) { _neutraliser870 = false; }   \/\/ saut apres le secteur : conserve\r\n                        }\r\n                        if (_neutraliser870 ? (window._viaPb869Off !== true) : false) {\r\n                            $item.find(sel).each(function () {\r\n                                this.style.setProperty('display', 'none', 'important');\r\n                                this.style.setProperty('flex', '0 0 0', 'important');\r\n                                this.style.setProperty('width', '0', 'important');\r\n                                this.style.setProperty('order', String(ordre), 'important');\r\n                            });\r\n                            return;\r\n                        }\r\n                        $item.find(sel).each(function () {\r\n                            this.classList.remove('elementor-hidden-desktop', 'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                            this.style.setProperty('order', String(ordre), 'important');\r\n                            this.style.setProperty('display', 'block', 'important');\r\n                            this.style.setProperty('flex', '0 0 100%', 'important');\r\n                            this.style.setProperty('width', '100%', 'important');\r\n                            this.style.setProperty('height', '0', 'important');\r\n                            this.style.setProperty('min-height', '0', 'important');\r\n                            this.style.setProperty('margin', '0', 'important');\r\n                            this.style.setProperty('padding', '0', 'important');\r\n                            this.style.setProperty('overflow', 'hidden', 'important');\r\n                        });\r\n                    };\r\n                    \/\/ pb1252 : pb1249 RETIRE (demande user) \u2014 l'annonceur ne recoit\r\n                    \/\/   plus d'ordre explicite.\r\n                    \/\/ ligne 1\r\n                    _rang793('.CampagnePaysClass', 1);\r\n                    _rang793('.CampagnePageTextClass', 2);\r\n                    _rang793('.ArticleTitre', 2);\r\n                    _saut793('.TarifClosedClass', 3);\r\n                    \/\/ ligne 2\r\n                    _rang793('.CampagnePositionClass', 4);\r\n                    _rang793('.CampagneFormatClass', 5);\r\n                    _rang793('.CampagneAnnonceDeposeClass', 6);\r\n                    \/\/ pb1249b : la REFERENCE n'est plus un simple SAUT DE LIGNE.\r\n                    \/\/   Constat user (HTML) : height:0 + overflow:hidden \u2014 la zone est\r\n                    \/\/   dans le flux mais invisible. C'est le role que _saut793 lui\r\n                    \/\/   donne : un separateur pleine largeur de hauteur nulle.\r\n                    \/\/   pb1247 l'a reaffichee avec un tiret, mais _saut793 lui remet\r\n                    \/\/   height:0 juste apres : le texte ne pouvait pas se voir.\r\n                    \/\/   Elle devient une zone normale, avec sa hauteur \u2014 c'est ce que\r\n                    \/\/   demande le meme gabarit que la carte complete. Le saut de ligne\r\n                    \/\/   qu'elle assurait est repris par .CampagneAnnonceDeposeClass,\r\n                    \/\/   voisine immediate et deja pleine largeur.\r\n                    \/\/ pb1252 : pb1249b RETIRE \u2014 la reference redevient un separateur.\r\n                    _saut793('.CampagneReferenceClass', 7);\r\n                    \/\/ ligne 3 : pb794b \u2014 la reference s'intercale APRES la mention de\r\n                    \/\/   depose et AVANT celle d'envoi differe (les deux s'excluent :\r\n                    \/\/   une seule est visible a la fois, l'autre reste en display:none).\r\n                    _rang793('.CampagneNoClass', 8);\r\n                    _rang793('.CampagneEnvoiUlterieurClass', 9);\r\n                    \/\/ la position n'occupe plus toute la largeur : elle partage la ligne 2\r\n                    $item.find('.CampagnePositionClass').each(function () {\r\n                        this.style.setProperty('flex-basis', 'auto', 'important');\r\n                        this.style.setProperty('width', 'auto', 'important');\r\n                    });\r\n                    \/\/ pb869 : en mode reduit, le conteneur doit pouvoir passer a la\r\n                    \/\/   ligne naturellement et grandir \u2014 sinon les zones rendues\r\n                    \/\/   visibles resteraient rognees.\r\n                    if (_reduit869 ? (window._viaPb869Off !== true) : false) {\r\n                        $item.find('.CampagnePageRefClass').each(function () {\r\n                            this.style.setProperty('flex-wrap', 'wrap', 'important');\r\n                            this.style.setProperty('height', 'auto', 'important');\r\n                            this.style.setProperty('overflow', 'visible', 'important');\r\n                        });\r\n                        \/\/ ================================================================\r\n                        \/\/ pb871 : RENFORCER la visibilite du titre d'article et de la\r\n                        \/\/   position en mode reduit, et MESURER le resultat.\r\n                        \/\/   Le HTML fourni montre les deux zones correctement remplies\r\n                        \/\/   (\"Art. Le secteur de l'elevage\", \"Position Haut de page 1\")\r\n                        \/\/   avec display:block !important inline \u2014 qui bat toute regle\r\n                        \/\/   de feuille. Le masquage vient donc d'ailleurs : visibility,\r\n                        \/\/   opacity, ou une hauteur nulle heritee. Le titre porte la\r\n                        \/\/   classe CommandeDetails, absente de nos fichiers, donc definie\r\n                        \/\/   dans la feuille Elementor \u2014 hors de portee d'une lecture.\r\n                        \/\/   On force les trois proprietes, et on releve la geometrie\r\n                        \/\/   obtenue : si la zone reste a 0, le log dira laquelle des\r\n                        \/\/   trois ne suffit pas.\r\n                        \/\/   Revert : window._viaPb871Off = true.\r\n                        \/\/ ================================================================\r\n                        if (window._viaPb871Off !== true) {\r\n                            var _diag871 = [];\r\n                            $item.find('.ArticleTitre, .CampagnePositionClass').each(function () {\r\n                                var _t871 = (this.textContent || '').trim();\r\n                                if (!_t871) { return; }   \/\/ zone vide : rien a montrer\r\n                                this.classList.remove('elementor-hidden-desktop',\r\n                                    'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                                this.style.setProperty('display', 'block', 'important');\r\n                                this.style.setProperty('visibility', 'visible', 'important');\r\n                                this.style.setProperty('opacity', '1', 'important');\r\n                                this.style.setProperty('min-height', '1em', 'important');\r\n                                this.style.setProperty('max-height', 'none', 'important');\r\n                                this.style.setProperty('height', 'auto', 'important');\r\n                                \/\/ ================================================================\r\n                                \/\/ pb873 : forcer aussi les DESCENDANTS. La mesure pb871 a donne\r\n                                \/\/   \"ArticleTitre=444x0\" : l'element est bien dans le flux\r\n                                \/\/   (444 de large) mais son contenu ne prend aucune place \u2014\r\n                                \/\/   c'est le .elementor-widget-container interne qui est\r\n                                \/\/   masque, pas l'element. Mes proprietes portaient sur le\r\n                                \/\/   mauvais noeud.\r\n                                \/\/   Le <p> interne est traite aussi : Elementor lui applique\r\n                                \/\/   parfois margin:0\/height:0 dans ses widgets masques.\r\n                                \/\/   Revert : window._viaPb873Off = true.\r\n                                \/\/ ================================================================\r\n                                if (window._viaPb873Off !== true) {\r\n                                    var _int873 = this.querySelectorAll('.elementor-widget-container, p');\r\n                                    for (var _j873 = 0; _j873 < _int873.length; _j873++) {\r\n                                        var _e873 = _int873[_j873];\r\n                                        _e873.style.setProperty('display', 'block', 'important');\r\n                                        _e873.style.setProperty('visibility', 'visible', 'important');\r\n                                        _e873.style.setProperty('opacity', '1', 'important');\r\n                                        _e873.style.setProperty('height', 'auto', 'important');\r\n                                        _e873.style.setProperty('max-height', 'none', 'important');\r\n                                        _e873.style.setProperty('overflow', 'visible', 'important');\r\n                                    }\r\n                                }\r\n                                var _r871 = this.getBoundingClientRect();\r\n                                var _cl871 = (this.className || '').indexOf('ArticleTitre') >= 0\r\n                                    ? 'ArticleTitre' : 'Position';\r\n                                \/\/ pb873 : mesurer aussi le conteneur interne \u2014 s'il reste a 0\r\n                                \/\/   alors que l'exterieur a une largeur, le masquage est plus bas.\r\n                                var _ci873 = this.querySelector('.elementor-widget-container');\r\n                                var _ri873 = _ci873 ? _ci873.getBoundingClientRect() : null;\r\n                                _diag871.push(_cl871 + '=' + Math.round(_r871.width) + 'x'\r\n                                    + Math.round(_r871.height)\r\n                                    + (_ri873 ? '[interne ' + Math.round(_ri873.width) + 'x'\r\n                                        + Math.round(_ri873.height) + ']' : '[sans conteneur]'));\r\n                            });\r\n                            if (_diag871.length) {\r\n                                var _sg871 = _diag871.join(' ');\r\n                                if (window._viaSig871 !== _sg871) {\r\n                                    window._viaSig871 = _sg871;\r\n                                    console.log('[pb871] mode reduit | ' + _sg871\r\n                                        + '  (0 de hauteur = encore masque par un ancetre)');\r\n                                }\r\n                            }\r\n                        }\r\n                        if (window._viaSig869 !== $item.attr('id')) {\r\n                            window._viaSig869 = $item.attr('id');\r\n                            console.log('[pb870] mode reduit : saut apres le secteur conserve,'\r\n                                + ' position et format sur la ligne suivante');\r\n                        }\r\n                    }\r\n                }\r\n\r\n                \/\/ pb1257 : le bloc pb1254\/pb1256 est devenu une methode \u2014 voir\r\n                \/\/   _normaliserCarte1254. Second point d'appel : ouvrirRecapitulatif.\r\n                try { this._normaliserCarte1254($item, item); } catch (_e1257) {}\r\n\r\n                \/\/ pb865 : la signature ET le log utilisent la valeur AFFICHEE.\r\n                \/\/ ================================================================\r\n                \/\/ pb968 : garde anti-repetition PAR CARTE (etait globale).\r\n                \/\/   Avec plusieurs reservations, chaque carte ecrasait la signature\r\n                \/\/   de la precedente : la garde ne bloquait donc JAMAIS rien et le log\r\n                \/\/   ressortait a chaque rafraichissement, en alternant les cartes\r\n                \/\/   (constat user : log illisible tellement il se repete).\r\n                \/\/   On memorise desormais une signature par item.id -> une carte ne\r\n                \/\/   loggue que si SON contenu change reellement.\r\n                \/\/   Revert : window._viaPb968Off = true (retour a la signature globale).\r\n                \/\/ ================================================================\r\n                var _sig793 = [_pays, _type, _sect, _art, _posLib, _rang, item.format, item.emplacementPageWeb, _annEcran865].join('|');\r\n                var _cle968 = item.id || '(sans-id)';\r\n                if (!window._viaSigs968) { window._viaSigs968 = {}; }\r\n                var _dejaVu968 = (window._viaPb968Off === true)\r\n                    ? (window._viaSig793 === _sig793)\r\n                    : (window._viaSigs968[_cle968] === _sig793);\r\n                if (!_dejaVu968) {\r\n                    window._viaSig793 = _sig793;\r\n                    window._viaSigs968[_cle968] = _sig793;\r\n                    console.log('[pb793] recap | Site ' + _pays + ' | '\r\n                        + (_estArticle ? 'Art.' : (_estHome ? 'Homepage' : 'Sect. ' + _sect))\r\n                        + ' | Position ' + _posLib + ' ' + _rang\r\n                        + ' | Format ' + (item.format || '-')\r\n                        + ' | Ref ' + (item.emplacementPageWeb || '-')\r\n                        + ' | Annonceur ' + (_annEcran865 || '-'));   \/\/ pb865\r\n                }\r\n                if (!window._viaTimer794) { this._armerPrefixes794(); }   \/\/ pb794 (une seule fois)\r\n            } catch (_e793) { console.warn('[pb793]', _e793.message); }\r\n        },\r\n\r\n        \/\/ pb794 : rejeu periodique des prefixes. Les writers concurrents sont\r\n        \/\/   declenches par des chemins varies (creation d'item, sync sessionStorage,\r\n        \/\/   mode reduit, changement de tarif) : aucun point d'ecoute unique ne les\r\n        \/\/   couvrirait. La projection etant idempotente, une passe a vide ne coute\r\n        \/\/   qu'une comparaison de chaine par zone.\r\n        _armerPrefixes794() {\r\n            if (window._viaTimer794) { return; }\r\n            var _self = this;\r\n            window._viaTimer794 = setInterval(function () { _self.majPrefixes794(); }, 600);\r\n            console.log('[pb794] rejeu des prefixes arme (600 ms)');\r\n        },\r\n\r\n        \/**\r\n         * D\u00e9termine la position selon le code espace (pour affichage LIBELL\u00c9)\r\n         *\/\r\n        determinerPosition(emplacementWeb, codePage) {\r\n            const indexCodePage = emplacementWeb.indexOf(codePage);\r\n            if (indexCodePage < 0) return 'Corps de page';\r\n            \r\n            const suffixe = emplacementWeb.substring(indexCodePage + codePage.length);\r\n            \r\n            \/\/ Extraire le chiffre apr\u00e8s \"L\" (ex: \"L1A\" \u2192 1, \"L2B\" \u2192 2)\r\n            const match = suffixe.match(\/L(\\d+)\/);\r\n            if (match) {\r\n                const numero = parseInt(match[1]);\r\n                return (numero === 1 || numero === 2) ? 'Haut de page' : 'Corps de page';\r\n            }\r\n            \r\n            return 'Corps de page';\r\n        },\r\n        \r\n        \/**\r\n         * Calcule le titre de la page selon la logique\r\n         *\/\r\n        \/\/ \u2705 v2.6 Option A : Restaurer des items depuis localStorage avec rendu DOM\r\n        restaurerItemsOptionA(items) {\r\n            var self = this;\r\n            \/\/ v4.9ds : D\u00c9DOUBLONNAGE par rank \u2014 sur mobile on observait que la\r\n            \/\/   restauration recevait parfois des items en double (m\u00eame rank\r\n            \/\/   pr\u00e9sent 2\u00d7 dans via_panier_items localStorage parent, d\u00fb \u00e0\r\n            \/\/   l'historique de session pr\u00e9c\u00e9dente). Sans ce filtre, le r\u00e9cap\r\n            \/\/   affichait des items vides en doublon.\r\n            \/\/   R\u00e8gle : pour un m\u00eame Rank_Emplacement_Page_Web, on garde le\r\n            \/\/   premier item rencontr\u00e9 (ordre = ordre dans via_panier_items).\r\n            var _seenRanks = {};\r\n            items = (items || []).filter(function(_it) {\r\n                var _rk = _it.donneesIframe ? _it.donneesIframe.Rank_Emplacement_Page_Web : '';\r\n                if (!_rk) { return true; } \/\/ pas de rank \u2192 on garde (cas atypique)\r\n                if (_seenRanks[_rk]) {\r\n                    console.log('[OptionA] d\u00e9doublonnage : rank ' + _rk + ' d\u00e9j\u00e0 pr\u00e9sent \u2192 skip item ' + _it.id);\r\n                    return false;\r\n                }\r\n                _seenRanks[_rk] = true;\r\n                return true;\r\n            });\r\n            var $template = $('#CampagneTemplate');\r\n            if ($template.length === 0) {\r\n                console.warn('[OptionA] Template introuvable, push sans DOM');\r\n                items.forEach(function(item) { self.state.items.push(item); });\r\n                return Promise.resolve();\r\n            }\r\n            var $conteneur = $(self.config.conteneurParent).first();\r\n            items.forEach(function(item) {\r\n                \/\/ Cloner le template\r\n                var $clone = $template.clone();\r\n                $clone.find('#Etape1Container').remove();\r\n                $clone.removeAttr('data-is-template');\r\n                $clone.attr('id', item.id);\r\n                $clone.attr('data-reference', item.reference || '');\r\n                $clone.css('display', 'block').show();\r\n                \/\/ Ajouter l'item dans state\r\n                self.state.items.push(item);\r\n                \/\/ Rendre dans le DOM\r\n                if ($conteneur.length) { $conteneur.append($clone); }\r\n                \/\/ Remplir l'affichage - forcer les donnees d'origine (pas sessionStorage page B)\r\n                \/\/ Deduire secteur depuis linkSecteurPage si selectedPageSecteurDisplayed vide\r\n                var _donnees = Object.assign({}, item);\r\n                if (!_donnees.selectedPageSecteurDisplayed && _donnees.linkSecteurPage) {\r\n                    var _path = _donnees.linkSecteurPage.replace(\/#.*$\/, '').replace(\/^https?:\\\/\\\/[^\/]+\/, '').replace(\/\\\/$\/, '');\r\n                    var _parts = _path.split('\/').filter(function(p) { return p.length > 0; });\r\n                    if (_parts.length > 0) {\r\n                        var _s = _parts[_parts.length - 1];\r\n                        _donnees.selectedPageSecteurDisplayed = _s.charAt(0).toUpperCase() + _s.slice(1).replace(\/-\/g, ' ');\r\n                    }\r\n                }\r\n                var _donneesIframe = item.donneesIframe ? Object.assign({}, item.donneesIframe, {\r\n                    commandePage: item.commandePage,\r\n                    selectedPageSecteurDisplayed: _donnees.selectedPageSecteurDisplayed\r\n                }) : null;\r\n                self.remplirItemComplet($clone, _donnees, _donneesIframe).then(function() {\r\n                    console.log('[OptionA] item rendu:', item.reference);\r\n                }).catch(function(e) {\r\n                    console.warn('[OptionA] erreur rendu item:', e);\r\n                });\r\n            });\r\n            console.log('[OptionA] ' + items.length + ' item(s) rendu(s) dans DOM');\r\n            \/\/ Retourner une Promise resolue apres un court delai (remplirItemComplet async)\r\n            return new Promise(function(resolve) { setTimeout(resolve, 300); });\r\n        },\r\n\r\n        calculerTitrePage(index = null) {\r\n            const commandePage = index ? \r\n                sessionStorage.getItem(`commandePage${index}`) :\r\n                sessionStorage.getItem(\"Commande_Page\");\r\n            \r\n            const continentPaysTitre = index ?\r\n                sessionStorage.getItem(`ContinentPaysTitre${index}`) :\r\n                sessionStorage.getItem(\"ContinentPaysTitre\") || '';\r\n            \r\n            const selectedPageSecteurDisplayed = index ?\r\n                sessionStorage.getItem(`SelectedPageSecteurDisplayed${index}`) :\r\n                sessionStorage.getItem(\"SelectedPageSecteurDisplayed\") || '';\r\n            \r\n            let selectedPage = '';\r\n            let titreComplet = typeof formatPaysDisplay === 'function' ? formatPaysDisplay(continentPaysTitre) : continentPaysTitre.replace(\"-en\", \" english\");\r\n            \r\n            switch (commandePage) {\r\n                case \"Homepage\":\r\n                    selectedPage = 'Homepage';\r\n                    titreComplet += ' - Homepage';\r\n                    break;\r\n                case \"Page sectorielle\":\r\n                    \/\/ \u2705 v2.4.6 : Supprimer \"Page\" devant le secteur\r\n                    selectedPage = selectedPageSecteurDisplayed;\r\n                    titreComplet += ' - ' + selectedPageSecteurDisplayed;\r\n                    break;\r\n                case \"Article\":\r\n                    selectedPage = 'Article ' + selectedPageSecteurDisplayed;\r\n                    \/\/ \u2705 v2.4.6 : Supprimer \"page\" devant \"article\"\r\n                    titreComplet += ' - Article ' + selectedPageSecteurDisplayed;\r\n                    break;\r\n                default:\r\n                    selectedPage = 'Homepage';\r\n            }\r\n            \r\n            const $titrePageWeb = $('#TitrePageWeb');\r\n            if ($titrePageWeb.length > 0) {\r\n                $titrePageWeb.html(titreComplet);\r\n                console.log('\u2705 Titre mis \u00e0 jour:', titreComplet);\r\n            }\r\n            \r\n            return selectedPage;\r\n        },\r\n\r\n        \/**\r\n         * Remplit TOUS les champs de l'item avec les donn\u00e9es compl\u00e8tes\r\n         *\/\r\n        async remplirItemComplet($item, donnees, donneesIframe) {\r\n            console.log('\ud83d\udd04 Remplissage complet de l\\'item...', donnees, donneesIframe);\r\n            \r\n            \/\/ \u2705 v4.9ds : restaurer .CampagnePageRefClass masqu\u00e9 par #AutreCommandeBouton\r\n            \/\/   (idem remplirItemPartiel). Demande user.\r\n            $item.find('.CampagnePageRefClass').each(function() {\r\n                if (this.style.display === 'none') {\r\n                    this.style.removeProperty('display');\r\n                }\r\n            });\r\n            if ($item.length && $item[0].style) {\r\n                $item[0].style.removeProperty('min-height');\r\n                $item[0].style.removeProperty('position');\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds : injecter bouton R\u00e9duire\/Agrandir si absent (\u00e0 c\u00f4t\u00e9 de la croix close)\r\n            \/\/   SVG repris de kit.js (popup Cr\u00e9ation).\r\n            if (!$item.find('.via-reduire-btn').length) {\r\n                var _svgReduire2 = '<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><line x1=\"2\" y1=\"10.5\" x2=\"12\" y2=\"10.5\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"\/><\/svg>';\r\n                var _svgAgrandir2 = '<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><rect x=\"1.5\" y=\"1.5\" width=\"9\" height=\"9\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg>';\r\n                var $btnReducer2 = $('<button type=\"button\" class=\"via-reduire-btn\" aria-label=\"R\u00e9duire\" title=\"R\u00e9duire\" data-via-svg-reduire=\"' + encodeURIComponent(_svgReduire2) + '\" data-via-svg-agrandir=\"' + encodeURIComponent(_svgAgrandir2) + '\">' + _svgReduire2 + '<\/button>');\r\n                var $closeBtn2 = $item.find('.CampagneCloseButton').first();\r\n                if ($closeBtn2.length) {\r\n                    $closeBtn2.before($btnReducer2);\r\n                } else {\r\n                    $item.prepend($btnReducer2);\r\n                }\r\n            }\r\n            \/\/ pb206 : picto \"S\u00e9lectionner\" (case \u00e0 cocher) \u2014 voir explication point 1.\r\n            if ((window._viaPb931Off === true) && !$item.find('.via-selectionner-btn').length) {\r\n                var _svgSelect2 = '<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><rect x=\"2.5\" y=\"2.5\" width=\"19\" height=\"19\" rx=\"3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.83\"\/><path d=\"M7 12.5 L10.5 16 L17 8.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.83\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg>';\r\n                var $btnSelect2 = $('<button type=\"button\" class=\"via-selectionner-btn\" aria-label=\"S\u00e9lectionner\" title=\"S\u00e9lectionner\">' + _svgSelect2 + '<\/button>');\r\n                var $reducerRef2 = $item.find('.via-reduire-btn').first();\r\n                if ($reducerRef2.length) {\r\n                    $reducerRef2.before($btnSelect2);\r\n                } else {\r\n                    var $closeRef2 = $item.find('.CampagneCloseButton').first();\r\n                    if ($closeRef2.length) { $closeRef2.before($btnSelect2); } else { $item.prepend($btnSelect2); }\r\n                }\r\n            }\r\n            \/\/ \u2705 v4.9ds Fix 19 v6 (Pb 14) : injecter croix Supprimer si absente (idem\r\n            \/\/   remplirItemPartiel \u2014 voir explication ci-dessus).\r\n            if (!$item.find('.CampagneCloseButton').length) {\r\n                var _svgClose2 = '<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><line x1=\"2\" y1=\"2\" x2=\"10\" y2=\"10\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"\/><line x1=\"10\" y1=\"2\" x2=\"2\" y2=\"10\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\"\/><\/svg>';\r\n                var $btnClose2 = $('<button type=\"button\" class=\"CampagneCloseButton\" aria-label=\"Supprimer\" title=\"Supprimer\">' + _svgClose2 + '<\/button>');\r\n                $item.append($btnClose2);\r\n            }\r\n            \r\n            \/\/ \u2705 R\u00e9cup\u00e9rer la langue\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            \/\/ 1. CampagneNoClass \u2014 r\u00e8gles :\r\n            \/\/    - Espace r\u00e9serv\u00e9 \u2192 \"Espace publicitaire r\u00e9serv\u00e9 ESPACE\"\r\n            \/\/    - Sans espace (ne devrait pas arriver ici) \u2192 cach\u00e9\r\n            \/\/ \u2705 emplacementPageWeb uniquement \u2014 donneesIframe.Commande_Emplacement_Page_Web\r\n            \/\/    est pos\u00e9 depuis URL en mode popup avant r\u00e9servation \u2192 ne pas l'utiliser ici\r\n            const emplacementReserve = donnees.emplacementPageWeb || '';\r\n            console.log('\ud83d\udd0d [remplirItemComplet] emplacementReserve:', emplacementReserve);\r\n            const $_noClass2 = $item.find('.CampagneNoClass');\r\n            \/\/ v4.9ds (estReserveEffective) : texte \"r\u00e9serv\u00e9\" UNIQUEMENT si flag pos\u00e9\r\n            \/\/   \u00e0 la r\u00e9servation effective. Sinon \"Espace publicitaire\" (juste d\u00e9pos\u00e9).\r\n            const _isReservedC = donnees.estReserveEffective === true || donnees.statut === 'complete';\r\n            \/\/ \u2705 v4.9ds Fix 26 : data-via-areserver \u2014 idem remplirItemPartiel ligne 2055.\r\n            $item.attr('data-via-areserver', _isReservedC ? 'false' : 'true');\r\n            if (emplacementReserve) {\r\n                const _labelReserve = _isReservedC\r\n                    ? (lang === 'EN' ? 'Reserved advertising space ' : 'Espace r\u00e9serv\u00e9 ')\r\n                    : (lang === 'EN' ? 'Advertising space ' : 'Espace publicitaire ');\r\n                \/\/ v4.9ds : pour Ele0A (emplacement se terminant par \"L0A\"), ins\u00e9rer\r\n                \/\/   \" Pop-up \" avant l'emplacement \u2192 \"Espace r\u00e9serv\u00e9 Pop-up MDG48442L0A\"\r\n                \/\/   v4.9ds : si non r\u00e9serv\u00e9, ajouter \" A r\u00e9server\" en #fb5e2a apr\u00e8s la r\u00e9f\u00e9rence\r\n                const _isEle0AC = \/L0A$\/.test(emplacementReserve);\r\n                const _emplAvecPopupC = _isEle0AC ? ('Pop-up ' + emplacementReserve) : emplacementReserve;\r\n                \/\/ \u2705 v4.9ds Fix 19 v3 (Pb 14) : ajouter la checkbox aussi dans remplirItemComplet\r\n                \/\/   sinon cette fonction \u00e9crase le HTML pos\u00e9 par remplirItemPartiel quand\r\n                \/\/   les 2 sont appel\u00e9es s\u00e9quentiellement (creerNouvelItem appelle souvent\r\n                \/\/   remplirItemComplet APR\u00c8S remplirItemPartiel pour des items partiels).\r\n                const _rankPartielFix19C = donnees.donneesIframe ? (donnees.donneesIframe.Rank_Emplacement_Page_Web || '') : '';\r\n                \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction : \"\u00e0 r\u00e9server\" + tooltip en EN\r\n                \/\/   margin-left:3px en EN (cf commentaire remplirItemPartiel).\r\n                var _isEN_C = lang === 'EN';\r\n                var _spanAReserverC = _isEN_C\r\n                    ? ' <span style=\"color:#fb5e2a;margin-left:3px;\">to be reserved<\/span>'\r\n                    : ' <span style=\"color:#fb5e2a\">\u00e0 r\u00e9server<\/span>';\r\n                var _titleCbC = _isEN_C ? 'Reserve this advertising space' : 'R\u00e9server cet espace publicitaire';\r\n                const _aReserverC = _isReservedC\r\n                    ? ''\r\n                    : _spanAReserverC\r\n                      + ' <input type=\"checkbox\" class=\"via-recap-reserver-cb\"'\r\n                      + ' data-rank=\"' + _rankPartielFix19C + '\"'\r\n                      + ' data-empl=\"' + emplacementReserve + '\"'\r\n                      + ' data-item-id=\"' + donnees.id + '\"'\r\n                      + ' title=\"' + _titleCbC + '\"'\r\n                      + ' style=\"margin-left:1px;cursor:pointer;width:10px;height:10px;z-index:110;position:relative;top:-2px;\">';\r\n                const texteNoClass = _labelReserve + _emplAvecPopupC + _aReserverC;\r\n                console.log('\u2705 [remplirItemComplet] \u2192 CampagneNoClass =', texteNoClass);\r\n                $_noClass2.html(texteNoClass);\r\n                $_noClass2.show();\r\n                \/\/ $item.find('.CampagneInfoEspaceMessage').hide(); \/\/ \u2699\ufe0f [COMMENT\u00c9] g\u00e9r\u00e9 par message global\r\n            } else {\r\n                $_noClass2.hide();\r\n            }\r\n            \r\n            \/\/ 2. Pays - extraire depuis l'URL de l'item (source fiable)\r\n            \/\/ \u2705 LoadedPageUrl : d'abord sur donnees racine, sinon donneesIframe, sinon linkSecteurPage\r\n            var _linkP2 = donnees.LoadedPageUrl || (donneesIframe && donneesIframe.LoadedPageUrl) || donnees.linkSecteurPage || '';\r\n            var _matchP2 = _linkP2.match(\/https?:\\\/\\\/([^.]+)\\.yearbook-media\\.com\/);\r\n            var _paysP2 = _matchP2 ? (_matchP2[1].charAt(0).toUpperCase() + _matchP2[1].slice(1)) : null;\r\n            \/\/ \u2705 donnees.pays est d\u00e9fini dans creerNouvelItem depuis iframeData.LoadedPageUrl\r\n            if (!_paysP2 && donnees.pays) { _paysP2 = donnees.pays; }\r\n            var _rawP2 = _paysP2 || donnees.pays || sessionStorage.getItem('ContinentPaysTitre') || '-';\r\n            var paysTitre = typeof formatPaysDisplay === 'function' ? formatPaysDisplay(_rawP2) : _rawP2.replace('-en', ' english');\r\n            $item.find('[id=\"CampagnePaysTexte\"], .CampagnePaysClass').html(paysTitre);\r\n            \r\n            \/\/ \u2705 3. Page - CORRECTION : Utiliser donnees.commandePage\r\n            let titrePage;\r\n            const commandePage = donnees.commandePage\r\n                || (donneesIframe && donneesIframe.commandePage)\r\n                || sessionStorage.getItem('Commande_Page')\r\n                || 'Homepage';\r\n            const selectedPageSecteurDisplayed = donnees.selectedPageSecteurDisplayed\r\n                || (donneesIframe && donneesIframe.selectedPageSecteurDisplayed)\r\n                || sessionStorage.getItem('SelectedPageSecteurDisplayed')\r\n                || sessionStorage.getItem('SelectedPageSecteur')\r\n                || '';\r\n            \r\n            switch (commandePage) {\r\n                case 'Homepage':\r\n                    \/\/ pb76 : pour les pages HPType qui sont des homepages secteur (ex: \/mines\/),\r\n                    \/\/   utiliser selectedPageSecteurDisplayed s'il est d\u00e9fini et diff\u00e9rent de\r\n                    \/\/   'Homepage' (ex: \"Mines\"). Pour la vraie homepage du pays, garder 'Homepage'.\r\n                    if (selectedPageSecteurDisplayed) {\r\n                        if (selectedPageSecteurDisplayed !== 'Homepage') {\r\n                            titrePage = selectedPageSecteurDisplayed;\r\n                        } else {\r\n                            titrePage = 'Homepage';\r\n                        }\r\n                    } else {\r\n                        titrePage = 'Homepage';\r\n                    }\r\n                    break;\r\n                case 'Page sectorielle':\r\n                    \/\/ \u2705 v2.4.6 : Supprimer \"Page\" devant le secteur\r\n                    titrePage = selectedPageSecteurDisplayed;\r\n                    break;\r\n                case 'Article':\r\n                    titrePage = 'Article ' + selectedPageSecteurDisplayed;\r\n                    break;\r\n                default:\r\n                    titrePage = commandePage;\r\n            }\r\n            \r\n            \/\/ \u2705 v2.4.5 : Position int\u00e9gr\u00e9e dans #CampagnePageText (apr\u00e8s le titre de page)\r\n            var _rankPos = (donneesIframe && donneesIframe.Rank_Emplacement_Page_Web)\r\n                || donnees.Rank_Emplacement_Page_Web || '';\r\n            var _pagePos = (donneesIframe && donneesIframe.commandePage)\r\n                || donnees.commandePage\r\n                || sessionStorage.getItem('Commande_Page') || 'Homepage';\r\n            console.log('[position] rank:', _rankPos, '| page:', _pagePos);\r\n            console.log('[position] donneesIframe.Rank:', donneesIframe ? donneesIframe.Rank_Emplacement_Page_Web : 'null');\r\n            console.log('[position] donnees.position:', donnees.position);\r\n            var _positionSuffix = '';\r\n            if (_rankPos) {\r\n                _positionSuffix = this.convertirPositionEnLibelle(this.calculerPosition(_rankPos, _pagePos));\r\n                console.log('[position] OK depuis rank:', _positionSuffix);\r\n            } else if (donnees.position) {\r\n                _positionSuffix = this.convertirPositionEnLibelle(donnees.position);\r\n                console.log('[position] OK depuis donnees.position:', _positionSuffix);\r\n            } else {\r\n                console.warn('[position] AUCUNE SOURCE - rank vide ET donnees.position vide');\r\n            }\r\n            \/\/ v4.9ds : pour Ele0A, NE JAMAIS ajouter \"    Pop-up\" dans CampagnePageText\r\n            \/\/   (la mention Pop-up est portee par CampagneNoClass uniquement)\r\n            var _isEle0APos = \/L0A$\/.test(emplacementReserve);\r\n            \/\/ pb82 : nettoyer et tronquer titrePage\r\n            \/\/   1. Si \"Article Art.\" -> supprimer \"Art.\" (doublon)\r\n            \/\/   2. Ne pas compter \"Article\" ni \"Art.\" dans la limite des 3 mots\r\n            \/\/   ex: \"Article Art. Le plan emergence...\" -> \"Article Le plan emergence\u2026\"\r\n            var _titrePageDisplay = titrePage.replace(\/\\bArt\\.\\s*\/g, '').replace(\/\\s{2,}\/g, ' ').trim();\r\n            var _prefixTp82 = '';\r\n            var _restTp82 = _titrePageDisplay;\r\n            if (\/^Article\\b\/.test(_titrePageDisplay)) {\r\n                _prefixTp82 = 'Article';\r\n                _restTp82 = _titrePageDisplay.slice('Article'.length).replace(\/^\\s+\/, '');\r\n            }\r\n            var _wordsTp82 = _restTp82.split(\/\\s+\/).filter(function(w) { return w.length > 0; });\r\n            if (_wordsTp82.length > 3) {\r\n                _restTp82 = _wordsTp82.slice(0, 3).join(' ') + '\\u2026';\r\n            }\r\n            _titrePageDisplay = _prefixTp82 ? (_prefixTp82 + (_restTp82 ? ' ' + _restTp82 : '')) : _restTp82;\r\n            var _titrePageAvecPos = (_positionSuffix ? !_isEle0APos : false)\r\n                ? _titrePageDisplay + '\u00a0\u00a0\u00a0\u00a0' + _positionSuffix\r\n                : _titrePageDisplay;\r\n            var $_pageText = $item.find('#CampagnePageText, .CampagnePageTextClass').first();\r\n            console.log('[position] $pageText.length:', $_pageText.length, '| avant:', $_pageText.text());\r\n            $_pageText.text(_titrePageAvecPos);\r\n            console.log('[position] apres injection:', $_pageText.text());\r\n\r\n            \/\/ 5. Format\r\n            if (donnees.format || (donneesIframe && donneesIframe.Commande_Format_Transmis)) {\r\n                let format = donnees.format || donneesIframe.Commande_Format_Transmis;\r\n                \r\n                \/\/ \u2705 Ajouter \"Pop-up \" si Rank commence par \"Ele0\"\r\n                if (donneesIframe && donneesIframe.Rank_Emplacement_Page_Web) {\r\n                    const rank = donneesIframe.Rank_Emplacement_Page_Web;\r\n                    if (rank.startsWith('Ele0')) {\r\n                        format = 'Pop-up ' + format;\r\n                    }\r\n                }\r\n                \r\n                const $_fmt3 = $item.find('.CampagneFormatClass');\r\n                if (format) {\r\n                    $_fmt3.find('p').text(_translateFormatLabel(format));\r\n                    $_fmt3.show();\r\n                } else {\r\n                    $_fmt3.hide();\r\n                }\r\n            }\r\n            \r\n            \/\/ 6. CampagneEnvoiUlterieurClass \u2014 r\u00e8gles :\r\n            \/\/    - R\u00e9serv\u00e9 : NE PAS changer le texte (il a \u00e9t\u00e9 d\u00e9fini \u00e0 l'\u00e9tape partielle)\r\n            \/\/    - Juste g\u00e9rer la visibilit\u00e9 selon pr\u00e9sence de donn\u00e9es\r\n            \/\/ \u2705 v4.9ds Pb 6 : si fichier d\u00e9pos\u00e9 \u2192 \"Annonce ins\u00e9r\u00e9e\" prioritaire (peu importe\r\n            \/\/   envoi diff\u00e9r\u00e9). Align\u00e9 avec remplirItemPartiel ligne 2599.\r\n            if (donneesIframe) {\r\n                const $envoiUlterieur = $item.find('.CampagneEnvoiUlterieurClass');\r\n                const $annonceDepose = $item.find('.CampagneAnnonceDeposeClass');\r\n                const isEnvoiDiffere = donneesIframe.EnvoiUlterieur === 'true' || donneesIframe.EnvoiUlterieur === true;\r\n                const hasFile = donneesIframe.FileReceived === 'Yes'\r\n                             || donneesIframe.HasAdLoadedDom === 'Yes';\r\n                const _langEnvoi = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                if (hasFile) {\r\n                    \/\/ Fichier d\u00e9pos\u00e9 \u2192 afficher .CampagneAnnonceDeposeClass, cacher .CampagneEnvoiUlterieurClass\r\n                    $envoiUlterieur.hide();\r\n                    $annonceDepose.show();\r\n                } else if (isEnvoiDiffere) {\r\n                    const _txtD = _langEnvoi === 'EN' ? 'Ad to be sent within 8 days of payment' : \"Annonce \u00e0 transmettre jusqu'\u00e0 8 jours apr\u00e8s paiement, un lien vous sera adress\u00e9 par contact@via-agency.media\";\r\n                    $envoiUlterieur.find('p').text(_txtD);\r\n                    $envoiUlterieur.show();\r\n                    $annonceDepose.hide();\r\n                } else {\r\n                    $envoiUlterieur.hide();\r\n                    $annonceDepose.hide();\r\n                }\r\n            }\r\n            \r\n            \/\/ 7. Dates - SEULEMENT si l'espace est disponible\r\n            if (donnees.dateDebut && donnees.dateFin) {\r\n                const estIndisponible = $('#IndisponibilitesMsg').is(':visible') || \r\n                                        donnees.disponibilite === false || \r\n                                        donnees.statut === 'indisponible';\r\n                \r\n                if (!estIndisponible) {\r\n                    const dates = lang === 'EN' \r\n                        ? `Campaign from ${donnees.dateDebut} to ${donnees.dateFin}`\r\n                        : `Campagne du ${donnees.dateDebut} au ${donnees.dateFin}`;\r\n                    $item.find('.CampagneDatesClass').html(dates).show();\r\n                } else {\r\n                    $item.find('.CampagneDatesClass').hide();\r\n                    console.log('\ud83d\udeab Dates masqu\u00e9es dans remplirItemComplet - espace indisponible');\r\n                }\r\n            }\r\n            \r\n            if (donnees.duree) {\r\n                const dureeText = lang === 'EN'\r\n                    ? (donnees.duree === 1 ? '1 day' : `${donnees.duree} days`)\r\n                    : (donnees.duree === 1 ? '1 jour' : `${donnees.duree} jours`);\r\n                $item.find('.CampagneNbJours').html(dureeText);\r\n            }\r\n            \r\n            \/\/ 8. Pays soci\u00e9t\u00e9 (depuis formulaire)\r\n            if (donnees.pays) {\r\n                $item.find('.CampagnePaysSocieteClass').html(donnees.paysAnnonceur || donnees.pays || '');\r\n            }\r\n            \r\n            \/\/ 9. Tarif - SEULEMENT si l'espace est disponible\r\n            const estTarifIndisponible = donnees.disponibilite === false || donnees.statut === 'indisponible';\r\n            const labelTarif = lang === 'EN' ? 'Price excl. VAT' : 'Tarif H.T.';\r\n            \r\n            \/\/ ================================================================\r\n            \/\/ pb1376 : LE WRITER QUI REPASSAIT APRES pb1375.\r\n            \/\/   Le log disait \u00ab tarif pos\u00e9 sur la carte \u2026 calcul\u00e9=block \u00bb, et le HTML\r\n            \/\/   montrait ensuite un contenu VIDE avec display:none. Un writer\r\n            \/\/   repassait donc apres \u2014 c'est celui-ci, branche \u00ab pas de tarif \u00bb :\r\n            \/\/   html('') + hide(). La signature ne trompe pas : contenu vide, pas un\r\n            \/\/   tiret. resetDonneesCampagne, l'autre candidat, ecrit '-'.\r\n            \/\/   Cause : la condition porte sur donnees.tarifHT alors que la carte a\r\n            \/\/   pu etre remplie entre-temps depuis l'ITEM (pb1373). Quand\r\n            \/\/   remplirItemComplet est appele avec des donnees partielles, il efface\r\n            \/\/   une valeur pourtant valide \u2014 meme defaut que pb1368 sur les cles de\r\n            \/\/   page : effacer parce qu'on n'a rien, plutot que parce qu'il n'y a rien.\r\n            \/\/   On se rabat donc sur le tarif de l'item avant de vider, et on applique\r\n            \/\/   l'idiome de revelation (pb1375) aux deux branches qui affichent : un\r\n            \/\/   .show() ne bat pas les classes elementor-hidden-*.\r\n            \/\/   Revert : window._viaPb1376Off = true.\r\n            \/\/ ================================================================\r\n            var _tarif1376 = donnees.tarifHT;\r\n            if (window._viaPb1376Off !== true) {\r\n                if (!_tarif1376) {\r\n                    try {\r\n                        var _st1376 = this.state || null;\r\n                        var _id1376 = donnees.id || ($item.length ? $item.attr('id') : '');\r\n                        var _it1376 = (_st1376 ? (_st1376.items || []) : [])\r\n                            .find(function (o) { return o.id === _id1376; });\r\n                        if (_it1376 ? _it1376.tarifHT : false) {\r\n                            _tarif1376 = _it1376.tarifHT;\r\n                            if (window._viaSig1376 !== _id1376 + '|' + _tarif1376) {\r\n                                window._viaSig1376 = _id1376 + '|' + _tarif1376;\r\n                                console.log('[pb1376] tarif absent des donn\u00e9es -> repris de'\r\n                                    + ' l\\'item (' + _tarif1376 + ') au lieu d\\'\u00eatre effac\u00e9');\r\n                            }\r\n                        }\r\n                    } catch (_e1376) {\r\n                        console.warn('[pb1376] lecture de l\\'item : ' + _e1376.message);\r\n                    }\r\n                }\r\n            }\r\n            var _revel1376 = function ($z1376) {\r\n                if (!$z1376.length) { return; }\r\n                if (window._viaPb1376Off === true) { $z1376.show(); return; }\r\n                $z1376.removeClass('elementor-hidden-desktop'\r\n                    + ' elementor-hidden-tablet elementor-hidden-mobile');\r\n                $z1376[0].style.setProperty('display', 'block', 'important');\r\n            };\r\n            if (_tarif1376 && window.VIA_App && !estTarifIndisponible) {\r\n                const tarifFormate = window.VIA_App.formaterMontant(_tarif1376, donnees.devise || 'EUR', 2);\r\n                var $zt1376 = $item.find('.CampagneTarifClass');\r\n                \/\/ pb2121 : resa active d'un commercial -> libelle seul.\r\n                $zt1376.html(window._viaLibelleTarif2121($item.length ? $item.attr('id') : '', `${labelTarif} ${tarifFormate}`));\r\n                _revel1376($zt1376);\r\n            } else if (estTarifIndisponible) {\r\n                \/\/ \u2705 Espace indisponible - afficher \"-\"\r\n                var $zi1376 = $item.find('.CampagneTarifClass');\r\n                $zi1376.html(`${labelTarif} -`);\r\n                _revel1376($zi1376);\r\n                console.log('\ud83d\udeab Tarif masqu\u00e9 dans remplirItemComplet - espace indisponible');\r\n            } else {\r\n                \/\/ \u2705 Pas de tarif NI dans les donn\u00e9es NI sur l'item - vider et masquer\r\n                $item.find('.CampagneTarifClass').html('').hide();\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds Fix 24 v2 : aligner les crit\u00e8res estReserve\/aReserver sur\r\n            \/\/   estReserveEffective (idem _isReservedC ligne 2503 + remplirItemPartiel\r\n            \/\/   ligne 1991). Sans cet alignement, un item au statut 'en_cours' mais avec\r\n            \/\/   estReserveEffective=false (= titre affich\u00e9 \"\u00c0 r\u00e9server\") passait par la\r\n            \/\/   branche else if !tarifHT et affichait \"Merci de choisir dates...\" alors\r\n            \/\/   qu'on doit le masquer sur site pays (cf Fix 24 partie 1 dans\r\n            \/\/   ajouterMsgAccompagnement).\r\n            var _estReservedF24v2 = donnees.estReserveEffective === true ? true : donnees.statut === 'complete';\r\n            this.ajouterMsgAccompagnement($item, {\r\n                espace: donnees.emplacementPageWeb || '',\r\n                estReserve: _estReservedF24v2,\r\n                tarifHT: donnees.tarifHT || null,\r\n                \/\/ v4.9ds : flag \"\u00c0 r\u00e9server\" \u2014 item pas encore effectivement r\u00e9serv\u00e9\r\n                aReserver: !_estReservedF24v2\r\n            });\r\n            \r\n            console.log('\u2705 Item rempli compl\u00e8tement');\r\n            \/\/ pb77 : forcer margin-top 12px en inline style sur #CampagnePage\r\n            (function() {\r\n                var _cp77c = $item.find('#CampagnePage')[0];\r\n                if (_cp77c) { _cp77c.style.setProperty('margin-top', window.VIA_Panier._mt801('12px'), 'important'); }   \/\/ pb801\r\n            })();\r\n        },\r\n\r\n        \/**\r\n         * Affiche Etape1Container\r\n         * \u2705 v1.9 : Simplifi\u00e9 - Etape1Container est fils de ProcessCommande, plus besoin d'insertion\r\n         * \u2705 v2.0.9 : V\u00e9rification aEspacePub sur desktop ET mobile\r\n         *             ProcessAchatInside ne s'ouvre que si l'utilisateur a cliqu\u00e9 \"R\u00e9server cet espace\"\r\n         *\/\r\n        afficherEtape1DansItem(itemId) {\r\n            const item = this.state.items.find(i => i.id === itemId);\r\n            const isDesktop = window.outerWidth >= 1000;\r\n            \r\n            if (!item) {\r\n                console.warn('\u26a0\ufe0f Item introuvable pour afficher Etape1:', itemId);\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v2.0.9 : V\u00e9rifier qu'un espace publicitaire a \u00e9t\u00e9 r\u00e9serv\u00e9 (desktop ET mobile)\r\n            \/\/ ProcessAchatInside ne s'ouvre que si \"R\u00e9server cet espace\" a \u00e9t\u00e9 cliqu\u00e9\r\n            \/\/ \u2192 emplacementPageWeb est renseign\u00e9 d\u00e8s le clic \"R\u00e9server\" (m\u00eame sans fichier d'annonce)\r\n            \/\/ \u2192 lienEspacePub \/ cheminFichierAnnonce \/ FileReceived \/ EnvoiUlterieur = fichier d\u00e9pos\u00e9\r\n            \/\/ \u2705 v2.4.9 : L'accord\u00e9on dates\/tarifs ne s'ouvre QUE si l'espace est r\u00e9ellement r\u00e9serv\u00e9\r\n            \/\/ emplacementPageWeb est pos\u00e9 UNIQUEMENT au clic \"R\u00e9server cet espace\" \u2192 source de v\u00e9rit\u00e9\r\n            \/\/ donneesIframe.Commande_Emplacement_Page_Web est pos\u00e9 d\u00e8s la s\u00e9lection du rank \u2192 insuffisant\r\n            \/\/ \u2705 source de v\u00e9rit\u00e9 = emplacementPageWeb (pos\u00e9 au clic R\u00e9server)\r\n            \/\/ statut 'en_cours' retir\u00e9 : popup envoi diff\u00e9r\u00e9 passe \u00e0 en_cours sans r\u00e9servation r\u00e9elle\r\n            \/\/ pb210 : ajouter item.estReserveEffective. Un espace r\u00e9serv\u00e9 via \"R\u00e9server\" en envoi\r\n            \/\/   diff\u00e9r\u00e9 (sans fichier) a estReserveEffective=true MAIS emplacementPageWeb peut \u00eatre\r\n            \/\/   null sur l'objet item (l'emplacement n'est pos\u00e9 qu'en sessionStorage index\u00e9) \u2192\r\n            \/\/   sans ce flag, aEspacePub=false \u2192 la s\u00e9lection des dates ne s'ouvrait pas alors que\r\n            \/\/   la r\u00e9sa affiche bien \"Espace r\u00e9serv\u00e9\" (cf log \"R\u00e9serv\u00e9\").\r\n            const aEspacePub = !!(item.emplacementPageWeb ||\r\n                               item.lienEspacePub || \r\n                               item.cheminFichierAnnonce ||\r\n                               item.estReserveEffective === true ||\r\n                               item.statut === 'complete');\r\n            \r\n            if (!aEspacePub) {\r\n                console.log('\u23ed\ufe0f Etape1 non affich\u00e9 - aucun espace publicitaire s\u00e9lectionn\u00e9 pour:', itemId);\r\n                var _isPopupModeED = window.location.search.indexOf('mode=popup') !== -1;\r\n                var _is3ColED = sessionStorage.getItem('PageWebColonneOpenclose') === 'Open';\r\n                \/\/ \u2705 En mode=popup ou 3 colonnes : montrer le titre Dates bloqu\u00e9\r\n                if (_isPopupModeED || _is3ColED) {\r\n                    console.log('\ud83d\udcc5 [popup\/3col] Etape1Container affich\u00e9 bloqu\u00e9 \u2014 en attente r\u00e9servation');\r\n                    $('#Etape1Container').show();\r\n                    $('.Etape1').show();\r\n                    \/\/ \u2705 v2.6 : ProcessAchatInside a la classe DatesDureeCampagneClass\r\n                    \/\/ show() apres hide() annulait le masquage -> Dates visibles. Supprime.\r\n                    $('.DatesDureeCampagneClass').hide();\r\n                    $('#ProcessAchatInside').css('pointer-events', 'none').css('opacity', '0.4');\r\n                    $('#MsgBlockDates').hide();\r\n                    return;\r\n                }\r\n                \/\/ \u2705 v2.4.9 : Refermer l'accord\u00e9on dates\/dur\u00e9e\/tarifs\r\n                $('#Etape1Container').hide();\r\n                $('.Etape1').hide();\r\n                $('.DatesDureeCampagneClass').hide();\r\n                $('#ProcessAchatInside').hide();\r\n                $('#MsgBlockDates').hide();\r\n                return;\r\n            }\r\n            \r\n            let $etape1 = $('#Etape1Container');\r\n            \r\n            \/\/ \u2705 Si Etape1Container n'existe pas, ne rien faire\r\n            if ($etape1.length === 0) {\r\n                \/\/ ============================================================\r\n                \/\/ pb1381 : LA GARDE D'AFFICHAGE BLOQUAIT AUSSI LA RESTAURATION.\r\n                \/\/   Constat user : le tarif ne s'affiche plus dans la resa, sauf\r\n                \/\/   avec une homepage. La sonde pb1380 a suivi la valeur sur l'item :\r\n                \/\/     tarifHT=null   statut=anticipee   (etat initial)\r\n                \/\/     tarifHT=916    statut=valide      (le tarif arrive)\r\n                \/\/     tarifHT=null   statut=valide      (il repart)\r\n                \/\/   Le tarif est efface par resetDonneesCampagne (~l.4036), qui remet\r\n                \/\/   dates, pays ET tarif a null a chaque changement de format ou de\r\n                \/\/   page. C'est voulu : le tarif depend du format.\r\n                \/\/   Ce qui devait suivre, c'est la restauration \u2014 pb746, plus bas dans\r\n                \/\/   CETTE fonction : \u00ab la restauration rendait les dates et le pays,\r\n                \/\/   mais PAS le tarif [\u2026] on relance donc le CALCUL \u00bb.\r\n                \/\/   Or en 3 colonnes #Etape1Container est absent du DOM, et la\r\n                \/\/   fonction sortait ICI, avant d'y arriver. Les dates sont reposees\r\n                \/\/   par d'autres chemins ; le tarif, lui, n'avait que celui-la. D'ou\r\n                \/\/   l'ecart avec la homepage, qui ne declenche pas le reset.\r\n                \/\/   Une garde d'AFFICHAGE ne doit pas emporter une restauration de\r\n                \/\/   DONNEES. Le recalcul est relance avant de sortir.\r\n                \/\/   Revert : window._viaPb1381Off = true.\r\n                \/\/ ============================================================\r\n                if (window._viaPb1381Off !== true) {\r\n                    try {\r\n                        var _it1381 = (this.state ? (this.state.items || []) : [])\r\n                            .find(function (o) { return o.id === itemId; });\r\n                        \/\/ ========================================================\r\n                        \/\/ pb1383 : CONDITION TROP ETROITE, ET MUETTE QUAND ELLE ECHOUE.\r\n                        \/\/   pb1381 exigeait _via_saved_dateDebut \u2014 la cle de sauvegarde\r\n                        \/\/   de resetDonneesCampagne. Elle est SUPPRIMEE des qu'une\r\n                        \/\/   restauration aboutit ailleurs (~l.5994) : quand on passe\r\n                        \/\/   ici, elle a souvent deja disparu, et la garde ne se\r\n                        \/\/   declenchait jamais. Le log filtre sur pb1381 ne montrait\r\n                        \/\/   que l'echo de version.\r\n                        \/\/   Le vrai critere n'est pas \u00ab une sauvegarde existe \u00bb mais\r\n                        \/\/   \u00ab cet item devrait avoir un tarif et n'en a pas \u00bb : des\r\n                        \/\/   dates, un format, pas de tarifHT.\r\n                        \/\/   Anti-repetition par signature (item + dates + format) :\r\n                        \/\/   _recalculerTarifItem746 est asynchrone, sans cela chaque\r\n                        \/\/   passage en relancerait un nouveau.\r\n                        \/\/   Et le log est INCONDITIONNEL : la version precedente ne\r\n                        \/\/   disait rien quand elle ne faisait rien, ce qui a coute ce\r\n                        \/\/   tour. Tout exit doit loguer.\r\n                        \/\/   Revert : window._viaPb1381Off = true.\r\n                        \/\/ ========================================================\r\n                        var _sig1383 = _it1381\r\n                            ? (itemId + '|' + (_it1381.dateDebut || '') + '|'\r\n                               + (_it1381.dateFin || '') + '|' + (_it1381.format || ''))\r\n                            : '';\r\n                        var _apte1383 = _it1381\r\n                            ? (!_it1381.tarifHT\r\n                                ? (!!_it1381.dateDebut ? !!_it1381.format : false)\r\n                                : false)\r\n                            : false;\r\n                        var _deja1383 = (window._viaTente1383 === _sig1383);\r\n                        console.log('[pb1383] Etape1Container absent | item=' + itemId\r\n                            + ' | trouv\u00e9=' + (!!_it1381)\r\n                            + ' | tarifHT=' + (_it1381 ? _it1381.tarifHT : 'n\/a')\r\n                            + ' | dates=' + (_it1381 ? !!_it1381.dateDebut : 'n\/a')\r\n                            + ' | format=' + (_it1381 ? (_it1381.format || '-') : 'n\/a')\r\n                            + ' | recalcul=' + (_apte1383 ? (_deja1383 ? 'd\u00e9j\u00e0 tent\u00e9' : 'OUI') : 'non'));\r\n                        if (_apte1383 ? !_deja1383 : false) {\r\n                            window._viaTente1383 = _sig1383;\r\n                            if (typeof this._recalculerTarifItem746 === 'function') {\r\n                                this._recalculerTarifItem746(_it1381,\r\n                                    'garde Etape1Container \u2014 pb1383');\r\n                            } else {\r\n                                console.warn('[pb1383] _recalculerTarifItem746 indisponible');\r\n                            }\r\n                        }\r\n                    } catch (_e1381) {\r\n                        console.warn('[pb1383] recalcul impossible : ' + _e1381.message);\r\n                    }\r\n                }\r\n                console.warn('\u26a0\ufe0f Etape1Container introuvable, skip');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v1.9 : Afficher Etape1Container et ProcessAchatInside\r\n            \/\/ \u2705 v2.0 : Afficher .Etape1 mais garder .DatesDureeCampagneClass ferm\u00e9 par d\u00e9faut\r\n            \/\/ \u2705 v2.6 : Accord\u00e9on Dates ferm\u00e9 par d\u00e9faut sur la r\u00e9gie\r\n            \/\/ \u2705 v2.7 : En mode=popup avec espace r\u00e9serv\u00e9, ouvrir imm\u00e9diatement les dates\/tarifs\r\n            $etape1.show();\r\n            $('.Etape1').show();\r\n            \/\/ v4.9ds : d\u00e9tection mode popup via HASH + search (params en hash dans v4.9ds)\r\n            var _isPopupAutoOpen = (new URLSearchParams(window.location.hash.substring(1) || window.location.search).get('mode') === 'popup');\r\n            if (_isPopupAutoOpen) {\r\n                $('.DatesDureeCampagneClass').show();\r\n                $('#DatesDureeCampagneIconeUp').show();\r\n                $('#DatesDureeCampagneIconeDown').hide();\r\n                \/\/ v4.9ds : replacer Dates apr\u00e8s R\u00e9cap + activer titre (rouge) si d\u00e9j\u00e0 valid\u00e9e\r\n                if (typeof this._viaActiverEtapeDates === 'function') { this._viaActiverEtapeDates(); }\r\n            } else {\r\n                $('.DatesDureeCampagneClass').hide();\r\n                $('#DatesDureeCampagneIconeUp').hide();\r\n                $('#DatesDureeCampagneIconeDown').show();\r\n            }\r\n            $('#MobileMsgChoixDatesMSgDefaut').removeClass('via-msg-visible');\r\n            \/\/ pb699 : l'etape 1 (formulaire dates \/ pays \/ tarif) n'a plus d'objet quand\r\n            \/\/   ces trois donnees sont DEJA renseignees \u2014 cas du flux Express checking,\r\n            \/\/   ou la resa se deploie pre-remplie. On masque alors #ProcessAchatInside\r\n            \/\/   au lieu de l'afficher.\r\n            \/\/   Pays : on accepte item.pays OU item.paysAnnonceur, les deux coexistent\r\n            \/\/   selon le chemin de creation (cf pb666\/pb669).\r\n            \/\/   Log INCONDITIONNEL, avec le detail des trois criteres : si le bloc reste\r\n            \/\/   visible, il dira lequel manque plutot que de rester muet.\r\n            \/\/   pb699b : condition supplementaire \u2014 la resa doit avoir ete INITIEE dans\r\n            \/\/   le popup Tarifs. Marqueur item._expressResa657 (pose par le bloc pb657\r\n            \/\/   plus bas) ; au TOUT PREMIER passage il n'est pas encore ecrit, on accepte\r\n            \/\/   donc aussi le flag window encore arme. Sans cette condition, une resa\r\n            \/\/   saisie normalement et devenue complete verrait son formulaire disparaitre.\r\n            \/\/   NB : sur desktop, pb657 clique deja Valider \u2014 ce masquage ne le remplace\r\n            \/\/   pas, il garantit seulement que le formulaire est bien masque la ou le\r\n            \/\/   clic n'aboutit pas (mobile).\r\n            var _pays699 = item.pays ? item.pays : item.paysAnnonceur;\r\n            var _express699 = (item._expressResa657 === true)\r\n                ? true\r\n                : (window._viaExpressResaAutoValider657 === true);\r\n            var _complet699 = false;\r\n            if (item.dateDebut) {\r\n                if (item.dateFin) {\r\n                    if (item.tarifHT) {\r\n                        if (_pays699) { if (_express699) { _complet699 = true; } }\r\n                    }\r\n                }\r\n            }\r\n            console.log('[pb699] ProcessAchatInside | dateDebut=' + item.dateDebut\r\n                + ' | dateFin=' + item.dateFin + ' | pays=' + _pays699\r\n                + ' | tarifHT=' + item.tarifHT + ' | express=' + _express699\r\n                + ' -> ' + (_complet699 ? 'MASQUE' : 'affiche')\r\n                + ' | item=' + item.id);\r\n            \/\/ pb716 : cette methode ne dispose PAS de $item (elle recoit itemId) ; on\r\n            \/\/   resout donc l'element ici, a partir de l'id.\r\n            const $item716 = $('#' + item.id);\r\n            \/\/ pb716b : le clic sur le lien rouvre #ProcessAchatInside, mais ne change\r\n            \/\/   RIEN aux donnees de l'item -> _complet699 reste vrai et la passe\r\n            \/\/   suivante re-masquait aussitot (l'ouverture ne tenait pas). Le flag\r\n            \/\/   _via716OuvertPour, pose au clic avec l'id de l'item, fait primer la\r\n            \/\/   reouverture manuelle sur le masquage auto POUR CET ITEM. Il tombe des\r\n            \/\/   que l'item redevient incomplet (branche else) ou change d'identite.\r\n            const _rouvert716 = (window._via716OuvertPour === item.id);\r\n            if (_complet699 ? !_rouvert716 : false) {\r\n                $('#ProcessAchatInside').hide();\r\n                this._lienOuvrirEtape1_716($item716, true);    \/\/ pb716\r\n            } else {\r\n                if (_complet699 ? _rouvert716 : false) {\r\n                    console.log('[pb716b] masquage auto court-circuite (reouverture manuelle) item=' + item.id);\r\n                }\r\n                if (!_complet699) { if (window._via716OuvertPour === item.id) { window._via716OuvertPour = null; } }\r\n                $('#ProcessAchatInside').show();\r\n                this._lienOuvrirEtape1_716($item716, false);   \/\/ pb716\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds Fix 21 : MsgBlockDates supprim\u00e9 (demande user) mais blocage\r\n            \/\/   ProcessAchatInside CONSERV\u00c9 pour items partiels (coh\u00e9rent avec\r\n            \/\/   updateBlockDates dans yearbook-media.js).\r\n            \/\/ \u2705 v4.9ds Fix 25 : aligner crit\u00e8re \"r\u00e9serv\u00e9\" sur estReserveEffective\r\n            \/\/   (idem _isReservedPartiel ligne 2052 \/ _isReservedC ligne 2503 \/ Fix 24 v2).\r\n            \/\/   Sans cet alignement, un item statut='en_cours' mais estReserveEffective=false\r\n            \/\/   (= titre \"\u00c0 r\u00e9server\" en orange) d\u00e9bloquait ProcessAchatInside alors qu'il\r\n            \/\/   doit rester bloqu\u00e9 tant que la r\u00e9servation n'est pas effective.\r\n            \/\/ \u2705 v4.9ds Fix 25 v2 : retir\u00e9 la condition `!_isPopupAutoOpen` qui h\u00e9ritait\r\n            \/\/   d'une ancienne logique v2.7 (\"en mode popup, aEspacePub garantit r\u00e9serv\u00e9 \u2192\r\n            \/\/   ne pas bloquer\"). Cette assomption tombe avec les items \"\u00e0 r\u00e9server\" qui\r\n            \/\/   peuvent exister en mode popup avec estReserveEffective=false. Maintenant\r\n            \/\/   la logique est claire : si l'item n'est pas effectivement r\u00e9serv\u00e9, on\r\n            \/\/   bloque ProcessAchatInside, point. Coh\u00e9rent avec updateBlockDates ligne\r\n            \/\/   9902 de yearbook-media.js (Fix 25).\r\n            var _isReserved = item.estReserveEffective === true ? true : item.statut === 'complete';\r\n            var _shouldBlock = !_isReserved;\r\n            if (_shouldBlock) {\r\n                $('#ProcessAchatInside').css('pointer-events', 'none').css('opacity', '0.4').css('border', '3px solid #a2c6f3');\r\n                console.log('\ud83d\udeab ProcessAchatInside bloqu\u00e9 (afficherEtape1DansItem) \u2014 item partielle sans annonce');\r\n            } else {\r\n                \/\/ \u2705 v4.9ds Pb 7 : retirer le liser\u00e9 vert (demande user)\r\n                $('#ProcessAchatInside').css('pointer-events', '').css('opacity', '').css('border', '');\r\n                console.log('\u2705 ProcessAchatInside d\u00e9bloqu\u00e9 \u2014 statut:', item.statut, '| popup:', _isPopupAutoOpen);\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds Pb 7 : LabelDatesDureeReservation supprim\u00e9 (\u00e9tape Dates retir\u00e9e\r\n            \/\/   d'Elementor). Le code de cr\u00e9ation\/maj du label est neutralis\u00e9. ProcessAchatInside\r\n            \/\/   est d\u00e9sormais d\u00e9plac\u00e9 dans l'item actif si R\u00e9serv\u00e9+agrandi, g\u00e9r\u00e9 par le\r\n            \/\/   helper window._viaUpdateProcessAchatLocation (cf. plus bas).\r\n            \/\/ Nettoyer un \u00e9ventuel r\u00e9sidu existant\r\n            try { $('#LabelDatesDureeReservation').remove(); } catch(_eL) {}\r\n            \r\n            \/\/ \u2705 v4.9ds Pb 7 : d\u00e9placer ProcessAchatInside dans l'item actif si conditions\r\n            \/\/   r\u00e9unies (R\u00e9serv\u00e9e + agrandi).\r\n            try {\r\n                if (typeof window._viaUpdateProcessAchatLocation === 'function') {\r\n                    window._viaUpdateProcessAchatLocation();\r\n                }\r\n            } catch(_eP) {}\r\n\r\n            \/\/ \u2705 Restauration dates\/pays sauvegard\u00e9s lors d'un reset (changement pays\/secteur\/format).\r\n            \/\/   Doit se faire AVANT remplirFormulaireDepuisItem pour que le formulaire\r\n            \/\/   soit pr\u00e9-rempli avec les valeurs restaur\u00e9es.\r\n            var _rstDateDebut = sessionStorage.getItem('_via_saved_dateDebut') || '';\r\n            \/\/ ================================================================\r\n            \/\/ pb959 : ne restaurer les DATES que sur l'item qui les a produites.\r\n            \/\/   Le mecanisme d'origine sauvait les dates avant un reset (changement\r\n            \/\/   pays\/secteur\/format) et les reposait sur l'item affiche ensuite, SANS\r\n            \/\/   verifier lequel. En creant une resa 2, la resa 1 declenchait le save,\r\n            \/\/   puis la resa 2 recevait ses dates : \"dates: 28\/08\/2026 -> 25\/09\/2026\"\r\n            \/\/   sur un item tout neuf (log user).\r\n            \/\/   Le PAYS ANNONCEUR reste restaure dans tous les cas : c'est une donnee\r\n            \/\/   de campagne, commune a toutes les reservations (cf pb958).\r\n            \/\/   Revert : window._viaPb959Off = true.\r\n            \/\/ ================================================================\r\n            var _ownerDates959 = sessionStorage.getItem('_via_saved_itemId') || '';\r\n            var _datesPourMoi959 = (window._viaPb959Off === true)\r\n                ? true\r\n                : (_ownerDates959 ? (_ownerDates959 === item.id) : true);\r\n            if (!_datesPourMoi959) {\r\n                if (_rstDateDebut) {\r\n                    console.log('[pb959] dates sauvegard\u00e9es ignor\u00e9es \u2014 elles appartiennent \u00e0 '\r\n                        + _ownerDates959 + ', item affich\u00e9 : ' + item.id);\r\n                }\r\n                var _rstPays959 = sessionStorage.getItem('_via_saved_pays') || '';\r\n                if (_rstPays959) { item.paysAnnonceur = _rstPays959; }\r\n                sessionStorage.removeItem('_via_saved_dateDebut');\r\n                sessionStorage.removeItem('_via_saved_dateFin');\r\n                sessionStorage.removeItem('_via_saved_duree');\r\n                sessionStorage.removeItem('_via_saved_pays');\r\n                sessionStorage.removeItem('_via_saved_itemId');\r\n                _rstDateDebut = '';\r\n            }\r\n            \/* ============================================================\r\n             * pb1693 : L ANNONCEUR ETAIT RESTAURE EN OTAGE DES DATES.\r\n             *   Constat user : sur mobile, l etape Annonceur redevient active des\r\n             *   la selection d un site pays.\r\n             *   Le choix d un espace remet a zero dateDebut, dateFin, duree, pays\r\n             *   ET paysAnnonceur (l.4385-4390), apres les avoir sauvegardes. La\r\n             *   restauration, elle, est enfermee dans \u00ab if (_rstDateDebut) \u00bb :\r\n             *   sans dates sauvegardees, paysAnnonceur n est jamais rendu, et\r\n             *   l etape annonceur repasse a \u00ab a faire \u00bb.\r\n             *   Sur desktop les dates sont en general saisies avant de choisir un\r\n             *   site : _rstDateDebut est renseigne, la branche s execute, le pays\r\n             *   revient avec elles. Sur mobile l ordre naturel est inverse \u2014 d ou\r\n             *   un defaut qui n a rien de mobile mais ne se voit que la.\r\n             *   Les dates et l annonceur n ont aucune raison d etre solidaires :\r\n             *   la branche voisine (_datesPourMoi959, dix lignes plus haut) rend\r\n             *   deja le pays SEUL quand les dates appartiennent a un autre item.\r\n             *   Le motif existait, il manquait ce cas.\r\n             *   On ne rend le pays que s il est absent : une valeur heritee\r\n             *   (pb1692) ne doit pas etre ecrasee par une sauvegarde plus ancienne.\r\n             *   Revert : window._viaPb1693Off = true.\r\n             * ============================================================ *\/\r\n            if (window._viaPb1693Off !== true) {\r\n                if (!_rstDateDebut) {\r\n                    var _pays1693 = sessionStorage.getItem('_via_saved_pays') || '';\r\n                    if (_pays1693) {\r\n                        if (item.paysAnnonceur) {\r\n                            console.log('[pb1693] annonceur deja present (' + item.paysAnnonceur\r\n                                + ') -> sauvegarde ignoree, pas d ecrasement');\r\n                        } else {\r\n                            item.paysAnnonceur = _pays1693;\r\n                            console.log('[pb1693] annonceur restaure SANS dates : ' + _pays1693\r\n                                + ' | item ' + item.id);\r\n                        }\r\n                        sessionStorage.removeItem('_via_saved_pays');\r\n                    }\r\n                }\r\n            }\r\n            if (_rstDateDebut) {\r\n                var _rstDateFin = sessionStorage.getItem('_via_saved_dateFin')   || '';\r\n                var _rstDureeS  = sessionStorage.getItem('_via_saved_duree')     || '';\r\n                var _rstPays    = sessionStorage.getItem('_via_saved_pays')       || '';\r\n                item.dateDebut = _rstDateDebut;\r\n                item.dateFin   = _rstDateFin   || null;\r\n                item.duree     = _rstDureeS    ? (parseInt(_rstDureeS) || null) : null;\r\n                item.paysAnnonceur = _rstPays  || null;\r\n                sessionStorage.removeItem('_via_saved_dateDebut');\r\n                sessionStorage.removeItem('_via_saved_dateFin');\r\n                sessionStorage.removeItem('_via_saved_duree');\r\n                sessionStorage.removeItem('_via_saved_pays');\r\n                sessionStorage.removeItem('_via_saved_itemId');   \/\/ pb959\r\n                console.log('\u2705 [afficherEtape1DansItem] dates\/pays restaur\u00e9s pour:', item.id, '| dateDebut:', _rstDateDebut, '| pays:', _rstPays);\r\n                \/\/ pb746 : la restauration rendait les dates et le pays, mais PAS le tarif \u2014\r\n                \/\/   resetDonneesCampagne le met a null a chaque changement de format, et rien\r\n                \/\/   ne le recalculait -> \"En attente ..\" jusqu'a une action manuelle.\r\n                \/\/   Le tarif n'est volontairement PAS restaure tel quel : il depend du format,\r\n                \/\/   qui vient de changer. On relance donc le CALCUL avec le nouveau format.\r\n                \/\/   Proxy same-origin obligatoire depuis la regie (CORS vers via-agency.media,\r\n                \/\/   cf PAYS-GLOBAL L6037). Asynchrone : on n'attend pas, l'item est rafraichi\r\n                \/\/   au retour. Revert : window._viaPb746Off = true.\r\n                this._recalculerTarifItem746(item, 'restauration apres changement de format');\r\n            }\r\n\r\n            this.remplirFormulaireDepuisItem(item);\r\n            \r\n            console.log('\u2705 Etape1Container, .Etape1, DatesDureeCampagne et ProcessAchatInside affich\u00e9s pour item:', itemId);\r\n\r\n            \/\/ pb657 : Express checking -> l'etape 1 est deja pre-remplie (dates, pays,\r\n            \/\/   tarif). Cette etape n'a plus lieu d'etre : simuler le clic Valider.\r\n            \/\/   Flag consomme one-shot (pose par le popup Tarifs au Continuer).\r\n            \/\/ pb657 (diag) : log INCONDITIONNEL. Les traces pb657\/pb695 etaient toutes\r\n            \/\/   DANS le if ci-dessous : quand le flag valait false, rien n'apparaissait\r\n            \/\/   et on ne pouvait pas distinguer \"flag jamais pose\" de \"flag consomme\".\r\n            console.log('[pb657] etat flag=' + window._viaExpressResaAutoValider657\r\n                + ' | item=' + item.id + ' | emplacement=' + item.emplacementPageWeb);\r\n            if (window._viaExpressResaAutoValider657 === true) {\r\n                \/\/ pb695 : NE PAS bruler le flag tant que la resa n'est pas EFFECTIVE.\r\n                \/\/   Le flag est pose au \"Continuer\" (rejouerSync635). Sur MOBILE, la page\r\n                \/\/   web s'ouvre d'abord et l'utilisateur clique Reserver ENSUITE : entre\r\n                \/\/   les deux, afficherEtape1DansItem est appelee sur un item encore SANS\r\n                \/\/   emplacement. La consommation one-shot brulait le flag a ce moment-la,\r\n                \/\/   et le vrai deploiement (apres Reserver) n'auto-validait plus -> aucun\r\n                \/\/   [pb657] dans les logs mobile. On attend donc un item porteur d'un\r\n                \/\/   emplacementPageWeb, c'est-a-dire un espace reellement reserve.\r\n                \/\/   Expiration : le flag ne vaut que pour le Continuer courant (cf\r\n                \/\/   _viaExpressResaAutoValider657At pose cote popup Tarifs), sinon une\r\n                \/\/   resa ulterieure sans rapport serait auto-validee.\r\n                var _age657 = (typeof window._viaExpressResaAutoValider657At === 'number')\r\n                    ? (Date.now() - window._viaExpressResaAutoValider657At)\r\n                    : 0;\r\n                if (_age657 > 180000) {\r\n                    window._viaExpressResaAutoValider657 = false;\r\n                    console.log('[pb657] flag expire (' + Math.round(_age657 \/ 1000) + 's) -> auto-validation abandonnee');\r\n                    return;\r\n                }\r\n                \/\/ pb699b : marquer l'item comme ISSU du popup Tarifs. Marqueur durable\r\n                \/\/   (le flag window, lui, est consomme) reutilise par le masquage de\r\n                \/\/   #ProcessAchatInside plus haut, pour qu'il ne s'applique QU'aux resas\r\n                \/\/   initiees depuis le popup.\r\n                item._expressResa657 = true;\r\n                if (!item.emplacementPageWeb) {\r\n                    console.log('[pb657] flag CONSERVE \u2014 item sans emplacement (Reserver pas encore clique) : ' + item.id);\r\n                    return;\r\n                }\r\n                window._viaExpressResaAutoValider657 = false;\r\n                var _self657 = this;\r\n                var _itemId657 = item.id;\r\n                \/\/ pb657b : ATTENDRE que le tarif de l'item soit calcule avant de cliquer\r\n                \/\/   Valider (au deploiement, tarifHT est encore null -> le Valider\r\n                \/\/   abandonne \"itemsAvecTarif: 0\"). Polling jusqu'a tarifHT non-null.\r\n                var _n657 = 0;\r\n                var _tryValider657 = function() {\r\n                    var _it = (_self657.state && _self657.state.items)\r\n                        ? _self657.state.items.find(function(x) { return x.id === _itemId657; }) : null;\r\n                    var _pret = _it ? (_it.tarifHT !== null ? _it.tarifHT !== undefined : false) : false;\r\n                    \/\/ pb661 : ne PAS valider tant qu'un recalcul de tarif est en vol\r\n                    \/\/   (mettreAJourCommandeExistante). Sinon pb657 validait sur le tarif\r\n                    \/\/   PERIME herite du popup Tarifs, et le vrai tarif arrivant ensuite\r\n                    \/\/   reaffichait l'Etape 1 -> fermeture puis reouverture visible.\r\n                    if (window._viaRecalcTarif661 === true) { _pret = false; }\r\n                    if (!_pret ? (++_n657 <= 30) : false) { setTimeout(_tryValider657, 200); return; }\r\n                    var _btn657 = document.getElementById('Etape1BoutonValider');\r\n                    if (!_pret) {\r\n                        console.warn('[pb657] tarif non calcule apres attente -> Valider annule');\r\n                        return;\r\n                    }\r\n                    if (_btn657) {\r\n                        console.log('[pb657] Express checking -> auto-validation Etape 1 (tarif=' + _it.tarifHT + ')');\r\n                        _btn657.click();\r\n                    } else {\r\n                        console.warn('[pb657] Etape1BoutonValider introuvable');\r\n                    }\r\n                };\r\n                setTimeout(_tryValider657, 400);\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * Remplit le formulaire Etape1 avec les donn\u00e9es de l'item\r\n         *\/\r\n        remplirFormulaireDepuisItem(item) {\r\n            console.log('\ud83d\udd04 Remplissage formulaire depuis item');\r\n            \r\n            \/\/ \u2705 R\u00e9cup\u00e9rer la langue\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            \/\/ Dates\r\n            if (item.dateDebut) {\r\n                $('#form-field-DebutCampagne').val(item.dateDebut);\r\n            } else {\r\n                $('#form-field-DebutCampagne').val('');\r\n            }\r\n            \r\n            if (item.dateFin) {\r\n                $('#form-field-FinCampagne').val(item.dateFin);\r\n            } else {\r\n                $('#form-field-FinCampagne').val('');\r\n            }\r\n            \r\n            \/\/ Dur\u00e9e\r\n            if (item.duree) {\r\n                const dureeText = lang === 'EN'\r\n                    ? (item.duree === 1 ? '1 day' : `${item.duree} days`)\r\n                    : (item.duree === 1 ? '1 jour' : `${item.duree} jours`);\r\n                $('.CampagneNbJours').text(dureeText);\r\n            } else {\r\n                \/\/ pb658b : si les inputs contiennent deja des dates valides (saisies\r\n                \/\/   mais pas encore transferees dans l'item), NE PAS les effacer.\r\n                var _dDeb658 = $('#form-field-DebutCampagne').val();\r\n                var _dFin658 = $('#form-field-FinCampagne').val();\r\n                if (_dDeb658 ? _dFin658 : false) {\r\n                    console.log('[pb658b] item sans duree mais dates formulaire presentes -> preserve');\r\n                } else {\r\n                    $('.CampagneNbJours').text('');\r\n                    \/\/ \u2705 v2.7 : Reset STATE.startDate\/endDate dans Formulaire.txt\r\n                    \/\/ \u00c9vite que triggerTarifCalculation utilise les dates stales de l'item pr\u00e9c\u00e9dent (pb 6)\r\n                    if (typeof window.reinitialiserDatesFormulaire === 'function') {\r\n                        window.reinitialiserDatesFormulaire();\r\n                    }\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds Pb 7 : pr\u00e9-remplir le pays depuis item.pays. Avant (v2.5),\r\n            \/\/   on vidait toujours le champ sous pr\u00e9texte que l'user devait le saisir.\r\n            \/\/   Mais avec ProcessAchatInside qui vit dans l'item actif, l'user attend\r\n            \/\/   que le pays soit restaur\u00e9 quand il re-s\u00e9lectionne une r\u00e9servation d\u00e9j\u00e0\r\n            \/\/   compl\u00e9t\u00e9e. item.pays est rempli par mettreAJourPaysGlobal (pays global\r\n            \/\/   pour toutes les r\u00e9servations du panier).\r\n            \/\/ \u2705 v4.9ds Pb 1 : ne pas se contenter de poser la valeur visuelle \u2014 il faut\r\n            \/\/   aussi re-poser STATE.selectedCountry dans Formulaire.txt (r\u00e9initialis\u00e9 \u00e0\r\n            \/\/   null par reinitialiserDatesFormulaire au switch d'item). Sans \u00e7a,\r\n            \/\/   triggerTarifCalculation refuse de calculer le tarif apr\u00e8s saisie de\r\n            \/\/   nouvelles dates (\"En attente de la s\u00e9lection du pays\") m\u00eame si le champ\r\n            \/\/   visuel \"France\" est rempli.\r\n            \/\/ \u2705 Pb 8 v3 : lire item.paysAnnonceur (nationalit\u00e9 soci\u00e9t\u00e9, saisie utilisateur,\r\n            \/\/   aliment\u00e9e par mettreAJourItem quand synchroniserDonnee('pays') est appel\u00e9).\r\n            \/\/   item.pays = pays publicitaire (R0, circuit r\u00e9servation) \u2192 ne pas l'utiliser ici.\r\n            if (item.paysAnnonceur) {\r\n                $('#form-field-Nationalite_Societe').val(item.paysAnnonceur);\r\n                try {\r\n                    if (typeof window.viaSetSelectedCountry === 'function') {\r\n                        window.viaSetSelectedCountry(item.paysAnnonceur);\r\n                    }\r\n                } catch(_eSC) {}\r\n            } else {\r\n                $('#form-field-Nationalite_Societe').val('');\r\n                try {\r\n                    if (typeof window.viaSetSelectedCountry === 'function') {\r\n                        window.viaSetSelectedCountry(null);\r\n                    }\r\n                } catch(_eSC2) {}\r\n            }\r\n            \/\/ \u2705 v4.9ds Pb 6 + Pb 7 : forcer la mise \u00e0 jour des couleurs des champs Dates\r\n            \/\/   (placeholder rouge si vide, valeur bleue si remplie). Le .val() par jQuery\r\n            \/\/   ne d\u00e9clenche pas d'event input\/change, donc nos listeners ne s'ex\u00e9cuteraient\r\n            \/\/   pas. On appelle directement le helper.\r\n            try {\r\n                if (typeof window._viaUpdateDatesColors === 'function') {\r\n                    window._viaUpdateDatesColors();\r\n                }\r\n            } catch(_eDC) {}\r\n            \r\n            \/\/ Tarif\r\n            if (item.tarifHT && window.VIA_App) {\r\n                const devise = item.devise || 'EUR';\r\n                \r\n                let montantAffiche = item.tarifHT;\r\n                \r\n                if (devise !== 'EUR') {\r\n                    montantAffiche = window.VIA_App.convertirDevise(item.tarifHT, 'EUR', devise);\r\n                }\r\n                \r\n                const tarifFormate = window.VIA_App.formaterMontant(montantAffiche, devise, 2);\r\n                \r\n                $('#Tariftobedisplayed')\r\n                    .html(tarifFormate)\r\n                    .css('color', '#4B689B');\r\n                \r\n                const $item = $(`#${item.id}`);\r\n                if ($item.length) {\r\n                    const labelTarif = lang === 'EN' ? 'Price excl. VAT' : 'Tarif H.T.';\r\n                    \/\/ pb2121 : resa active d'un commercial -> libelle seul.\r\n                    $item.find('.CampagneTarifClass')\r\n                        .html(window._viaLibelleTarif2121(item.id, `${labelTarif} ${tarifFormate}`));\r\n                    \r\n                    console.log('\u2705 Tarif campagne mis \u00e0 jour:', tarifFormate, devise);\r\n                }\r\n            } else {\r\n                $('#Tariftobedisplayed').html('-');\r\n                \r\n                const $item = $(`#${item.id}`);\r\n                if ($item.length) {\r\n                    const labelTarif = lang === 'EN' ? 'Price excl. VAT' : 'Tarif H.T.';\r\n                    $item.find('.CampagneTarifClass')\r\n                        .html(`${labelTarif} -`);\r\n                }\r\n            }\r\n            \r\n            this.mettreAJourCouleursTitres(item.id);\r\n            \r\n            \/\/ \u2705 v1.8 : Restaurer STATE dans VIA_Elementor pour que le calcul de tarif fonctionne\r\n            if (window.VIA_Elementor && window.VIA_Elementor.state) {\r\n                const state = window.VIA_Elementor.state;\r\n                \r\n                \/\/ Restaurer format et position\r\n                if (item.format) {\r\n                    state.format = item.format;\r\n                    console.log('\u2705 STATE.format restaur\u00e9:', item.format);\r\n                }\r\n                if (item.position) {\r\n                    state.position = item.position;\r\n                    console.log('\u2705 STATE.position restaur\u00e9:', item.position);\r\n                }\r\n                \r\n                \/\/ Restaurer emplacementPageWeb et espacePubSelected\r\n                if (item.emplacementPageWeb) {\r\n                    state.emplacementPageWeb = item.emplacementPageWeb;\r\n                    state.espacePubSelected = true;\r\n                    console.log('\u2705 STATE.emplacementPageWeb restaur\u00e9:', item.emplacementPageWeb);\r\n                }\r\n                \r\n                \/\/ Restaurer les dates dans STATE\r\n                if (item.dateDebut) {\r\n                    const parts = item.dateDebut.split('\/');\r\n                    if (parts.length === 3) {\r\n                        state.startDate = new Date(parts[2], parts[1] - 1, parts[0]);\r\n                    }\r\n                }\r\n                if (item.dateFin) {\r\n                    const parts = item.dateFin.split('\/');\r\n                    if (parts.length === 3) {\r\n                        state.endDate = new Date(parts[2], parts[1] - 1, parts[0]);\r\n                    }\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 v1.8 : Envoyer message \u00e0 l'iframe pour afficher la bordure du format\r\n            if (item.format) {\r\n                \/\/ pb45 : item VLP \u2192 ne pas envoyer SelectFormat \u00e0 yearbook-iframe\r\n                if (window._vlpSkipPageWeb45 === true) {\r\n                    console.log('[pb45] sendSelectFormat bloqu\u00e9 \u2014 item VLP actif');\r\n                } else {\r\n                const iframeId = sessionStorage.getItem(\"PageWebframeId\");\r\n                const iframe = $('#' + iframeId)[0];\r\n                \r\n                \/\/ Extraire le rankId depuis emplacementPageWeb (ex: \"MDG34871L1A\" \u2192 \"Ele1A\")\r\n                let rankId = null;\r\n                if (item.emplacementPageWeb) {\r\n                    const match = item.emplacementPageWeb.match(\/L(\\d+[A-Z]?)$\/);\r\n                    if (match) {\r\n                        rankId = 'Ele' + match[1];\r\n                    }\r\n                }\r\n                \r\n                if (iframe) {\r\n                    \/\/ \u2705 V\u00e9rifier contentWindow au moment de l'envoi (pas au moment du check)\r\n                    const sendSelectFormat = () => {\r\n                        if (!iframe || !iframe.contentWindow) {\r\n                            console.warn('\u26a0\ufe0f sendSelectFormat : contentWindow non disponible, skip');\r\n                            return;\r\n                        }\r\n                        iframe.contentWindow.postMessage({\r\n                            action: 'SelectFormat',\r\n                            iframeId: iframeId,\r\n                            format: item.format,\r\n                            rankId: rankId\r\n                        }, '*');\r\n                        console.log('\ud83d\udce8 Message SelectFormat envoy\u00e9 \u00e0 iframe:', item.format, 'rankId:', rankId);\r\n                    };\r\n                    \r\n                    \/\/ Envoyer apr\u00e8s 500ms puis \u00e0 nouveau apr\u00e8s 1500ms pour \u00eatre s\u00fbr\r\n                    setTimeout(sendSelectFormat, 500);\r\n                    setTimeout(sendSelectFormat, 1500);\r\n                }\r\n                } \/\/ fin else pb45\r\n            }\r\n            \r\n            console.log('\u2705 Formulaire rempli depuis item');\r\n        },\r\n        \r\n        \/**\r\n         * Charge les donn\u00e9es d'un item dans le formulaire\r\n         *\/\r\n        chargerDonneesItemDansFormulaire(itemId) {\r\n            const item = this.state.items.find(i => i.id === itemId);\r\n            \r\n            if (!item) {\r\n                console.warn('\u26a0\ufe0f Item introuvable pour chargement:', itemId);\r\n                return;\r\n            }\r\n            \r\n            console.log('\ud83d\udd04 Chargement donn\u00e9es item dans formulaire:', item);\r\n            \r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            const hasData = item.dateDebut || item.dateFin || item.pays;\r\n            \r\n            if (!hasData) {\r\n                console.log('\ud83d\udd04 Item sans donn\u00e9es, r\u00e9initialisation du formulaire');\r\n                this.reinitialiserFormulaire();\r\n                return;\r\n            }\r\n            \r\n            \/\/ Charger date d\u00e9but\r\n            if (item.dateDebut) {\r\n                $('#form-field-DebutCampagne').val(item.dateDebut);\r\n                \r\n                if (typeof $.fn.datepicker !== 'undefined') {\r\n                    try {\r\n                        const parts = item.dateDebut.split('\/');\r\n                        if (parts.length === 3) {\r\n                            const date = new Date(parts[2], parts[1] - 1, parts[0]);\r\n                            $('#form-field-DebutCampagne').datepicker('setDate', date);\r\n                            \r\n                            if (window.VIA_Elementor && window.VIA_Elementor.state) {\r\n                                window.VIA_Elementor.state.startDate = date;\r\n                            }\r\n                        }\r\n                    } catch(e) {\r\n                        console.warn('Erreur datepicker d\u00e9but:', e);\r\n                    }\r\n                }\r\n            } else {\r\n                $('#form-field-DebutCampagne').val('');\r\n                try {\r\n                    $('#form-field-DebutCampagne').datepicker('setDate', null);\r\n                } catch(e) {}\r\n            }\r\n            \r\n            \/\/ Charger date fin\r\n            if (item.dateFin) {\r\n                $('#form-field-FinCampagne').val(item.dateFin);\r\n                \r\n                if (typeof $.fn.datepicker !== 'undefined') {\r\n                    try {\r\n                        const parts = item.dateFin.split('\/');\r\n                        if (parts.length === 3) {\r\n                            const date = new Date(parts[2], parts[1] - 1, parts[0]);\r\n                            $('#form-field-FinCampagne').datepicker('setDate', date);\r\n                            \r\n                            if (window.VIA_Elementor && window.VIA_Elementor.state) {\r\n                                window.VIA_Elementor.state.endDate = date;\r\n                            }\r\n                        }\r\n                    } catch(e) {\r\n                        console.warn('Erreur datepicker fin:', e);\r\n                    }\r\n                }\r\n            } else {\r\n                $('#form-field-FinCampagne').val('');\r\n                try {\r\n                    $('#form-field-FinCampagne').datepicker('setDate', null);\r\n                } catch(e) {}\r\n            }\r\n            \r\n            \/\/ \u2705 v2.5 : Ne pas pr\u00e9-remplir le pays\r\n            $('#form-field-Nationalite_Societe').val('');\r\n            if (window.VIA_Elementor && window.VIA_Elementor.state) {\r\n                window.VIA_Elementor.state.selectedCountry = null;\r\n            }\r\n            \r\n            \/\/ Afficher dur\u00e9e\r\n            if (item.duree) {\r\n                const dureeText = lang === 'EN'\r\n                    ? (item.duree === 1 ? '1 day' : `${item.duree} days`)\r\n                    : (item.duree === 1 ? '1 jour' : `${item.duree} jours`);\r\n                $('.CampagneNbJours').text(dureeText);\r\n            } else {\r\n                $('.CampagneNbJours').text('');\r\n            }\r\n            \r\n            console.log('\u2705 Donn\u00e9es charg\u00e9es dans formulaire');\r\n            \r\n            \/\/ \u2705 v1.7 : Recalcul via API si donn\u00e9es compl\u00e8tes (incluant emplacementPageWeb)\r\n            \/\/ pb1513c : item.format teste par le helper \u2014 la sentinelle 'a choisir' ne\r\n            \/\/   doit pas declencher le recalcul de tarif (format inconnu du tarif API).\r\n            if (item.dateDebut && item.dateFin && item.pays && _viaFormatValide1513(item.format) && item.position && item.duree && item.emplacementPageWeb) {\r\n                console.log('\ud83d\udd04 Toutes les donn\u00e9es pr\u00e9sentes (incluant espace pub), recalcul du tarif via API...');\r\n                \r\n                setTimeout(async () => {\r\n                    if (window.VIA_App && window.VIA_Countries) {\r\n                        const country = window.VIA_Countries.getCountryByLabel(item.pays);\r\n                        \r\n                        if (country) {\r\n                            const resultat = await window.VIA_App.calculerTarifAPI(\r\n                                item.format,\r\n                                item.position,\r\n                                item.duree,\r\n                                country.code\r\n                            );\r\n                            \r\n                            if (resultat.success) {\r\n                                console.log('\u2705 Tarif recalcul\u00e9 via API:', resultat.tarif_ht, 'EUR');\r\n                                \r\n                                \/\/ \u2705 v2.7 : Attacher l'itemId au r\u00e9sultat \u2014 \u00e9vite d'appliquer\r\n                                \/\/ le tarif d'un item \u00e0 un autre (multi-achat, pb 6)\r\n                                window.VIA_App.state.dernierResultatCalcul = Object.assign({}, resultat, { itemId: item.id });\r\n                                \r\n                                const devise = window.VIA_Panier.state.deviseAffichage || 'EUR';\r\n                                const montantConverti = devise === 'EUR' ? \r\n                                    resultat.tarif_ht : \r\n                                    window.VIA_App.convertirDevise(resultat.tarif_ht, 'EUR', devise);\r\n                                \r\n                                const tarifFormate = window.VIA_App.formaterMontant(montantConverti, devise, 2);\r\n                                \r\n                                $('#Tariftobedisplayed')\r\n                                    .html(tarifFormate)\r\n                                    .css('color', '#4B689B');\r\n                            }\r\n                        } else {\r\n                            console.warn('\u26a0\ufe0f Pays introuvable:', item.pays);\r\n                        }\r\n                    }\r\n                }, 100);\r\n            } else {\r\n                \/\/ \u2705 Si donn\u00e9es incompl\u00e8tes, r\u00e9initialiser l'affichage du tarif\r\n                $('#Tariftobedisplayed').html('-');\r\n                \r\n                \/\/ \u2705 R\u00e9initialiser aussi le dernier r\u00e9sultat de calcul pour \u00e9viter les confusions\r\n                if (window.VIA_App && window.VIA_App.state) {\r\n                    window.VIA_App.state.dernierResultatCalcul = null;\r\n                }\r\n                \r\n                console.log('\ud83d\udd04 Tarif r\u00e9initialis\u00e9 (donn\u00e9es incompl\u00e8tes)');\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * R\u00e9initialise compl\u00e8tement le formulaire Etape1Container\r\n         *\/\r\n        reinitialiserFormulaire() {\r\n            console.log('\ud83d\udd04 R\u00e9initialisation compl\u00e8te du formulaire');\r\n            \r\n            \/\/ Vider les champs\r\n            $('#form-field-DebutCampagne').val('');\r\n            $('#form-field-FinCampagne').val('');\r\n            $('#form-field-Nationalite_Societe').val('');\r\n            $('.CampagneNbJours').text('');\r\n            \r\n            \/\/ R\u00e9initialiser les datepickers\r\n            if (typeof $.fn.datepicker !== 'undefined') {\r\n                try {\r\n                    $('#form-field-DebutCampagne').datepicker('setDate', null);\r\n                    $('#form-field-FinCampagne').datepicker('setDate', null);\r\n                } catch(e) {\r\n                    console.warn('Erreur r\u00e9initialisation datepickers:', e);\r\n                }\r\n            }\r\n            \r\n            \/\/ R\u00e9initialiser l'\u00e9tat de VIA_Elementor\r\n            if (window.VIA_Elementor && window.VIA_Elementor.state) {\r\n                window.VIA_Elementor.state.selectedCountry = null;\r\n                window.VIA_Elementor.state.startDate = null;\r\n                window.VIA_Elementor.state.endDate = null;\r\n            }\r\n            \r\n            \/\/ Vider l'affichage du tarif\r\n            const $tarifDisplay = $('#Tariftobedisplayed');\r\n            if ($tarifDisplay.length > 0) {\r\n                $tarifDisplay.html('');\r\n            }\r\n            \r\n            console.log('\u2705 Formulaire r\u00e9initialis\u00e9');\r\n        },\r\n        \r\n        \/**\r\n         * MODIFICATION de mettreAJourItem pour utiliser remplirItemComplet\r\n         *\/\r\n        \/* pb1517 : PROMOTION d'un espace en attente en RESERVATION.\r\n           Appelee apres chaque ecriture sur un item. Ne fait rien tant que les cinq\r\n           donnees ne sont pas reunies ; des qu'elles le sont, l'item cesse d'etre en\r\n           attente et sa carte rejoint \u00ab Vos reservations \u00bb.\r\n           La carte n'est pas reconstruite : pb1516 l'a gardee de cote dans\r\n           _vueEnAttente1516. Repli sur remplirItemComplet si elle a disparu.\r\n           Revert : window._viaPb1517Off = true. *\/\r\n        \/* pb1525 : passe en revue tous les espaces en attente. Voir le commentaire au\r\n           point d'appel : l'ecriture sur un item peut completer un autre. *\/\r\n        _promouvoirTousSiComplet1525() {\r\n            var _self = this;\r\n            var _ids = (this.state.items || [])\r\n                \/\/ pb1526d : inclure les items qui ont quitte 'attente' sans passer par la\r\n                \/\/   promotion mais dont la carte est encore en main \u2014 sinon le rattrapage\r\n                \/\/   ci-dessus ne serait jamais atteint par le balayage.\r\n                .filter(function (i) { return (i.statut === 'attente') ? true : !!i._vueEnAttente1516; })\r\n                .map(function (i) { return i.id; });\r\n            var _n = 0;\r\n            _ids.forEach(function (_id) {\r\n                if (_self._promouvoirSiComplet1517(_id)) { _n++; }\r\n            });\r\n            return _n;\r\n        },\r\n\r\n        \/* pb1526 : SEUL ECRIVAIN de l'insertion d'une carte gardee en attente.\r\n           Idempotent : ne fait rien si la carte est deja dans le DOM. Consomme\r\n           _vueEnAttente1516 pour qu'un second passage n'insere pas de doublon. *\/\r\n        \/* pb1529 : l'item porte-t-il un tarif exploitable ? updateRecapitulatif masque\r\n           toute carte qui n'en a pas ; on ne l'appelle donc qu'a bon escient. *\/\r\n        _tarifPose1529(_it) {\r\n            if (!_it) { return false; }\r\n            if (!_it.tarifHT) { return false; }\r\n            return (_it.tarifHT > 0);\r\n        },\r\n\r\n        _insererCarteEnAttente1526(_it) {\r\n            if (!_it) { return false; }\r\n            var $vue = _it._vueEnAttente1516 || null;\r\n            delete _it._vueEnAttente1516;\r\n            try {\r\n                if ($('#' + _it.id).length > 0) { return false; }\r\n                var $cont = $(this.config.conteneurParent).first();\r\n                if (!$cont.length) { console.warn('[pb1526] conteneur parent introuvable'); return false; }\r\n                if (!$vue) { console.warn('[pb1526] vue en attente perdue | ' + _it.id); return false; }\r\n                $cont.append($vue);\r\n                console.log('[pb1526] carte inseree | ' + (_it.emplacementPageWeb || _it.reference || _it.id));\r\n                \/\/ pb1528 : TRACEUR \u2014 la carte est inseree (log ci-dessus) mais reste\r\n                \/\/   invisible a l'ecran. Trois hypotheses ont ete avancees sans preuve ;\r\n                \/\/   on mesure au lieu de supposer. On releve l'etat REEL de la carte juste\r\n                \/\/   apres l'insertion, puis a T+400ms pour attraper un masquage differe.\r\n                \/\/   A retirer une fois la cause identifiee.\r\n                var _etat1528 = function (_quand) {\r\n                    try {\r\n                        var _n = document.getElementById(_it.id);\r\n                        if (!_n) { console.log('[pb1528] ' + _quand + ' | carte ABSENTE du DOM'); return; }\r\n                        var _cs = getComputedStyle(_n);\r\n                        var _ref = _n.getAttribute('data-reference');\r\n                        var _its = (window.VIA_Panier ? (window.VIA_Panier.state.items || []) : []);\r\n                        var _match = _its.filter(function (i) { return i.reference === _ref; })[0] || null;\r\n                        var _par = _n.parentElement;\r\n                        console.log('[pb1528] ' + _quand\r\n                            + ' | display=' + _cs.display + ' visibility=' + _cs.visibility + ' opacity=' + _cs.opacity\r\n                            + ' | h=' + Math.round(_n.getBoundingClientRect().height)\r\n                            + ' | data-reference=' + _ref\r\n                            + ' | item.reference=' + _it.reference\r\n                            + ' | trouve par ref=' + (_match ? 'OUI' : 'NON')\r\n                            + ' | tarifHT=' + _it.tarifHT\r\n                            + ' | statut=' + _it.statut\r\n                            + ' | parent=' + (_par ? (_par.id || _par.className || '?') : 'AUCUN')\r\n                            + ' | parent display=' + (_par ? getComputedStyle(_par).display : '-'));\r\n                    } catch (_e) { console.warn('[pb1528] ' + _quand + ' : ' + _e.message); }\r\n                };\r\n                _etat1528('T+0');\r\n                setTimeout(function () { _etat1528('T+400ms'); }, 400);\r\n                return true;\r\n            } catch (_e1526) { console.warn('[pb1526] insertion carte : ' + _e1526.message); return false; }\r\n        },\r\n\r\n        _promouvoirSiComplet1517(itemId) {\r\n            \/\/ pb1523 : CHAQUE SORTIE JOURNALISE. Cette fonction avait quatre retours muets :\r\n            \/\/   verrou, item introuvable, statut different d'attente, cinq donnees\r\n            \/\/   incompletes. Resultat : console filtree sur pb1517, AUCUNE ligne, et donc\r\n            \/\/   aucun moyen de distinguer \u00ab jamais appelee \u00bb de \u00ab appelee et ajournee \u00bb.\r\n            \/\/   C'est la regle que je m'etais donnee et que je n'ai pas appliquee : une\r\n            \/\/   sortie silencieuse coute un aller-retour de diagnostic.\r\n            \/\/   Journalisation dedupee par signature (verdict + detail) : la veille tourne\r\n            \/\/   a chaque ecriture d'item, on ne veut pas inonder la console \u2014 seuls les\r\n            \/\/   CHANGEMENTS d'etat sortent.\r\n            var _sig1523 = function (_it0, _verdict, _detail) {\r\n                var _s = _verdict + '|' + (_detail || '');\r\n                if (_it0) {\r\n                    if (_it0._sigPb1523 === _s) { return; }\r\n                    _it0._sigPb1523 = _s;\r\n                }\r\n                console.log('[pb1523] promotion ' + _verdict + ' | ' + (itemId || '?')\r\n                    + (_detail ? ' | ' + _detail : ''));\r\n            };\r\n            if (window._viaPb1517Off === true) { console.log('[pb1523] promotion DESACTIVEE (verrou pb1517)'); return false; }\r\n            var _it = (this.state.items || []).find(function (i) { return i.id === itemId; });\r\n            if (!_it) { _sig1523(null, 'ABANDON', 'item introuvable'); return false; }\r\n            if (_it.statut !== 'attente') {\r\n                \/\/ pb1526 : RATTRAPAGE. Le statut a QUATRE autres ecrivains que ma promotion :\r\n                \/\/   synchroniserAvecEtape1 pose 'valide' des qu'un tarif revient (l.10151,\r\n                \/\/   via Object.assign), l.4172 et l.8587 font de meme, et\r\n                \/\/   completerCommandePartielle pose 'en_cours'. Un item pouvait donc quitter\r\n                \/\/   'attente' SANS passer par ici \u2014 et sa carte, gardee dans\r\n                \/\/   _vueEnAttente1516, n'etait jamais inseree.\r\n                \/\/   C'est exactement la capture a 707,00 EUR : tarif calcule, bouton\r\n                \/\/   \"Cliquer ici pour finaliser\" affiche, statut passe a 'valide' par\r\n                \/\/   l.10151, et aucune carte a l'ecran.\r\n                \/\/   L'insertion ne peut donc pas dependre de MON chemin : elle doit dependre\r\n                \/\/   de l'INVARIANT \u00ab une vue en attente sur un item qui n'attend plus doit\r\n                \/\/   etre a l'ecran \u00bb. On la rattrape ici, quel que soit l'ecrivain.\r\n                if (_it._vueEnAttente1516) {\r\n                    this._insererCarteEnAttente1526(_it);\r\n                    _sig1523(_it, 'RATTRAPAGE', 'statut passe a ' + _it.statut + ' par un autre ecrivain \u2014 carte inseree');\r\n                    if (typeof this.calculerTotalPanier === 'function') { this.calculerTotalPanier(); }\r\n                    \/\/ pb1529 : NE PAS APPELER L'ARBITRE AVANT QU'IL PUISSE TRANCHER.\r\n                    \/\/   updateRecapitulatif masque toute carte dont l'item n'a pas encore de\r\n                    \/\/   tarifHT. Le rattrapage survient AVANT le calcul du tarif (c'est\r\n                    \/\/   completerCommandePartielle qui l'a declenche) : l'appeler ici, c'est\r\n                    \/\/   masquer la carte qu'on vient d'inserer. Et rien ne le rappelait\r\n                    \/\/   ensuite \u2014 mettreAJourItem ne fait que rafraichirItemHTML et\r\n                    \/\/   calculerTotalPanier. D'ou la carte constatee dans le DOM, complete\r\n                    \/\/   (Annonceur, Site, Homepage, Position, Format, Ref, Tarif 1 516,00 EUR)\r\n                    \/\/   et pourtant en display:none.\r\n                    \/\/   C'est pb1529b qui rappellera l'arbitre quand le tarif arrivera.\r\n                    if (this._tarifPose1529(_it) ? (typeof this.updateRecapitulatif === 'function') : false) {\r\n                        this.updateRecapitulatif();\r\n                    }\r\n                    return true;\r\n                }\r\n                _sig1523(_it, 'SANS OBJET', 'statut=' + _it.statut);\r\n                return false;\r\n            }\r\n            var _c = this._cinqDonnees1515(_it);\r\n            if (!_c.ok) { _sig1523(_it, 'AJOURNEE', 'manque : ' + _c.manquantes.join(', ')); return false; }\r\n            _sig1523(_it, 'DECLENCHEE', 'cinq donnees reunies');\r\n            _it.statut = _it.emplacementPageWeb ? 'en_cours' : 'partielle';\r\n            \/\/ pb1526b : une seule fonction insere la carte, quel que soit le chemin.\r\n            this._insererCarteEnAttente1526(_it);\r\n            console.log('[pb1517] espace en attente PROMU en reservation | '\r\n                + (_it.emplacementPageWeb || _it.reference) + ' | statut -> ' + _it.statut);\r\n            if (typeof this.calculerTotalPanier === 'function') { this.calculerTotalPanier(); }\r\n            \/\/ pb1529a : meme regle sur le chemin de promotion normal.\r\n            if (this._tarifPose1529(_it) ? (typeof this.updateRecapitulatif === 'function') : false) {\r\n                this.updateRecapitulatif();\r\n            }\r\n            return true;\r\n        },\r\n\r\n        mettreAJourItem(itemId, donnees, autoRefresh = true) {\r\n            const item = this.state.items.find(i => i.id === itemId);\r\n            if (!item) {\r\n                console.warn('\u26a0\ufe0f Item introuvable:', itemId);\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 D\u00e9tecter si le tarif est dans les donn\u00e9es (nouveau ou modifi\u00e9)\r\n            const tarifDansLesData = donnees.tarifHT !== undefined;\r\n            console.log('\ud83d\udd27 [mettreAJourItem] itemId:', itemId, '| tarifHT dans donn\u00e9es:', donnees.tarifHT, '| statut dans donn\u00e9es:', donnees.statut);\r\n            \r\n            Object.assign(item, donnees);\r\n            \/\/ \u2705 paysAnnonceur : s\u00e9paration pays publicitaire (item.pays, pos\u00e9 par R0 depuis\r\n            \/\/   ContinentPaysTitre) et nationalit\u00e9 soci\u00e9t\u00e9 (saisie utilisateur).\r\n            \/\/   synchroniserDonnee('pays', val) passe par mettreAJourItem \u2192 on en profite\r\n            \/\/   pour alimenter paysAnnonceur. R0 bypasse mettreAJourItem \u2192 pas de collision.\r\n            if (donnees.pays !== undefined) {\r\n                item.paysAnnonceur = donnees.pays;\r\n            }\r\n            \/\/ pb1517b : toute ecriture sur un item est une occasion de completion.\r\n            \/\/   mettreAJourItem est la voie par laquelle passent les dates, le pays\r\n            \/\/   annonceur et la duree (synchroniserEtape1 et syncVersResa651 l'appellent\r\n            \/\/   toutes deux) : c'est le point de veille naturel, sans minuterie ni\r\n            \/\/   observateur. Le format, lui, s'ecrit ailleurs \u2014 le clic vignette appelle\r\n            \/\/   la promotion directement (pb1517c, yearbook-media.js).\r\n            \/\/ pb1525 : BALAYER TOUS LES ESPACES EN ATTENTE, pas seulement celui qu'on ecrit.\r\n            \/\/   pb1517b n'evaluait que l'item passe a mettreAJourItem. Or l'item qui recoit\r\n            \/\/   l'ecriture n'est pas forcement celui qui devient complet : plusieurs espaces\r\n            \/\/   en attente coexistent (le log en montrait trois), et le pays annonceur est\r\n            \/\/   commun a toutes les resas \u2014 le renseigner peut completer un AUTRE espace.\r\n            \/\/   Chaque item est evalue sur SES propres donnees, le balayage est donc sur.\r\n            try { this._promouvoirTousSiComplet1525(); } catch (_e1517) { console.warn('[pb1517]', _e1517.message); }\r\n            console.log('\ud83d\udd27 [mettreAJourItem] item APR\u00c8S assign | tarifHT:', item.tarifHT, '| statut:', item.statut);\r\n            \r\n            if (autoRefresh) {\r\n                this.rafraichirItemHTML(itemId);\r\n            }\r\n            \r\n            if (this.state.itemActif === itemId) {\r\n                this.mettreAJourCouleursTitres(itemId);\r\n                \/\/ \u2705 v2.4.3 : Blanc ins\u00e9cable si pas de tarif (conserve la hauteur), texte original sinon\r\n                var $_e1msg = $('#Etape1MessageTexte');\r\n                if ($_e1msg.length) {\r\n                    if (!$_e1msg.data('orig')) { $_e1msg.data('orig', $_e1msg.html()); }\r\n                    if (!item.tarifHT) {\r\n                        $_e1msg.html('&nbsp;');\r\n                    } else {\r\n                        $_e1msg.html($_e1msg.data('orig'));\r\n                    }\r\n                }\r\n                \/\/ \u2705 v2.4.3 : Masquer le message accompagnement si tarif obtenu\r\n                if (item.tarifHT) {\r\n                    var _tplSel = (this.config && this.config.templateItem) ? this.config.templateItem : '.CampagneTemplateClass';\r\n                    var $itemEl = $(_tplSel + '[data-item-id=\"' + itemId + '\"]');\r\n                    if (!$itemEl.length) { $itemEl = $(_tplSel).filter(function() { return $(this).data('itemId') === itemId || $(this).attr('id') === itemId; }); }\r\n                    $itemEl.find('.CampagneMsgAccompagnement').hide();\r\n                }\r\n            }\r\n            \r\n            this.calculerTotalPanier();\r\n            \/\/ pb1529b : REJOUER L'ARBITRAGE QUAND SON CRITERE CHANGE. updateRecapitulatif\r\n            \/\/   decide de montrer ou masquer chaque carte sur le seul critere tarifHT > 0.\r\n            \/\/   Or mettreAJourItem \u2014 la voie par laquelle le tarif ARRIVE \u2014 ne le rappelait\r\n            \/\/   jamais : il ne fait que rafraichirItemHTML et calculerTotalPanier. Une carte\r\n            \/\/   masquee faute de tarif restait donc masquee pour toujours, meme une fois le\r\n            \/\/   tarif pose. On rejoue l'arbitrage a l'instant precis ou le critere change.\r\n            \/\/   Revert : window._viaPb1529Off = true.\r\n            if (window._viaPb1529Off !== true ? tarifDansLesData : false) {\r\n                if (typeof this.updateRecapitulatif === 'function') {\r\n                    console.log('[pb1529] tarif recu (' + donnees.tarifHT + ') -> reevaluation de l\\'affichage des cartes');\r\n                    this.updateRecapitulatif();\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 Si les donn\u00e9es contiennent un tarif, mettre \u00e0 jour imm\u00e9diatement l'\u00e9tape Mode de paiement\r\n            if (tarifDansLesData && window.VIA_Paiement && typeof window.VIA_Paiement.rafraichirMontants === 'function') {\r\n                console.log('\ud83d\udcb0 Tarif dans les donn\u00e9es, rafra\u00eechissement de l\\'\u00e9tape paiement');\r\n                window.VIA_Paiement.rafraichirMontants();\r\n            }\r\n            \/\/ pb651d : DIRECTION A LIVE \u2014 item actif modifie + popup Tarifs ouvert -> repousser.\r\n            try {\r\n                var _popup651 = document.getElementById('popup3');\r\n                var _ouvert651 = _popup651 ? _popup651.classList.contains('active') : false;\r\n                var _clicA651 = (typeof window !== 'undefined') ? window._sync651AClic : false;\r\n                \/\/ pb783 : meme principe que pb781, applique au sens INVERSE. Le verrou\r\n                \/\/   _sync651AClic (500 ms poses par le clic tarif de la synchro A) ecartait\r\n                \/\/   aussi les GESTES UTILISATEUR faits dans le process \u2014 changer le pays de\r\n                \/\/   l'annonceur juste apres un clic tarif ne remontait donc jamais au popup\r\n                \/\/   (log : \"Pays change dans Etape 1: Guyana\" sans aucun [pb651d]).\r\n                \/\/   Un geste physique n'est pas un echo : event.isTrusted le distingue.\r\n                \/\/   Revert : window._viaPb783Off = true.\r\n                if (_clicA651 ? (window._viaPb783Off !== true) : false) {\r\n                    var _evt783 = null;\r\n                    try { _evt783 = (typeof event !== 'undefined') ? event : null; } catch (_e783a) { _evt783 = null; }\r\n                    if (_evt783 ? _evt783.isTrusted === true : false) {\r\n                        console.log('[pb783] verrou sync651AClic outrepasse \u2014 modification UTILISATEUR dans le process (isTrusted)');\r\n                        _clicA651 = false;\r\n                    }\r\n                }\r\n                \/\/ pb783 : le process vient d'ecrire le pays de l'ANNONCEUR -> l'horodater\r\n                \/\/   cote resa, sinon _popupGagne749('annonceur') donnerait raison au popup\r\n                \/\/   et le sens A refuserait poliment d'ecraser le champ (pb749\/pb751).\r\n                \/\/   C'est l'ordre qui compte, comme en pb750.\r\n                if (window._viaPb783Off !== true) {\r\n                    try {\r\n                        var _ann783 = donnees ? donnees.paysAnnonceur : undefined;\r\n                        if (_ann783 !== undefined) {\r\n                            window._viaTs749 = window._viaTs749 || {};\r\n                            window._viaTs749.annonceur = { ts: Date.now(), src: 'resa' };\r\n                            console.log('[pb783] horodate annonceur <- resa (\"' + _ann783 + '\")');\r\n                        }\r\n                    } catch (_e783b) { console.warn('[pb783]', _e783b.message); }\r\n                }\r\n                if (_ouvert651 ? (itemId === this.state.itemActif ? !_clicA651 : false) : false) {\r\n                    if (typeof window.viaSyncVersPopupTarifs651 === 'function') {\r\n                        var _it651 = this.state.items ? this.state.items.find(function(x) { return x.id === itemId; }) : null;\r\n                        if (_it651 ? !this._syncAAutorisee666(_it651) : false) {\r\n                            console.log('[pb666] resa incomplete (statut ' + _it651.statut + ') -> sync A ignoree');\r\n                        }\r\n                        if (this._syncAAutorisee666(_it651)) {\r\n                            window.clearTimeout(window._pb651dTimer);\r\n                                var _itRef651 = _it651;\r\n                                window._pb651dTimer = window.setTimeout(function() {\r\n                                    console.log('[pb651d] item actif modifie + popup ouvert -> sync A live (debounce)');\r\n                                    if (typeof window.viaSyncVersPopupTarifs651 === 'function') {\r\n                                        window.viaSyncVersPopupTarifs651(_itRef651);\r\n                                    }\r\n                                }, 300);\r\n                        }\r\n                    }\r\n                }\r\n            } catch (e651d) { console.warn('[pb651d]', e651d.message); }\r\n        },\r\n\r\n        \/**\r\n         * pb666 : la synchro A (resa -> popup Tarifs) ne doit piloter le popup que\r\n         *   depuis une resa dans un etat COHERENT. Sur un item incomplet (resa\r\n         *   \"anticipee\", dates partielles, pays absent) le popup RESTAIT sur l'etat\r\n         *   de la resa precedente ; pb651o re-selectionnait alors ce tarif et pb651m\r\n         *   le poussait dans l'item courant -> la resa 2 heritait du tarif de la\r\n         *   resa 1 (mesure : 441 EUR recopie des la saisie de la date de debut).\r\n         *\/\r\n        _syncAAutorisee666(_it666) {\r\n            if (!_it666) { return false; }\r\n            if (_it666.statut === 'anticipee') { return false; }\r\n            if (!_it666.dateDebut) { return false; }\r\n            if (!_it666.dateFin) { return false; }\r\n            var _p666 = _it666.pays ? _it666.pays : _it666.paysAnnonceur;\r\n            if (!_p666) { return false; }\r\n            return true;\r\n        },\r\n\r\n        \/**\r\n         * pb667 : pays du SITE (jamais celui de l'annonceur). item.pays porte la\r\n         *   nationalite de l'ANNONCEUR des que la resa est completee (popup Tarifs \/\r\n         *   Etape 1) : s'en servir faisait basculer le bandeau pays et le SousTitre\r\n         *   \"Communication associee au site X\" du site pays (ex. Cameroun) vers\r\n         *   France. Le sous-domaine identifie le site sans ambiguite.\r\n         *   Retourne null si l'URL manque -> l'appelant retombe sur item.pays.\r\n         *\/\r\n        \/* pb1515 : LES 5 DONNEES D'UNE RESERVATION \u2014 une seule definition.\r\n           Ouvrir le popup du process d'achat ne cree plus une reservation : il cree un\r\n           ESPACE EN ATTENTE (statut 'attente'), qui porte deja ce qu'on sait (site pays,\r\n           secteur, format deduit) et attend ce que l'utilisateur doit fournir. La\r\n           reservation nait quand les cinq donnees sont reunies, comme dans le process\r\n           classique de la regie.\r\n           Quatre des cinq sont PROPRES a chaque espace ; seul l'annonceur est commun a\r\n           toutes les resas (mettreAJourPaysGlobal + heritage pb669).\r\n           Retourne { ok, manquantes } \u2014 'manquantes' sert au log et au futur affichage.\r\n           Revert : window._viaPb1515Off = true -> plus aucun espace en attente. *\/\r\n        _cinqDonnees1515(_it) {\r\n            var _manque = [];\r\n            if (!_it) { return { ok: false, manquantes: ['item'] }; }\r\n            \/\/ 1. annonceur (commun a toutes les resas)\r\n            if (!(_it.paysAnnonceur || _it.pays)) { _manque.push('annonceur'); }\r\n            \/\/ 2. pays du SITE \u2014 deduit de l'URL de la page, connu des la reservation\r\n            if (!this._paysSite667(_it)) { _manque.push('pays'); }\r\n            \/\/ 3. secteur ou page ; la Homepage compte (l'etape est verte sur la capture)\r\n            \/\/ pb1524 : LA HOMEPAGE VAUT UN SECTEUR \u2014 je n'interrogeais qu'une famille de cles.\r\n            \/\/   Une Homepage n'a PAS de secteur nomme : selectedPageSecteur reste null et\r\n            \/\/   selectedPageSecteurDisplayed vide (constate dans le log : selectedPageType\r\n            \/\/   'HPType', commandePage 'Homepage', selectedPageSecteur null,\r\n            \/\/   selectedPageSecteurDisplayed ''). Mon critere declarait donc \u00ab manque\r\n            \/\/   secteur \u00bb pour toute reservation sur Homepage, et la promotion n'arrivait\r\n            \/\/   jamais \u2014 alors que les cinq etapes etaient vertes a l'ecran.\r\n            \/\/   C'est le meme angle mort que la garde pb857 a paye CINQ fois : pb792\/pb843\r\n            \/\/   (l'article), pb911 (la homepage), pb858 (la creation de format), pb963 (le\r\n            \/\/   format pop-up). A chaque fois : une seule cle interrogee, un parcours\r\n            \/\/   legitime exclu. On lit la cle LOGIQUE (selectedPageType \/ commandePage),\r\n            \/\/   pas l'affichage \u2014 lecon pb734.\r\n            \/\/   Revert : window._viaPb1524Off = true.\r\n            var _sect1524 = _it.selectedPageSecteurDisplayed || _it.selectedPageSecteur || _it.articleTitre || '';\r\n            if (!_sect1524 ? (window._viaPb1524Off !== true) : false) {\r\n                if (_it.selectedPageType === 'HPType') { _sect1524 = '(homepage)'; }\r\n                else if (String(_it.commandePage || '').toLowerCase() === 'homepage') { _sect1524 = '(homepage)'; }\r\n                else if (_it.selectedPageType === 'ArtType') { _sect1524 = '(article)'; }\r\n            }\r\n            if (!_sect1524) { _manque.push('secteur'); }\r\n            \/\/ 4. format \u2014 la sentinelle 'a choisir' ne vaut pas un format (pb1513)\r\n            var _fmtOk = (typeof _viaFormatValide1513 === 'function') ? _viaFormatValide1513(_it.format) : !!_it.format;\r\n            if (!_fmtOk) { _manque.push('format'); }\r\n            \/\/ 5. dates\r\n            if (!_it.dateDebut) { _manque.push('dates'); }\r\n            else { if (!_it.dateFin) { _manque.push('dates'); } }\r\n            return { ok: _manque.length === 0, manquantes: _manque };\r\n        },\r\n\r\n        _paysSite667(_it667) {\r\n            if (!_it667) { return null; }\r\n            var _u667 = _it667.linkSecteurPage || '';\r\n            if (!_u667) { if (_it667.donneesIframe) { _u667 = _it667.donneesIframe.LoadedPageUrl || ''; } }\r\n            var _m667 = _u667.match(\/https?:\\\/\\\/([^.]+)\\.yearbook-media\\.com\/);\r\n            if (!_m667) { return null; }\r\n            if (!_m667[1]) { return null; }\r\n            \/\/ \"cameroun-en\" -> \"Cameroun\" (suffixe de langue, pas un nom de pays)\r\n            var _s667 = _m667[1].replace(\/-en$\/, '');\r\n            var _p667 = _s667.charAt(0).toUpperCase() + _s667.slice(1);\r\n            console.log('[pb667] pays SITE = ' + _p667 + ' | url = ' + _u667 + ' | item.pays (annonceur) = ' + _it667.pays);\r\n            return _p667;\r\n        },\r\n\r\n        \/**\r\n         * pb669 : pays de l'ANNONCEUR deja saisi sur une resa existante. Il est commun\r\n         *   a toutes les resas -> une nouvelle resa en herite au lieu de naitre vide.\r\n         *   Lit paysAnnonceur en priorite (champ affiche\/relu par le formulaire),\r\n         *   avec repli sur pays. Retourne null si aucune resa n'en porte encore.\r\n         *\/\r\n        _paysAnnonceurCommun669() {\r\n            try {\r\n                var _its669 = (this.state ? this.state.items : null) || [];\r\n                for (var _i669 = 0; _i669 < _its669.length; _i669++) {\r\n                    \/\/ ========================================================\r\n                    \/\/ pb1015 : NE PLUS REPLIER SUR item.pays.\r\n                    \/\/   Constat user : au clic sur AutreCommandeBouton, le pays\r\n                    \/\/   de la societe annonceur \u2014 laisse VIDE par l'utilisateur \u2014\r\n                    \/\/   arrivait renseigne a \"Gabon\" sur la nouvelle resa, soit\r\n                    \/\/   le pays du SITE de la resa 1.\r\n                    \/\/   Cause : le repli 'paysAnnonceur sinon pays'. Or item.pays\r\n                    \/\/   n'est PAS toujours le pays de l'annonceur : selon le\r\n                    \/\/   chemin de creation il porte le pays du site (cf pb667,\r\n                    \/\/   qui distingue explicitement les deux). Heriter de ce\r\n                    \/\/   champ revient a inventer une saisie annonceur que\r\n                    \/\/   l'utilisateur n'a jamais faite.\r\n                    \/\/   Seul paysAnnonceur est fiable : c'est le champ ecrit par\r\n                    \/\/   le formulaire annonceur. Aucune resa ne le porte ->\r\n                    \/\/   la nouvelle resa nait vide, ce qui est le comportement\r\n                    \/\/   attendu.\r\n                    \/\/   Revert : window._viaPb1015Off = true.\r\n                    \/\/ ========================================================\r\n                    var _c669;\r\n                    if (window._viaPb1015Off === true) {\r\n                        _c669 = _its669[_i669].paysAnnonceur ? _its669[_i669].paysAnnonceur : _its669[_i669].pays;\r\n                    } else {\r\n                        _c669 = _its669[_i669].paysAnnonceur || '';\r\n                    }\r\n                    if (_c669) {\r\n                        console.log('[pb1692] annonceur herite d une resa existante : ' + _c669);\r\n                        return _c669;\r\n                    }\r\n                }\r\n            } catch (_e669) { console.warn('[pb669]', _e669.message); }\r\n            \/* ============================================================\r\n             * pb1692 : REPLI SUR LA MEMOIRE DE CAMPAGNE (pb926).\r\n             *   Demande user : l annonceur doit se reporter sur la nouvelle\r\n             *   reservation, comme sur la regie.\r\n             *   pb669 le fait deja \u2014 mais seulement si une resa EXISTANTE porte\r\n             *   paysAnnonceur. Sur un site pays, pb1561\/pb1570 interdisent de\r\n             *   relire le champ ecran : si la premiere resa n a jamais recu\r\n             *   paysAnnonceur, la chaine est vide et personne n a rien a leguer.\r\n             *   On ne touche pas a cet interdit \u2014 le relire ici recreerait\r\n             *   exactement le report accidentel que pb1561 avait ferme.\r\n             *   On se replie sur viaCampagne926, ecrite a chaque saisie reelle\r\n             *   de l utilisateur et deja employee par pb1205 pour ce meme motif :\r\n             *   elle survit aux instants ou l item et les champs sont en\r\n             *   transition. C est une source, pas l ecran.\r\n             *   Un seul endroit decide de l heritage : les deux creations d item\r\n             *   (l.2259 et l.3347) appellent cette fonction, elles en beneficient\r\n             *   toutes les deux sans etre touchees.\r\n             *   Revert : window._viaPb1692Off = true (retour a pb669 seul).\r\n             * ============================================================ *\/\r\n            if (window._viaPb1692Off !== true) {\r\n                try {\r\n                    var _j1692 = sessionStorage.getItem('viaCampagne926');\r\n                    var _m1692 = _j1692 ? JSON.parse(_j1692) : null;\r\n                    var _p1692 = _m1692 ? (_m1692.paysAnnonceur || '') : '';\r\n                    if (_p1692) {\r\n                        console.log('[pb1692] aucune resa ne porte l annonceur ->'\r\n                            + ' repli sur la memoire de campagne : ' + _p1692);\r\n                        return _p1692;\r\n                    }\r\n                    console.log('[pb1692] ni resa ni memoire de campagne -> nouvelle resa sans annonceur');\r\n                } catch (_e1692) {\r\n                    console.warn('[pb1692] memoire de campagne illisible : ' + _e1692.message);\r\n                }\r\n            }\r\n            return null;\r\n        },\r\n        \r\n        \/**\r\n         * Rafra\u00eechit l'affichage d'un item\r\n         *\/\r\n        \/**\r\n         * pb716 : quand #ProcessAchatInside est masque (pb699), afficher sous l'item\r\n         *   un texte rouge cliquable qui permet de le rouvrir. Insere en DERNIER\r\n         *   enfant de .CampagneTemplateClass, la ou #ProcessAchatInside lui-meme est\r\n         *   deplace (pb231 \/ Pb 7) : le lien occupe donc sa place.\r\n         *   flex 0 0 100% : l'item est un conteneur flex, sans base a 100% le texte\r\n         *   partagerait sa ligne avec le voisin precedent (meme mecanique qu'en pb714).\r\n         *\/\r\n        _lienOuvrirEtape1_716($item, afficher) {\r\n            if (!$item) { return; }\r\n            if ($item.length === 0) { return; }\r\n            const el716 = $item[0];\r\n            if (!el716) { console.warn('[pb716] element item introuvable'); return; }\r\n            let lien716 = el716.querySelector('.via-ouvrir-etape1-716');\r\n            if (!afficher) {\r\n                if (lien716 ? lien716.parentNode : null) {\r\n                    lien716.parentNode.removeChild(lien716);\r\n                    console.log('[pb716] lien retire (ProcessAchatInside visible)');\r\n                }\r\n                return;\r\n            }\r\n            if (!lien716) {\r\n                lien716 = document.createElement('div');\r\n                lien716.className = 'via-ouvrir-etape1-716';\r\n                const _lang716 = sessionStorage.getItem('SiteLangue') === 'EN' ? 'EN' : 'FR';\r\n                lien716.textContent = (_lang716 === 'EN')\r\n                    ? '> Campaign dates, duration and currency'\r\n                    : '> Dates, dur\\u00e9e et devise de campagne';\r\n                el716.appendChild(lien716);\r\n                console.log('[pb716] lien ajoute sous l\\'item ' + el716.id);\r\n            }\r\n            lien716.style.setProperty('color', '#fb5e2a', 'important');\r\n            lien716.style.setProperty('font-size', '11px', 'important');\r\n            lien716.style.setProperty('font-weight', '600', 'important');\r\n            lien716.style.setProperty('line-height', '1.3', 'important');\r\n            lien716.style.setProperty('text-align', 'center', 'important');\r\n            lien716.style.setProperty('cursor', 'pointer', 'important');\r\n            lien716.style.setProperty('margin-top', '4px', 'important');\r\n            lien716.style.setProperty('flex', '0 0 100%', 'important');\r\n            lien716.style.setProperty('width', '100%', 'important');\r\n            lien716.style.setProperty('order', '99', 'important');\r\n        },\r\n\r\n        \/**\r\n         * pb716 : clic sur le lien -> reouvrir #ProcessAchatInside. Delegation sur\r\n         *   document (le lien est cree et detruit au fil des rendus d'item) et\r\n         *   liaison unique, gardee par un flag.\r\n         *   touchend en plus de click : l'item est dans une zone ou le tap peut etre\r\n         *   avale (meme precaution qu'en pb655\/pb710).\r\n         *\/\r\n        brancherLienEtape1_716() {\r\n            if (window._viaLien716Bound) { return; }\r\n            window._viaLien716Bound = true;\r\n            const _ouvrir716 = (e) => {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                \/\/ pb716b : memoriser POUR QUEL item la reouverture est demandee, afin\r\n                \/\/   que l'evaluation pb699 suivante ne re-masque pas aussitot.\r\n                const _itEl716 = e.currentTarget ? e.currentTarget.closest('.CampagneTemplateClass') : null;\r\n                window._via716OuvertPour = (_itEl716 ? _itEl716.id : null);\r\n                $('#ProcessAchatInside').show();\r\n                $('.via-ouvrir-etape1-716').remove();\r\n                console.log('[pb716] clic -> ProcessAchatInside reouvert (item=' + window._via716OuvertPour + ')');\r\n            };\r\n            $(document).on('click', '.via-ouvrir-etape1-716', _ouvrir716);\r\n            $(document).on('touchend', '.via-ouvrir-etape1-716', _ouvrir716);\r\n            console.log('[pb716] lien Etape1 branche');\r\n        },\r\n\r\n        \/**\r\n         * pb694 : titre de l'ARTICLE dans la reservation (.ArticleTitre).\r\n         *   Appelee par les TROIS moteurs de rendu d'item : rafraichirItemHTML,\r\n         *   remplirItemPartiel et remplirItemHTML. pb693 n'avait branche que le\r\n         *   premier -> le flux VLP, qui passe par remplirItemPartiel, n'affichait\r\n         *   rien et ne loguait rien.\r\n         *   Le titre vit dans selectedPageSecteurDisplayed (meme champ que le\r\n         *   secteur pour les autres types de page, cf pb208).\r\n         *   L'element porte elementor-hidden-desktop\/tablet\/mobile, qui appliquent\r\n         *   display:none !important : un .show() jQuery (inline sans important)\r\n         *   perdrait. On retire donc les classes ET on pose display en !important.\r\n         *\/\r\n        _majArticleTitre694($item, src, origine) {\r\n            if (!$item) { return; }\r\n            if (!src) { return; }\r\n            const $at = $item.find('.ArticleTitre');\r\n            const estArticle = (src.selectedPageType === 'ArtType')\r\n                ? true\r\n                : (src.commandePage === 'Article');\r\n            \/\/ pb696 : le TITRE de l'article n'est PAS selectedPageSecteurDisplayed, qui\r\n            \/\/   ne porte que le secteur (\"Croissance\"). Le vrai titre (\"Vers une\r\n            \/\/   croissance de 3,1% - Gabon\") est ecrit dans sessionStorage.Commande_Article\r\n            \/\/   par viaSyncArticle635 (yearbook-media.js) au choix de l'article.\r\n            \/\/   Ordre : titre deja memorise sur l'item -> sessionStorage -> repli secteur.\r\n            \/\/   sessionStorage etant GLOBAL, il serait ecrase par une resa suivante : on\r\n            \/\/   recopie donc la valeur sur l'item des la premiere lecture, pour que chaque\r\n            \/\/   reservation garde SON titre lors des rafraichissements ulterieurs.\r\n            let titre = '';\r\n            const _ssArt696 = (sessionStorage.getItem('Commande_Article') || '').trim();\r\n            if (estArticle) {\r\n                titre = src.articleTitre || '';\r\n                if (!titre) {\r\n                    titre = _ssArt696;\r\n                    if (titre) { src.articleTitre = titre; }\r\n                }\r\n                if (!titre) { titre = src.selectedPageSecteurDisplayed || src.selectedPageSecteur || ''; }\r\n            }\r\n            console.log('[pb693] .ArticleTitre (' + origine + ') | trouve=' + $at.length\r\n                + ' | selectedPageType=' + src.selectedPageType\r\n                + ' | commandePage=' + src.commandePage\r\n                + ' | estArticle=' + estArticle\r\n                + ' | item.articleTitre=' + src.articleTitre\r\n                + ' | Commande_Article=\"' + _ssArt696 + '\"'\r\n                + ' | secteurDisplayed=' + src.selectedPageSecteurDisplayed\r\n                + ' | titre=\"' + titre + '\"');\r\n            if ($at.length === 0) { return; }\r\n            if (!titre) {\r\n                $at[0].style.setProperty('display', 'none', 'important');\r\n                return;\r\n            }\r\n            const $cible = $at.find('.elementor-widget-container').first();\r\n            ($cible.length ? $cible : $at).html(titre);\r\n            $at.removeClass('elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile');\r\n            $at[0].style.setProperty('display', 'block', 'important');\r\n            \/\/ pb698 : afficher le titre en PREMIERE ligne de la carte. Le conteneur\r\n            \/\/   parent est un flex Elementor (e-flex) : l'ordre visuel y est pilote par\r\n            \/\/   la propriete `order`, pas par la position DOM. .ArticleTitre est 8e dans\r\n            \/\/   le DOM et sans order (=0), d'ou son rendu en fin de carte ; un voisin\r\n            \/\/   utilise deja ce levier (CampagneFormatClass, order:5 !important).\r\n            \/\/   order:-1 le place avant TOUS les autres (tous a 0 par defaut).\r\n            \/\/   Reglage : passer a une valeur entre 0 et 5 pour l'intercaler plus bas.\r\n            $at[0].style.setProperty('order', '-1', 'important');\r\n            \/\/ pb714 : titre SEUL sur sa ligne. Dans un conteneur flex en ligne, un\r\n            \/\/   element occupe toute la largeur disponible quand sa BASE vaut 100% :\r\n            \/\/   les suivants sont alors renvoyes a la ligne d'apres. flex-grow 0 et\r\n            \/\/   flex-shrink 0 empechent qu'il soit etire ou comprime par les voisins.\r\n            \/\/   width:100% double la mesure pour les navigateurs qui resolvent mal\r\n            \/\/   flex-basis sur un element a box-sizing herite.\r\n            $at[0].style.setProperty('flex', '0 0 100%', 'important');\r\n            $at[0].style.setProperty('width', '100%', 'important');\r\n            \/\/ pb714 : 4px d'espace SOUS le titre. margin-bottom plutot que padding :\r\n            \/\/   le padding aurait agrandi la boite du widget Elementor (fond, bordure\r\n            \/\/   eventuels), la marge se contente d'ecarter la ligne suivante.\r\n            $at[0].style.setProperty('margin-bottom', '4px', 'important');\r\n            \/\/ Prerequis : le parent doit AUTORISER le retour a la ligne. S'il est en\r\n            \/\/   nowrap, une base de 100% comprimerait les voisins au lieu de les\r\n            \/\/   renvoyer plus bas -> on le loggue pour le voir tout de suite.\r\n            const _par714 = $at[0].parentElement;\r\n            if (_par714) {\r\n                const _cs714 = getComputedStyle(_par714);\r\n                console.log('[pb714] parent .ArticleTitre | display=' + _cs714.display\r\n                    + ' | flex-direction=' + _cs714.flexDirection\r\n                    + ' | flex-wrap=' + _cs714.flexWrap);\r\n                if (_cs714.display.indexOf('flex') !== -1) {\r\n                    if (_cs714.flexWrap === 'nowrap') {\r\n                        _par714.style.setProperty('flex-wrap', 'wrap', 'important');\r\n                        console.log('[pb714] parent en nowrap -> passe en wrap (sinon pas de saut de ligne)');\r\n                    }\r\n                }\r\n            }\r\n            console.log('[pb693] .ArticleTitre affiche (' + origine + ') :', titre);\r\n        },\r\n\r\n        rafraichirItemHTML(itemId) {\r\n            const item = this.state.items.find(i => i.id === itemId);\r\n            if (!item) return;\r\n            \r\n            const $item = $(`#${itemId}`);\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            console.log('\ud83d\udd0d Rafra\u00eechissement item:', itemId, item);\r\n            \r\n            \/\/ \u2705 Pays soci\u00e9t\u00e9 \u2014 lit item.pays (aliment\u00e9 par synchroniserDonnee quand\r\n            \/\/   l'utilisateur renseigne form-field-Nationalite_Societe, vide par d\u00e9faut\r\n            \/\/   depuis le fix Pb 8). Si item.pays absent : ne pas toucher l'affichage.\r\n            if (item.pays) {\r\n                $item.find('.CampagnePaysSocieteClass').html(item.paysAnnonceur || '').show();\r\n            }\r\n\r\n            \/\/ pb693 : TITRE DE L'ARTICLE dans la reservation.\r\n            \/\/   Un item \"article\" porte le titre dans selectedPageSecteurDisplayed :\r\n            \/\/   c'est le meme champ que le secteur pour les autres types de page\r\n            \/\/   (cf le message \"Un article X est selectionne\" de pb208, qui le relit).\r\n            \/\/   Detection sur selectedPageType==='ArtType' OU commandePage==='Article' :\r\n            \/\/   les deux coexistent selon le chemin de creation (pb76 renseigne\r\n            \/\/   commandePage depuis LoadedPageType, pb255 le derive de l'URL).\r\n            \/\/   On masque l'element quand l'item n'est PAS un article : le template est\r\n            \/\/   clone d'un item a l'autre, un titre resterait affiche a tort.\r\n            \/\/   La visibilite en mode reduit reste geree par la regle CSS existante\r\n            \/\/   (data-via-reduit=\"true\" .ArticleTitre) : on ne touche qu'au contenu.\r\n            this._majArticleTitre694($item, item, 'rafraichirItemHTML');\r\n            this._majRecap793($item, item);   \/\/ pb793\r\n            \r\n            \/\/ \u2705 Dates - SEULEMENT si l'espace est disponible\r\n            const $datesElem = $item.find('.CampagneDatesClass');\r\n            \r\n            if ($datesElem.length > 0) {\r\n                const estIndisponible = $('#IndisponibilitesMsg').is(':visible') || \r\n                                        item.disponibilite === false || \r\n                                        item.statut === 'indisponible';\r\n                \r\n                \/* ====================================================================\r\n                 * pb1944 : LA CARTE GARDE SES DATES QUAND L'ESPACE EST INDISPONIBLE.\r\n                 *   Constat user, regie : \u00ab si je selectionne des dates indisponibles,\r\n                 *   les dates sont effacees, une nouvelle resa est creee \u00bb.\r\n                 *   Le log dement la seconde moitie \u2014 aucun creerNouvelItem, et l'id\r\n                 *   reste CampagneTemplate_1788081377056 d'un bout a l'autre. Ce qui\r\n                 *   ressemble a une resa neuve est la MEME carte, videe de ses dates.\r\n                 *   Et les dates ne sont pas perdues non plus : le meme log les montre\r\n                 *   en session, Debut_de_campagne1 = 16\/10\/2026. C'est CE bloc qui les\r\n                 *   masque a l'affichage.\r\n                 *   L'intention d'origine se comprend \u2014 ne pas laisser croire qu'une\r\n                 *   periode est retenue alors qu'elle est refusee. Mais le resultat est\r\n                 *   contraire : une carte sans dates ne dit pas \u00ab ces dates sont\r\n                 *   refusees \u00bb, elle dit \u00ab il n'y a pas de dates \u00bb, et l'utilisateur\r\n                 *   croit avoir perdu sa saisie. Le message d'indisponibilite, lui, dit\r\n                 *   deja exactement ce qu'il faut, et depuis pb1940 il dit aussi quoi\r\n                 *   faire \u2014 \u00ab Merci de choisir des dates a partir du \u2026 \u00bb.\r\n                 *   Demande user : garder les dates affichees, et laisser le message\r\n                 *   porter l'information. C'est ce que fait ce pb : la branche de\r\n                 *   masquage disparait, les dates suivent le meme chemin qu'en cas\r\n                 *   disponible.\r\n                 *   Le TARIF continue d'etre masque par ailleurs (estTarifIndisponible,\r\n                 *   l.8313) : lui n'a effectivement aucune valeur a montrer.\r\n                 *   Revert : window._viaPb1944Off = true (masquage d'origine).\r\n                 * ==================================================================== *\/\r\n                if (estIndisponible ? (window._viaPb1944Off === true) : false) {\r\n                    $datesElem.hide();\r\n                    console.log('\ud83d\udeab Dates masqu\u00e9es - espace indisponible:', item.id);\r\n                } else if (item.dateDebut && item.dateFin) {\r\n                    if (estIndisponible) {\r\n                        if (window._viaSig1944 !== item.id + '|' + item.dateDebut + '|' + item.dateFin) {\r\n                            window._viaSig1944 = item.id + '|' + item.dateDebut + '|' + item.dateFin;\r\n                            console.log('[pb1944] espace indisponible : dates CONSERV\u00c9ES'\r\n                                + ' \u00e0 l affichage (' + item.dateDebut + ' > ' + item.dateFin + ')'\r\n                                + ' \u2014 le message d indisponibilit\u00e9 porte l information');\r\n                        }\r\n                    }\r\n                    const dates = lang === 'EN' \r\n                        ? `Campaign from ${item.dateDebut} to ${item.dateFin}`\r\n                        : `Campagne du ${item.dateDebut} au ${item.dateFin}`;\r\n                    \r\n                    $item.find('.CampagneDatesContainer').show();\r\n                    $datesElem.html(dates).show();\r\n                }\r\n            }\r\n\r\n\r\n\r\n            \/\/ \u2705 Dur\u00e9e\r\n            if (item.duree) {\r\n                const dureeText = lang === 'EN'\r\n                    ? (item.duree === 1 ? '1 day' : `${item.duree} days`)\r\n                    : (item.duree === 1 ? '1 jour' : `${item.duree} jours`);\r\n                \r\n                const $dureeElem = $item.find('.CampagneNbJours');\r\n                \r\n                if ($dureeElem.length > 0) {\r\n                    $item.find('.CampagneDatesContainer').show();\r\n                    $dureeElem.html(dureeText).show();\r\n                    console.log('\u2705 Dur\u00e9e mise \u00e0 jour:', dureeText);\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 Tarif - SEULEMENT si l'espace est disponible\r\n            const estTarifIndisponible = item.disponibilite === false || item.statut === 'indisponible';\r\n\r\n            if (item.tarifHT && item.tarifHT > 0 && window.VIA_App && !estTarifIndisponible) {\r\n                const deviseAffichage = this.state.deviseAffichage || item.devise || 'EUR';\r\n                \r\n                const montantConverti = window.VIA_App.convertirDevise(item.tarifHT, 'EUR', deviseAffichage);\r\n                const tarifFormate = window.VIA_App.formaterMontant(montantConverti, deviseAffichage, 2);\r\n                \r\n                const labelTarif = lang === 'EN' ? 'Price excl. VAT' : 'Tarif H.T.';\r\n                \/\/ pb2121 : resa active d'un commercial -> libelle seul.\r\n                const tarifHTML = window._viaLibelleTarif2121(item.id, `${labelTarif} ${tarifFormate}`);\r\n                \r\n                const $tarifElem = $item.find('.CampagneTarifClass');\r\n                \r\n                if ($tarifElem.length > 0) {\r\n                    $item.find('.CampagneDatesContainer').show();\r\n                    $tarifElem.html(tarifHTML).show();\r\n                    console.log(`\u2705 Tarif item ${item.id} rafra\u00eechi:`, tarifHTML);\r\n                }\r\n            } else {\r\n                \/\/ \u2705 Pas de tarif OU espace indisponible - masquer l'affichage\r\n                const labelTarif = lang === 'EN' ? 'Price excl. VAT' : 'Tarif H.T.';\r\n                const $tarifElem = $item.find('.CampagneTarifClass');\r\n                if ($tarifElem.length > 0) {\r\n                    if (estTarifIndisponible) {\r\n                        $tarifElem.html(`${labelTarif} -`).show();\r\n                        console.log(`\ud83d\udeab Tarif item ${item.id} masqu\u00e9 - espace indisponible`);\r\n                    } else {\r\n                        \/\/ pb1420 : sonde pb1377 retiree (diagnostic termine).\r\n                        \/\/   Elle avait servi a etablir que ce writer efface faute de\r\n                        \/\/   tarif sur l'ITEM, et non par defaut d'affichage \u2014 cause\r\n                        \/\/   corrigee en pb1385. La branche reste correcte telle quelle :\r\n                        \/\/   c'est le TROISIEME writer de cette zone, apres\r\n                        \/\/   remplirItemPartiel (pb1373) et remplirItemComplet (pb1376),\r\n                        \/\/   et le seul qui teste item.tarifHT, la bonne source.\r\n                        $tarifElem.html('').hide();\r\n                    }\r\n                }\r\n            }\r\n            \/\/ \u2705 v2.4.3 : Masquer le message accompagnement si tarif obtenu\r\n            if (item.tarifHT && item.tarifHT > 0) {\r\n                $item.find('.CampagneMsgAccompagnement').hide();\r\n            }\r\n\r\n            \/\/ \u2705 Pb 2 : span tarif mode r\u00e9duit \u2014 affich\u00e9 sur la m\u00eame ligne que\r\n            \/\/   pays\/secteur\/format (apr\u00e8s .CampagneFormatClass dans le flex container).\r\n            \/\/ \u2705 Pb 2 : tarif mode r\u00e9duit \u2014 inject\u00e9 INSIDE .CampagneFormatClass via .html()\r\n            \/\/   (pas via .after() qui cr\u00e9e un \u00e9l\u00e9ment sibling dans le flex container\r\n            \/\/   Elementor et d\u00e9clenche ses MutationObserver \u2192 reset dates\/pays soci\u00e9t\u00e9).\r\n            \/\/   \"Banni\u00e8re <span>360\u20ac HT<\/span>\" reste dans la m\u00eame cellule flex.\r\n            \/\/   Le CSS hide\/show (display:none sur .CampagneTarifModeReduit par d\u00e9faut,\r\n            \/\/   display:inline-block quand data-via-reduit=\"true\") g\u00e8re la visibilit\u00e9.\r\n            \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction format \u2014 _formatBase est utilis\u00e9 4 fois\r\n            \/\/   plus bas. Traduire ici une fois pour couvrir tous les chemins.\r\n            var _formatBase = _translateFormatLabel(item.format || '');\r\n            if (item.tarifHT) {\r\n                if (item.tarifHT > 0) {\r\n                    if (!estTarifIndisponible) {\r\n                        var _tarifMRNum = Math.round(item.tarifHT * 100) \/ 100;\r\n                        var _tarifMRStr = (Math.round(_tarifMRNum) === _tarifMRNum)\r\n                            ? Math.round(_tarifMRNum)\r\n                            : _tarifMRNum;\r\n                        var _tarifMRLabel = (lang === 'EN')\r\n                            ? (_tarifMRStr + '\u20ac excl. VAT')\r\n                            : (_tarifMRStr + '\u20ac HT');\r\n                        $item.find('.CampagneFormatClass').html(\r\n                            _formatBase + ' <span class=\"CampagneTarifModeReduit\" style=\"margin-left:3px;\">' + _tarifMRLabel + '<\/span>'\r\n                        );\r\n                    } else {\r\n                        $item.find('.CampagneFormatClass').html(_formatBase);\r\n                    }\r\n                } else {\r\n                    $item.find('.CampagneFormatClass').html(_formatBase);\r\n                }\r\n            } else {\r\n                $item.find('.CampagneFormatClass').html(_formatBase);\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * Met en avant le format, site et secteur de la commande\r\n         *\/\r\n        mettreEnAvantSelection(itemId) {\r\n            const item = this.state.items.find(i => i.id === itemId);\r\n            if (!item) return;\r\n            \r\n            \/\/ 1\ufe0f\u20e3 FORMAT\r\n            if (typeof FormatSelection !== 'undefined' && typeof FormatSelection.restoreBorder === 'function') {\r\n                FormatSelection.restoreBorder();\r\n            } else {\r\n                $('.FormatClassique, .FormatPopup').css('border', 'none');\r\n                \r\n                const popUpChoice = sessionStorage.getItem('PopUpChoice');\r\n                const formatSelect = sessionStorage.getItem('FormatSelect');\r\n                \r\n                if (popUpChoice && formatSelect) {\r\n                    const selector = popUpChoice === 'Yes' \r\n                        ? '.FormatPopup.FormatSelect' + formatSelect\r\n                        : '.FormatClassique.FormatSelect' + formatSelect;\r\n                    \r\n                    $(selector).css('border', '4px solid rgb(0, 255, 25)');\r\n                } else if (formatSelect) {\r\n                    $('.FormatSelect' + formatSelect).first().css('border', '4px solid rgb(0, 255, 25)');\r\n                }\r\n            }\r\n            \r\n            \/\/ 2\ufe0f\u20e3 SITE - Utiliser la fonction centralis\u00e9e de yearbook-media.js\r\n            if (typeof window.SiteSelection !== 'undefined' && typeof window.SiteSelection.updateBorders === 'function') {\r\n                \/\/ pb208 : d\u00e9river le pays FIABLE de la r\u00e9sa s\u00e9lectionn\u00e9e. item.pays est\r\n                \/\/   souvent null (r\u00e9sa partielle\/anticip\u00e9e) \u2192 fallback : extraire le pays du\r\n                \/\/   sous-domaine de linkSecteurPage (ex. cameroun.yearbook-media.com \u2192 Cameroun),\r\n                \/\/   m\u00eame m\u00e9thode que syncAdditionalData \/ remplirItemPartiel. On \u00e9vite ainsi de\r\n                \/\/   lire SitePays\/ContinentPaysTitre (globales stale = \"R\u00e9servation\").\r\n                \/\/ pb667 : le pays du SITE doit venir de l'URL, PAS de item.pays.\r\n                \/\/   pb208 lisait item.pays EN PRIORITE en supposant qu'il portait le\r\n                \/\/   pays du site (null sur resa partielle). Faux des que la resa est\r\n                \/\/   completee : item.pays porte alors la nationalite de l'ANNONCEUR\r\n                \/\/   (ex. France). Le sous-titre \"Communication associee au site X\" et\r\n                \/\/   le bandeau basculaient donc du site pays (Cameroun) vers France.\r\n                \/\/   Le sous-domaine identifie le site sans ambiguite -> il PRIME, et\r\n                \/\/   item.pays ne sert plus que de repli.\r\n                var _paysItem208 = this._paysSite667(item);\r\n                if (!_paysItem208) { _paysItem208 = item.pays || null; }\r\n                \/\/ Re-synchroniser les globales pour que le sous-titre \"Communication associ\u00e9e\r\n                \/\/   au site X\" (lu en aval) affiche aussi le bon pays.\r\n                if (_paysItem208) {\r\n                    sessionStorage.setItem('ContinentPaysTitreDisplayed', _paysItem208);\r\n                    sessionStorage.setItem('ContinentPaysTitre', _paysItem208);\r\n                    \/\/ Rendre directement le sous-titre vert pays (ne pas d\u00e9pendre de l'ordre\r\n                    \/\/   d'ex\u00e9cution du code r\u00e9gie qui lit la cl\u00e9). M\u00eame rendu que yearbook-media.js.\r\n                    var _isEN208 = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                    var _msgPays208 = _isEN208\r\n                        ? 'Communication linked to the ' + _paysItem208 + ' site'\r\n                        : 'Communication associ\u00e9e au site ' + _paysItem208;\r\n                    var $_paysST208 = $('.AssocierPaysClass .SousTitre');\r\n                    if ($_paysST208.length) {\r\n                        $_paysST208.find('p').html(_msgPays208).css('color', '#56BE50');\r\n                        $_paysST208.show();\r\n                    }\r\n                    var _amt208 = document.getElementById('AssocierPaysMessageTexte');\r\n                    if (_amt208) { $(_amt208).text(_msgPays208); }\r\n                }\r\n                const sitePays = _paysItem208 || sessionStorage.getItem('SitePays') || sessionStorage.getItem('ContinentPaysTitre');\r\n                if (sitePays) {\r\n                    window.SiteSelection.updateBorders(sitePays);\r\n                    console.log('\u2705 Site mis en avant via SiteSelection.updateBorders:', sitePays, '(source:', _paysItem208 ? 'item\/url' : 'sessionStorage', ')');\r\n                }\r\n            } else {\r\n                \/\/ Fallback si SiteSelection n'est pas disponible\r\n                $('.HPContinentPays').css('border', 'none');\r\n                \r\n                if (item.linkSecteurPage) {\r\n                    try {\r\n                        const url = new URL(item.linkSecteurPage);\r\n                        const domain = url.hostname.replace('www.', '').replace('.yearbook-media.com', '');\r\n                        \r\n                        \/\/ \u2705 G\u00e9rer les acronymes (RDC, DRC) qui doivent rester en majuscules\r\n                        const acronymes = ['rdc', 'drc'];\r\n                        const domainBase = domain.replace('-en', ''); \/\/ Retirer -en pour la comparaison\r\n                        let siteId;\r\n                        \r\n                        if (acronymes.includes(domainBase.toLowerCase())) {\r\n                            siteId = domainBase.toUpperCase();\r\n                        } else {\r\n                            siteId = domainBase.charAt(0).toUpperCase() + domainBase.slice(1);\r\n                        }\r\n                        \r\n                        \/\/ \u2705 Ajouter -en seulement si le domain original contenait -en\r\n                        let siteSelector = `.SiteId${siteId}`;\r\n                        if (domain.includes('-en')) {\r\n                            siteSelector += '-en';\r\n                        }\r\n                        \r\n                        $(siteSelector).css('border', '4px solid rgb(0, 255, 25)');\r\n                        console.log('\u2705 Site mis en avant (fallback):', siteSelector);\r\n                    } catch (e) {\r\n                        console.warn('\u26a0\ufe0f URL invalide:', item.linkSecteurPage);\r\n                    }\r\n                }\r\n            }\r\n            \r\n            \/\/ 3\ufe0f\u20e3 SECTEUR \/ ARTICLE\r\n            $('.PTType, .HPType, .ArtType, .CartoucheArticles').css('border', 'none');\r\n            \r\n            if (item.selectedPageType === 'ArtType') {\r\n                \/\/ \u2705 Pour les articles, mettre en avant CartoucheArticles\r\n                $('.CartoucheArticles').css('border', '4px solid rgb(0, 255, 25)');\r\n                console.log('\u2705 CartoucheArticles mis en avant (Article s\u00e9lectionn\u00e9)');\r\n            } else if (item.selectedPageType === 'HPType' ? (window._viaPb1021Off !== true) : false) {\r\n                \/\/ ====================================================================\r\n                \/\/ pb1021 : METTRE EN AVANT LA VIGNETTE HOMEPAGE.\r\n                \/\/   Comme pour ArtType\/CartoucheArticles, la Homepage est un TYPE de\r\n                \/\/   page et non un secteur : item.selectedPageSecteur est vide, donc\r\n                \/\/   la branche suivante (repli par .SecteurIdXxx) n'etait jamais\r\n                \/\/   atteinte et aucune vignette n'etait bordee.\r\n                \/\/   Bonne nouvelle confirmee par le HTML fourni : la vignette porte\r\n                \/\/   DEJA la classe .SecteurIdHomepage (en plus de .HPType). Le\r\n                \/\/   mecanisme existant convient donc tel quel \u2014 il suffit de nommer\r\n                \/\/   la cible explicitement, sans inventer de selecteur.\r\n                \/\/   On vise .SecteurIdHomepage et non .HPType : cette derniere est\r\n                \/\/   deja utilisee juste au-dessus pour RESET les bordures de toutes\r\n                \/\/   les vignettes du groupe, et pourrait etre portee par plusieurs\r\n                \/\/   elements.\r\n                \/\/   Revert : window._viaPb1021Off = true.\r\n                \/\/ ====================================================================\r\n                $('.SecteurIdHomepage').css('border', '4px solid rgb(0, 255, 25)');\r\n                console.log('[pb1021] vignette Homepage mise en avant (.SecteurIdHomepage)');\r\n            } else if (item.selectedPageSecteur) {\r\n                const secteurClass = `.SecteurId${item.selectedPageSecteur}`;\r\n                $(secteurClass).css('border', '4px solid rgb(0, 255, 25)');\r\n                console.log('\u2705 Secteur mis en avant:', secteurClass);\r\n            }\r\n\r\n            \/\/ pb208 : rendre directement le sous-titre vert SECTEUR (comme le pays). Sans \u00e7a\r\n            \/\/   il restait sur le secteur de la r\u00e9sa pr\u00e9c\u00e9dente (cf capture : \"La page\r\n            \/\/   Agro-industries est s\u00e9lectionn\u00e9e\" alors que Banque est la r\u00e9sa active).\r\n            (function _pb208Secteur() {\r\n                var _secDisp208 = item.selectedPageSecteurDisplayed || item.selectedPageSecteur || '';\r\n                if (!_secDisp208) { return; }\r\n                var _isEN_S208 = sessionStorage.getItem('SiteLangue') === 'EN';\r\n                var _msgSec208;\r\n                if (item.selectedPageType === 'ArtType' ? true : (item.commandePage === 'Article')) {\r\n                    _msgSec208 = _isEN_S208 ? \"The \" + _secDisp208 + \" article has been selected\" : \"L'article \" + _secDisp208 + \" est s\u00e9lectionn\u00e9\";\r\n                } else {\r\n                    _msgSec208 = _isEN_S208 ? \"The \" + _secDisp208 + \" page has been selected\" : \"La page \" + _secDisp208 + \" est s\u00e9lectionn\u00e9e\";\r\n                }\r\n                var $_secST208 = $('.AssocierSecteurClass .SousTitre');\r\n                if ($_secST208.length) {\r\n                    $_secST208.find('p').html(_msgSec208).css('color', '#56BE50');\r\n                    $_secST208.show();\r\n                }\r\n            })();\r\n\r\n            \/\/ pb208 : centrer les bandeaux Pays et Secteur sur la vignette s\u00e9lectionn\u00e9e,\r\n            \/\/   comme lors de la 1\u00e8re s\u00e9lection (preselector \u2192 HorizontalScroll.centerOnSelected\r\n            \/\/   sur les 3 listes). centerOnSelected s'appuie sur findChildWithBorder, qui pour\r\n            \/\/   le secteur lit la cl\u00e9 globale SelectedPageSecteur \u2014 NON mise \u00e0 jour pour les\r\n            \/\/   items anticip\u00e9s (GetURLCommandeFromItem ignor\u00e9) \u2192 centrage sur l'ancien secteur.\r\n            \/\/   On synchronise donc les cl\u00e9s que findChildWithBorder utilise, et on vide les\r\n            \/\/   *ElementId stale pour forcer le fallback fiable par classe (SiteId\/SecteurId).\r\n            (function _pb208Center() {\r\n                if (typeof window.HorizontalScroll === 'undefined') { return; }\r\n                if (typeof window.HorizontalScroll.centerOnSelected !== 'function') { return; }\r\n                var _secForCenter = item.selectedPageSecteur || '';\r\n                if (_secForCenter) { sessionStorage.setItem('SelectedPageSecteur', _secForCenter); }\r\n                \/\/ forcer le fallback par classe (les ElementId peuvent pointer l'ancienne r\u00e9sa)\r\n                sessionStorage.removeItem('SelectedSiteElementId');\r\n                sessionStorage.removeItem('SelectedSecteurElementId');\r\n                setTimeout(function() {\r\n                    try {\r\n                        window.HorizontalScroll.centerOnSelected('ListeSitesConteneurScroll', 20000);\r\n                        window.HorizontalScroll.centerOnSelected('ListeSecteurs', 20000);\r\n                        console.log('\u2705 [pb208] bandeaux Pays + Secteur centr\u00e9s | pays:', sessionStorage.getItem('ContinentPaysTitre'), '| secteur:', _secForCenter);\r\n                    } catch (_eCenter208) {\r\n                        console.warn('\u26a0\ufe0f [pb208] centerOnSelected:', _eCenter208);\r\n                    }\r\n                }, 300);\r\n            })();\r\n            \r\n            \/\/ \u2705 v2.4.9g : Mettre \u00e0 jour les SousTitres bandeaux depuis les donn\u00e9es de la r\u00e9servation\r\n            \/\/ \u2705 v1.11 : Pour les items anticip\u00e9s, pas de fallback sessionStorage\r\n            \/\/           (\u00e9vite de restaurer pays\/format depuis l'ancien item)\r\n            const _isAnticipe = item.statut === 'anticipee';\r\n            \/\/ pb667 (2e emplacement, meme fonction) : c'est CE calcul qui alimente le\r\n            \/\/   SousTitre sur le flux \"click Reserver -> remplirItemPartiel\". item.pays\r\n            \/\/   valant France (annonceur), le bandeau affichait \"associee au site\r\n            \/\/   France\" sur une page Cameroun. Le sous-domaine prime.\r\n            \/\/ ====================================================================\r\n            \/\/ pb1019 : une resa ANTICIPEE peut etre renseignee APRES sa creation.\r\n            \/\/   Constat user : clic sur un lien dans un VLP regie -> la resa est\r\n            \/\/   creee vide par AutreCommandeBouton, puis remplie par pb989\r\n            \/\/   (\"nouvelle resa ... renseignee | pays=Gabon | type=Article\", et\r\n            \/\/   SelectedPageSecteur = Agro-industries). Or pb989 ecrit les champs\r\n            \/\/   REELS de l'item \u2014 selectedPageSecteur, linkSecteurPage \u2014 et NON les\r\n            \/\/   champs _anticipePaysDisplay \/ _anticipeSecteurDisplay, qui ne sont\r\n            \/\/   poses qu'a la creation par creerReservationAnticipee.\r\n            \/\/   Les deux lignes ci-dessous ne lisaient que les champs _anticipe* :\r\n            \/\/   _paysDisp et _secteurDisp restaient vides malgre une resa complete,\r\n            \/\/   et les branches d'effacement pb1016\/pb1016b se declenchaient a tort\r\n            \/\/   (les bandeaux verts pays et secteur ne s'affichaient plus).\r\n            \/\/   Correction : pour une resa anticipee, replier sur les champs reels\r\n            \/\/   quand les champs _anticipe* sont vides. L'ordre _anticipe* d'abord\r\n            \/\/   preserve le comportement v1.11 (pas de restauration depuis l'ancien\r\n            \/\/   item) : on ne descend au repli que si le champ dedie ne dit rien.\r\n            \/\/   Le pays vient de _paysSite667 (URL), JAMAIS de item.pays, qui porte\r\n            \/\/   la nationalite de l'ANNONCEUR une fois la resa completee (pb667,\r\n            \/\/   pb1015). La resa reellement vide (AutreCommandeBouton sans lien)\r\n            \/\/   n'a ni URL ni secteur -> les deux restent vides et l'effacement\r\n            \/\/   pb1016 continue de s'appliquer.\r\n            \/\/   Rend pb1017 redondant : sa condition est un cas particulier de\r\n            \/\/   celle-ci. On le laisse en place \u2014 il ne se declenchera plus, son\r\n            \/\/   garde _paysDisp etant desormais renseigne \u2014 plutot que de retirer\r\n            \/\/   du code encore en cours de validation.\r\n            \/\/   Revert : window._viaPb1019Off = true.\r\n            \/\/ ====================================================================\r\n            \/\/ ====================================================================\r\n            \/\/ pb1022 : UNE PAGE PEUT ETRE CHOISIE SANS SECTEUR.\r\n            \/\/   Constat user : article sans secteur (SelectedPageType=ArtType,\r\n            \/\/   SelectedPageSecteur absent) -> vignettes Congo et Articles bien\r\n            \/\/   bordees, mais les DEUX phrases vertes effacees par pb1016\/pb1016b.\r\n            \/\/   Jusqu'ici \"la resa porte une page\" etait assimile a \"_secteurDisp\r\n            \/\/   est renseigne\". C'est faux pour les deux TYPES de page :\r\n            \/\/   Homepage (pb1020\/pb1021) et Article sans rubrique. On nomme donc\r\n            \/\/   la notion une fois pour toutes et on s'en sert partout.\r\n            \/\/   Revert : window._viaPb1022Off = true.\r\n            \/\/ ====================================================================\r\n            var _typePage1022 = (window._viaPb1022Off !== true)\r\n                ? (item.selectedPageType === 'HPType' || item.selectedPageType === 'ArtType'\r\n                    || item.commandePage === 'Homepage' || item.commandePage === 'Article')\r\n                : false;\r\n            var _anticipeReplis1019 = _isAnticipe ? (window._viaPb1019Off !== true) : false;\r\n            var _paysRepli1019 = '';\r\n            var _secteurRepli1019 = '';\r\n            if (_anticipeReplis1019) {\r\n                try {\r\n                    _paysRepli1019 = (typeof this._paysSite667 === 'function' ? (this._paysSite667(item) || '') : '');\r\n                    \/\/ pb1022b : l'URL peut manquer sur un article ouvert depuis un VLP\r\n                    \/\/   (linkSecteurPage pas encore pose sur l'item \u2014 cf log : aucune\r\n                    \/\/   cle LinkSecteurPage pour cette resa, contrairement au cas\r\n                    \/\/   Homepage). On accepte alors la globale sessionStorage, mais\r\n                    \/\/   UNIQUEMENT si la resa porte deja une page : sinon elle est\r\n                    \/\/   stale et vaut encore le site de la resa precedente \u2014 c'est\r\n                    \/\/   tout l'interet de la garde de pb1017.\r\n                    if (!_paysRepli1019) {\r\n                        if (_secteurRepli1019 || _typePage1022) {\r\n                            _paysRepli1019 = sessionStorage.getItem('ContinentPaysTitreDisplayed') || '';\r\n                        }\r\n                    }\r\n                } catch (_eP1019) { console.warn('[pb1019]', _eP1019.message); }\r\n                _secteurRepli1019 = item.selectedPageSecteurDisplayed || item.selectedPageSecteur || '';\r\n            }\r\n            const _paysDisp = _isAnticipe\r\n                ? (item._anticipePaysDisplay || _paysRepli1019 || '')\r\n                : (this._paysSite667(item) || item.pays || sessionStorage.getItem('ContinentPaysTitreDisplayed') || '');\r\n            const _secteurDisp = _isAnticipe\r\n                ? (item._anticipeSecteurDisplay || _secteurRepli1019 || '')\r\n                : (item.selectedPageSecteurDisplayed || item.selectedPageSecteur || '');\r\n            if (_anticipeReplis1019 ? (!item._anticipePaysDisplay ? !!_paysRepli1019 : false) : false) {\r\n                console.log('[pb1019] r\u00e9sa anticip\u00e9e renseign\u00e9e apr\u00e8s coup -> pays repris de l URL : ' + _paysRepli1019);\r\n            }\r\n            if (_anticipeReplis1019 ? (!item._anticipeSecteurDisplay ? !!_secteurRepli1019 : false) : false) {\r\n                console.log('[pb1019] r\u00e9sa anticip\u00e9e renseign\u00e9e apr\u00e8s coup -> secteur repris de l item : ' + _secteurRepli1019);\r\n            }\r\n            const _formatDisp = _isAnticipe\r\n                ? (item.format || '')\r\n                : (item.format || sessionStorage.getItem('FormatSelect') || '');\r\n            \r\n            \/\/ \u2705 v1.11 : Pour les items anticip\u00e9s, ne pas masquer les messages d'invitation\r\n            \/\/           (CheckSteps123 les a affich\u00e9s pour guider l'utilisateur)\r\n            if (_isAnticipe) {\r\n                \/\/ Masquer uniquement le message correspondant \u00e0 ce qui EST s\u00e9lectionn\u00e9\r\n                if (item.type === 'pays' || item._anticipePaysDisplay) { $('#MsgPaysStep2').hide(); }\r\n                if (item.type === 'secteur' || item._anticipeSecteurDisplay) { $('#MsgSecteurStep3').hide(); }\r\n                \/\/ MsgFormatStep1 et MsgSecteurStep3\/MsgPaysStep2 manquants \u2192 laisser affich\u00e9s\r\n            } else {\r\n                \/\/ Masquer tous les messages d'erreur\r\n                $('#MsgPaysStep2, #MsgSecteurStep3, #MsgFormatStep1').hide();\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction EN \u2014 sous-titres pays\/secteur\r\n            var _isEN_ST = sessionStorage.getItem('SiteLangue') === 'EN';\r\n            \/\/ SousTitre pays\r\n            if (_paysDisp) {\r\n                var _paysMsg = _isEN_ST\r\n                    ? 'Communication linked to the ' + _paysDisp + ' site'\r\n                    : 'Communication associ\u00e9e au site ' + _paysDisp;\r\n                $('.AssocierPaysClass .SousTitre').find('p').html(_paysMsg).css('color', '#56BE50');\r\n                $('.AssocierPaysClass .SousTitre').show();\r\n            } else if (window._viaPb1016Off !== true) {\r\n                \/\/ ====================================================================\r\n                \/\/ pb1016 : EFFACER le sous-titre quand la resa n'a PAS de pays.\r\n                \/\/   Constat user (capture) : a la creation d'une resa par\r\n                \/\/   AutreCommandeBouton, le message vert \"Communication associee au\r\n                \/\/   site Gabon\" restait affiche alors que la nouvelle resa ne porte\r\n                \/\/   aucun site.\r\n                \/\/   Cause : le writer est garde par 'if (_paysDisp)'. Pour une resa\r\n                \/\/   anticipee sans pays, _paysDisp vaut '' -> on n'ecrit RIEN, et le\r\n                \/\/   texte de la resa PRECEDENTE reste en place dans le DOM (le bloc\r\n                \/\/   est partage par toutes les resas). Ecrire ou ne pas ecrire n'est\r\n                \/\/   pas symetrique : l'absence de valeur doit EFFACER, pas laisser.\r\n                \/\/   Le message reapparaitra normalement des que l'utilisateur\r\n                \/\/   selectionnera lui-meme un site \u2014 ce writer sera rappele avec un\r\n                \/\/   _paysDisp renseigne.\r\n                \/\/   Revert : window._viaPb1016Off = true.\r\n                \/\/ ====================================================================\r\n                \/\/ ====================================================================\r\n                \/\/ pb1017 : NE PAS EFFACER quand le site EST selectionne mais que la\r\n                \/\/   resa ne porte pas encore son libelle.\r\n                \/\/   Constat user : pays choisi, puis secteur choisi -> le texte vert\r\n                \/\/   du pays disparaissait.\r\n                \/\/   Cause : creerReservationAnticipee({type:'secteur'}) ne renseigne\r\n                \/\/   pas _anticipePaysDisplay (il n'est pose que pour type:'pays').\r\n                \/\/   _paysDisp vaut donc '' alors que le site Gabon est bel et bien\r\n                \/\/   selectionne \u2014 le log le montre : \"Site mis en avant ... Gabon\".\r\n                \/\/   pb1016 effacait a tort.\r\n                \/\/   Repli, dans cet ordre : le pays deduit de l'URL (_paysSite667,\r\n                \/\/   deja la reference depuis pb667) puis ContinentPaysTitreDisplayed.\r\n                \/\/   On n'utilise JAMAIS item.pays : il porte la nationalite de\r\n                \/\/   l'ANNONCEUR une fois la resa completee (pb667, pb1015).\r\n                \/\/   Condition : uniquement si la resa porte un SECTEUR. Un secteur\r\n                \/\/   appartient a un site, donc le site est determine. A l'inverse, la\r\n                \/\/   resa vide creee par AutreCommandeBouton n'a ni pays ni secteur :\r\n                \/\/   la globale sessionStorage y serait stale (elle vaut encore le\r\n                \/\/   site de la resa precedente) et on doit bien effacer \u2014 c'est le\r\n                \/\/   cas d'origine de pb1016, qui reste couvert.\r\n                \/\/   Independant du mode 1 \/ 2 \/ 3 colonnes : aucun test de layout,\r\n                \/\/   donc pas de dependance a _via1ColMode (fonction locale, piege\r\n                \/\/   pb972).\r\n                \/\/   Revert : window._viaPb1017Off = true.\r\n                \/\/ ====================================================================\r\n                var _repl1017 = '';\r\n                if (window._viaPb1017Off !== true) {\r\n                    if (_secteurDisp) {\r\n                        try {\r\n                            _repl1017 = (typeof this._paysSite667 === 'function' ? (this._paysSite667(item) || '') : '')\r\n                                || sessionStorage.getItem('ContinentPaysTitreDisplayed') || '';\r\n                        } catch (_e1017) { console.warn('[pb1017]', _e1017.message); _repl1017 = ''; }\r\n                    }\r\n                }\r\n                if (_repl1017) {\r\n                    var _msg1017 = _isEN_ST\r\n                        ? 'Communication linked to the ' + _repl1017 + ' site'\r\n                        : 'Communication associ\u00e9e au site ' + _repl1017;\r\n                    console.log('[pb1017] pays absent de la r\u00e9sa mais site s\u00e9lectionn\u00e9 ('\r\n                        + _repl1017 + ') -> sous-titre conserv\u00e9');\r\n                    $('.AssocierPaysClass .SousTitre').find('p').html(_msg1017).css('color', '#56BE50');\r\n                    $('.AssocierPaysClass .SousTitre').show();\r\n                } else {\r\n                console.log('[pb1016] r\u00e9sa sans pays -> sous-titre site effac\u00e9');\r\n                $('.AssocierPaysClass .SousTitre').find('p').html('');\r\n                $('.AssocierPaysClass .SousTitre').hide();\r\n                }\r\n            }\r\n            \r\n            \/\/ ====================================================================\r\n            \/\/ pb1020 : UNE HOMEPAGE N'A PAS DE SECTEUR \u2014 et c'est normal.\r\n            \/\/   Constat user : en revenant sur une resa de type Homepage, la phrase\r\n            \/\/   verte du bandeau secteur ne s'affichait pas (log : SelectedPageSecteur\r\n            \/\/   vide, commandePage=Homepage, SelectedPageType=HPType -> pb1016b\r\n            \/\/   effacait).\r\n            \/\/   Cause : la garde 'if (_secteurDisp)' confond \"pas de page choisie\"\r\n            \/\/   et \"page choisie qui n'est pas un secteur\". Une Homepage est une\r\n            \/\/   page pleinement selectionnee, simplement sans secteur : son libelle\r\n            \/\/   ne depend pas de _secteurDisp. Le message dedie existe d'ailleurs\r\n            \/\/   deja juste en dessous (branche HPType, \"La Homepage est\r\n            \/\/   selectionnee\") \u2014 il etait devenu inatteignable.\r\n            \/\/   La condition devient donc : un secteur OU une Homepage.\r\n            \/\/   Le cas ArtType reste couvert par _secteurDisp (un article porte le\r\n            \/\/   secteur de sa rubrique).\r\n            \/\/   Revert : window._viaPb1020Off = true.\r\n            \/\/ ====================================================================\r\n            var _estHP1020 = (window._viaPb1020Off !== true)\r\n                ? (item.selectedPageType === 'HPType')\r\n                : false;\r\n            if (_estHP1020 ? !_secteurDisp : false) {\r\n                console.log('[pb1020] r\u00e9sa Homepage sans secteur -> sous-titre secteur affich\u00e9 quand m\u00eame');\r\n            }\r\n            \/\/ pb1022c : meme raisonnement que pb1020, etendu a l'ARTICLE sans rubrique.\r\n            if (_typePage1022 ? (!_secteurDisp ? !_estHP1020 : false) : false) {\r\n                console.log('[pb1022] r\u00e9sa Article sans secteur -> sous-titre secteur affich\u00e9 quand m\u00eame');\r\n            }\r\n            \/\/ SousTitre secteur\r\n            if (_secteurDisp || _estHP1020 || _typePage1022) {\r\n                var _secteurMsg;\r\n                if (item.selectedPageType === 'ArtType') {\r\n                    \/\/ pb1022d : sans rubrique, ne pas produire \"Un article  est\r\n                    \/\/   selectionne\" (double espace) \u2014 libelle dedie.\r\n                    if (_secteurDisp) {\r\n                        _secteurMsg = _isEN_ST\r\n                            ? \"An \" + _secteurDisp + \" article has been selected\"\r\n                            : \"Un article \" + _secteurDisp + \" est s\u00e9lectionn\u00e9\";\r\n                    } else {\r\n                        _secteurMsg = _isEN_ST\r\n                            ? \"An article has been selected\"\r\n                            : \"Un article est s\u00e9lectionn\u00e9\";\r\n                    }\r\n                }\r\n                else if (item.selectedPageType === 'HPType') {\r\n                    _secteurMsg = _isEN_ST\r\n                        ? \"The Homepage has been selected\"\r\n                        : \"La Homepage est s\u00e9lectionn\u00e9e\";\r\n                }\r\n                else {\r\n                    _secteurMsg = _isEN_ST\r\n                        ? \"The \" + _secteurDisp + \" page has been selected\"\r\n                        : \"La page \" + _secteurDisp + \" est s\u00e9lectionn\u00e9e\";\r\n                }\r\n                $('.AssocierSecteurClass .SousTitre').find('p').html(_secteurMsg).css('color', '#56BE50');\r\n                $('.AssocierSecteurClass .SousTitre').show();\r\n            } else if (window._viaPb1016Off !== true) {\r\n                \/\/ pb1016b : meme dissymetrie que pb1016 sur le sous-titre SECTEUR.\r\n                \/\/   Le bloc .AssocierSecteurClass .SousTitre est lui aussi partage par\r\n                \/\/   toutes les resas : sans branche d'effacement, \"La page X est\r\n                \/\/   selectionnee\" survit a une resa qui n'a pas de secteur. Symptome\r\n                \/\/   non encore constate a l'ecran, mais strictement le meme defaut.\r\n                console.log('[pb1016b] r\u00e9sa sans secteur -> sous-titre secteur effac\u00e9');\r\n                $('.AssocierSecteurClass .SousTitre').find('p').html('');\r\n                $('.AssocierSecteurClass .SousTitre').hide();\r\n            }\r\n            \r\n            \/\/ SousTitre format\r\n            if (_formatDisp) {\r\n                var _popupDisp = sessionStorage.getItem('PopUpChoice') === 'Yes' ? 'Pop-up' : _formatDisp;\r\n                \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction EN (r\u00e9utilise _isEN_ST d\u00e9fini plus haut)\r\n                var _formatMsg = _isEN_ST\r\n                    ? 'Selected format: ' + _popupDisp\r\n                    : 'Format s\u00e9lectionn\u00e9\u00a0: ' + _popupDisp;\r\n                $('.ChoixFormatClass .SousTitre').find('p').html(_formatMsg).css('color', '#56BE50');\r\n                $('.ChoixFormatClass .SousTitre').show();\r\n                \/\/ Mettre en avant visuellement dans la liste des formats\r\n                if (typeof window.SiteSelection !== 'undefined') {\r\n                    var _fmtLower = _formatDisp.toLowerCase().normalize('NFD').replace(\/[\u0300-\u036f]\/g, '');\r\n                    $('.FormatClassique, .FormatPopup').css('border', 'none');\r\n                    $('.FormatSelect' + _formatDisp).first().css('border', '4px solid rgb(0, 255, 25)');\r\n                }\r\n            } else if (window._viaPb1016Off !== true) {\r\n                \/\/ pb1016c : meme dissymetrie que pb1016 sur le sous-titre FORMAT.\r\n                \/\/   Ce cas echappait jusqu'ici au symptome parce que le clic sur\r\n                \/\/   AutreCommandeBouton fait deja un reset format defensif dans\r\n                \/\/   yearbook-media.js \u2014 mais ce reset est propre a CE point d'entree.\r\n                \/\/   Sur tout autre chemin menant a une resa sans format, le message\r\n                \/\/   \"Format selectionne : X\" de la resa precedente survivrait.\r\n                \/\/   On efface le SOUS-TITRE uniquement : les bordures des vignettes\r\n                \/\/   format restent geres par leur proprietaire (FormatSelection \/\r\n                \/\/   reset ACB). Ne pas melanger les deux responsabilites.\r\n                console.log('[pb1016c] r\u00e9sa sans format -> sous-titre format effac\u00e9');\r\n                $('.ChoixFormatClass .SousTitre').find('p').html('');\r\n                $('.ChoixFormatClass .SousTitre').hide();\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * D\u00e9finit un item comme actif avec chargement des donn\u00e9es\r\n         * \u2705 v1.6 : Gestion BonCommandeCree pour permettre s\u00e9lection de commandes\r\n         *\/\r\n        setItemActif(itemId) {\r\n            \/\/ \u2705 v1.7 : Ignorer pendant un resize\r\n            if (window.VIA_Panier_ResizeEnCours) {\r\n                console.log('\u23ed\ufe0f setItemActif ignor\u00e9 (resize en cours)');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 Si bon de commande cr\u00e9\u00e9 \u2192 bloquer et afficher message\r\n            if (sessionStorage.getItem('BonCommandeCree') === 'Yes') {\r\n                console.log('\ud83d\udd12 setItemActif bloqu\u00e9 - Bon de commande cr\u00e9\u00e9');\r\n                this.afficherMessageNouvelleCommande();\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 Si FinaliserStep mais pas BonCommandeCree \u2192 r\u00e9initialiser les validations\r\n            const finaliserStep = sessionStorage.getItem('FinaliserStep');\r\n            if (finaliserStep === 'Yes') {\r\n                console.log('\ud83d\udd12 setItemActif bloqu\u00e9 - FinaliserStep=Yes');\r\n                this.afficherMessageFinaliser();\r\n                return;\r\n            }\r\n\r\n            \/\/ pb63 : masquer le lien \"Modifier\" VLP sur tous les items (sera re-montr\u00e9\r\n            \/\/   uniquement pour l'item actif si c'est un item VLP, via GetURLCommandeFromItem)\r\n            $('.via-vlp-modifier-btn').hide();\r\n            $(this.config.templateItem).removeClass('via-has-modifier');\r\n            \r\n            \/\/ \u2705 D\u00e9sactiver TOUS les items (fond #F8F8F8)\r\n            \/\/   v4.9ds : liser\u00e9 gris #EEEEEE de m\u00eame \u00e9paisseur (3px) que le liser\u00e9 vert\r\n            \/\/     sur les items inactifs \u2014 au lieu de border:none \u2014 pour donner un cadre\r\n            \/\/     visible mais discret \u00e0 toutes les r\u00e9servations non-actives.\r\n            \/\/     L'item actif aura ensuite son liser\u00e9 vert qui \u00e9crase celui-ci.\r\n            \/\/     \u2705 v4.9ds : #EEEEEE \u2192 #BBBBBB (gris plus fonc\u00e9, demande user). Le cadre\r\n            \/\/     reste sur les items inactifs (data-via-reduit=\"true\") et est \u00e9cras\u00e9 par\r\n            \/\/     le liser\u00e9 vert #00fa19 lorsque l'item devient actif (lignes 3733\/3737).\r\n            \/\/   v4.9ds : poser aussi data-via-reduit=\"true\" sur tous les items (r\u00e9duits\r\n            \/\/     par d\u00e9faut). L'item actif sera ensuite remis \u00e0 \"false\" plus bas.\r\n            \/\/     Le bouton .via-reduire-btn voit son SVG bascul\u00e9 selon l'\u00e9tat.\r\n            \/\/   v4.9ds : poser data-via-no-ref=\"true\" si la 1\u00e8re ligne .CampagneNoClass\r\n            \/\/     n'est pas affich\u00e9e pour l'item \u2014 masquer le bouton R\u00e9duire\/Agrandir\r\n            \/\/     dans ce cas (demande user). Cela couvre les items en cours de cr\u00e9ation,\r\n            \/\/     anticip\u00e9es sans r\u00e9f\u00e9rence compl\u00e8te, etc.\r\n            console.log('\ud83d\udd32 [setItemActif] Reset bordures sur', $(this.config.templateItem).length, 'items');\r\n            $(this.config.templateItem).each(function() {\r\n                \/\/ [pb77 DIAG inactif] mesure AVANT transition\r\n                var _cpDiag77 = this.querySelector('#CampagnePage');\r\n                var _paysDiag77 = this.querySelector('[id=\"CampagnePaysTexte\"]') || this.querySelector('.CampagnePaysClass');\r\n                var _topAvant77 = _paysDiag77 ? Math.round(_paysDiag77.getBoundingClientRect().top) : null;\r\n                var _mtAvant77 = _cpDiag77 ? window.getComputedStyle(_cpDiag77).marginTop : null;\r\n                var _ptAvant77 = window.getComputedStyle(this).paddingTop;\r\n                var _self77 = this;\r\n                \/\/ \u2705 pb224 : retirer l'inline margin-top (-10px pos\u00e9 \u00e0 la r\u00e9activation) du\r\n                \/\/   titre \"Nouvelle r\u00e9servation\" quand l'item se d\u00e9sactive, pour que la r\u00e8gle\r\n                \/\/   CSS inactif (-20px) reprenne le dessus.\r\n                var _titreNRreset = this.querySelector('.via-nouvelle-resa-titre');\r\n                if (_titreNRreset) { _titreNRreset.style.removeProperty('margin-top'); }\r\n                var _before = this.style.border;\r\n                this.style.removeProperty('border');\r\n                \/\/ \u2705 v2.4.3 \/ v4.9ds : Forcer 3px solid !important pour surpasser le CSS Elementor\r\n                \/\/ \u2705 v4.9ds : gris #EEEEEE \u2192 #BBBBBB (plus fonc\u00e9, demande user)\r\n                this.style.setProperty('border', '3px solid #BBBBBB', 'important');\r\n                if (_before) { console.log('\ud83d\udd32 Reset bordure sur', this.id, '| avant:', _before); }\r\n                $(this).css('background', '#F8F8F8');\r\n                \/\/ v4.9ds : marquer r\u00e9duit + basculer SVG du bouton\r\n                this.setAttribute('data-via-reduit', 'true');\r\n                \/\/ \u2705 pb224 : item devient inactif \u2192 si le titre \"Nouvelle r\u00e9servation\" est\r\n                \/\/   encore affich\u00e9, remonter son margin-top \u00e0 -20px (inline, coh\u00e9rent avec le\r\n                \/\/   -10px pos\u00e9 \u00e0 la r\u00e9activation dans setItemActif \u2192 pas de conflit CSS\/inline).\r\n                var _titreNRinact = this.querySelector('.via-nouvelle-resa-titre');\r\n                if (_titreNRinact) { _titreNRinact.style.setProperty('margin-top', '-20px', 'important'); }\r\n                \/\/ pb77 : item inactif \u2192 margin-top 12px inline (r\u00e9siste au ResizeObserver)\r\n                var _cpReset = this.querySelector('#CampagnePage');\r\n                if (_cpReset) {\r\n                    \/\/ pb1006 : items INACTIFS sur MOBILE descendus de 20px (16 -> 36).\r\n                    \/\/   C'est CE writer qui s'applique (log user : \"[pb77 DIAG inactif]\r\n                    \/\/   #CampagnePage mt: ... -> 1px\"), pas celui de yearbook-media.js\r\n                    \/\/   que j'avais modifie en pb1003 \u2014 sa branche n'est jamais prise\r\n                    \/\/   (aucun log [pb809] dans le releve).\r\n                    \/\/   La valeur reste passee dans le knob unique _mt801 : on ajuste la\r\n                    \/\/   BASE, aucun writer supplementaire, pas d'empilement.\r\n                    \/\/   Desktop inchange (20px). Revert : window._viaPb1006Off = true.\r\n                    var _mtReset = (window.outerWidth < 1000)\r\n                        ? ((window._viaPb1006Off === true) ? '16px' : '36px')\r\n                        : '20px'; \/\/ pb90 +8px desktop\r\n                    _cpReset.style.setProperty('margin-top', window.VIA_Panier._mt801(_mtReset), 'important');   \/\/ pb801\/pb805\r\n                }\r\n                var _btnR = this.querySelector('.via-reduire-btn');\r\n                if (_btnR) {\r\n                    var _svgA = _btnR.getAttribute('data-via-svg-agrandir');\r\n                    if (_svgA) { _btnR.innerHTML = decodeURIComponent(_svgA); }\r\n                    _btnR.setAttribute('aria-label', 'Agrandir');\r\n                    _btnR.setAttribute('title', 'Agrandir');\r\n                }\r\n                \/\/ \u2705 pb503 : item INACTIF -> title du bouton S\u00e9lectionner reste \"S\u00e9lectionner\"\r\n                \/\/   (reset systematique ; seul l item REELLEMENT actif passe a \"S\u00e9lectionn\u00e9\",\r\n                \/\/   pose plus bas juste apres data-via-item-actif=\"true\").\r\n                var _btnSelR503 = this.querySelector('.via-selectionner-btn');\r\n                if (_btnSelR503) {\r\n                    _btnSelR503.setAttribute('title', 'S\u00e9lectionner');\r\n                    _btnSelR503.setAttribute('aria-label', 'S\u00e9lectionner');\r\n                }\r\n                \/\/ \u2705 v4.9ds Fix 18 : title \"Supprimer\" sur la croix de fermeture (demande user)\r\n                var _btnC = this.querySelector('.CampagneCloseButton');\r\n                if (_btnC) {\r\n                    _btnC.setAttribute('aria-label', 'Supprimer');\r\n                    _btnC.setAttribute('title', 'Supprimer');\r\n                    \/\/ \u00c9galement sur le <a> et <img> internes (Elementor) pour que le tooltip\r\n                    \/\/   apparaisse quel que soit l'\u00e9l\u00e9ment pr\u00e9cis survol\u00e9.\r\n                    var _btnCa = _btnC.querySelector('a');\r\n                    if (_btnCa) { _btnCa.setAttribute('title', 'Supprimer'); }\r\n                    var _btnCi = _btnC.querySelector('img');\r\n                    if (_btnCi) { _btnCi.setAttribute('alt', 'Supprimer'); _btnCi.setAttribute('title', 'Supprimer'); }\r\n                }\r\n                \/\/ v4.9ds : flag no-ref (en r\u00e9alit\u00e9 = \"1\u00e8re ligne CampagneNoClass non\r\n                \/\/   affich\u00e9e\") \u2192 masquer le bouton R\u00e9duire\/Agrandir tant que la\r\n                \/\/   1\u00e8re ligne n'est pas visible. Demande user : pas de r\u00e9duction\r\n                \/\/   possible si la ligne d'identification de la commande n'est m\u00eame\r\n                \/\/   pas affich\u00e9e (item en cours de cr\u00e9ation, anticip\u00e9e sans r\u00e9f\u00e9rence\r\n                \/\/   compl\u00e8te, etc.). On lit directement la visibilit\u00e9 de l'\u00e9l\u00e9ment\r\n                \/\/   au lieu de la r\u00e9f\u00e9rence \u2014 plus robuste car refl\u00e8te exactement ce\r\n                \/\/   que l'utilisateur voit (CampagneNoClass est .show()\/hide()'d\r\n                \/\/   dans remplirItemPartiel selon hasAnnonce\/isReserved).\r\n                var _noClassEl = this.querySelector('.CampagneNoClass');\r\n                var _noClassVisible = false;\r\n                if (_noClassEl) {\r\n                    var _ncCs = window.getComputedStyle(_noClassEl);\r\n                    _noClassVisible = _ncCs.display !== 'none'\r\n                        ? _ncCs.visibility !== 'hidden' ? parseFloat(_ncCs.opacity) > 0 : false\r\n                        : false;\r\n                }\r\n                if (_noClassVisible) {\r\n                    this.removeAttribute('data-via-no-ref');\r\n                } else {\r\n                    this.setAttribute('data-via-no-ref', 'true');\r\n                }\r\n                \/\/ [pb77 DIAG inactif] mesure APR\u00c8S (setTimeout 0 pour laisser CSS recalculer)\r\n                (function(_el77, _pays77, _topAv77, _mtAv77, _ptAv77) {\r\n                    setTimeout(function() {\r\n                        var _cpAp77 = _el77.querySelector('#CampagnePage');\r\n                        var _topAp77 = _pays77 ? Math.round(_pays77.getBoundingClientRect().top) : null;\r\n                        var _mtAp77 = _cpAp77 ? window.getComputedStyle(_cpAp77).marginTop : null;\r\n                        var _mtInl77 = _cpAp77 ? _cpAp77.style.marginTop : null;\r\n                        var _ptAp77 = window.getComputedStyle(_el77).paddingTop;\r\n                        var _delta77 = (_topAv77 !== null ? _topAp77 !== null : false) ? (_topAp77 - _topAv77) : '?';\r\n                        console.log('[pb77 DIAG inactif] item:', _el77.id,\r\n                            '| \u0394top pays:', _delta77, 'px',\r\n                            '| #CampagnePage mt:', _mtAv77, '\u2192', _mtAp77, '(inline:', _mtInl77 + ')',\r\n                            '| item pt:', _ptAv77, '\u2192', _ptAp77);\r\n                    }, 50);\r\n                })(_self77, _paysDiag77, _topAvant77, _mtAvant77, _ptAvant77);\r\n            });\r\n            \r\n            \/\/ \u2705 v4.9ds Pb 7 : liser\u00e9 vert sur #ProcessAchatInside RETIR\u00c9 (demande user).\r\n            \/\/   Les liser\u00e9s sur l'item .CampagneTemplateClass actif sont conserv\u00e9s.\r\n            \/\/ $('#ProcessAchatInside')[0].style.setProperty('border', '3px solid #00fa19', 'important');\r\n            \r\n            \/\/ \u2705 Marquer visuellement l'item actif\r\n            const $item = $(`#${itemId}`);\r\n            const isMobile = window.outerWidth < 1000;\r\n            \r\n            \/\/ pb1522 : UN ESPACE EN ATTENTE N'A PAS DE CARTE \u2014 setItemActif doit le supporter.\r\n            \/\/   $item[0] etait dereference sans garde ici (et l.8096 pour l'attribut).\r\n            \/\/   Depuis pb1516\/pb1520, l'item actif peut legitimement n'avoir aucune carte\r\n            \/\/   dans le DOM : $item[0] vaut alors undefined et la TypeError remontait\r\n            \/\/   AVANT `this.state.itemActif = itemId`, plus bas. Consequence observee dans\r\n            \/\/   le log : \"Cannot read properties of undefined (reading 'style') at\r\n            \/\/   setItemActif\", puis itemActif NULL, puis les dates rattachees a personne\r\n            \/\/   (\"[pb958] dates NON restituees \u2014 elles appartiennent a (inconnu)\").\r\n            \/\/   Le marquage visuel est simplement saute ; l'etat logique, lui, doit passer.\r\n            \/\/   Revert : window._viaPb1522Off = true.\r\n            var _aCarte1522 = ($item.length > 0);\r\n            if (window._viaPb1522Off === true) { _aCarte1522 = true; }\r\n            if (!_aCarte1522) {\r\n                console.log('[pb1522] item actif sans carte (espace en attente) \u2014 marquage visuel saute | ' + itemId);\r\n            }\r\n            if (isMobile ? _aCarte1522 : false) {\r\n                console.log('\u2705 [setItemActif] Liser\u00e9 vert MOBILE sur:', itemId);\r\n                $item[0].style.setProperty('border', '3px solid #00fa19', 'important');\r\n                $item.css('background', '#F8F8F8');\r\n            } else if (_aCarte1522) {\r\n                console.log('\u2705 [setItemActif] Liser\u00e9 vert DESKTOP sur:', itemId);\r\n                $item[0].style.setProperty('border', '3px solid #00fa19', 'important');\r\n                $item.css('background', '#f8f8f8');  \/* pb218 : gris clair comme les r\u00e9sa inactives (\u00e9tait #ffffff) *\/\r\n                \/\/ pb220 T3 : d\u00e9calage des textes bleus d\u00e9plac\u00e9 dans remplirItemPartiel\r\n                \/\/   (data-via-areserver y est pos\u00e9, et c'est le dernier maillon du flux).\r\n            }\r\n            \/\/ \u2705 pb227 : marquer l'item R\u00c9ELLEMENT actif (celui qui re\u00e7oit le liser\u00e9 vert)\r\n            \/\/   avec data-via-item-actif. La couleur du picto S\u00e9lectionner d\u00e9pend de CET\r\n            \/\/   attribut, et NON de data-via-reduit (r\u00e9duit\/agrandi) \u2014 sinon cliquer\r\n            \/\/   R\u00e9duire\/Agrandir changeait la couleur de S\u00e9lectionner \u00e0 tort.\r\n            $(this.config.templateItem).removeAttr('data-via-item-actif');\r\n            \/\/ pb1522b : meme garde \u2014 pas de carte, pas d'attribut a poser.\r\n            if (_aCarte1522) { $item[0].setAttribute('data-via-item-actif', 'true'); }\r\n            \/\/ \u2705 pb503 : resa REELLEMENT active (data-via-item-actif) -> title du bouton\r\n            \/\/   S\u00e9lectionner passe a \"S\u00e9lectionn\u00e9\". Cet attribut est le meme critere que\r\n            \/\/   celui deja utilise pour la couleur du picto (pb227, cf CSS ligne ~780) \u2014\r\n            \/\/   PAS data-via-reduit (r\u00e9duit\/agrandi change sans changer l item actif).\r\n            var _btnSelA503 = $item.length ? $item[0].querySelector('.via-selectionner-btn') : null;\r\n            if (_btnSelA503) {\r\n                _btnSelA503.setAttribute('title', 'S\u00e9lectionn\u00e9');\r\n                _btnSelA503.setAttribute('aria-label', 'S\u00e9lectionn\u00e9');\r\n            }\r\n            \/\/ \u2705 pb224 : si le titre \"Nouvelle r\u00e9servation\" est encore affich\u00e9 ET que la r\u00e9sa\r\n            \/\/   REDEVIENT active (r\u00e9activation, pas la 1re fois), passer son margin-top \u00e0 -10px.\r\n            \/\/   Flag data-via-activated-once pos\u00e9 \u00e0 la 1re activation (tous contextes).\r\n            (function() {\r\n                \/\/ pb1522c : seconde deference non gardee de la meme fonction. Sans carte,\r\n                \/\/   $item[0] est undefined et cette IIFE relancait la meme TypeError trois\r\n                \/\/   lignes apres celle que pb1522 vient de fermer.\r\n                if (!_aCarte1522) { return; }\r\n                var _titreNRel = $item[0].querySelector('.via-nouvelle-resa-titre');\r\n                if (_titreNRel) {\r\n                    if ($item[0].getAttribute('data-via-activated-once') === '1') {\r\n                        \/\/ r\u00e9activation \u2192 -10px\r\n                        _titreNRel.style.setProperty('margin-top', '-10px', 'important');\r\n                    } else {\r\n                        \/\/ \u2705 pb224 : 1re activation (cr\u00e9ation) \u2192 conserver le margin-top d'origine\r\n                        \/\/   (9px en 2 colonnes, 0px en 3 colonnes). Contre le -20px pos\u00e9 par la\r\n                        \/\/   boucle reset qui passe sur le nouvel item avant qu'il soit actif.\r\n                        var _is3ColNR224 = sessionStorage.getItem('PageWebColonneOpenclose') === 'Open';\r\n                        _titreNRel.style.setProperty('margin-top', _is3ColNR224 ? '0px' : '9px', 'important');\r\n                    }\r\n                }\r\n                $item[0].setAttribute('data-via-activated-once', '1');\r\n            })();\r\n            var _cpActif = $item.length ? $item[0].querySelector('#CampagnePage') : null;\r\n            if (_cpActif) {\r\n                var _mtActif = (window.outerWidth < 1000) ? '22px' : '20px'; \/\/ pb90 +8px desktop\r\n                _cpActif.style.setProperty('margin-top', window.VIA_Panier._mt801(_mtActif), 'important');   \/\/ pb801\/pb805\r\n            }\r\n            \/\/ v4.9ds : item actif \u2192 agrandi par d\u00e9faut (data-via-reduit=\"false\") + SVG R\u00e9duire\r\n            if ($item.length) {\r\n                $item[0].setAttribute('data-via-reduit', 'false');\r\n                var _btnRA = $item[0].querySelector('.via-reduire-btn');\r\n                if (_btnRA) {\r\n                    var _svgRA = _btnRA.getAttribute('data-via-svg-reduire');\r\n                    if (_svgRA) { _btnRA.innerHTML = decodeURIComponent(_svgRA); }\r\n                    _btnRA.setAttribute('aria-label', 'R\u00e9duire');\r\n                    _btnRA.setAttribute('title', 'R\u00e9duire');\r\n                }\r\n            }\r\n            console.log('\ud83d\udd0d [setItemActif] Apr\u00e8s marquage \u2014 tous les items et leurs bordures:');\r\n            $(this.config.templateItem).each(function() {\r\n                if (this.style.border) { console.log('  \u26a0\ufe0f', this.id, '\u2192 border:', this.style.border); }\r\n            });\r\n            \r\n            this.deplacerItemEnHaut(itemId);\r\n            \r\n            this.state.itemActif = itemId;\r\n            \r\n            \/\/ \u2705 v4.9ds : forcer un re-scan des couleurs des \u00e9tapes Recap\/Dates\r\n            \/\/   \u00e0 chaque changement d'item actif. La couleur d\u00e9pend de l'\u00e9tat de\r\n            \/\/   r\u00e9servation de l'item actif (\u00c0 r\u00e9server \/ R\u00e9serv\u00e9e), donc switcher\r\n            \/\/   d'item peut changer les couleurs.\r\n            \/\/ \u2705 v4.9ds Pb 4 : retries pour battre les setTimeout(1000) externes\r\n            \/\/   (notamment celui dans yearbook-media qui pose la couleur active sur Recap\r\n            \/\/   apr\u00e8s 1s). Sans ces retries, le watchdog tournait avant que le DOM soit\r\n            \/\/   color\u00e9, et le rouge \"d\u00e9faut\" r\u00e9-\u00e9crasait le bleu correct.\r\n            try {\r\n                if (typeof window._viaScanEtapeColors === 'function') {\r\n                    window._viaScanEtapeColors();\r\n                    [200, 600, 1100, 1500, 2200].forEach(function(_t) {\r\n                        setTimeout(function() {\r\n                            if (typeof window._viaScanEtapeColors === 'function') {\r\n                                window._viaScanEtapeColors();\r\n                            }\r\n                        }, _t);\r\n                    });\r\n                }\r\n            } catch(_eC) {}\r\n            \/\/ \u2705 v4.9ds Pb 7 : d\u00e9placer ProcessAchatInside dans l'item actif si R\u00e9serv\u00e9+agrandi\r\n            try {\r\n                if (typeof window._viaUpdateProcessAchatLocation === 'function') {\r\n                    window._viaUpdateProcessAchatLocation();\r\n                }\r\n            } catch(_ePAI) {}\r\n            \/\/ \u2705 v4.9ds Pb 3 : re-cocher la checkbox \"R\u00e9server cet espace publicitaire\" dans\r\n            \/\/   la page web pour les items r\u00e9serv\u00e9s. Permet \u00e0 l'user de voir visuellement\r\n            \/\/   l'\u00e9tat r\u00e9serv\u00e9 quand il re-s\u00e9lectionne une r\u00e9servation.\r\n            try {\r\n                if (typeof window._viaSyncReserverCheckboxFromItem === 'function') {\r\n                    window._viaSyncReserverCheckboxFromItem();\r\n                    \/\/ Retries pour g\u00e9rer les renders Elementor diff\u00e9r\u00e9s (page iframe)\r\n                    [200, 600, 1500].forEach(function(_t) {\r\n                        setTimeout(function() {\r\n                            if (typeof window._viaSyncReserverCheckboxFromItem === 'function') {\r\n                                window._viaSyncReserverCheckboxFromItem();\r\n                            }\r\n                        }, _t);\r\n                    });\r\n                }\r\n            } catch(_eRC) {}\r\n            \r\n            \/\/ \u2705 Fermer l'\u00e9tape PageWeb si l'item actif vient d'un site pays\r\n            \/\/ \u2705 sujet 8 : exception \u2014 si l'item n'est qu'en Envoi diff\u00e9r\u00e9 sans d\u00e9p\u00f4t (FileReceived!=Yes),\r\n            \/\/              ne pas fermer la PageWeb. Seul un d\u00e9p\u00f4t d'annonce ou un clic R\u00e9server doit fermer.\r\n            \/\/ \u2705 v4.9ds+ (suite 6) Pb Reserver content : exception suppl\u00e9mentaire \u2014 si l'item est\r\n            \/\/   PARTIEL (ni FileReceived ni EnvoiUlterieur), c'est une nouvelle s\u00e9lection pays\/secteur\/\r\n            \/\/   format en cours ; la PageWeb doit rester ouverte pour que l'utilisateur puisse\r\n            \/\/   s\u00e9lectionner l'emplacement publicitaire sur la nouvelle page charg\u00e9e.\r\n            var _activeItemForClose = this.state.items.find(function(i) { return i.id === itemId; });\r\n            if (_activeItemForClose) {\r\n              if (_activeItemForClose.pays) {\r\n                var _diAIFC = _activeItemForClose.donneesIframe || {};\r\n                var _hasFileAIFC = _diAIFC.FileReceived === 'Yes';\r\n                var _euAIFC = _diAIFC.EnvoiUlterieur;\r\n                var _hasEnvDAIFC = (_euAIFC === 'true' || _euAIFC === true || _euAIFC === 'Yes');\r\n                var _isEnvoiDiffereSeul = false;\r\n                if (_hasEnvDAIFC) { if (!_hasFileAIFC) { _isEnvoiDiffereSeul = true; } }\r\n                \/\/ \u2705 v4.9ds+ (suite 6) : item partiel = ni d\u00e9p\u00f4t ni envoi diff\u00e9r\u00e9\r\n                var _isItemPartielSansDepot = false;\r\n                if (!_hasFileAIFC) { if (!_hasEnvDAIFC) { _isItemPartielSansDepot = true; } }\r\n                if (_isEnvoiDiffereSeul) {\r\n                    console.log('\u2139\ufe0f [sujet 8 setItemActif] Envoi diff\u00e9r\u00e9 pur \u2014 PageWeb reste ouvert');\r\n                } else if (_isItemPartielSansDepot) {\r\n                    console.log('\u2139\ufe0f [Pb Reserver setItemActif] Item partiel sans d\u00e9p\u00f4t ni envoi diff\u00e9r\u00e9 \u2014 PageWeb reste ouvert');\r\n                } else {\r\n                    if (typeof this.fermerPageWeb === 'function') { this.fermerPageWeb(true); }\r\n                }\r\n              }\r\n            }\r\n            \r\n            \/\/ \u2705 v2.7 : R\u00e9initialiser dernierResultatCalcul au changement d'item\r\n            \/\/ \u00c9vite que le tarif de l'item pr\u00e9c\u00e9dent soit attribu\u00e9 au nouvel item (multi-achat)\r\n            if (window.VIA_App && window.VIA_App.state) {\r\n                window.VIA_App.state.dernierResultatCalcul = null;\r\n            }\r\n                    \r\n            \/\/ \u2705 Pr\u00e9parer sessionStorage et appeler GetURLCommande\r\n            if (window.VIA_Adaptateur) {\r\n                const item = this.state.items.find(i => i.id === itemId);\r\n                \r\n                if (item) {\r\n                    \/\/ \u2705 v2.7 : Restaurer item.format depuis sessionStorage si null\r\n                    \/\/ Le format peut \u00eatre absent si le tarif a \u00e9t\u00e9 calcul\u00e9 via Formulaire.txt sans passer par item.format\r\n                    if (!item.format && item.emplacementPageWeb) {\r\n                        for (let _si = 1; _si <= 20; _si++) {\r\n                            if (sessionStorage.getItem('Commande_Emplacement_Page_Web' + _si) === item.emplacementPageWeb) {\r\n                                const _ssFmt = sessionStorage.getItem('Commande_Format_Transmis' + _si);\r\n                                const _ssPos = sessionStorage.getItem('PositionDataVosCampagnes' + _si);\r\n                                const _ssDur = parseInt(sessionStorage.getItem('Duree_de_la_campagne' + _si)) || 0;\r\n                                if (_ssFmt) { item.format = _ssFmt; console.log('\ud83d\udccb [setItemActif] format restaur\u00e9 depuis sessionStorage:', _ssFmt); }\r\n                                if (_ssPos && !item.position) { item.position = _ssPos; }\r\n                                if (_ssDur && !item.duree) { item.duree = _ssDur; }\r\n                                break;\r\n                            }\r\n                        }\r\n                    }\r\n                    \r\n                    \/\/ \u2705 Forcer CampagneClose=Yes avant navigation : \u00e9vite le blocage\r\n                    \/\/ si l'iframe pr\u00e9c\u00e9dente n'a pas encore d\u00e9clench\u00e9 handleIframeReady\r\n                    sessionStorage.setItem('CampagneClose', 'Yes');\r\n                    \r\n                    window.VIA_Adaptateur.syncItemToSessionStorage(itemId);\r\n                    \r\n                    \/\/ \u2705 v1.11 : Ne pas charger de page pour un item anticip\u00e9 (pays ou secteur seul)\r\n                    \/\/ \u2705 v2.7 : En mode=popup (site pays), ne pas appeler GetURLCommandeFromItem\r\n                    \/\/ La page web est d\u00e9j\u00e0 l'article du site pays \u2014 charger l'iframe ici cr\u00e9erait un double chargement dans le popup\r\n                    var _isPopupSkipNav = window.location.search.indexOf('mode=popup') !== -1;\r\n                    if (_isPopupSkipNav) {\r\n                        console.log('\u23ed\ufe0f [setItemActif] GetURLCommandeFromItem ignor\u00e9 \u2014 mode=popup, page d\u00e9j\u00e0 charg\u00e9e');\r\n                    } else if (typeof window.GetURLCommandeFromItem === 'function' && item.statut !== 'anticipee') {\r\n                        console.log('\ud83d\udd17 Appel GetURLCommandeFromItem');\r\n                        window.GetURLCommandeFromItem(item);\r\n                    } else if (item.statut === 'anticipee') {\r\n                        \/\/ ====================================================================\r\n                        \/\/ pb1029 : UNE RESA ANTICIPEE PEUT AVOIR UNE PAGE A OUVRIR.\r\n                        \/\/   Constat user (mobile) : deux resas creees par clic sur un lien \u2014\r\n                        \/\/   en basculant de l'une a l'autre, l'affichage inline restait sur la\r\n                        \/\/   page de la premiere. pb1028 a corrige la moitie du probleme (l'URL\r\n                        \/\/   est bien posee sur la resa, le log le confirme), mais le\r\n                        \/\/   chargement restait bloque ICI.\r\n                        \/\/   Le skip date de v1.11 : une resa 'anticipee' naissait alors du clic\r\n                        \/\/   pays ou secteur, AVANT qu'une URL existe \u2014 il n'y avait donc rien a\r\n                        \/\/   charger, et appeler GetURLCommandeFromItem aurait charge la page de\r\n                        \/\/   la resa precedente. Le critere \"statut anticipee\" servait de\r\n                        \/\/   raccourci pour dire \"pas encore d'URL\".\r\n                        \/\/   Depuis pb989\/pb1028, une resa creee par clic sur un lien est\r\n                        \/\/   anticipee ET porte son URL des sa creation : le raccourci est\r\n                        \/\/   devenu faux. On teste donc ce qui compte reellement \u2014 la PRESENCE\r\n                        \/\/   d'une URL \u2014 plutot que le statut, qui n'en etait qu'un indice.\r\n                        \/\/   Une anticipee sans URL (clic pays \/ secteur) continue d'etre\r\n                        \/\/   ignoree, exactement comme avant.\r\n                        \/\/   Revert : window._viaPb1029Off = true.\r\n                        \/\/ ====================================================================\r\n                        var _url1029 = (window._viaPb1029Off === true)\r\n                            ? ''\r\n                            : (item.linkSecteurPage\r\n                                || (item.donneesIframe ? item.donneesIframe.LoadedPageUrl : '')\r\n                                || '');\r\n                        if (_url1029 ? (typeof window.GetURLCommandeFromItem === 'function') : false) {\r\n                            console.log('[pb1029] r\u00e9sa anticip\u00e9e MAIS porteuse d une URL -> chargement de ' + _url1029);\r\n                            window.GetURLCommandeFromItem(item);\r\n                        } else {\r\n                            console.log('\u23ed\ufe0f [setItemActif] GetURLCommandeFromItem ignor\u00e9 \u2014 item anticip\u00e9e (sans URL)');\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            \r\n            this.afficherEtape1DansItem(itemId);\r\n            this.mettreAJourCouleursTitres(itemId);\r\n            this.mettreEnAvantSelection(itemId);\r\n            \r\n            \/\/ \u2705 v2.4.3 : Blanc ins\u00e9cable si pas de tarif (conserve la hauteur), texte original sinon\r\n            var _itemActifTarif = this.state.items.find(function(i) { return i.id === itemId; });\r\n            if (_itemActifTarif) {\r\n                var $_e1msgSIA = $('#Etape1MessageTexte');\r\n                if ($_e1msgSIA.length) {\r\n                    if (!$_e1msgSIA.data('orig')) { $_e1msgSIA.data('orig', $_e1msgSIA.html()); }\r\n                    if (!_itemActifTarif.tarifHT) {\r\n                        $_e1msgSIA.html('&nbsp;');\r\n                    } else {\r\n                        $_e1msgSIA.html($_e1msgSIA.data('orig'));\r\n                    }\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 v2.4.7 : Rafra\u00eechir le message de l'item actif (d\u00e9l\u00e9gu\u00e9 \u00e0 ajouterMsgAccompagnement)\r\n            if (typeof window.updateRecapInfoMessage === 'function') {\r\n                const _itemActif = this.state.items.find(i => i.id === itemId);\r\n                const _urlActif = _itemActif && (\r\n                    (_itemActif.donneesIframe && _itemActif.donneesIframe.LoadedPageUrl)\r\n                    || _itemActif.linkSecteurPage\r\n                    || ''\r\n                );\r\n                window.updateRecapInfoMessage(_urlActif);\r\n            }\r\n            \r\n            console.log('\u2705 Item actif:', itemId);\r\n            \/\/ ================================================================\r\n            \/\/ pb1283d : LE NETTOYAGE SE BRANCHE SUR setItemActif.\r\n            \/\/   Constat user : l'invite reste sur une resa inactive, et AUCUNE\r\n            \/\/   ligne [pb1283] n'apparait \u2014 le nettoyage pose dans le sequenceur\r\n            \/\/   ne s'execute donc pas dans ce scenario, quelle qu'en soit la\r\n            \/\/   raison. J'ai deja perdu deux tours a le placer ailleurs.\r\n            \/\/   On le met a l'endroit dont le log prouve qu'il passe, et qui est\r\n            \/\/   de surcroit le bon moment : le changement de reservation active.\r\n            \/\/   C'est exactement quand l'invite doit changer de carte.\r\n            \/\/   Critere : contains() depuis la carte de la resa activee \u2014 aucune\r\n            \/\/   hypothese sur les classes, c'est ce qui avait fait echouer\r\n            \/\/   pb1283b (le noeud porteur de l'id n'est pas .CampagneTemplateClass).\r\n            \/\/   Revert : window._viaPb1283Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1283Off !== true) {\r\n                try {\r\n                    var _carte1283d = itemId ? document.getElementById(itemId) : null;\r\n                    var _inv1283d = document.querySelectorAll('.via-invite-haut-1262');\r\n                    for (var _n1283d = _inv1283d.length - 1; _n1283d >= 0; _n1283d--) {\r\n                        var _e1283d = _inv1283d[_n1283d];\r\n                        if (_carte1283d ? _carte1283d.contains(_e1283d) : false) { continue; }\r\n                        if (_e1283d.parentNode) { _e1283d.parentNode.removeChild(_e1283d); }\r\n                        console.log('[pb1283] invite retir\u00e9e d\\'une carte inactive'\r\n                            + ' | active = ' + (itemId || '(aucune)'));\r\n                    }\r\n                    \/\/ ============================================================\r\n                    \/\/ pb1284 : REEVALUER, PAS SEULEMENT NETTOYER (demande user).\r\n                    \/\/   Retirer l'invite des autres cartes ne suffit pas : la carte\r\n                    \/\/   qui vient d'etre activee doit etre RE-EXAMINEE tout de\r\n                    \/\/   suite \u2014 l'invite y est peut-etre attendue, et rien ne\r\n                    \/\/   garantit qu'une autre passe viendra la poser.\r\n                    \/\/   _inviteEspace1262 porte deja toutes les conditions (carte\r\n                    \/\/   active, espace non reserve, page web connue) : on l'appelle,\r\n                    \/\/   on ne les reecrit pas.\r\n                    \/\/ ============================================================\r\n                    var _it1284 = null;\r\n                    var _its1284 = (this.state ? (this.state.items || []) : []);\r\n                    for (var _k1284 = 0; _k1284 < _its1284.length; _k1284++) {\r\n                        if (_its1284[_k1284] ? (_its1284[_k1284].id === itemId) : false) {\r\n                            _it1284 = _its1284[_k1284];\r\n                            break;\r\n                        }\r\n                    }\r\n                    if (_carte1283d ? !!_it1284 : false) {\r\n                        this._inviteEspace1262($(_carte1283d), _it1284);\r\n                    }\r\n                } catch (_e1283d) { console.warn('[pb1283]', _e1283d.message); }\r\n            }\r\n            \r\n            \/\/ \u2705 Si l'accord\u00e9on dates est ouvert \u2192 mettre \u00e0 jour #MsgBlockDates \/ #ProcessAchatInside selon le statut\r\n            if (typeof window.updateBlockDates === 'function' && jQuery('.DatesDureeCampagneClass').is(':visible')) {\r\n                const _itemForBlock = this.state.items.find(i => i.id === itemId);\r\n                window.updateBlockDates(_itemForBlock);\r\n            }\r\n\r\n            \/\/ pb662 : DIRECTION A sur CHANGEMENT d'item actif. pb651d ne couvre que\r\n            \/\/   mettreAJourItem (modification de DONNEES) ; en switchant d'une resa a\r\n            \/\/   une autre, le popup Tarifs restait sur l'ancien item. Timer partage\r\n            \/\/   avec pb651d (_pb651dTimer) pour eviter une double synchro.\r\n            try {\r\n                var _pop662 = document.getElementById('popup3');\r\n                var _ouv662 = _pop662 ? _pop662.classList.contains('active') : false;\r\n                var _lock662 = window._sync651AClic ? true : (window._sync651EnCours ? true : false);\r\n                if (_ouv662 ? !_lock662 : false) {\r\n                    if (typeof window.viaSyncVersPopupTarifs651 === 'function') {\r\n                        var _it662 = this.state.items ? this.state.items.find(function(x) { return x.id === itemId; }) : null;\r\n                        \/\/ pb666 : ne PAS piloter le popup depuis un item VIDE. Une resa\r\n                        \/\/   \"anticipee\" (creee au clic pays\/secteur) n'a ni pays, ni dates,\r\n                        \/\/   ni format, ni tarif. La sync A laissait alors le popup sur\r\n                        \/\/   l'etat de la resa PRECEDENTE, puis pb651o re-selectionnait ce\r\n                        \/\/   tarif et pb651m le poussait dans le NOUVEL item : la resa 2\r\n                        \/\/   heritait du tarif de la resa 1 (mesure : 441 EUR, total 882).\r\n                        var _ok666 = this._syncAAutorisee666(_it662);\r\n                        if (_it662 ? !_ok666 : false) {\r\n                            console.log('[pb666] resa incomplete (statut ' + _it662.statut + ') -> sync A ignoree');\r\n                        }\r\n                        if (_ok666) {\r\n                            window.clearTimeout(window._pb651dTimer);\r\n                            var _ref662 = _it662;\r\n                            window._pb651dTimer = window.setTimeout(function() {\r\n                                console.log('[pb662] switch item actif + popup ouvert -> sync A');\r\n                                if (typeof window.viaSyncVersPopupTarifs651 === 'function') {\r\n                                    window.viaSyncVersPopupTarifs651(_ref662);\r\n                                }\r\n                            }, 300);\r\n                        }\r\n                    }\r\n                }\r\n            } catch (e662) { console.warn('[pb662]', e662.message); }\r\n        },\r\n        \r\n        \/**\r\n         * R\u00e9cup\u00e8re le pays commun \u00e0 toutes les commandes\r\n         *\/\r\n        getPaysCommun() {\r\n            const paysUnique = [...new Set(\r\n                this.state.items\r\n                    .filter(i => i.pays)\r\n                    .map(i => i.pays)\r\n            )];\r\n            \r\n            return paysUnique.length === 1 ? paysUnique[0] : null;\r\n        },\r\n        \r\n        \/**\r\n         * Met \u00e0 jour le pays dans TOUTES les commandes et recalcule les tarifs\r\n         *\/\r\n        async mettreAJourPaysGlobal(nouveauPays) {\r\n            console.log('\ud83c\udf0d Mise \u00e0 jour pays global:', nouveauPays);\r\n            \r\n            const countryObj = window.VIA_Countries?.getCountryByLabel(nouveauPays);\r\n            \r\n            if (!countryObj) {\r\n                console.warn('\u26a0\ufe0f Pays introuvable:', nouveauPays);\r\n                return;\r\n            }\r\n            \r\n            console.log(`\ud83c\udf0d [PAYS-GLOBAL] countryObj: code=${countryObj.code} | items: ${this.state.items.length}`);\r\n            \r\n            for (const item of this.state.items) {\r\n                item.pays = nouveauPays;\r\n                \/\/ pb669 : mettreAJourPaysGlobal ecrit l'item DIRECTEMENT (il court-circuite\r\n                \/\/   mettreAJourItem, qui est le seul endroit ou paysAnnonceur suivait pays).\r\n                \/\/   Sans cette ligne, le pays PROPAGE n'etait pas AFFICHE : rafraichirItemHTML\r\n                \/\/   rend item.paysAnnonceur, et remplirFormulaireDepuisItem le relit pour\r\n                \/\/   repeupler #form-field-Nationalite_Societe -> l'ancien pays revenait.\r\n                item.paysAnnonceur = nouveauPays;\r\n                \r\n                \/\/ \u2705 v2.7 : Fallback format\/position depuis donneesIframe\r\n                let _fmt = item.format || (item.donneesIframe && item.donneesIframe.Commande_Format_Transmis) || '';\r\n                let _pos = item.position || (item.donneesIframe && item.donneesIframe.position) || '';\r\n                let _dur = item.duree || (item.donneesIframe && item.donneesIframe.duree) || 0;\r\n                \r\n                \/\/ \u2705 Log \u00e9tat brut de l'item avant r\u00e9solution\r\n                console.log(`\ud83d\udd0e [PAYS-GLOBAL] item ${item.reference} | item.format=${item.format} | item.position=${item.position} | item.duree=${item.duree} | item.dateDebut=${item.dateDebut} | item.dateFin=${item.dateFin} | item.emplacementPageWeb=${item.emplacementPageWeb} | item.tarifHT=${item.tarifHT}`);\r\n                console.log(`\ud83d\udd0e [PAYS-GLOBAL] donneesIframe.Commande_Format_Transmis=${item.donneesIframe && item.donneesIframe.Commande_Format_Transmis}`);\r\n                console.log(`\ud83d\udd0e [PAYS-GLOBAL] apr\u00e8s 1er fallback: _fmt=${_fmt} | _pos=${_pos} | _dur=${_dur}`);\r\n                \r\n                \/\/ \u2705 v2.7 : Fallback sessionStorage si item.format toujours vide\r\n                if (!_fmt && item.emplacementPageWeb) {\r\n                    for (let _si = 1; _si <= 20; _si++) {\r\n                        if (sessionStorage.getItem('Commande_Emplacement_Page_Web' + _si) === item.emplacementPageWeb) {\r\n                            const _ssFmt = sessionStorage.getItem('Commande_Format_Transmis' + _si) || '';\r\n                            const _ssPos = sessionStorage.getItem('PositionDataVosCampagnes' + _si) || '';\r\n                            const _ssDur = parseInt(sessionStorage.getItem('Duree_de_la_campagne' + _si)) || 0;\r\n                            console.log(`\ud83d\udd0e [PAYS-GLOBAL] sessionStorage index ${_si}: Commande_Format_Transmis=${_ssFmt} | PositionDataVosCampagnes=${_ssPos} | Duree_de_la_campagne=${_ssDur}`);\r\n                            _fmt = _ssFmt;\r\n                            if (!_pos) _pos = _ssPos;\r\n                            if (!_dur) _dur = _ssDur;\r\n                            if (_fmt) console.log(`\ud83d\udccb [mettreAJourPaysGlobal] format r\u00e9cup\u00e9r\u00e9 depuis sessionStorage (index ${_si}): ${_fmt}`);\r\n                            break;\r\n                        }\r\n                    }\r\n                }\r\n                \r\n                console.log(`\ud83d\udd0e [PAYS-GLOBAL] \u00e9tat final r\u00e9solu: _fmt=${_fmt} | _pos=${_pos} | _dur=${_dur} | dateDebut OK: ${!!(item.dateDebut && item.dateFin)}`);\r\n                \r\n                if (item.dateDebut && item.dateFin && _dur && \r\n                    _fmt && _pos && window.VIA_App) {\r\n                    \r\n                    \/\/ \u2705 v2.7 : Utiliser le proxy same-origin (_viaProxyCalculerTarif) si disponible\r\n                    \/\/ window.VIA_App.calculerTarifAPI appelle via-agency.media \u2192 CORS fail depuis yearbook-media.com\r\n                    \/\/ _viaProxyCalculerTarif appelle window.location.origin\/wp-json\/yearbook\/v1\/calculer-tarif \u2192 same-origin, pas de CORS\r\n                    const _apiFn = window._viaProxyCalculerTarif || window.VIA_App.calculerTarifAPI;\r\n                    \r\n                    console.log(`\ud83d\udcb0 [PAYS-GLOBAL] Lancement recalcul API pour ${item.reference} | format: ${_fmt} | pos: ${_pos} | duree: ${_dur} | paysCible: ${countryObj.code} | proxy: ${!!window._viaProxyCalculerTarif}`);\r\n                    \r\n                    const resultat = await _apiFn(\r\n                        _fmt,\r\n                        _pos,\r\n                        _dur,\r\n                        countryObj.code\r\n                    );\r\n                    \r\n                    console.log(`\ud83d\udd0e [PAYS-GLOBAL] r\u00e9sultat API pour ${item.reference}:`, JSON.stringify(resultat));\r\n                    \r\n                    if (resultat.success) {\r\n                        item.tarifHT = resultat.tarif_ht;\r\n                        item.tarifTTC = resultat.tarif_ttc;\r\n                        item.statut = 'valide';\r\n                        if (!item.format && _fmt) { item.format = _fmt; }\r\n                        if (!item.position && _pos) { item.position = _pos; }\r\n                        console.log(`\u2705 [PAYS-GLOBAL] Tarif mis \u00e0 jour ${item.reference}: ${item.tarifHT} EUR`);\r\n                    } else {\r\n                        console.warn(`\u274c [PAYS-GLOBAL] API \u00e9chec pour ${item.reference} \u2014 tarif inchang\u00e9: ${item.tarifHT} EUR`);\r\n                    }\r\n                } else {\r\n                    console.log(`\u23ed\ufe0f [PAYS-GLOBAL] item ${item.reference} ignor\u00e9 | _fmt=${_fmt} | _dur=${_dur} | dateDebut=${item.dateDebut} | dateFin=${item.dateFin} | VIA_App=${!!window.VIA_App}`);\r\n                }\r\n                \r\n                this.rafraichirItemHTML(item.id);\r\n            }\r\n            \r\n            this.calculerTotalPanier();\r\n            \r\n            if (window.VIA_Paiement && typeof window.VIA_Paiement.rafraichirMontants === 'function') {\r\n                window.VIA_Paiement.rafraichirMontants();\r\n            }\r\n            \r\n            console.log('\u2705 Pays global mis \u00e0 jour dans toutes les commandes');\r\n        },\r\n\r\n        \/**\r\n         * D\u00e9place un item en haut de la liste\r\n         *\/\r\n        deplacerItemEnHaut(itemId) {\r\n            \/\/ pb129 : en popup d'achat, le scroll vers le haut ne doit se produire QUE pour le\r\n            \/\/   clic #AutreCommandeBouton (qui pose window._viaScrollItemToTopOnce). Pour un clic\r\n            \/\/   sur une r\u00e9servation existante, pas de scroll. Flag one-shot : lu et consomm\u00e9 ici.\r\n            var _scrollTop129 = (window._viaScrollItemToTopOnce === true);\r\n            window._viaScrollItemToTopOnce = false;\r\n            \/\/ \u2705 .first() : \u00e9vite la duplication si plusieurs \u00e9l\u00e9ments VosCampagnesConteneurClass dans le DOM (Elementor)\r\n            const $conteneur = $(this.config.conteneurParent).first();\r\n            const $item = $(`#${itemId}`);\r\n            \r\n            if ($conteneur.length === 0 || $item.length === 0) return;\r\n            \r\n            \/\/ \u2705 Sur desktop, arr\u00eater tout scroll en cours avant manipulation DOM\r\n            const isMobile = window.innerWidth <= 767;\r\n            if (!isMobile) {\r\n                $('html, body').stop(true, true);\r\n            }\r\n            \r\n            $conteneur.prepend($item);\r\n            \r\n            \/\/ \u2705 v4.9ds+ : en mode popup (iframe 480px \u2192 isMobile=true), scroller la body\r\n            \/\/   de l'iframe vers le haut. Check popup EN PREMIER car isMobile est true\r\n            \/\/   dans le popup (viewport 480px) et le else if ne s'ex\u00e9cuterait jamais.\r\n            \/\/ pb129 : scroll r\u00e9serv\u00e9 au clic #AutreCommandeBouton (flag _scrollTop129).\r\n            if (document.body.classList.contains('via-popup-achat')) {\r\n                if (_scrollTop129) {\r\n                    $('html, body').animate({ scrollTop: 0 }, 300);\r\n                }\r\n            } else if (isMobile) {\r\n                \/\/ \u2705 Scroll seulement sur mobile (hors popup)\r\n                const conteneurParent = $conteneur.parent();\r\n                if (conteneurParent.length > 0) {\r\n                    conteneurParent.animate({ scrollTop: 0 }, 300);\r\n                }\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * Calcule le total du panier\r\n         *\/\r\n        calculerTotalPanier() {\r\n            let totalHT = 0;\r\n            let hasIndisponible = false;\r\n            \r\n            this.state.items.forEach(item => {\r\n                if (item.disponibilite === false || item.statut === 'indisponible') {\r\n                    hasIndisponible = true;\r\n                }\r\n                \r\n                if (item.tarifHT && item.tarifHT > 0 && item.disponibilite !== false && item.statut !== 'indisponible') {\r\n                    totalHT += item.tarifHT;\r\n                }\r\n            });\r\n            \r\n            this.state.totalPanier = totalHT;\r\n            this.afficherTotal(this.state.deviseAffichage);\r\n            \r\n            \/\/ \u2705 v1.10 : Ne plus afficher la synth\u00e8se automatiquement\r\n            \/\/ L'utilisateur doit cliquer sur #Etape1BoutonValider\r\n            \/\/ if (totalHT > 0) {\r\n            \/\/     this.afficherSynthese();\r\n            \/\/ } else {\r\n            \/\/     $(this.config.syntheseConteneur).hide();\r\n            \/\/ }\r\n            \r\n            \/\/ \u2705 v1.8 : Mettre \u00e0 jour l'\u00e9tape Mode de paiement d\u00e8s que le total change\r\n            if (window.VIA_Paiement && typeof window.VIA_Paiement.rafraichirMontants === 'function') {\r\n                window.VIA_Paiement.rafraichirMontants();\r\n            }\r\n            \r\n            console.log('\ud83d\udcb0 [calculerTotalPanier] total:', totalHT, '| items:', JSON.stringify(this.state.items.map(i => ({id:i.id, statut:i.statut, tarifHT:i.tarifHT}))));\r\n        },\r\n        \r\n        \/**\r\n         * Affiche le total dans le bouton de commande\r\n         *\/\r\n        afficherTotal(deviseAffichage = null) {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            deviseAffichage = deviseAffichage || this.state.deviseAffichage;\r\n            \r\n            const $bouton = $(this.config.boutonCommande);\r\n            \r\n            if ($bouton.length === 0) return;\r\n            \r\n            let totalHT = 0;\r\n            let nbItemsAvecTarif = 0;\r\n            \r\n            this.state.items.forEach(item => {\r\n                \/\/ \u2705 v1.8 : Exclure les items indisponibles du total\r\n                const estIndisponible = item.disponibilite === false || item.statut === 'indisponible';\r\n                if (item.tarifHT && item.tarifHT > 0 && !estIndisponible) {\r\n                    totalHT += item.tarifHT;\r\n                    nbItemsAvecTarif++;\r\n                }\r\n            });\r\n            \r\n            if (nbItemsAvecTarif > 0) {\r\n                const totalConverti = window.VIA_App.convertirDevise(totalHT, 'EUR', deviseAffichage);\r\n                const totalFormate = window.VIA_App.formaterMontant(totalConverti, deviseAffichage, 2);\r\n                \r\n                \/\/ \u2705 v4.9ds Pb 7 : texte singulier vs pluriel selon nbItemsAvecTarif.\r\n                \/\/   \"la r\u00e9servation\" si 1 seule, \"les r\u00e9servations\" si plusieurs.\r\n                \/\/   + couleur rouge #fb5e2a (demande user).\r\n                const _isPlural = nbItemsAvecTarif > 1;\r\n                const texteFinaliser = lang === 'EN'\r\n                    ? (_isPlural ? 'Click here to finalize your orders' : 'Click here to finalize your order')\r\n                    : (_isPlural ? 'Cliquer ici pour finaliser les r\u00e9servations' : 'Cliquer ici pour finaliser la r\u00e9servation');\r\n                const textePrix = lang === 'EN' \r\n                    ? 'Total price'\r\n                    : 'Prix total';\r\n                const texteHT = lang === 'EN' \r\n                    ? 'excl. VAT'\r\n                    : 'H.T.';\r\n                \r\n                \/* pb1859 : la premiere ligne est balisee ici, a la source. *\/\r\n                \/* pb2052 : la SECONDE aussi. Elle etait un noeud texte nu apres le\r\n                   <br> \u2014 rien a cibler en CSS, exactement le probleme que pb1859\r\n                   avait resolu pour la premiere. Meme remede, meme endroit : le\r\n                   seul ecrivain du contenu. *\/\r\n                $bouton.html(`<span class=\"via-fin-l1\">${texteFinaliser}<\/span><br><span class=\"via-fin-l2\">${textePrix} ${totalFormate} ${texteHT}<\/span>`);\r\n                $bouton.css('color', '#FB5E2A');\r\n                $bouton.find('*').css('color', '#FB5E2A');\r\n                \r\n                \/\/ \u2705 v1.10 : Ne plus ouvrir automatiquement le r\u00e9capitulatif\r\n                \/\/ L'utilisateur doit cliquer sur #Etape1BoutonValider\r\n                \/\/ this.ouvrirRecapitulatif();\r\n            } else {\r\n                const texteFinaliser = lang === 'EN' \r\n                    ? 'Click here to finalize your order(s)'\r\n                    : 'Cliquer ici pour finaliser la ou les r\u00e9servation(s)';\r\n                \/* pb1859 : meme balisage dans la branche sans tarif \u2014 c'est le meme\r\n                   libelle d'action, il ne doit pas changer de taille selon le cas. *\/\r\n                $bouton.html('<span class=\"via-fin-l1\">' + texteFinaliser + '<\/span>');\r\n                $bouton.css('color', '#FB5E2A');\r\n                $bouton.find('*').css('color', '#FB5E2A');\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * Calcule la position selon Rank_Emplacement_Page_Web et type de page\r\n         *\/\r\n        calculerPosition(rankEmplacement, typePage) {\r\n            if (!rankEmplacement) {\r\n                console.warn('\u26a0\ufe0f Rank_Emplacement_Page_Web manquant');\r\n                return 'cdp Autres P.';\r\n            }\r\n            \r\n            const match = rankEmplacement.match(\/Ele(\\d+)[A-Z]\/);\r\n            \r\n            if (!match) {\r\n                console.warn('\u26a0\ufe0f Format Rank invalide:', rankEmplacement);\r\n                return 'cdp Autres P.';\r\n            }\r\n            \r\n            const rang = parseInt(match[1]);\r\n            console.log('\ud83d\udcca Rank extrait:', rang, 'de', rankEmplacement);\r\n            \r\n            let positionBase;\r\n            if (rang === 0) {\r\n                positionBase = 'Pop-up';\r\n            } else if (rang === 1 || rang === 2) {\r\n                positionBase = 'hdp';\r\n            } else {\r\n                positionBase = 'cdp';\r\n            }\r\n            \r\n            let position;\r\n            if (positionBase === 'Pop-up') {\r\n                position = typePage === 'Homepage' ? 'Pop-up Homepage' : 'Pop-up Autres P.';\r\n            } else {\r\n                position = typePage === 'Homepage' ? \r\n                    `${positionBase} Home P.` : \r\n                    `${positionBase} Autres P.`;\r\n            }\r\n            \r\n            console.log(`\u2705 Position calcul\u00e9e: ${position} (rang=${rang}, type=${typePage})`);\r\n            return position;\r\n        },\r\n        \r\n        \/**\r\n         * Affiche le conteneur de synth\u00e8se\r\n         * \u2705 v1.7 : Anti-rebond + pas de scroll pendant finalisation\r\n         * \u2705 v1.10 : Ne pas afficher si \u00e9tape suivante ouverte\r\n         *\/\r\n        afficherSynthese() {\r\n            \/\/ \u2705 v1.7 : Anti-rebond pour \u00e9viter les affichages multiples\r\n            if (this.state.syntheseEnCoursAffichage) {\r\n                console.log('\u23ed\ufe0f afficherSynthese() ignor\u00e9 - d\u00e9j\u00e0 en cours');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds Pb 5 : ne plus afficher la synth\u00e8se 15min si aucune r\u00e9servation\r\n            \/\/   avec tarif ne subsiste (toutes les r\u00e9servations avec tarif ont \u00e9t\u00e9\r\n            \/\/   supprim\u00e9es). Demande user.\r\n            try {\r\n                var _hasTarif = false;\r\n                var _items = (this.state ? this.state.items : null) || [];\r\n                for (var _i = 0; _i < _items.length; _i++) {\r\n                    var _t = _items[_i].tarifHT;\r\n                    if (_t ? (_t !== '-' ? _t !== 0 : false) : false) { _hasTarif = true; break; }\r\n                }\r\n                if (!_hasTarif) {\r\n                    var $_sNone = $(this.config.syntheseConteneur);\r\n                    if ($_sNone.length) { $_sNone.hide(); }\r\n                    console.log('\u23ed\ufe0f afficherSynthese() ignor\u00e9 - aucune r\u00e9servation avec tarif');\r\n                    return;\r\n                }\r\n            } catch(_eS) {}\r\n            \r\n            this.state.syntheseEnCoursAffichage = true;\r\n            \r\n            const $synthese = $(this.config.syntheseConteneur);\r\n            const $conteneurParent = $(this.config.conteneurParent);\r\n            \r\n            if ($synthese.length > 0) {\r\n                if ($conteneurParent.length > 0) {\r\n                    $conteneurParent.after($synthese);\r\n                }\r\n                \r\n                $synthese.show();\r\n                console.log('\u2705 Synth\u00e8se affich\u00e9e en bas');\r\n                \r\n                \/\/ \u2705 v1.7 : Ne PAS scroller sur mobile si en mode finalisation\r\n                const isMobile = window.innerWidth <= 767;\r\n                const finaliserStep = sessionStorage.getItem('FinaliserStep');\r\n                \r\n                if (isMobile && finaliserStep !== 'Yes') {\r\n                    \/\/ \u2705 v1.7 : Scroll seulement lors de la PREMI\u00c8RE cr\u00e9ation de commande\r\n                    \/\/ Pas pendant la saisie des r\u00e9f\u00e9rences ou le paiement\r\n                    const isPremiereCommande = this.state.items.length === 1 && !this.state.items[0].dateDebut;\r\n                    \r\n                    if (isPremiereCommande) {\r\n                        setTimeout(() => {\r\n                            $('html, body').animate({ scrollTop: $(document).height() }, 500);\r\n                            console.log('\ud83d\udcf1 Scroll vers le bas (premi\u00e8re commande)');\r\n                        }, 100);\r\n                    } else {\r\n                        console.log('\ud83d\udcf1 Scroll \u00e9vit\u00e9 (pas premi\u00e8re commande ou r\u00e9f\u00e9rences en cours)');\r\n                    }\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 v1.7 : Lib\u00e9rer le flag apr\u00e8s 500ms\r\n            const self = this;\r\n            setTimeout(function() {\r\n                self.state.syntheseEnCoursAffichage = false;\r\n            }, 500);\r\n        },\r\n        \r\n        \/**\r\n         * Met \u00e0 jour l'affichage du r\u00e9capitulatif des commandes\r\n         *\/\r\n        updateRecapitulatif() {\r\n            console.log('\ud83d\udccb [updateRecap] Mise \u00e0 jour r\u00e9capitulatif...');\r\n            console.log('\ud83d\udccb [updateRecap] state.items:', JSON.stringify(this.state.items.map(i => ({id:i.id, ref:i.reference, statut:i.statut, tarifHT:i.tarifHT, emplacementPageWeb:i.emplacementPageWeb}))));\r\n            const $domItems = $('.CampagneTemplateClass').not('#CampagneTemplate');\r\n            console.log('\ud83d\udccb [updateRecap] \u00e9l\u00e9ments DOM CampagneTemplateClass:', $domItems.length);\r\n            \r\n            $domItems.each((index, element) => {\r\n                const $element = $(element);\r\n                const reference = $element.attr('data-reference');\r\n                console.log('\ud83d\udccb [updateRecap] DOM item id:', $element.attr('id'), '| data-reference:', reference);\r\n                \r\n                \/* ============================================================\r\n                 * pb1673 : LA CARTE ETAIT CHERCHEE PAR SA REFERENCE, QU ELLE N A PAS.\r\n                 *   Constat user apres pb1672 :\r\n                 *     [pb1672] \u2192 cach\u00e9 (item introuvable dans le modele)\r\n                 *               id=CampagneTemplate_1787663402546\r\n                 *               data-reference=QLR-???-?????\r\n                 *   L item EXISTE \u2014 c est l appariement qui echoue. Une reservation\r\n                 *   anticipee porte reference=null DANS LE MODELE, tandis que sa carte\r\n                 *   affiche le gabarit XXX-???-????? dans data-reference. La comparaison\r\n                 *   i.reference === reference ne peut donc JAMAIS aboutir tant que la\r\n                 *   reference reelle n est pas attribuee \u2014 c est-a-dire pendant toute la\r\n                 *   phase ou la reservation se construit.\r\n                 *   pb1672 avait raison sur la regle et se trompait de cause : la carte\r\n                 *   n etait pas masquee faute de tarif, mais faute d etre reconnue.\r\n                 *   L identite fiable est l ID : $newItem.attr('id', itemId) le pose a la\r\n                 *   creation, il vaut item.id, il ne change jamais, et c est deja par lui\r\n                 *   que rafraichirItemHTML retrouve ses items. La reference reste en\r\n                 *   repli pour les cartes anciennes qui n auraient pas d id exploitable.\r\n                 *   Consequence sur la garde precedente : une carte sans data-reference\r\n                 *   n est plus masquee d office ; si son id correspond a un item, elle\r\n                 *   est legitime.\r\n                 *   Revert : window._viaPb1673Off = true (appariement par reference seule).\r\n                 * ============================================================ *\/\r\n                const _idDom1673 = $element.attr('id') || '';\r\n                let item = null;\r\n                let _via1673 = 'reference';\r\n                if (window._viaPb1673Off !== true) {\r\n                    if (_idDom1673) {\r\n                        item = this.state.items.find(i => i.id === _idDom1673);\r\n                        if (item) { _via1673 = 'id'; }\r\n                    }\r\n                }\r\n                if (!item) {\r\n                    if (reference) { item = this.state.items.find(i => i.reference === reference); }\r\n                }\r\n                if (!item) {\r\n                    if (!reference) {\r\n                        $element.hide();\r\n                        console.log('\ud83d\udccb [updateRecap] [pb1673] \u2192 cach\u00e9 (ni id ni reference connus) | id='\r\n                            + (_idDom1673 || '?'));\r\n                        return;\r\n                    }\r\n                }\r\n                console.log('\ud83d\udccb [updateRecap] item trouv\u00e9:', item ? ('OUI par ' + _via1673) : 'NON',\r\n                    '| tarifHT:', item ? item.tarifHT : 'N\/A');\r\n                \r\n                \/* ============================================================\r\n                 * pb1672 : UN ITEM SANS TARIF N EST PAS UNE LIGNE FANTOME.\r\n                 *   Ecrivain nomme par le piege pb1670\/pb1671, apres sept tours :\r\n                 *     [pb1670] display = none sur CampagneTemplate_1787663048999\r\n                 *              at HTMLDivElement.<anonymous> (index):27460\r\n                 *   soit ce hide, dans updateRecapitulatif.\r\n                 *   La regle pb1528 confondait DEUX situations sous une seule\r\n                 *   condition :\r\n                 *     - item INTROUVABLE : une carte orpheline, dont l item a\r\n                 *       disparu du modele. La masquer est juste.\r\n                 *     - item TROUVE mais sans tarif : une reservation en cours de\r\n                 *       constitution \u2014 statut anticipee ou attente, espace pas\r\n                 *       encore choisi, tarif pas encore calcule. C est precisement\r\n                 *       l objet du chantier pb1515-pb1529 : ces cartes DOIVENT\r\n                 *       rester visibles, sinon la reservation active disparait\r\n                 *       sous les yeux de l utilisateur.\r\n                 *   Le tarif n arrive qu apres l espace publicitaire ; toute\r\n                 *   reservation passe donc par cet etat. La regle masquait un\r\n                 *   passage oblige.\r\n                 *   On separe les deux cas : orpheline -> masquee ; connue du\r\n                 *   modele -> visible, avec ou sans tarif.\r\n                 *   Revert : window._viaPb1672Off = true (retour a pb1528).\r\n                 * ============================================================ *\/\r\n                \/* item peut etre undefined : ne pas le dereferencer avant de l avoir teste *\/\r\n                var _sansTarif1672 = item ? (!item.tarifHT || item.tarifHT <= 0) : true;\r\n                var _masquer1672 = !item;\r\n                if (window._viaPb1672Off === true) { _masquer1672 = (!item || _sansTarif1672); }\r\n                if (_masquer1672) {\r\n                    $element.hide();\r\n                    console.log('\ud83d\udccb [updateRecap] [pb1672] \u2192 cach\u00e9 (item introuvable dans le modele) | id='\r\n                        + ($element.attr('id') || '?') + ' | data-reference=' + reference);\r\n                } else if (_sansTarif1672) {\r\n                    $element.show();\r\n                    console.log('\ud83d\udccb [updateRecap] [pb1672] \u2192 affich\u00e9 SANS tarif (reservation en cours) | id='\r\n                        + ($element.attr('id') || '?') + ' | statut=' + (item.statut || '-')\r\n                        + ' | actif=' + $element.attr('data-via-item-actif'));\r\n                } else {\r\n                    $element.show();\r\n                    console.log('\ud83d\udccb [updateRecap] \u2192 affich\u00e9 \u2705 tarif:', item.tarifHT);\r\n                }\r\n            });\r\n            \r\n            console.log('\ud83d\udccb [updateRecap] \u2705 Termin\u00e9');\r\n        },\r\n        \r\n        \/**\r\n         * D\u00e9place une annonce vers un nouvel espace publicitaire\r\n         *\/\r\n        async deplacerAnnonce(itemId, nouvellesDonnees) {\r\n            console.log('\ud83d\udd04 D\u00e9placement annonce:', itemId);\r\n            \r\n            const item = this.state.items.find(i => i.id === itemId);\r\n            if (!item) {\r\n                console.error('\u274c Item introuvable');\r\n                return;\r\n            }\r\n            \r\n            const ancienEmplacement = item.emplacementPageWeb;\r\n            const nouvelEmplacement = nouvellesDonnees.Commande_Emplacement_Page_Web;\r\n            \r\n            console.log(`\ud83d\udce6 ${ancienEmplacement} \u2192 ${nouvelEmplacement}`);\r\n            \r\n            \/\/ 1. Construire nouvelle r\u00e9f\u00e9rence\r\n            const emplacementWeb = nouvelEmplacement;\r\n            const codePage = nouvellesDonnees.codePage || item.donneesIframe?.codePage;\r\n            \r\n            const indexCodePage = emplacementWeb.indexOf(codePage);\r\n            const suffixeEspace = indexCodePage >= 0 ? \r\n                emplacementWeb.substring(indexCodePage + codePage.length) : '';\r\n            \r\n            const partiesRef = item.reference.split('-');\r\n            const nouvelleReference = partiesRef.length >= 3 ? \r\n                `${partiesRef[0]}-${partiesRef[1]}-${partiesRef[2]}-${suffixeEspace}` :\r\n                `${item.reference}-${suffixeEspace}`;\r\n            \r\n            \/\/ 2. Calculer nouvelle position (TECHNIQUE)\r\n            const nouvellePosition = this.calculerPosition(\r\n                nouvellesDonnees.Rank_Emplacement_Page_Web,\r\n                sessionStorage.getItem('Commande_Page') || 'Homepage'\r\n            );\r\n            \r\n            \/\/ Mettre \u00e0 jour item\r\n            item.emplacementPageWeb = nouvelEmplacement;\r\n            item.reference = nouvelleReference;\r\n            item.position = nouvellePosition;\r\n            \r\n            if (item.donneesIframe) {\r\n                item.donneesIframe.Commande_Emplacement_Page_Web = nouvelEmplacement;\r\n                item.donneesIframe.Rank_Emplacement_Page_Web = nouvellesDonnees.Rank_Emplacement_Page_Web;\r\n            }\r\n            \r\n            \/\/ 4. Mettre \u00e0 jour affichage\r\n            const $item = $(`#${itemId}`);\r\n            $item.attr('data-reference', nouvelleReference);\r\n            \r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const prefixeRef = lang === 'EN' ? 'Reservation ' : 'R\u00e9servation ';\r\n            const labelEspaceD = lang === 'EN' ? 'Space ' : 'Espace publicitaire ';\r\n            \/\/ \u2705 R\u00e8gles CampagneNoClass : espace r\u00e9serv\u00e9 \u2192 \"Espace r\u00e9serv\u00e9 ESPACE\" (v4.9ds)\r\n            \/\/ \u2705 v2.4.5 : Label selon statut \u2014 ne pas marquer r\u00e9serv\u00e9 si item est partiel\r\n            \/\/ v4.9ds (estReserveEffective) : idem _isReservedPartiel ligne 1346 \u2014 \"r\u00e9serv\u00e9\"\r\n            \/\/   UNIQUEMENT si flag pos\u00e9 \u00e0 la r\u00e9servation effective (clic R\u00e9server).\r\n            const _isReservedD = item.estReserveEffective === true || item.statut === 'complete';\r\n            \/\/ v4.9ds : .CampagneNoClass \u2014 idem remplirItemPartiel (FR raccourci, span retir\u00e9)\r\n            const _lblReserveD = _isReservedD\r\n                ? (lang === 'EN' ? 'Reserved advertising space ' : 'Espace r\u00e9serv\u00e9 ')\r\n                : (lang === 'EN' ? 'Advertising space ' : 'Espace publicitaire ');\r\n            \/\/ v4.9ds : pour Ele0A (emplacement \"L0A\"), inserer Pop-up dans CampagneNoClass\r\n            \/\/   v4.9ds : si non r\u00e9serv\u00e9, ajouter \" A r\u00e9server\" en #fb5e2a apr\u00e8s la r\u00e9f\u00e9rence\r\n            var _isEle0AD = \/L0A$\/.test(nouvelEmplacement);\r\n            \/\/ \u2705 v4.9ds+ (suite 6) Pb traduction : \"\u00e0 r\u00e9server\" en EN\r\n            \/\/   margin-left:3px en EN (cf commentaire remplirItemPartiel).\r\n            var _aReserverD = _isReservedD\r\n                ? ''\r\n                : (lang === 'EN'\r\n                    ? ' <span style=\"color:#fb5e2a;margin-left:3px;\">to be reserved<\/span>'\r\n                    : ' <span style=\"color:#fb5e2a\">\u00e0 r\u00e9server<\/span>');\r\n            $item.find('.CampagneNoClass').html(_lblReserveD + (_isEle0AD ? 'Pop-up ' : '') + nouvelEmplacement + _aReserverD).show();\r\n            \/\/ \u2705 v2.4.5 : Injecter position dans #CampagnePageText\r\n            var _rankDep = nouvellesDonnees.Rank_Emplacement_Page_Web || '';\r\n            var _posLibDep = '';\r\n            console.log('[deplacerAnnonce] rank:', _rankDep, '| itemId:', itemId);\r\n            if (_rankDep) {\r\n                var _cmdPageDep = sessionStorage.getItem('Commande_Page') || 'Homepage';\r\n                _posLibDep = this.convertirPositionEnLibelle(this.calculerPosition(_rankDep, _cmdPageDep));\r\n                var $_ptDep = $item.find('#CampagnePageText, .CampagnePageTextClass').first();\r\n                console.log('[deplacerAnnonce] $pageText.length:', $_ptDep.length, '| posLibDep:', _posLibDep, '| avant:', $_ptDep.text());\r\n                \/\/ v4.9ds : pour Ele0A, NE JAMAIS ajouter \"    Pop-up\" dans CampagnePageText\r\n                if (($_ptDep.length ? _posLibDep : false) ? !_isEle0AD : false) {\r\n                    var _titrePageDep = $_ptDep.text().split('\u00a0')[0].trim();\r\n                    $_ptDep.text(_titrePageDep + '\u00a0\u00a0\u00a0\u00a0' + _posLibDep);\r\n                    console.log('[deplacerAnnonce] $pageText apr\u00e8s:', $_ptDep.text());\r\n                }\r\n            } else {\r\n                console.warn('[deplacerAnnonce] rank vide \u2014 Rank_Emplacement_Page_Web manquant dans nouvellesDonnees');\r\n                console.log('[deplacerAnnonce] nouvellesDonnees keys:', Object.keys(nouvellesDonnees || {}));\r\n            }\r\n            \/\/ $item.find('.CampagneInfoEspaceMessage').hide(); \/\/ \u2699\ufe0f [COMMENT\u00c9] g\u00e9r\u00e9 par message global\r\n            \r\n            console.log('\u2705 R\u00e9f\u00e9rence mise \u00e0 jour:', nouvelleReference);\r\n            console.log('\u2705 Position mise \u00e0 jour:', nouvellePosition, '\u2192', _posLibDep);\r\n            \r\n            \/\/ 5. Recalculer tarif si donn\u00e9es compl\u00e8tes\r\n            console.log('[deplacerAnnonce] tarif \u2014 dateDebut:', item.dateDebut, '| dateFin:', item.dateFin, '| pays:', item.pays, '| VIA_App:', !!window.VIA_App);\r\n            if (item.dateDebut && item.dateFin && item.pays && window.VIA_App) {\r\n                console.log('\ud83d\udd04 Recalcul du tarif...');\r\n                \r\n                const duree = item.duree;\r\n                \/\/ \u2705 v2.4.5 : Utiliser le code pays (comme le 1er calcul) et non le libell\u00e9\r\n                var _paysCode = item.pays;\r\n                if (window.VIA_Countries) {\r\n                    var _country = window.VIA_Countries.getCountryByLabel(item.pays);\r\n                    if (_country && _country.code) { _paysCode = _country.code; }\r\n                }\r\n                const resultat = await window.VIA_App.calculerTarifAPI(\r\n                    item.format,\r\n                    nouvellePosition,\r\n                    duree,\r\n                    _paysCode\r\n                );\r\n                \r\n                if (resultat.success) {\r\n                    item.tarifHT = resultat.tarif_ht;\r\n                    item.tarifTTC = resultat.tarif_ttc;\r\n                    \r\n                    this.rafraichirItemHTML(itemId);\r\n                    this.calculerTotalPanier();\r\n                    \r\n                    \/\/ \u2705 Rafra\u00eechir les montants de l'\u00e9tape paiement\r\n                    if (window.VIA_Paiement && typeof window.VIA_Paiement.rafraichirMontants === 'function') {\r\n                        window.VIA_Paiement.rafraichirMontants();\r\n                    }\r\n                    \r\n                    console.log('\u2705 Tarif recalcul\u00e9:', resultat.tarif_ht, 'EUR');\r\n                }\r\n            }\r\n            \r\n            this.setItemActif(itemId);\r\n            \r\n            \/\/ \u2705 Fermer PageWeb sur mobile quand espace pub d\u00e9plac\u00e9\r\n            this.fermerPageWeb();\r\n            \r\n            console.log('\u2705 Annonce d\u00e9plac\u00e9e avec succ\u00e8s');\r\n        },\r\n        \r\n        \/**\r\n         * SUPPRESSION D'UNE COMMANDE INDIVIDUELLE\r\n         *\/\r\n        supprimerCommande(itemId, afficherSuivante = true, fromProcessDelAd = false) {\r\n            console.log('\ud83d\uddd1\ufe0f Suppression commande:', itemId);\r\n            \r\n            \/\/ \u2705 v1.6 : V\u00e9rifier si modification autoris\u00e9e (sauf si appel\u00e9 depuis reinitialiserProcessComplet)\r\n            if (!fromProcessDelAd) {\r\n                if (!this.gererModificationCommande('suppression')) {\r\n                    console.log('\ud83d\udd12 Suppression annul\u00e9e - bon de commande d\u00e9j\u00e0 cr\u00e9\u00e9');\r\n                    return;\r\n                }\r\n            }\r\n            \r\n            const item = this.state.items.find(i => i.id === itemId);\r\n            if (!item) {\r\n                console.warn('\u26a0\ufe0f Commande introuvable');\r\n                return;\r\n            }\r\n            \r\n            const $item = $(`#${itemId}`);\r\n            \r\n            \/\/ 1. R\u00e9initialiser l'espace publicitaire\r\n            \/\/ \u2705 Bug 10 : couvrir aussi les items partiels (emplacementPageWeb=null)\r\n            \/\/   Pour les items jamais r\u00e9serv\u00e9s, utiliser donneesIframe comme source de rankId\r\n            const _refEspaceForDel = item.emplacementPageWeb\r\n                || (item.donneesIframe && item.donneesIframe.Commande_Emplacement_Page_Web)\r\n                || '';\r\n            const _rankIdForDel = _refEspaceForDel\r\n                ? ('Ele' + _refEspaceForDel.substring(_refEspaceForDel.lastIndexOf('L') + 1))\r\n                : ((item.donneesIframe && item.donneesIframe.Rank_Emplacement_Page_Web) || '');\r\n            if ((_refEspaceForDel || _rankIdForDel) && !fromProcessDelAd) {\r\n                const refEspace = _refEspaceForDel;\r\n                const rankId = _rankIdForDel;\r\n                \r\n                console.log('\ud83d\udd0d Recherche droppable:', rankId, 'depuis refEspace:', refEspace);\r\n                \r\n                \/\/ \u2705 Bug 10 : toujours envoyer DelAdInIframe via l'iframe active\r\n                \/\/   PageWebframeId = ID de l'iframe sites pays courante (r\u00e9gie ou popup)\r\n                const iframeId = sessionStorage.getItem('PageWebframeId');\r\n                const iframeEl = iframeId ? document.getElementById(iframeId) : null;\r\n                if (iframeEl && iframeEl.contentWindow) {\r\n                    iframeEl.contentWindow.postMessage({\r\n                        action: 'DelAdInIframe',\r\n                        iframeId: iframeId,\r\n                        RefEspacePubToDel: refEspace,\r\n                        RankId: rankId\r\n                    }, '*');\r\n                    console.log('\ud83d\udce4 [Bug10] DelAdInIframe \u2192 iframe:', iframeId, '| rank:', rankId);\r\n                } else if (window.location.search.indexOf('mode=popup') !== -1) {\r\n                    window.parent.postMessage({\r\n                        type: 'resetEspacePub', refEspace: refEspace, rankId: rankId\r\n                    }, '*');\r\n                    console.log('\ud83d\udce4 [mode=popup] resetEspacePub \u2192 parent:', refEspace, rankId);\r\n                } else {\r\n                    \/\/ Fallback page directe (hors iframe)\r\n                    const $droppable = $('#' + rankId);\r\n                    if ($droppable.length) {\r\n                        const $container = $droppable.find('.OrdiMobileConteneurClass');\r\n                        const elementToReset = $container.length ? $container[0] : $droppable[0];\r\n                        if (typeof window.RestoreadSpaceTemplate === 'function') {\r\n                            window.RestoreadSpaceTemplate(elementToReset);\r\n                        } else if (typeof window.FonctionCroixResetAnnonce === 'function') {\r\n                            window.FonctionCroixResetAnnonce(elementToReset);\r\n                        }\r\n                        console.log('\u2705 Espace publicitaire r\u00e9initialis\u00e9 (page directe):', refEspace);\r\n                    } else if (window.parent !== window) {\r\n                        \/\/ pb230 : droppable absent du document courant -> l'espace pub est\r\n                        \/\/   dans la page parent (process d'achat ouvert depuis la page pays).\r\n                        \/\/   On escalade le reset au parent via resetEspacePub ; le parent\r\n                        \/\/   re-dispatch DelAdInIframe en interne (cf Entete.txt:4289).\r\n                        window.parent.postMessage({\r\n                            type: 'resetEspacePub', refEspace: refEspace, rankId: rankId\r\n                        }, '*');\r\n                        console.log('[pb230] resetEspacePub -> parent (droppable absent local):', refEspace, rankId);\r\n                    } else {\r\n                        console.warn('\u26a0\ufe0f Droppable non trouv\u00e9:', rankId);\r\n                    }\r\n                }\r\n            }\r\n            \r\n            \/\/ 2. Supprimer du DOM\r\n            \/\/ pb231 : #ProcessAchatInside (formulaire dates\/pays\/tarif) est un singleton\r\n            \/\/   deplace dans le noeud de l'item actif par _viaUpdateProcessAchatLocation\r\n            \/\/   (appendChild). Si on retire l'item qui le contient, l'element serait detruit\r\n            \/\/   et n'apparaitrait plus pour les reservations suivantes (Dates ABSENT du DOM).\r\n            \/\/   -> on l'evacue vers sa position d'origine AVANT $item.remove() ; le relocator\r\n            \/\/   (polling 500ms) le replacera ensuite dans le prochain item actif.\r\n            try {\r\n                var _paiDel231 = document.getElementById('ProcessAchatInside');\r\n                var _inItem231 = _paiDel231 ? ($item[0] ? $item[0].contains(_paiDel231) : false) : false;\r\n                if (_inItem231) {\r\n                    var _home231 = window._viaProcessAchatHome;\r\n                    if (_home231 ? _home231.parent : false) {\r\n                        if (_home231.next ? (_home231.next.parentNode === _home231.parent) : false) {\r\n                            _home231.parent.insertBefore(_paiDel231, _home231.next);\r\n                        } else {\r\n                            _home231.parent.appendChild(_paiDel231);\r\n                        }\r\n                    }\r\n                }\r\n            } catch(_ePAI231) {}\r\n            $item.remove();\r\n            \r\n            \/\/ 3. Nettoyer sessionStorage\r\n            if (window.VIA_Adaptateur && item.sessionStorageIndex) {\r\n                window.VIA_Adaptateur.cleanSessionStorageIndex(item.sessionStorageIndex);\r\n            }\r\n            \r\n            \/\/ 4. Retirer de state.items\r\n            this.state.items = this.state.items.filter(i => i.id !== itemId);\r\n            \/\/ pb277 : synchro VLP <-> resa (sites pays). Si plus aucune resa sur cette page,\r\n            \/\/   demander au parent de fermer le VLP (le 1er VLP reste non fermable cote parent).\r\n            try {\r\n                if (item && item.pays && window.parent !== window) {\r\n                    var _urlVlp277 = (item.donneesIframe && item.donneesIframe.LoadedPageUrl) || item.linkSecteurPage || '';\r\n                    if (_urlVlp277) {\r\n                        var _n277 = function(u) {\r\n                            try { var _x = new URL(u, window.location.href); return (_x.host + _x.pathname).replace(\/\\\/+$\/, '').toLowerCase(); }\r\n                            catch (e) { return String(u || '').split('?')[0].split('#')[0].replace(\/\\\/+$\/, '').toLowerCase(); }\r\n                        };\r\n                        var _norm277 = _n277(_urlVlp277);\r\n                        var _reste277 = this.state.items.some(function(_i) {\r\n                            var _u = (_i.donneesIframe && _i.donneesIframe.LoadedPageUrl) || _i.linkSecteurPage || '';\r\n                            return _u && _n277(_u) === _norm277;\r\n                        });\r\n                        if (!_reste277) { \/* pb277 (revision) : NE PAS fermer le VLP (demande user). Le VLP reste ouvert ; l'espace pub est reinitialise via DelAdInIframe \/ RestoreadSpaceTemplateLocal. Envoi viaCloseVlpForResa retire. *\/ }\r\n                    }\r\n                }\r\n            } catch (_e277) {}\r\n            \r\n            \/\/ \u2705 5. Recalculer le total\r\n            this.calculerTotalPanier();\r\n            \r\n            \/\/ \u2705 v4.9ds Pb 5 : si plus aucune r\u00e9servation avec tarif ne subsiste, masquer\r\n            \/\/   la synth\u00e8se 15min (demande user). On ne se base pas seulement sur\r\n            \/\/   items.length > 0 \u2014 il peut rester des items \"\u00e0 r\u00e9server\" sans tarif.\r\n            try {\r\n                var _hasTarifS = false;\r\n                for (var _is = 0; _is < this.state.items.length; _is++) {\r\n                    var _ts = this.state.items[_is].tarifHT;\r\n                    if (_ts ? (_ts !== '-' ? _ts !== 0 : false) : false) { _hasTarifS = true; break; }\r\n                }\r\n                if (!_hasTarifS) {\r\n                    var $_syS = $(this.config.syntheseConteneur);\r\n                    if ($_syS.length) { $_syS.hide(); }\r\n                }\r\n            } catch(_eHS) {}\r\n            \r\n            \/\/ \u2705 6. Rafra\u00eechir les montants de l'\u00e9tape paiement\r\n            if (window.VIA_Paiement && typeof window.VIA_Paiement.rafraichirMontants === 'function') {\r\n                window.VIA_Paiement.rafraichirMontants();\r\n            }\r\n            \r\n            console.log('\u2705 Commande supprim\u00e9e');\r\n            \/\/ \u2705 v2.6 Option A : Mettre a jour localStorage apres suppression\r\n            if (typeof window._viaEnvoyerPanierAuParent === 'function') {\r\n                window._viaEnvoyerPanierAuParent(false);\r\n            }\r\n            \r\n            \/\/ 6. Afficher commande suivante ou fermer\r\n            if (afficherSuivante && this.state.items.length > 0) {\r\n                \/\/ \u2705 v2.4.6 : Si l'item supprim\u00e9 n'est PAS l'item actif \u2192 conserver l'item actif courant\r\n                \/\/ (\u00e9vite de basculer vers items[0] alors que Congo est d\u00e9j\u00e0 affich\u00e9)\r\n                const _itemActifToujours = this.state.items.find(i => i.id === this.state.itemActif);\r\n                if (_itemActifToujours) {\r\n                    console.log('\u23ed\ufe0f supprimerCommande \u2014 item actif conserv\u00e9:', this.state.itemActif);\r\n                    \/\/ Pas de changement d'affichage \u2014 l'item actif est encore pr\u00e9sent\r\n                } else {\r\n                    \/\/ L'item actif vient d'\u00eatre supprim\u00e9 \u2192 passer au premier restant\r\n                    const suivante = this.state.items[0];\r\n                    this.setItemActif(suivante.id);\r\n                    \r\n                    if (typeof window.GetURLCommandeFromItem === 'function') {\r\n                        \/\/ \u2705 Ne pas recharger la page web si l'item suivant est sur la m\u00eame URL\r\n                        const _urlSupprimee = (item.donneesIframe && item.donneesIframe.LoadedPageUrl) || item.linkSecteurPage || '';\r\n                        const _urlSuivante = (suivante.donneesIframe && suivante.donneesIframe.LoadedPageUrl) || suivante.linkSecteurPage || '';\r\n                        const _memeUrl = _urlSupprimee && _urlSuivante &&\r\n                            _urlSupprimee.replace(\/\\\/$\/, '') === _urlSuivante.replace(\/\\\/$\/, '');\r\n                        if (_memeUrl) {\r\n                            console.log('\u23ed\ufe0f GetURLCommandeFromItem ignor\u00e9 \u2014 m\u00eame URL, iframe d\u00e9j\u00e0 charg\u00e9e');\r\n                        } else {\r\n                            window.GetURLCommandeFromItem(suivante);\r\n                        }\r\n                    }\r\n                }\r\n            } else if (this.state.items.length === 0) {\r\n                this.fermerTout();\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * SUPPRESSION DE TOUTES LES COMMANDES\r\n         *\/\r\n        supprimerToutesCommandes() {\r\n            console.log('\ud83d\uddd1\ufe0f Suppression de TOUTES les commandes');\r\n            \r\n            const itemIds = [...this.state.items.map(i => i.id)];\r\n            \r\n            itemIds.forEach(itemId => {\r\n                this.supprimerCommande(itemId, false);\r\n            });\r\n            \r\n            this.fermerTout();\r\n        },\r\n\r\n        \/**\r\n         * SUPPRESSION DES COMMANDES D'UNE PAGE\r\n         *\/\r\n        supprimerCommandesPage(urlPage) {\r\n            console.log('\ud83d\uddd1\ufe0f Suppression commandes de la page:', urlPage);\r\n            \r\n            const commandesPage = this.state.items.filter(i => \r\n                i.donneesIframe?.LoadedPageUrl === urlPage || \r\n                i.linkSecteurPage === urlPage\r\n            );\r\n            \r\n            commandesPage.forEach(item => {\r\n                this.supprimerCommande(item.id, false);\r\n            });\r\n            \r\n            if (this.state.items.length > 0) {\r\n                const suivante = this.state.items[0];\r\n                this.setItemActif(suivante.id);\r\n                \r\n                if (typeof window.GetURLCommandeFromItem === 'function') {\r\n                    window.GetURLCommandeFromItem(suivante);\r\n                }\r\n            } else {\r\n                this.fermerTout();\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * FERMER COLONNE COMMANDE ET PAGE WEB\r\n         *\/\r\n        fermerTout() {\r\n            console.log('\ud83d\udd12 Fermeture compl\u00e8te du panier');\r\n            \r\n            $('#PopupProcessCommandeContainer, .ToBeHidden, .AchatsPublicitairesTitre, #AchatsPublicitairesTitreSubContainer')\r\n                .fadeOut(500);\r\n            \r\n            if (typeof window.unlockBodyScroll === 'function') {\r\n                window.unlockBodyScroll();\r\n            }\r\n            \r\n            if (typeof window.resetAllEspacesPub === 'function') {\r\n                window.resetAllEspacesPub();\r\n            }\r\n            \r\n            if (typeof window.supprimerToutesCommandes === 'function') {\r\n                window.supprimerToutesCommandes();\r\n            }\r\n            \r\n            \/\/ \u2705 pb493 : plus aucune r\u00e9servation \u2192 r\u00e9initialiser les 3 bandeaux\r\n            \/\/   (Associer votre communication \u00e0 des pays \/ S\u00e9lectionner des th\u00e8mes,\r\n            \/\/   secteurs... \/ Cr\u00e9er et\/ou choisir des formats d'annonce). R\u00e9utilise\r\n            \/\/   _viaHideColonneCentre (yearbook-media.js), d\u00e9j\u00e0 expos\u00e9e sur window et\r\n            \/\/   d\u00e9j\u00e0 utilis\u00e9e pour ce m\u00eame reset au clic #AutreCommandeBouton et sur\r\n            \/\/   item anticip\u00e9 \u2014 sessionStorage (ContinentPaysTitre\/SelectedPageSecteur\/\r\n            \/\/   FormatSelect...) + bordures + messages d'invitation rouges.\r\n            if (typeof window._viaHideColonneCentre === 'function') {\r\n                window._viaHideColonneCentre();\r\n                console.log('[pb493] _viaHideColonneCentre appele (reset bandeaux pays\/secteur\/format)');\r\n            } else {\r\n                console.log('[pb493] _viaHideColonneCentre INDISPONIBLE -> bandeaux non reinitialises');\r\n            }\r\n            \/\/ \u2705 pb493 v3 : _viaHideColonneCentre masque les .SousTitre (visibles bandeau\r\n            \/\/   OUVERT) mais PAS les messages de confirmation verts affiches bandeau FERME\r\n            \/\/   (#AssocierPaysMessageContainer \"Communication associee au site X\",\r\n            \/\/   #SecteursMessageContainer \"La page X est selectionnee\"). Comme les 3\r\n            \/\/   bandeaux sont replies apres fermeture du panier, ces messages restaient\r\n            \/\/   verts a l ecran. On les masque + vide explicitement ici. FormatMessageContainer\r\n            \/\/   est deja masque par _viaHideColonneCentre mais on le remet par securite.\r\n            ['AssocierPaysMessageContainer', 'SecteursMessageContainer', 'FormatMessageContainer', 'PageWebMessageContainer', 'RecapitulatifMessageContainer'].forEach(function(_mid493) {\r\n                var _mc493 = document.getElementById(_mid493);\r\n                if (_mc493) { _mc493.style.setProperty('display', 'none', 'important'); }\r\n            });\r\n            ['AssocierPaysMessageTexte', 'SecteursMessageTexte', 'FormatMessageTexte'].forEach(function(_tid493) {\r\n                var _mt493 = document.getElementById(_tid493);\r\n                if (_mt493) { _mt493.textContent = ''; }\r\n            });\r\n            console.log('[pb493] messages de confirmation pays\/secteur\/format masques');\r\n            \r\n            this.state.items = [];\r\n            this.state.activeItemId = null;\r\n            \r\n            $('.CampagneNoClass').hide();\r\n            \r\n            \/\/ \u2705 v1.7 : Uniquement sur desktop\r\n            const isMobile = window.innerWidth <= 767;\r\n            if (!isMobile) {\r\n                $('#PaysSecteurs').width('60%');\r\n            }\r\n            \r\n            \/\/ \u2705 pb493 : centrer #AutreCommandeBouton (\"Ajouter une r\u00e9servation\") quand\r\n            \/\/   il devient le seul \u00e9l\u00e9ment du r\u00e9capitulatif (plus de carte r\u00e9servation\r\n            \/\/   au-dessus). display:block + margin auto, en inline !important pour\r\n            \/\/   gagner sur le style Elementor (cf. width 450px d\u00e9j\u00e0 forc\u00e9e ailleurs).\r\n            var _acb493 = document.getElementById('AutreCommandeBouton');\r\n            if (_acb493) {\r\n                \/\/ \u2705 pb493 v4 : display:block ne centrait pas VERTICALEMENT le texte\r\n                \/\/   (il restait cale en haut du rectangle). On passe le bouton en FLEX\r\n                \/\/   colonne, contenu centre H+V. Pleine largeur conservee (e-con-full) ->\r\n                \/\/   pas besoin de width fixe ; margin auto\/float none par securite.\r\n                _acb493.style.setProperty('display', 'flex', 'important');\r\n                _acb493.style.setProperty('flex-direction', 'column', 'important');\r\n                _acb493.style.setProperty('justify-content', 'center', 'important');\r\n                _acb493.style.setProperty('align-items', 'center', 'important');\r\n                _acb493.style.setProperty('text-align', 'center', 'important');\r\n                _acb493.style.setProperty('margin-left', 'auto', 'important');\r\n                _acb493.style.setProperty('margin-right', 'auto', 'important');\r\n                _acb493.style.setProperty('float', 'none', 'important');\r\n                \/\/ Conteneurs internes : centres H+V ET pleine largeur pour que text-align\r\n                \/\/   center opere sur toute la largeur (sinon widget etroit = texte decale).\r\n                var _inner493 = _acb493.querySelectorAll('.e-con-inner, [data-element_type=\"container\"], .elementor-widget, .elementor-widget-container');\r\n                for (var _i493 = 0; _i493 < _inner493.length; _i493++) {\r\n                    _inner493[_i493].style.setProperty('justify-content', 'center', 'important');\r\n                    _inner493[_i493].style.setProperty('align-items', 'center', 'important');\r\n                    _inner493[_i493].style.setProperty('text-align', 'center', 'important');\r\n                    _inner493[_i493].style.setProperty('width', '100%', 'important');\r\n                }\r\n                console.log('[pb493] AutreCommandeBouton flex centre H+V (' + _inner493.length + ' conteneurs internes)');\r\n            } else {\r\n                console.log('[pb493] AutreCommandeBouton introuvable au moment du centrage');\r\n            }\r\n            \r\n            $('.FormatClassique, .FormatPopup , .SiteContinentPaysTitre, .HPType, .ArtType, .PTType').css('border', 'none');\r\n\r\n            \/\/ \u2705 v1.7 : Afficher un message au lieu de recharger la page\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \/\/ pb127 : texte sur UNE SEULE ligne (sans <br>). Demande user.\r\n            const message = lang === 'EN'\r\n                ? 'Please select a country, a sector and a format'\r\n                : 'Merci de s\u00e9lectionner un pays, un secteur et un format';\r\n            \r\n            \/\/ Masquer les \u00e9l\u00e9ments du panier\r\n            $(this.config.templateItem).hide();\r\n            $('#Etape1Container').hide();\r\n            $('#SyntheseConteneur').hide();\r\n            \r\n            \/\/ \u2705 v2.3.2 : Style bleu avec encadr\u00e9, d\u00e9cal\u00e9 vers le haut\r\n            \/\/ \u2705 v4.9ds+ (suite 8) : margin-bottom 15px \u2192 30px (demande user)\r\n            \/\/ pb92 : position:relative pour ancrer la croix de fermeture\r\n            \/\/ pb127 : white-space:nowrap + width:fit-content (au lieu de max-width:350px) pour\r\n            \/\/   garder le texte sur UNE SEULE ligne. Centr\u00e9 via margin auto.\r\n            const messageStyle = `\r\n                position: relative;\r\n                padding: 12px 28px 12px 20px;\r\n                text-align: center;\r\n                color: #213864;\r\n                font-size: 13px;\r\n                line-height: 1.5;\r\n                margin: 10px auto 30px auto;\r\n                border: 1px solid #213864;\r\n                border-radius: 5px;\r\n                background-color: #f8fafc;\r\n                white-space: nowrap;\r\n                width: fit-content;\r\n                max-width: 100%;\r\n            `;\r\n            \r\n            \/\/ \u2705 v2.6 : VosCampagnesConteneurClass doit \u00eatre visible (peut \u00eatre hidden par la suppression des items)\r\n            var _vccEl = document.querySelector('.VosCampagnesConteneurClass');\r\n            if (_vccEl) { _vccEl.style.setProperty('display', 'block', 'important'); }\r\n\r\n            let $msgAucuneCommande = $('#MsgAucuneCommande');\r\n            if ($msgAucuneCommande.length === 0) {\r\n                $msgAucuneCommande = $(`\r\n                    <div id=\"MsgAucuneCommande\" style=\"${messageStyle}\">${message}<\/div>\r\n                `);\r\n                $('.VosCampagnesConteneurClass').append($msgAucuneCommande);\r\n            } else {\r\n                $msgAucuneCommande.attr('style', messageStyle).html(message);\r\n            }\r\n            \/\/ \u2705 v2.6 : display:none !important dans yearbook-media.js bloque .show() \u2014 setProperty n\u00e9cessaire\r\n            var _msgEl = document.getElementById('MsgAucuneCommande');\r\n            if (_msgEl) { _msgEl.style.setProperty('display', 'block', 'important'); }\r\n            \/\/ pb92 : croix de fermeture \u2014 inject\u00e9e\/r\u00e9initialis\u00e9e \u00e0 chaque affichage\r\n            if (_msgEl) {\r\n                var _existClose92 = _msgEl.querySelector('.via-msg-close-btn');\r\n                if (!_existClose92) {\r\n                    var _close92 = document.createElement('button');\r\n                    _close92.className = 'via-msg-close-btn';\r\n                    _close92.setAttribute('type', 'button');\r\n                    _close92.setAttribute('aria-label', 'Fermer');\r\n                    _close92.innerHTML = '\\u00d7';\r\n                    _close92.style.cssText = 'position:absolute;top:4px;right:6px;background:none;border:none;cursor:pointer;font-size:16px;font-weight:700;color:#213864;line-height:1;padding:0;opacity:0.6;';\r\n                    _close92.onmouseover = function() { this.style.opacity = '1'; };\r\n                    _close92.onmouseout  = function() { this.style.opacity = '0.6'; };\r\n                    _close92.onclick = function() {\r\n                        \/\/ \u2705 pb493 : actualiser la page au clic sur la croix (au lieu de\r\n                        \/\/   simplement masquer le message) \u2014 demande user.\r\n                        window.location.reload();\r\n                    };\r\n                    _msgEl.insertBefore(_close92, _msgEl.firstChild);\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 v2.4.5 : Reload apr\u00e8s 1mn sans action (plus d'auto-reload \u00e0 3s)\r\n            var _self = this;\r\n            \/\/ Annuler un timer pr\u00e9c\u00e9dent\r\n            if (window._viaNoCommandeTimer) {\r\n                clearTimeout(window._viaNoCommandeTimer);\r\n                window._viaNoCommandeTimer = null;\r\n            }\r\n            \/\/ Reset du timer \u00e0 chaque interaction utilisateur\r\n            function _resetInactivityTimer() {\r\n                if (window._viaNoCommandeTimer) { clearTimeout(window._viaNoCommandeTimer); }\r\n                window._viaNoCommandeTimer = setTimeout(function() {\r\n                    if (_self.state.items.length === 0) {\r\n                        \/\/ Nettoyer les listeners avant reload\r\n                        document.removeEventListener('click', _resetInactivityTimer);\r\n                        document.removeEventListener('keydown', _resetInactivityTimer);\r\n                        document.removeEventListener('scroll', _resetInactivityTimer);\r\n                        document.removeEventListener('mousemove', _resetInactivityTimer);\r\n                        window.location.reload();\r\n                    }\r\n                }, 60000); \/\/ 1 minute\r\n            }\r\n            \/\/ D\u00e9marrer le timer et \u00e9couter les actions\r\n            _resetInactivityTimer();\r\n            document.addEventListener('click',     _resetInactivityTimer);\r\n            document.addEventListener('keydown',   _resetInactivityTimer);\r\n            document.addEventListener('scroll',    _resetInactivityTimer);\r\n            document.addEventListener('mousemove', _resetInactivityTimer);\r\n            \/\/ Stocker la fonction pour pouvoir la retirer si une commande est ajout\u00e9e\r\n            window._viaNoCommandeReset = _resetInactivityTimer;\r\n            \r\n            \/\/ \u2705 v1.8 : Fermer l'\u00e9tape \"Choisir un espace publicitaire\"\r\n            \/\/ \u2705 v2.0 : Sur desktop, ne pas masquer PageWebTemplate (mode 3 colonnes)\r\n            if (window.outerWidth < 1000) {\r\n                $('.PageWebTemplate').hide();\r\n            }\r\n            $('#PageWebTitreIconeUp').hide();\r\n            $('#PageWebTitreIconeDown').show();\r\n            console.log('\ud83d\udcc1 \u00c9tape PageWeb ferm\u00e9e (aucune commande)');\r\n            \r\n            console.log('\u2705 Panier ferm\u00e9 - message affich\u00e9');\r\n        },\r\n        \r\n        \/**\r\n         * Initialise les listeners\r\n         *\/\r\n        initListeners() {\r\n            const self = this;\r\n            \r\n            \/\/ \u2705 v1.8 : Listener sur le bouton \"Passer Commande\"\r\n            $(document).on('click', '.PasserCommandeBouton', function(e) {\r\n                console.log('\ud83c\udfc1 [PasserCommandeBouton] cliqu\u00e9 | items:', JSON.stringify(self.state.items.map(i => ({id:i.id, ref:i.reference, statut:i.statut, tarifHT:i.tarifHT, emplacementPageWeb:i.emplacementPageWeb}))));\r\n                \/\/ \u2705 v4.9ds Pb 7 : poser le flag _viaFinaliserClique=true \u2192 l'\u00e9tape\r\n                \/\/   \"references\" peut maintenant \u00eatre marqu\u00e9e en cours (rouge). Avant\r\n                \/\/   ce clic, marquerEtapeEnCours skip references (titre reste gris).\r\n                window._viaFinaliserClique = true;\r\n                \/\/ D\u00e9clencher imm\u00e9diatement marquerEtapeEnCours pour passer references en rouge\r\n                try { self.marquerEtapeEnCours(); } catch(_eME) {}\r\n                \/\/ \u2705 v2.4.3 : Poser FinaliserStep=Yes \u2014 les r\u00e9servations ne sont plus modifiables\r\n                sessionStorage.setItem('FinaliserStep', 'Yes');\r\n                \/\/ \u2705 v2.4.3 : Bloquer toutes interactions dans colonne droite, centre et \u00e9tapes r\u00e9cap\/dates\r\n                self.bloquerInteractionsApresFinalisation();\r\n                \/\/ \u2705 v1.9 : Fermer le r\u00e9capitulatif\r\n                self.fermerRecapitulatif();\r\n                \r\n                \/\/ \u2705 v1.10 : Griser l'\u00e9tape Dates ET R\u00e9capitulatif\r\n                self.griserEtape('dates');\r\n                self.griserEtape('recapitulatif');\r\n                \r\n                \/\/ \u2705 v2.4.3 : Masquer SyntheseConteneur apr\u00e8s finalisation\r\n                $('#SyntheseConteneur').hide();\r\n                \r\n                \/\/ \u2705 v2.4.3 : Fermer le contenu de l'\u00e9tape dates\/dur\u00e9e\/tarif + masquer synth\u00e8se\r\n                $('.DatesDureeCampagneClass').hide();\r\n                $('#SyntheseConteneur').hide();\r\n                $('#DatesDureeCampagneIconeUp').hide();\r\n                $('#DatesDureeCampagneIconeDown').show();\r\n                \r\n                console.log('\ud83d\udcc1 R\u00e9capitulatif ferm\u00e9 (clic sur PasserCommandeBouton)');\r\n                \r\n                \/\/ ================================================================\r\n                \/\/ pb1851 : A LA FINALISATION, REFERMER TOUTES LES ETAPES AMONT.\r\n                \/\/   Demande JF : annonceur, site pays, secteurs, dates, reservation.\r\n                \/\/   Avant (v2.4.4) : seules pays\/secteur\/format etaient fermees, et\r\n                \/\/   UNIQUEMENT sous outerWidth < 1000. Sur desktop, rien ne se\r\n                \/\/   fermait. L'annonceur et les dates du process n'etaient fermes\r\n                \/\/   dans aucun des deux contextes.\r\n                \/\/\r\n                \/\/   PIEGE DES DEUX \u00ab DATES \u00bb : le .DatesDureeCampagneClass ferme\r\n                \/\/   quelques lignes plus haut est l'ANCIENNE etape 'dates'\r\n                \/\/   (#Etape1Container), retiree du sequenceur par pb915. L'etape\r\n                \/\/   reellement affichee est processDatesDevise\r\n                \/\/   (.ProcessDatesDeviseConteneurClass). C'est celle-la qu'il faut\r\n                \/\/   fermer ; l'autre fermeture est laissee en place, inoffensive.\r\n                \/\/\r\n                \/\/   La RESERVATION (recapitulatif) est deja fermee par\r\n                \/\/   fermerRecapitulatif() ci-dessus : rien a ajouter, le controle\r\n                \/\/   differe ci-dessous le verifie.\r\n                \/\/\r\n                \/\/   Annonceur et dates passent par window._viaFermerEtape915\r\n                \/\/   (yearbook-media.js, expose l.38664) : c'est le fermeur officiel\r\n                \/\/   de ces deux etapes, il pose display:none !important, bascule les\r\n                \/\/   chevrons et resynchronise le message. Ne pas refaire a la main\r\n                \/\/   ce qu'il fait deja.\r\n                \/\/\r\n                \/\/   POURQUOI CA TIENT : la boucle de synchro de pb915 rouvre toute\r\n                \/\/   etape \u00ab non renseignee \u00bb (pb1565) \u2014 et la finalisation\r\n                \/\/   deselectionne l'item, donc toutes les etapes redeviennent non\r\n                \/\/   renseignees. Mais pb1585 retire precisement cette regle des que\r\n                \/\/   window._viaFinaliserClique est vrai, pose l.10079 juste au-dessus.\r\n                \/\/   Aucune couche de compensation n'est donc necessaire ici.\r\n                \/\/   Un CONTROLE differe verifie et JOURNALISE l'etat reel a 1200ms\r\n                \/\/   sans rien reecrire : si une etape se rouvre, le log le dit au\r\n                \/\/   lieu de le masquer par une seconde ecriture.\r\n                \/\/\r\n                \/\/   Le FORMAT est inclus bien que non cite dans la demande : il\r\n                \/\/   etait deja ferme en mobile, et le laisser seul ouvert au milieu\r\n                \/\/   d'etapes toutes fermees serait incoherent. Knob pour l'exclure.\r\n                \/\/   Knobs : window._viaPb1851Off = true      -> comportement d'avant\r\n                \/\/           window._viaPb1851Format = false  -> laisse le format ouvert\r\n                \/\/ ================================================================\r\n                if (window._viaPb1851Off === true) {\r\n                    if (window.outerWidth < 1000) {\r\n                        if (typeof closeAssocierPays === 'function') { closeAssocierPays({ animate: 400 }); }\r\n                        setTimeout(function() { if (typeof closeAssocierSecteur === 'function') { closeAssocierSecteur({ animate: 400 }); } }, 200);\r\n                        setTimeout(function() { if (typeof closeChoixFormat === 'function') { closeChoixFormat({ animate: 400 }); } }, 400);\r\n                        console.log('\ud83d\udcf1 \u00c9tapes Pays\/Secteur\/Format ferm\u00e9es (mobile \u2014 finalisation)');\r\n                    }\r\n                } else {\r\n                    var _fmt1851 = (window._viaPb1851Format === false) ? false : true;\r\n                    if (typeof window._viaFermerEtape915 === 'function') {\r\n                        window._viaFermerEtape915('processAnnonceur');\r\n                        window._viaFermerEtape915('processDatesDevise');\r\n                    } else {\r\n                        console.log('[pb1851] SORTIE : _viaFermerEtape915 indisponible \u2014 annonceur et dates NON ferm\u00e9s');\r\n                    }\r\n                    if (typeof closeAssocierPays === 'function') { closeAssocierPays({ animate: 400 }); }\r\n                    else { console.log('[pb1851] SORTIE : closeAssocierPays indisponible'); }\r\n                    setTimeout(function() {\r\n                        if (typeof closeAssocierSecteur === 'function') { closeAssocierSecteur({ animate: 400 }); }\r\n                        else { console.log('[pb1851] SORTIE : closeAssocierSecteur indisponible'); }\r\n                    }, 200);\r\n                    if (_fmt1851) {\r\n                        setTimeout(function() {\r\n                            if (typeof closeChoixFormat === 'function') { closeChoixFormat({ animate: 400 }); }\r\n                            else { console.log('[pb1851] SORTIE : closeChoixFormat indisponible'); }\r\n                        }, 400);\r\n                    }\r\n                    console.log('[pb1851] fermeture des \u00e9tapes amont demand\u00e9e | format '\r\n                        + (_fmt1851 ? 'inclus' : 'exclu') + ' | outerWidth=' + window.outerWidth);\r\n                    setTimeout(function() {\r\n                        try {\r\n                            var _ctl1851 = [\r\n                                ['annonceur',   '.ProcessAnnonceurConteneurClass'],\r\n                                ['pays',        '.AssocierPaysClass'],\r\n                                ['secteurs',    '.AssocierSecteurClass'],\r\n                                ['format',      '.ChoixFormatClass'],\r\n                                ['dates',       '.ProcessDatesDeviseConteneurClass'],\r\n                                ['reservation', '.VosCampagnesConteneurClass']\r\n                            ];\r\n                            var _res1851 = [];\r\n                            for (var _i1851 = 0; _i1851 < _ctl1851.length; _i1851++) {\r\n                                var _el1851 = document.querySelector(_ctl1851[_i1851][1]);\r\n                                var _et1851 = 'absent';\r\n                                if (_el1851) {\r\n                                    _et1851 = (window.getComputedStyle(_el1851).display === 'none') ? 'ferm\u00e9' : 'OUVERT';\r\n                                }\r\n                                _res1851.push(_ctl1851[_i1851][0] + '=' + _et1851);\r\n                            }\r\n                            console.log('[pb1851] contr\u00f4le \u00e0 1200ms | ' + _res1851.join(' | '));\r\n                        } catch (_e1851) { console.log('[pb1851] contr\u00f4le impossible : ' + _e1851.message); }\r\n                    }, 1200);\r\n                }\r\n                \r\n                \/\/ \u2705 v1.9 : Enlever les liser\u00e9s de toutes les commandes\r\n                $(self.config.templateItem).css({\r\n                    'border': 'none',\r\n                    'background': ''\r\n                });\r\n                self.state.itemActif = null;\r\n                console.log('\ud83e\uddf9 Liser\u00e9s enlev\u00e9s de toutes les commandes');\r\n            });\r\n            \r\n            \/\/ \u2705 v1.8 : Listener sur le titre du r\u00e9capitulatif pour toggle\r\n            $(document).off('click', '.RecapitulatifVosCommandestitre').on('click', '.RecapitulatifVosCommandestitre', function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                console.log('\ud83d\udd04 Clic sur RecapitulatifVosCommandestitre');\r\n                self.toggleRecapitulatif();\r\n            });\r\n            \r\n            \/\/ Listener sur les boutons \"Modifier\"\r\n            $(document).on('click', '.CampagneModifierButton', function(e) {\r\n                e.preventDefault();\r\n                const $item = $(this).closest(self.config.templateItem);\r\n                const itemId = $item.attr('id');\r\n                if (itemId) {\r\n                    self.setItemActif(itemId);\r\n                }\r\n            });\r\n            \r\n            \/\/ \u2705 v4.9ds : Click sur bouton R\u00e9duire\/Agrandir d'une commande\r\n            \/\/   Bascule data-via-reduit sur l'item + remet le bon SVG.\r\n            \/\/   Pas de persistance : le prochain setItemActif r\u00e9initialise tous les \u00e9tats.\r\n            $(document).on('click', '.via-reduire-btn', function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                var $btn = $(this);\r\n                var $itemR = $btn.closest(self.config.templateItem);\r\n                if (!$itemR.length) { return; }\r\n                var _itemEl = $itemR[0];\r\n                var _estReduit = _itemEl.getAttribute('data-via-reduit') === 'true';\r\n                if (_estReduit) {\r\n                    \/\/ Passer \u00e0 agrandi\r\n                    _itemEl.setAttribute('data-via-reduit', 'false');\r\n                    var _svgR = $btn.attr('data-via-svg-reduire');\r\n                    if (_svgR) { $btn.html(decodeURIComponent(_svgR)); }\r\n                    $btn.attr('aria-label', 'R\u00e9duire').attr('title', 'R\u00e9duire');\r\n                } else {\r\n                    \/\/ Passer \u00e0 r\u00e9duit\r\n                    _itemEl.setAttribute('data-via-reduit', 'true');\r\n                    var _svgA = $btn.attr('data-via-svg-agrandir');\r\n                    if (_svgA) { $btn.html(decodeURIComponent(_svgA)); }\r\n                    $btn.attr('aria-label', 'Agrandir').attr('title', 'Agrandir');\r\n                }\r\n                \/\/ \u2705 v4.9ds Pb 7 : d\u00e9clencher la relocalisation de ProcessAchatInside\r\n                \/\/   (visible si l'item devient agrandi+r\u00e9serv\u00e9, sinon retour \u00e0 la maison).\r\n                try {\r\n                    if (typeof window._viaUpdateProcessAchatLocation === 'function') {\r\n                        window._viaUpdateProcessAchatLocation();\r\n                    }\r\n                } catch(_eR) {}\r\n            });\r\n\r\n            \/\/ \u2705 pb223 : Click sur le picto \"S\u00e9lectionner\" \u2192 rendre la r\u00e9servation ACTIVE.\r\n            \/\/   Le picto \u00e9tait purement visuel (pb206) et le handler clic-item ignore les\r\n            \/\/   <button>, donc cliquer dessus ne faisait rien. On reproduit l'activation\r\n            \/\/   (setItemActif) avec les m\u00eames gardes que le clic item.\r\n            $(document).on('click', '.via-selectionner-btn', function(e) {\r\n                \/\/ pb931 : fonctionnalite DESACTIVEE (demande user). Le bouton est masque\r\n                \/\/   par CSS et sa creation est court-circuitee ; ce garde couvre le cas\r\n                \/\/   ou un exemplaire subsisterait (clone, rendu anterieur, cache).\r\n                \/\/   Revert : window._viaPb931Off = true (retablit les 2 boutons).\r\n                if (window._viaPb931Off !== true) { return; }\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                var $itemSel = $(this).closest(self.config.templateItem);\r\n                if (!$itemSel.length) { return; }\r\n                var _itemIdSel = $itemSel.attr('id');\r\n                if (!_itemIdSel) { return; }\r\n                if (_itemIdSel === 'CampagneTemplate') { return; }\r\n                if (sessionStorage.getItem('FinaliserStep') === 'Yes') {\r\n                    self.afficherMessageFinaliser();\r\n                    return;\r\n                }\r\n                if (sessionStorage.getItem('BonCommandeCree') === 'Yes') {\r\n                    self.afficherMessageNouvelleCommande();\r\n                    return;\r\n                }\r\n                \/\/ pb815 : si la resa est DEJA active, le picto la DESACTIVE.\r\n                if (self.state.itemActif === _itemIdSel) {\r\n                    if (self.desactiverResa815(_itemIdSel)) { return; }\r\n                }\r\n                window._viaSelectingReservation = true;\r\n                self.setItemActif(_itemIdSel);\r\n                \/\/ Ouvrir PageWeb sauf pour les r\u00e9servations issues de sites pays (item.pays non-null)\r\n                var _clickedItemSel = self.state.items.find(function(i) { return i.id === _itemIdSel; });\r\n                var _isFromSitesPaysSel = _clickedItemSel ? !!_clickedItemSel.pays : false;\r\n                if (!_isFromSitesPaysSel) { self.ouvrirPageWeb(); }\r\n                else if (window.parent !== window && _clickedItemSel) {\r\n                    \/\/ pb277 : resa site pays -> ouvrir \/ ramener au 1er plan le VLP de sa page (cote parent)\r\n                    var _u277s = (_clickedItemSel.donneesIframe && _clickedItemSel.donneesIframe.LoadedPageUrl) || _clickedItemSel.linkSecteurPage || '';\r\n                    if (_u277s) { window.parent.postMessage({ type: 'VIA_OPEN_LINK_POPUP', url: _u277s, title: '' }, '*'); }\r\n                }\r\n            });\r\n            \r\n            \/\/ Click sur croix d'une commande\r\n            $(document).on('click', '.CampagneCloseButton', function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                \/* ====================================================================\r\n                 * pb2350 : LA CROIX CHANGE DE ROLE UNE FOIS LA COMMANDE FINALISEE.\r\n                 *   Demande JF : tant que la commande n est PAS finalisee, comportement\r\n                 *   actuel inchange (supprimer la reservation). Une fois finalisee, le\r\n                 *   picto devient << Fermer >> et referme l etape Vos reservations.\r\n                 *   C est coherent : apres finalisation les reservations ne sont plus\r\n                 *   modifiables (pb2043 pose FinaliserStep=Yes pour cela), donc une croix\r\n                 *   qui supprime n a plus de sens \u2014 elle ne pourrait que tromper.\r\n                 *\r\n                 *   << FINALISEE >> : on reprend _viaRacineAval2051(), la definition deja\r\n                 *   en place. Elle vaut mieux que sessionStorage.FinaliserStep, dont pb1220\r\n                 *   puis pb1222 ont montre qu il survit a la session \u2014 << une valeur laissee\r\n                 *   par une session precedente suffisait >>. Les deux temoins memoire de\r\n                 *   pb2051 disparaissent au rechargement, donc ils ne peuvent pas etre\r\n                 *   perimes par construction.\r\n                 *   Revert : window._viaPb2350Off = true.\r\n                 * ==================================================================== *\/\r\n                if (window._viaPb2350Off === true ? false : true) {\r\n                    var _fin2350 = false;\r\n                    try {\r\n                        _fin2350 = (typeof window._viaRacineAval2051 === 'function')\r\n                            ? window._viaRacineAval2051(null) : false;\r\n                    } catch (_ef2350) { _fin2350 = false; }\r\n                    if (_fin2350) {\r\n                        console.log('[pb2350] commande finalisee -> la croix referme l etape Vos reservations (pas de suppression)');\r\n                        try { self.fermerRecapitulatif(); } catch (_ec2350) { console.warn('[pb2350] ' + _ec2350.message); }\r\n                        return;\r\n                    }\r\n                }\r\n                \r\n                const itemId = $(this).closest(self.config.templateItem).attr('id');\r\n                if (itemId) {\r\n                    if (itemId !== 'CampagneTemplate') {\r\n                        self.supprimerCommande(itemId, true);\r\n                    }\r\n                }\r\n            });\r\n            \r\n            \/\/ Click sur fermer page web\r\n            $(document).on('click', '#PageWebClosebutton', function(e) {\r\n                e.preventDefault();\r\n                const urlPage = sessionStorage.getItem('LinkSecteurPage');\r\n                if (urlPage) {\r\n                    self.supprimerCommandesPage(urlPage);\r\n                }\r\n            });\r\n            \r\n            \/\/ \u2705 v1.7 : Listener sur tout l'item - SIMPLIFI\u00c9\r\n            $(document).on('click', self.config.templateItem, function(e) {\r\n                const itemId = $(this).attr('id');\r\n                console.log('\ud83d\uddb1\ufe0f [clic templateItem] id:', itemId, '| inEtape1:', $(e.target).closest('#Etape1Container').length > 0, '| target:', e.target.tagName, e.target.className?.substring(0,40));\r\n                \/\/ Ignorer les clics provenant de Etape1Container\r\n                if ($(e.target).closest('#Etape1Container').length > 0) {\r\n                    return;\r\n                }\r\n                \r\n                \/\/ \u2705 v2.4.9f : bloquer seulement les <a> avec href r\u00e9el et les <button>\r\n                if ($(e.target).is('button') || $(e.target).closest('button').length > 0) {\r\n                    return;\r\n                }\r\n                var $closestA = $(e.target).is('a') ? $(e.target) : $(e.target).closest('a');\r\n                if ($closestA.length > 0) {\r\n                    var _href = ($closestA.attr('href') || '').trim();\r\n                    if (_href && _href !== '#' && _href !== 'javascript:void(0)') {\r\n                        return;\r\n                    }\r\n                }\r\n                \r\n                \/\/ \u2705 v1.7 : Ignorer les clics sur les inputs\/formulaires INTERACTIFS\r\n                \/\/ \u2705 v2.4.9f : ne pas bloquer sur .elementor-form hors Etape1Container\r\n                \/\/ (sur mobile, les cartes contiennent des \u00e9l\u00e9ments Elementor qui bloquaient tout le clic)\r\n                if ($(e.target).is('input, select, textarea, label')) {\r\n                    return;\r\n                }\r\n                if ($(e.target).closest('form, .elementor-form').length > 0) {\r\n                    if ($(e.target).closest('#Etape1Container').length > 0) {\r\n                        return;\r\n                    }\r\n                }\r\n                \r\n                if (itemId) {\r\n                    if (itemId !== 'CampagneTemplate') {\r\n                        \/\/ \u2705 v2.4.3 : Bloquer si FinaliserStep=Yes\r\n                        if (sessionStorage.getItem('FinaliserStep') === 'Yes') {\r\n                            console.log('\ud83d\udd12 Clic sur commande bloqu\u00e9 - FinaliserStep=Yes');\r\n                            self.afficherMessageFinaliser();\r\n                            return;\r\n                        }\r\n                        \/\/ \u2705 v1.6 : G\u00e9rer BonCommandeCree\r\n                        if (sessionStorage.getItem('BonCommandeCree') === 'Yes') {\r\n                            console.log('\ud83d\udd12 Clic sur commande bloqu\u00e9 - Bon de commande cr\u00e9\u00e9');\r\n                            self.afficherMessageNouvelleCommande();\r\n                            return;\r\n                        }\r\n                        \r\n                        \/\/ \u2705 v2.4.9g : flag pour bloquer openBandeauxMobile3Colonnes pendant la s\u00e9lection r\u00e9servation\r\n                        window._viaSelectingReservation = true;\r\n                        self.setItemActif(itemId);\r\n                        \/\/ \u2705 Ouvrir PageWeb sauf pour les r\u00e9servations issues de sites pays (item.pays non-null)\r\n                        var _clickedItem = self.state.items.find(function(i) { return i.id === itemId; });\r\n                        var _isFromSitesPays = _clickedItem ? !!_clickedItem.pays : false;\r\n                        if (!_isFromSitesPays) { self.ouvrirPageWeb(); }\r\n                        else if (window.parent !== window && _clickedItem) {\r\n                            \/\/ pb277 : resa site pays -> ouvrir \/ ramener le VLP de sa page (cote parent)\r\n                            var _u277 = (_clickedItem.donneesIframe && _clickedItem.donneesIframe.LoadedPageUrl) || _clickedItem.linkSecteurPage || '';\r\n                            if (_u277) { window.parent.postMessage({ type: 'VIA_OPEN_LINK_POPUP', url: _u277, title: '' }, '*'); }\r\n                        }\r\n                        setTimeout(function() { window._viaSelectingReservation = false; }, 500);\r\n                    }\r\n                }\r\n            });\r\n            \r\n            \/\/ Date d\u00e9but (change, input, blur pour mobile)\r\n            $(document).on('change input blur', '#form-field-DebutCampagne', function() {\r\n                const dateDebut = $(this).val();\r\n                if (dateDebut) {\r\n                    console.log('\ud83d\udcc5 Date d\u00e9but chang\u00e9e:', dateDebut);\r\n                    self.synchroniserDonnee('dateDebut', dateDebut);\r\n                }\r\n            });\r\n            \r\n            \/\/ Date fin (change, input, blur pour mobile)\r\n            $(document).on('change input blur', '#form-field-FinCampagne', function() {\r\n                const dateFin = $(this).val();\r\n                if (dateFin) {\r\n                    console.log('\ud83d\udcc5 Date fin chang\u00e9e:', dateFin);\r\n                    self.synchroniserDonnee('dateFin', dateFin);\r\n                    \r\n                    const dureeText = $('.CampagneNbJours').text();\r\n                    if (dureeText) {\r\n                        const duree = parseInt(dureeText.replace(\/[^\\d]\/g, ''));\r\n                        if (duree) {\r\n                            self.synchroniserDonnee('duree', duree);\r\n                        }\r\n                    }\r\n                }\r\n            });\r\n            \r\n            \/\/ Pays - \u2705 v1.10 : Ajout blur et input pour capturer tous les cas\r\n            $(document).on('change autocompleteselect blur', '#form-field-Nationalite_Societe', function() {\r\n                const pays = $(this).val();\r\n                if (pays) {\r\n                    console.log('\ud83c\udf0d Pays chang\u00e9 dans \u00c9tape 1:', pays);\r\n                    self.synchroniserDonnee('pays', pays);\r\n                    \r\n                    \/\/ \u2705 v1.10 : Synchroniser vers le champ pays dans R\u00e9f\u00e9rences\r\n                    const $champPaysReferences = $('input[name=\"form_fields[annonceur_pays]\"]');\r\n                    if ($champPaysReferences.length && $champPaysReferences.val() !== pays) {\r\n                        $champPaysReferences.val(pays);\r\n                        console.log('\u2705 Pays synchronis\u00e9 vers R\u00e9f\u00e9rences:', pays);\r\n                        \r\n                        \/\/ \u2705 v1.10 : Mettre \u00e0 jour la logique TVA\r\n                        if (window.VIA_References?.mettreAJourLogiqueTVA) {\r\n                            window.VIA_References.mettreAJourLogiqueTVA(pays);\r\n                        }\r\n                    }\r\n                }\r\n            });\r\n\r\n            \/\/ \u2705 Toggle commande (chevron)\r\n            $(document).on('click', '.CommandesIcone', function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                \r\n                const $item = $(this).closest(self.config.templateItem);\r\n                const itemId = $item.attr('id');\r\n                \r\n                if (itemId) {\r\n                    if (itemId !== 'CampagneTemplate') {\r\n                        self.toggleCommande(itemId);\r\n                    }\r\n                }\r\n            });\r\n            \r\n            \/\/ \u2705 Toggle PageWeb sur mobile (clic sur titre ou ic\u00f4nes)\r\n            $(document).on('click', '.PageWebTitre', function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                \r\n                \/\/ \u2705 v2.7.3 : Sur sites pays (mode=popup), ne jamais afficher #MobileMsgReserverMSgDefaut\r\n                \/\/ v4.9ds : detection via search OU hash\r\n                var _pwtHash = window.location.hash || '';\r\n                var _pwtSearch = window.location.search || '';\r\n                var _isPopupModePWT = (_pwtSearch.indexOf('mode=popup') !== -1) ? true : (_pwtHash.indexOf('mode=popup') !== -1);\r\n                var $msg = $('#MobileMsgReserverMSgDefaut');\r\n                var msgVisible = $msg.hasClass('via-msg-visible');\r\n                var pageWebSelectionnee = !!sessionStorage.getItem('LinkSecteurPage');\r\n                var isDesktop = window.outerWidth >= 1000;\r\n\r\n                \/\/ \u2705 Desktop + 3 colonnes pas encore ouvertes \u2192 juste afficher\/masquer le message\r\n                \/\/ \u2705 v2.7.3 : En mode=popup (sites pays), PageWebColonneOpenclose n'est jamais 'Open'\r\n                \/\/ \u2192 ne pas retourner ici sinon togglePageWeb() n'est jamais appel\u00e9\r\n                if (isDesktop && sessionStorage.getItem('PageWebColonneOpenclose') !== 'Open') {\r\n                    if (_isPopupModePWT) {\r\n                        \/\/ Sites pays : laisser continuer vers togglePageWeb()\r\n                        $msg.removeClass('via-msg-visible');\r\n                    } else if (msgVisible) {\r\n                        $msg.removeClass('via-msg-visible');\r\n                        return;\r\n                    } else {\r\n                        $msg.addClass('via-msg-visible');\r\n                        return;\r\n                    }\r\n                }\r\n\r\n                if (msgVisible) {\r\n                    \/\/ Toggle : fermer le message si d\u00e9j\u00e0 visible\r\n                    $msg.removeClass('via-msg-visible');\r\n                    return;\r\n                }\r\n                if (!pageWebSelectionnee) {\r\n                    \/\/ \u2705 v2.7.3 : Sur sites pays, ne jamais afficher ce message\r\n                    if (!_isPopupModePWT) {\r\n                        $msg.addClass('via-msg-visible');\r\n                        $('.PageWebTemplate').hide();\r\n                    }\r\n                    return;\r\n                }\r\n\r\n                \/\/ \u2705 v1.9 : V\u00e9rifier si l'\u00e9tape est active\r\n                const $titre = $(this);\r\n                if ($titre.attr('data-etape-active') === 'false') {\r\n                    console.log('\ud83d\udd12 PageWebTitre d\u00e9sactiv\u00e9, clic ignor\u00e9');\r\n                    return;\r\n                }\r\n                \r\n                self.togglePageWeb();\r\n            });\r\n            \r\n            \/\/ \u2705 v1.10 : Toggle \u00e9tape R\u00e9f\u00e9rences (clic sur titre)\r\n            \/\/ Permet la visualisation m\u00eame si bon de commande cr\u00e9\u00e9\r\n            \/\/ Attacher directement apr\u00e8s un d\u00e9lai pour s'assurer que les \u00e9l\u00e9ments existent\r\n            setTimeout(function() {\r\n                \/\/ Supprimer tous les handlers existants sur cet \u00e9l\u00e9ment\r\n                $('.ReferencesTitre').off('click').on('click', function(e) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    e.stopImmediatePropagation();\r\n                    \r\n                    console.log('\ud83d\udccb Clic sur ReferencesTitre (handler direct)');\r\n                    self.toggleEtapeReferences();\r\n                    return false;\r\n                });\r\n                \r\n                \/\/ Supprimer tous les handlers existants sur cet \u00e9l\u00e9ment\r\n                $('.ChoisirPaiementTitre').off('click').on('click', function(e) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    e.stopImmediatePropagation();\r\n                    \r\n                    console.log('\ud83d\udcb3 Clic sur ChoisirPaiementTitre (handler direct)');\r\n                    self.toggleEtapePaiement();\r\n                    return false;\r\n                });\r\n\r\n                \/\/ \u2705 pb58 : Handler manquant pour .ValidationsTitre \u2014 r\u00e9gression\r\n                $('.ValidationsTitre').off('click').on('click', function(e) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    e.stopImmediatePropagation();\r\n\r\n                    console.log('\u2705 Clic sur ValidationsTitre (handler direct)');\r\n                    self.toggleEtapeValidations();\r\n                    return false;\r\n                });\r\n                \r\n                \/\/ \u2705 v1.10 : Handler pour #ProcederPaiementTitre - toggle #ProcederPaiementContenu\r\n                $('.ProcederPaiementTitre').off('click').on('click', function(e) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    e.stopImmediatePropagation();\r\n                    \r\n                    console.log('\ud83d\udcb0 Clic sur ProcederPaiementTitre (handler direct)');\r\n                    self.toggleEtapePaiementFinal();\r\n                    return false;\r\n                });\r\n                \r\n                \/\/ \u2705 Handler pour .DatesDureeCampagneTitre \u2014 toggle dates\/dur\u00e9e\/tarif\r\n                $('.DatesDureeCampagneTitre').off('click.datesHandler').on('click.datesHandler', function(e) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    e.stopImmediatePropagation();\r\n                    console.log('\ud83d\udcc5 Clic sur DatesDureeCampagneTitre');\r\n                    var $datesContent = $('.DatesDureeCampagneClass');\r\n                    var $iconeUp = $('#DatesDureeCampagneIconeUp');\r\n                    var $iconeDown = $('#DatesDureeCampagneIconeDown');\r\n                    var isVisible = $datesContent.is(':visible');\r\n                    console.log('[DatesTitre] DatesDureeCampagneClass visible:', isVisible, '| length:', $datesContent.length);\r\n                    if (isVisible) {\r\n                        $datesContent.hide();\r\n                        $iconeUp.hide();\r\n                        $iconeDown.show();\r\n                        console.log('[DatesTitre] \u2192 ferm\u00e9');\r\n                    } else {\r\n                        $datesContent.show();\r\n                        $iconeUp.show();\r\n                        $iconeDown.hide();\r\n                        \/\/ v4.9ds : \u00e0 la r\u00e9ouverture, replacer Dates apr\u00e8s R\u00e9cap + activer titre\r\n                        if (typeof self._viaActiverEtapeDates === 'function') { self._viaActiverEtapeDates(); }\r\n                        console.log('[DatesTitre] \u2192 ouvert');\r\n                    }\r\n                    return false;\r\n                });\r\n\r\n                console.log('\u2705 Handlers directs attach\u00e9s aux titres R\u00e9f\u00e9rences, Paiement, PaiementFinal et Dates');\r\n            }, 1000);\r\n            \r\n            \/\/ \u2705 v1.10 : Protection contre la touche Enter sur tous les formulaires\r\n            $(document).on('keydown', '#ProcessCommande input, #ProcessCommande select, .ChoisirPaiementClass input, .ChoisirPaiementClass select', function(e) {\r\n                if (e.key === 'Enter' || e.keyCode === 13) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    console.log('\u2328\ufe0f Touche Enter bloqu\u00e9e');\r\n                    return false;\r\n                }\r\n            });\r\n            \r\n            \/\/ Emp\u00eacher le submit des formulaires Elementor masqu\u00e9s\r\n            $(document).on('submit', '#ProcessCommande form, .elementor-form', function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                console.log('\ud83d\udeab Submit formulaire Elementor bloqu\u00e9');\r\n                return false;\r\n            });\r\n            \r\n            \/\/ \u2705 v1.10 : Bouton Valider \u00c9tape 1 - ferme l'\u00e9tape 1, ouvre le r\u00e9capitulatif et la synth\u00e8se\r\n            \/\/ \u2705 Sur desktop, .AjouterBouton ne fait rien\r\n            \/\/ \u2705 v2.4.3 : Sur mobile, ouvre les 3 bandeaux + scroll to top\r\n            $(document).on('click', '.AjouterBouton', function(e) {\r\n                e.preventDefault();\r\n                var isDesktop = window.outerWidth >= 1000;\r\n                var isPopupMode = (new URLSearchParams(window.location.search).get('mode') === 'popup');\r\n                if (isDesktop && !isPopupMode) {\r\n                    e.stopPropagation();\r\n                    return false;\r\n                }\r\n                \/\/ Mobile ou mode=popup : ouvrir les 3 bandeaux + scroll to top\r\n                if (typeof openAssocierPays === 'function') { openAssocierPays(); }\r\n                if (typeof openAssocierSecteur === 'function') { setTimeout(function() { openAssocierSecteur(); }, 150); }\r\n                if (typeof openChoixFormat === 'function') { setTimeout(function() { openChoixFormat(); }, 300); }\r\n                $('html, body').animate({ scrollTop: 0 }, 400);\r\n            });\r\n\r\n            $(document).on('click', '#Etape1BoutonValider', function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                \r\n                console.log('\u2705 Clic sur Etape1BoutonValider');\r\n                console.log('\ud83d\udd0d [BoutonValider] items total:', self.state.items.length);\r\n                console.log('\ud83d\udd0d [BoutonValider] items d\u00e9tail:', JSON.stringify(self.state.items.map(i => ({id:i.id, statut:i.statut, tarifHT:i.tarifHT, emplacementPageWeb:i.emplacementPageWeb, dateDebut:i.dateDebut, dateFin:i.dateFin}))));\r\n                \r\n                \/\/ V\u00e9rifier qu'il y a au moins un item avec tarif\r\n                const itemsAvecTarif = self.state.items.filter(item => {\r\n                    const estIndisponible = item.disponibilite === false || item.statut === 'indisponible';\r\n                    return item.tarifHT && item.tarifHT > 0 && !estIndisponible;\r\n                });\r\n                console.log('\ud83d\udd0d [BoutonValider] itemsAvecTarif:', itemsAvecTarif.length);\r\n                \r\n                if (itemsAvecTarif.length > 0) {\r\n                    \/\/ \u2705 Fermer l'\u00e9tape Dates, dur\u00e9e et tarif\r\n                    $('.DatesDureeCampagneClass').hide();\r\n                    $('#DatesDureeCampagneIconeUp').hide();\r\n                    $('#DatesDureeCampagneIconeDown').show();\r\n                    self._updateMessagesEtapes();\r\n                    \r\n                    \/\/ \u2705 v1.10 : Griser seulement les 4 premi\u00e8res \u00e9tapes (pas dates ni recapitulatif)\r\n                    self.griserEtapesJusquA('pageWeb');\r\n\r\n                    \/\/ v4.9ds : \u00e0 la validation de l'\u00e9tape Dates (tarif obtenu),\r\n                    \/\/   1) Griser le titre + chevron de l'\u00e9tape Dates (\u00e9tape termin\u00e9e)\r\n                    \/\/ \u2705 v4.9ds Pb 7 : r\u00e8gle de d\u00e9placement DatesDureeTarifContainer avant\r\n                    \/\/   EtapeRecapitulatif SUPPRIM\u00c9E \u2014 l'\u00e9tape Dates est d\u00e9sormais retir\u00e9e\r\n                    \/\/   d'Elementor et la saisie se fait dans ProcessAchatInside qui vit dans\r\n                    \/\/   l'item actif. Le container DatesDureeTarifContainer r\u00e9siduel ne doit\r\n                    \/\/   plus appara\u00eetre entre R\u00e9server et Recap.\r\n                    try { self.griserEtape('dates'); } catch(_eGD) { console.warn('[v4.9ds] griserEtape(dates) \u00e9chec:', _eGD); }\r\n\r\n                    \/\/ \u2705 Ouvrir le r\u00e9capitulatif et la synth\u00e8se\r\n                    self.ouvrirRecapitulatif();\r\n                    self.afficherSynthese();\r\n                    \r\n                    console.log('\u2705 \u00c9tapes 1 \u00e0 4 gris\u00e9es (associerPays \u2192 pageWeb), r\u00e9capitulatif ouvert');\r\n                } else {\r\n                    console.log('\u26a0\ufe0f Aucun item avec tarif, r\u00e9capitulatif non ouvert');\r\n                }\r\n                \r\n                return false;\r\n            });\r\n            \r\n            \/\/ \u2705 v4.9ds Fix 19 (Pb 14) : handler change sur la checkbox cliquable du r\u00e9cap\r\n            \/\/   (.via-recap-reserver-cb, ajout\u00e9e par remplirItemPartiel pour items \"\u00c0 r\u00e9server\").\r\n            \/\/   Au change \u2192 postMessage vers la cible ad\u00e9quate :\r\n            \/\/   - Si on est dans le popup d'achat (mode=popup) : window.parent = site pays\r\n            \/\/   - Sinon (r\u00e9gie en acc\u00e8s direct) : yearbook-iframe = site pays affich\u00e9\r\n            \/\/   Le listener c\u00f4t\u00e9 Entete.txt re\u00e7oit le message, trouve le droppable par rankId,\r\n            \/\/   et coche la vraie checkbox (.reserver-dynamic-checkbox ou ReserverEspacePublicitaire).\r\n            \/\/   Le change d\u00e9clench\u00e9 par .trigger('change') enclenche le flow normal de r\u00e9servation.\r\n            \/\/ \u2705 v4.9ds Fix 19 v2 : stopPropagation sur le click pour emp\u00eacher l'event de\r\n            \/\/   remonter \u00e0 .CampagneTemplateClass (qui d\u00e9clenche setItemActif et risque de\r\n            \/\/   re-render la checkbox avant que le change ne se d\u00e9clenche). Le check\/uncheck\r\n            \/\/   natif fonctionne et d\u00e9clenche bien le change ensuite.\r\n            $(document).on('click', '.via-recap-reserver-cb', function(_eFix19c) {\r\n                _eFix19c.stopPropagation();\r\n                \/\/ Pas de preventDefault \u2014 laisse le check\/uncheck natif s'ex\u00e9cuter\r\n            });\r\n            $(document).on('change', '.via-recap-reserver-cb', function(_eFix19) {\r\n                var $cbF19 = $(this);\r\n                var _rankF19 = $cbF19.attr('data-rank');\r\n                var _emplF19 = $cbF19.attr('data-empl');\r\n                var _itemIdF19 = $cbF19.attr('data-item-id');\r\n                var _checkedF19 = $cbF19.prop('checked');\r\n                console.log('[Fix 19] checkbox r\u00e9cap change | rank:', _rankF19, '| checked:', _checkedF19);\r\n                if (!_checkedF19) {\r\n                    \/\/ D\u00e9cocher : ne pas envoyer (pas de cas d'usage dans la demande user)\r\n                    return;\r\n                }\r\n                if (!_rankF19) {\r\n                    console.warn('[Fix 19] rank manquant, abandon');\r\n                    return;\r\n                }\r\n                var _msgF19 = {\r\n                    type: 'reserveFromRecap',\r\n                    rankId: _rankF19,\r\n                    emplacement: _emplF19,\r\n                    itemId: _itemIdF19\r\n                };\r\n                var _isPopupF19 = window.location.search.indexOf('mode=popup') !== -1\r\n                    ? true\r\n                    : window.location.hash.indexOf('mode=popup') !== -1;\r\n                if (_isPopupF19) {\r\n                    \/\/ popup achat \u2192 parent = site pays\r\n                    window.parent.postMessage(_msgF19, '*');\r\n                    console.log('[Fix 19] reserveFromRecap envoy\u00e9 au parent (mode popup)');\r\n                } else {\r\n                    \/\/ r\u00e9gie \u2192 yearbook-iframe = site pays\r\n                    var _ifrF19 = document.getElementById('yearbook-iframe');\r\n                    if (_ifrF19 ? _ifrF19.contentWindow : false) {\r\n                        _ifrF19.contentWindow.postMessage(_msgF19, '*');\r\n                        console.log('[Fix 19] reserveFromRecap envoy\u00e9 \u00e0 yearbook-iframe (mode r\u00e9gie)');\r\n                    } else {\r\n                        console.warn('[Fix 19] yearbook-iframe introuvable, message non envoy\u00e9');\r\n                    }\r\n                }\r\n                \/\/ \u2705 pb219 : au lieu de masquer en fondu, passer IMM\u00c9DIATEMENT la case ET le\r\n                \/\/   texte \"\u00e0 r\u00e9server\" en vert #3eaa13 (feedback que la r\u00e9servation est prise\r\n                \/\/   en compte). L'item sera de toute fa\u00e7on re-rendu en \"Espace r\u00e9serv\u00e9\" via le\r\n                \/\/   flow normal (postMessage \u2192 site pays \u2192 coche r\u00e9elle \u2192 \u00e9tat propag\u00e9).\r\n                var $spanAReserverF24 = $cbF19.prevAll('span[style*=\"fb5e2a\"]').first();\r\n                if ($spanAReserverF24.length) {\r\n                    $spanAReserverF24.css('color', '#3eaa13');\r\n                    $spanAReserverF24.text('\u00e0 r\u00e9server');\r\n                }\r\n                \/\/ la case coche passe en vert via le CSS :checked (#3eaa13) ; on s'assure\r\n                \/\/   qu'elle reste visible (pas de fade).\r\n                $cbF19.css('opacity', '1');\r\n                \/\/ \u2705 v4.9ds : d\u00e9clencher le scan des couleurs Recap\/Dates apr\u00e8s que l'\u00e9tat\r\n                \/\/   r\u00e9servation aura \u00e9t\u00e9 propag\u00e9 (le postMessage met ~500-1000ms \u00e0 revenir\r\n                \/\/   avec le state \"r\u00e9serv\u00e9\" mis \u00e0 jour). Plusieurs timeouts pour couvrir\r\n                \/\/   les d\u00e9lais variables de propagation cross-iframe.\r\n                [600, 1200, 2200].forEach(function(_t) {\r\n                    setTimeout(function() {\r\n                        try { if (typeof window._viaScanEtapeColors === 'function') { window._viaScanEtapeColors(); } } catch(_eC) {}\r\n                    }, _t);\r\n                });\r\n            });\r\n            \r\n            console.log('\u2705 Listeners panier initialis\u00e9s');\r\n        },\r\n        \r\n        \/**\r\n         * Synchronise les donn\u00e9es de Etape1 avec l'item actif\r\n         *\/\r\n        synchroniserAvecEtape1() {\r\n            if (!this.state.itemActif) {\r\n                console.log('\u23ed\ufe0f Aucun item actif, synchronisation ignor\u00e9e');\r\n                return;\r\n            }\r\n            \r\n            const itemActif = this.state.items.find(i => i.id === this.state.itemActif);\r\n            \r\n            if (!itemActif) {\r\n                console.warn('\u26a0\ufe0f Item actif introuvable');\r\n                return;\r\n            }\r\n            \r\n            const dateDebut = $('#form-field-DebutCampagne').val();\r\n            const dateFin = $('#form-field-FinCampagne').val();\r\n            const pays = $('#form-field-Nationalite_Societe').val();\r\n            const dureeText = $('.CampagneNbJours').text();\r\n            const duree = dureeText ? parseInt(dureeText.replace(\/[^\\d]\/g, '')) : null;\r\n            \r\n            let tarifHT = null;\r\n            let tarifTTC = null;\r\n            let devise = 'EUR';\r\n            \r\n            console.log('\ud83d\udd04 [synchroniserEtape1] dateDebut:', dateDebut, '| dateFin:', dateFin, '| pays:', pays, '| duree:', duree);\r\n            console.log('\ud83d\udd04 [synchroniserEtape1] itemActif id:', itemActif ? itemActif.id : 'NULL', '| emplacementPageWeb:', itemActif ? itemActif.emplacementPageWeb : 'N\/A', '| tarifHT actuel:', itemActif ? itemActif.tarifHT : 'N\/A');\r\n            console.log('\ud83d\udd04 [synchroniserEtape1] dernierResultatCalcul:', window.VIA_App && window.VIA_App.state ? JSON.stringify(window.VIA_App.state.dernierResultatCalcul) : 'VIA_App non dispo');\r\n            \r\n            if (window.VIA_App && window.VIA_App.state && window.VIA_App.state.dernierResultatCalcul) {\r\n                \/\/ \u2705 v1.7 : V\u00e9rifier que l'espace pub est bien s\u00e9lectionn\u00e9 avant d'utiliser le tarif\r\n                if (!itemActif.emplacementPageWeb) {\r\n                    console.warn('\u26a0\ufe0f [synchroniserEtape1] Espace pub non s\u00e9lectionn\u00e9, tarif ignor\u00e9');\r\n                } else {\r\n                    const datesCorrespondent = \r\n                        itemActif.dateDebut === dateDebut && \r\n                        itemActif.dateFin === dateFin;\r\n                    \/\/ \u2705 v2.7 : N'appliquer dernierResultatCalcul que si le formulaire a des dates ET un pays\r\n                    \/\/ \u00c9vite d'attribuer le tarif de l'item pr\u00e9c\u00e9dent \u00e0 un nouvel item vide (multi-achat)\r\n                    const hasFormDates = !!(dateDebut && dateFin);\r\n                    const hasFormPays = !!pays;\r\n                    \/\/ \u2705 v2.7 : V\u00e9rifier que le r\u00e9sultat appartient bien \u00e0 l'item actif (itemId attach\u00e9)\r\n                    const _drc = window.VIA_App.state.dernierResultatCalcul;\r\n                    const resultAppartientAItem = !_drc.itemId || _drc.itemId === itemActif.id;\r\n                    console.log('\ud83d\udd04 [synchroniserEtape1] datesCorrespondent:', datesCorrespondent, '| !itemActif.tarifHT:', !itemActif.tarifHT, '| hasFormDates:', hasFormDates, '| hasFormPays:', hasFormPays, '| resultAppartientAItem:', resultAppartientAItem);\r\n                    \r\n                    if (hasFormDates && hasFormPays && resultAppartientAItem && (!itemActif.tarifHT || !datesCorrespondent)) {\r\n                        tarifHT = _drc.tarif_ht;\r\n                        tarifTTC = _drc.tarif_ttc;\r\n                        devise = window.VIA_App.state.deviseActuelle || 'EUR';\r\n                        console.log('\ud83d\udcb0 [synchroniserEtape1] tarifHT r\u00e9cup\u00e9r\u00e9:', tarifHT);\r\n                    } else if (!resultAppartientAItem) {\r\n                        console.log('\ud83d\udcb0 [synchroniserEtape1] tarif ignor\u00e9 \u2014 r\u00e9sultat appartient \u00e0 item:', _drc.itemId, '\u2260 actif:', itemActif.id);\r\n                    } else if (!hasFormDates || !hasFormPays) {\r\n                        console.log('\ud83d\udcb0 [synchroniserEtape1] tarif ignor\u00e9 \u2014 formulaire incomplet (dates\/pays manquants)');\r\n                    } else {\r\n                        console.log('\ud83d\udcb0 [synchroniserEtape1] tarif non r\u00e9cup\u00e9r\u00e9 \u2014 tarifHT d\u00e9j\u00e0 pos\u00e9 et dates identiques');\r\n                    }\r\n                }\r\n            } else {\r\n                console.warn('\u26a0\ufe0f [synchroniserEtape1] dernierResultatCalcul absent \u2192 tarifHT restera null');\r\n            }\r\n            \r\n            const donnees = {};\r\n            let hasChanges = false;\r\n            \r\n            if (dateDebut) {\r\n                donnees.dateDebut = dateDebut;\r\n                hasChanges = true;\r\n            }\r\n            if (dateFin) {\r\n                donnees.dateFin = dateFin;\r\n                hasChanges = true;\r\n            }\r\n            if (pays) {\r\n                donnees.pays = pays;\r\n                hasChanges = true;\r\n            }\r\n            if (duree) {\r\n                donnees.duree = duree;\r\n                hasChanges = true;\r\n            }\r\n            \r\n            if (tarifHT) {\r\n                donnees.tarifHT = tarifHT;\r\n                donnees.tarifTTC = tarifTTC;\r\n                donnees.devise = devise;\r\n                donnees.statut = 'valide';\r\n                hasChanges = true;\r\n            }\r\n            \r\n            if (hasChanges) {\r\n                this.mettreAJourItem(this.state.itemActif, donnees);\r\n                \r\n                if (tarifHT) {\r\n                    const montantFormate = this.formaterMontant(tarifHT);\r\n                    const $item = $(`#${this.state.itemActif}`);\r\n                    \r\n                    if ($item.length) {\r\n                        \/\/ pb2121 : resa active d'un commercial -> libelle seul.\r\n                        $item.find('.CampagneTarifClass')\r\n                            .html(window._viaLibelleTarif2121(this.state.itemActif, `Tarif H.T. ${montantFormate} ${devise}`));\r\n                        \r\n                        console.log('\u2705 Tarif campagne mis \u00e0 jour:', montantFormate);\r\n                    }\r\n                    \r\n                    \/\/ \u2705 v1.8 : Rafra\u00eechir explicitement l'\u00e9tape Mode de paiement\r\n                    if (window.VIA_Paiement && typeof window.VIA_Paiement.rafraichirMontants === 'function') {\r\n                        window.VIA_Paiement.rafraichirMontants();\r\n                    }\r\n                }\r\n                \r\n                console.log('\ud83d\udd04 Item synchronis\u00e9 avec Etape1:', donnees);\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * Formate un montant\r\n         *\/\r\n        formaterMontant(montant) {\r\n            if (!montant) return '0,00';\r\n            return new Intl.NumberFormat('fr-FR', {\r\n                minimumFractionDigits: 2,\r\n                maximumFractionDigits: 2\r\n            }).format(montant);\r\n        },\r\n        \r\n        \/**\r\n         * Synchronise imm\u00e9diatement une seule donn\u00e9e\r\n         *\/\r\n        synchroniserDonnee(cle, valeur) {\r\n            if (!this.state.itemActif) return;\r\n            \r\n            const donnees = {};\r\n            donnees[cle] = valeur;\r\n            \r\n            this.mettreAJourItem(this.state.itemActif, donnees);\r\n            console.log(`\ud83d\udd04 ${cle} synchronis\u00e9:`, valeur);\r\n        },\r\n        \r\n        \/**\r\n         * Trouve une commande par son emplacement page web\r\n         *\/\r\n        trouverCommandeParEmplacement(emplacementWeb) {\r\n            return this.state.items.find(i => i.emplacementPageWeb === emplacementWeb);\r\n        },\r\n        \r\n        \/**\r\n         * Initialise le panier\r\n         *\/\r\n        init() {\r\n            console.log('\ud83d\udd04 Initialisation du panier...');\r\n            this.brancherLienEtape1_716();   \/\/ pb716\r\n            \r\n            \/\/ \u2705 Purge des cl\u00e9s sessionStorage transientes au d\u00e9marrage (reload page).\r\n            \/\/   Ces cl\u00e9s ne doivent pas survivre \u00e0 un reload et contaminer une nouvelle r\u00e9sa.\r\n            \/\/   a) Cl\u00e9s de sauvegarde temporaire (resetDonneesCampagne \u2192 afficherEtape1DansItem)\r\n            sessionStorage.removeItem('_via_saved_dateDebut');\r\n            sessionStorage.removeItem('_via_saved_dateFin');\r\n            sessionStorage.removeItem('_via_saved_duree');\r\n            sessionStorage.removeItem('_via_saved_pays');\r\n            \/\/   b) Cl\u00e9s index\u00e9es dates\/tarif\/pays annonceur \u2014 recalcul\u00e9es \u00e0 chaque session.\r\n            \/\/      Les cl\u00e9s de structure (espace pub, format, secteur, statut) sont conserv\u00e9es.\r\n            (function _purgeIndexedTransient() {\r\n                for (var _pi = 1; _pi <= 20; _pi++) {\r\n                    var _hasIndex = sessionStorage.getItem('Commande_Emplacement_Page_Web' + _pi) !== null\r\n                                 || sessionStorage.getItem('Commande_Format_Transmis' + _pi) !== null;\r\n                    if (!_hasIndex) { break; } \/\/ plus d'items \u00e0 cet index, on arr\u00eate\r\n                    sessionStorage.removeItem('Debut_de_campagne'         + _pi);\r\n                    sessionStorage.removeItem('Fin_de_campagne'           + _pi);\r\n                    sessionStorage.removeItem('Duree_de_la_campagne'      + _pi);\r\n                    sessionStorage.removeItem('TarifHTDataVosCampagnes'   + _pi);\r\n                    sessionStorage.removeItem('TarifTTCDataVosCampagnes'  + _pi);\r\n                    sessionStorage.removeItem('NationaliteDataVosCampagnes' + _pi);\r\n                }\r\n                console.log('\ud83e\uddf9 [init] cl\u00e9s transientes purg\u00e9es (dates\/tarif\/pays annonceur)');\r\n            })();\r\n            \r\n            if (typeof jQuery === 'undefined') {\r\n                console.error('\u274c jQuery non charg\u00e9, panier non initialis\u00e9');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v2.4.3 : Restaurer le blocage si FinaliserStep=Yes (rechargement de page)\r\n            if (sessionStorage.getItem('FinaliserStep') === 'Yes') {\r\n                var self2 = this;\r\n                setTimeout(function() { self2.bloquerInteractionsApresFinalisation(); }, 500);\r\n            }\r\n            \r\n            \/\/ \u2705 Styles desktop\/mobile d\u00e8s le chargement\r\n            \/* ============================================================\r\n             * pb1637 : LARGEUR NULLE N'EST PAS LARGEUR MOBILE.\r\n             *   Constat user : les liseres bleus s'affichent sur desktop. Ils sont\r\n             *   poses par la branche mobile de ce bloc (l.10570,\r\n             *   $('.LisereBleu').css('border', '3px solid #A2C6F3')) \u2014 branche qui ne\r\n             *   devrait jamais s'executer a 1030 px.\r\n             *   Elle s'execute pourtant, parce que ce test tourne au chargement, quand\r\n             *   innerWidth vaut encore 0 dans l'iframe : et 0 <= 767 est vrai. Le\r\n             *   contexte est donc juge mobile, la bordure est posee, et plus rien ne la\r\n             *   retire.\r\n             *   Meme famille que pb1538, pb1539, pb1584 et pb1593 : une decision prise\r\n             *   avant que la valeur mesuree existe. La parade est la meme \u2014 exiger une\r\n             *   largeur reelle.\r\n             *   Revert : window._viaPb1637Off = true (test d'origine).\r\n             * ============================================================ *\/\r\n            const isMobile = (window._viaPb1637Off === true)\r\n                ? (window.innerWidth <= 767)\r\n                : (window.innerWidth > 0 ? (window.innerWidth <= 767) : false);\r\n            if (window.innerWidth === 0) {\r\n                if (window._viaSig1637 !== '1') {\r\n                    window._viaSig1637 = '1';\r\n                    console.log('[pb1637] largeur encore nulle \u2014 contexte NON juge mobile');\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 v2.4.3 : Sur mobile, aligner horizontalement les \u00e9l\u00e9ments des items\r\n            if (isMobile) {\r\n            \/\/ \u2705 CampagnePositionClass : s\u00e9parateur flex invisible entre Pays et Page\r\n            if (!document.getElementById('via-panier-position-style')) {\r\n                var _posStyle = document.createElement('style');\r\n                _posStyle.id = 'via-panier-position-style';\r\n                _posStyle.textContent = '.CampagneTemplateClass .CampagnePositionClass { order: 3 !important; flex-basis: 100% !important; height: 0 !important; margin: 0 !important; padding: 0 !important; overflow: hidden !important; }';\r\n                document.head.appendChild(_posStyle);\r\n            }\r\n                            if (!document.getElementById('via-panier-mobile-style')) {\r\n                    var _mobileStyle = document.createElement('style');\r\n                    _mobileStyle.id = 'via-panier-mobile-style';\r\n                    _mobileStyle.textContent = [\r\n                        '.CampagnePageRefClass [data-id=\"2f82cc64\"] {',\r\n                        '  align-items: center !important;',\r\n                        '}',\r\n                        '.CampagnePageRefClass [data-id=\"2f82cc64\"] .elementor-widget-container,',\r\n                        '.CampagnePageRefClass [data-id=\"2f82cc64\"] .elementor-widget-container p {',\r\n                        '  margin: 0 !important;',\r\n                        '  padding: 0 !important;',\r\n                        '  line-height: inherit !important;',\r\n                        '}'\r\n                    ].join(' ');\r\n                    document.head.appendChild(_mobileStyle);\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 R\u00e9initialiser BonCommandeCree au chargement de la page\r\n            sessionStorage.removeItem('BonCommandeCree');\r\n            console.log('\ud83d\udd04 BonCommandeCree r\u00e9initialis\u00e9 au chargement');\r\n            \r\n            if (!isMobile) {\r\n                $('.VosCampagnesConteneurClass').css('border', 'none');\r\n            } else {\r\n                \/\/ v4.9ds : skip max-height:335px si on est en popup desktop etroit (mode=popup).\r\n                \/\/   Le popup d'achat dans la regie peut avoir innerWidth <= 767px\r\n                \/\/   sans pour autant etre un vrai mobile : il ne faut pas couper\r\n                \/\/   l'iframe a 335px (les espaces pub seraient mal rendus).\r\n                var _shMobHash = window.location.hash || '';\r\n                var _shMobSearch = window.location.search || '';\r\n                var _isShMobPopup = (_shMobHash.indexOf('mode=popup') !== -1) ? true : (_shMobSearch.indexOf('mode=popup') !== -1);\r\n                if (!_isShMobPopup) {\r\n                    \/\/ \u2705 Max-height sur .PageWebTemplate sur mobile (vrai mobile uniquement)\r\n                    $('.PageWebTemplate').css({\r\n                        'max-height': '335px',\r\n                        'overflow-y': 'hidden'\r\n                    });\r\n                }\r\n                \/\/ \u2705 Fond blanc sur .MobileFondBlanc\r\n                $('.MobileFondBlanc').css('background-color', '#FFFFFF');\r\n                \/\/ \u2705 Border bleu sur .LisereBleu\r\n                \/* pb1637b : filet \u2014 si la bordure a ete posee par un autre chemin, elle\r\n                   est retiree des que la largeur depasse le seuil mobile. *\/\r\n                if (window.innerWidth > 767) {\r\n                    $('.LisereBleu').css('border', '');\r\n                } else {\r\n                    $('.LisereBleu').css('border', '3px solid #A2C6F3');\r\n                }\r\n            }\r\n            \r\n            \/\/ \u2705 Tarifs en bleu (ordi et mobile)\r\n            $('#Tariftobedisplayed').css('color', '#4B689B');\r\n            $('[id*=\"TarifCommercial\"]').css('color', '#4B689B');\r\n            \r\n            if (!sessionStorage.getItem('AchatEspaceCall')) {\r\n                sessionStorage.setItem('AchatEspaceCall', 'Yes');\r\n                console.log('\u2705 AchatEspaceCall initialis\u00e9 \u00e0 Yes');\r\n            }\r\n            \r\n            $('#VosCampagnesConteneur').hide();\r\n            console.log('\ud83e\uddf9 VosCampagnesConteneur masqu\u00e9 au d\u00e9marrage');\r\n            \r\n            \/\/ \u2705 v1.8 : Fermer le r\u00e9capitulatif par d\u00e9faut\r\n            this.fermerRecapitulatif();\r\n            \r\n            \/\/ \u2705 Ne cacher que si l'utilisateur n'est pas commercial\r\n            if (sessionStorage.getItem('CommercialConnected') !== 'Yes') {\r\n                $('#TarifCommercialtobedisplayedConteneur').hide();\r\n                console.log('\ud83e\uddf9 TarifCommercialtobedisplayedConteneur masqu\u00e9 au d\u00e9marrage');\r\n            }\r\n            \r\n            const $template = $('#CampagneTemplate');\r\n            $template.hide();\r\n            $template.css('display', 'none');\r\n            $template.attr('data-is-template', 'true');\r\n            \r\n            this.initListeners();\r\n            \r\n            \/\/ \u2705 Initialiser les titres des \u00e9tapes (visibles mais d\u00e9sactiv\u00e9s)\r\n            this.initTitresEtapesDesactives();\r\n            \r\n            const finaliserStep = sessionStorage.getItem('FinaliserStep');\r\n            if (finaliserStep === 'Yes') {\r\n                setTimeout(() => {\r\n                    this.gererModeFinalisationCommandes();\r\n                }, 500);\r\n            }\r\n            \r\n            console.log('\u2705 Panier initialis\u00e9');\r\n            \r\n\r\n        },\r\n        \r\n        \/**\r\n         * Met \u00e0 jour les couleurs des titres selon l'\u00e9tat de la commande\r\n         *\/\r\n        mettreAJourCouleursTitres(itemId) {\r\n            const item = this.state.items.find(i => i.id === itemId);\r\n            \r\n            if (!item) {\r\n                $('#ChoisirDatesDureeCampagneTitreText').css('color', '#FB5E2A');\r\n                $('#ChoisirNationaliteAnnonceurTitreText').css('color', '#FB5E2A');\r\n                return;\r\n            }\r\n            \r\n            if (item.dateDebut && item.dateFin && item.duree) {\r\n                $('#ChoisirDatesDureeCampagneTitreText').css('color', '#213864');\r\n                console.log('\u2705 Dates compl\u00e8tes \u2192 Titre bleu');\r\n                \/\/ pb94 : dates compl\u00e8tes \u2192 masquer CampagneMsgAccompagnement sur l'item actif\r\n                var _itemElDates = document.getElementById(itemId);\r\n                if (_itemElDates) {\r\n                    var _msgDates = _itemElDates.querySelector('.CampagneMsgAccompagnement');\r\n                    if (_msgDates) { _msgDates.style.setProperty('display', 'none', 'important'); }\r\n                }\r\n            } else {\r\n                $('#ChoisirDatesDureeCampagneTitreText').css('color', '#FB5E2A');\r\n                console.log('\u26a0\ufe0f Dates incompl\u00e8tes \u2192 Titre orange');\r\n            }\r\n            \r\n            if (item.pays) {\r\n                $('#ChoisirNationaliteAnnonceurTitreText').css('color', '#213864');\r\n                console.log('\u2705 Pays valide \u2192 Titre bleu');\r\n            } else {\r\n                $('#ChoisirNationaliteAnnonceurTitreText').css('color', '#FB5E2A');\r\n                console.log('\u26a0\ufe0f Pays manquant \u2192 Titre orange');\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 Initialise les titres des \u00e9tapes (visibles mais d\u00e9sactiv\u00e9s)\r\n         * Les titres sont affich\u00e9s avec chevron ferm\u00e9, mais non cliquables\r\n         *\/\r\n        initTitresEtapesDesactives() {\r\n            console.log('\ud83d\udd12 Initialisation titres \u00e9tapes d\u00e9sactiv\u00e9s...');\r\n            \r\n            \/\/ \u2705 v1.9 : Afficher #ProcessEtapes qui contient les \u00e9tapes (Partie3 fusionn\u00e9)\r\n            const $processCommande = $('#ProcessCommande');\r\n            const $processEtapes = $('#ProcessEtapes');\r\n            \r\n            console.log('\ud83d\udd0d \u00c9l\u00e9ments trouv\u00e9s:');\r\n            console.log('   - #ProcessCommande:', $processCommande.length > 0 ? 'OUI' : 'NON');\r\n            console.log('   - #ProcessEtapes:', $processEtapes.length > 0 ? 'OUI' : 'NON');\r\n            \r\n            \/\/ \u2705 v1.9 : Afficher #ProcessEtapes (avec display:flex pour le layout)\r\n            $processEtapes.css('display', 'flex');\r\n            \r\n            \/\/ Configuration des \u00e9tapes\r\n            const etapes = [\r\n                \/\/ \u2705 v1.10 : Ajout des \u00e9tapes initiales\r\n                { \r\n                    id: 'associerPays',\r\n                    titre: '.AssocierPaysTitre',\r\n                    conteneur: '#AssocierPaysConteneur',\r\n                    etape: '#Etape1Container',\r\n                    iconeUp: '#AssocierPaysTitreIconeUp',\r\n                    iconeDown: '#AssocierPaysTitreIconeDown'\r\n                },\r\n                { \r\n                    id: 'associerSecteur',\r\n                    titre: '#AssocierSecteurTitre, .AssocierSecteurTitre',\r\n                    conteneur: '#AssocierSecteurConteneur',\r\n                    etape: '#Etape1Container',\r\n                    iconeUp: '#AssocierSecteurTitreIconeUp',\r\n                    iconeDown: '#AssocierSecteurTitreIconeDown'\r\n                },\r\n                { \r\n                    id: 'choixFormat',\r\n                    titre: '#ChoixFormatTitre, .ChoixFormatTitre',\r\n                    conteneur: '#ChoixFormatConteneur',\r\n                    etape: '#Etape1Container',\r\n                    iconeUp: '#ChoixFormatTitreIconeUp',\r\n                    iconeDown: '#ChoixFormatTitreIconeDown'\r\n                },\r\n                { \r\n                    id: 'pageWeb',\r\n                    titre: '#PageWebTitre, .PageWebTitre',\r\n                    conteneur: '.PageWebTemplate',\r\n                    etape: '#PageWebColonne',\r\n                    iconeUp: '#PageWebTitreIconeUp',\r\n                    iconeDown: '#PageWebTitreIconeDown'\r\n                },\r\n                { \r\n                    id: 'dates',\r\n                    titre: '.DatesDureeCampagneTitre',\r\n                    conteneur: '.DatesDureeCampagneClass',\r\n                    etape: '#Etape1Container',\r\n                    iconeUp: '#DatesDureeCampagneIconeUp',\r\n                    iconeDown: '#DatesDureeCampagneIconeDown'\r\n                },\r\n                { \r\n                    id: 'recapitulatif',\r\n                    titre: '.RecapitulatifVosCommandestitre',\r\n                    conteneur: '.VosCampagnesConteneurClass',\r\n                    etape: '#RecapitulatifVosCommandesContainer',\r\n                },\r\n                { \r\n                    id: 'references',\r\n                    titre: '.ReferencesTitre',\r\n                    conteneur: '.ReferencesConteneur',\r\n                    etape: '#EtapeReferences',\r\n                    iconeUp: '#ReferencesTitreIconeUp',\r\n                    iconeDown: '#ReferencesTitreIconeDown'\r\n                },\r\n                { \r\n                    id: 'paiement',\r\n                    titre: '.ChoisirPaiementTitre',\r\n                    conteneur: '.ChoisirPaiementClass',\r\n                    etape: '#EtapeModedePaiement',\r\n                    iconeUp: '#ChoisirPaiementTitreIconeUp',\r\n                    iconeDown: '#ChoisirPaiementTitreIconeDown'\r\n                },\r\n                { \r\n                    id: 'validations',\r\n                    titre: '.ValidationsTitre',\r\n                    conteneur: '#ValidationsConteneur',\r\n                    etape: '#EtapeValidations',\r\n                    iconeUp: '#ValidationsTitreIconeUp',\r\n                    iconeDown: '#ValidationsTitreIconeDown'\r\n                },\r\n                { \r\n                    id: 'paiementFinal',\r\n                    titre: '.ProcederPaiementTitre',\r\n                    conteneur: '#ProcederPaiementContenu',  \/\/ \u2705 v1.10 : Cibler #ProcederPaiementContenu\r\n                    etape: '#EtapePaiement',\r\n                    iconeUp: '#ProcederPaiementTitreIconeUp',\r\n                    iconeDown: '#ProcederPaiementTitreIconeDown'\r\n                }\r\n            ];\r\n            \r\n            \/\/ ================================================================\r\n            \/\/ pb907 : l'etape PageWebMobile (pb892) est inseree ICI, de facon\r\n            \/\/   CONDITIONNELLE, et non dans le tableau litteral ci-dessus (pb901).\r\n            \/\/   Deux bugs corriges d'un coup :\r\n            \/\/   (1) DESKTOP \u2014 la boucle d'init fait $(etape.etape).show() sur chaque\r\n            \/\/       entree : avec #PageWebMobileEtape dans la config, le show() posait\r\n            \/\/       display:block INLINE et ecrasait le elementor-hidden-desktop de\r\n            \/\/       l'element (cf capture DOM user). Absente de la config sur desktop,\r\n            \/\/       l'etape n'est plus jamais touchee -> Elementor la garde masquee.\r\n            \/\/   (2) COULEUR \u2014 marquerEtapeEnCours() prend la PREMIERE etape non grisee\r\n            \/\/       puis \"break\". 'pageWeb' (etape desktop, jamais grisee sur mobile)\r\n            \/\/       venait AVANT 'pageWebMobile' : la boucle s'arretait sur pageWeb et\r\n            \/\/       n'atteignait jamais pageWebMobile -> titre toujours gris (pb906).\r\n            \/\/       Insertion AVANT pageWeb -> elle est evaluee en premier sur mobile.\r\n            \/\/   Revert : window._viaPb907Off = true (etape non enregistree du tout).\r\n            \/\/ ================================================================\r\n            \/\/ ================================================================\r\n            \/\/ pb915 : ORDRE du process d'achat regie (desktop + mobile) :\r\n            \/\/     processAnnonceur -> associerPays -> associerSecteur\r\n            \/\/     -> processDatesDevise -> choixFormat -> ...\r\n            \/\/   Les blocs sont deja au bon endroit dans le DOM Elementor : seul\r\n            \/\/   l'ordre LOGIQUE compte ici, car marquerEtapeEnCours() prend la\r\n            \/\/   PREMIERE etape non grisee de ce tableau (cf pb907 : c'est\r\n            \/\/   exactement l'ordre qui avait fait echouer pageWebMobile).\r\n            \/\/   L'ancienne etape 'dates' (#Etape1Container \/ DatesDureeTarif) est\r\n            \/\/   RETIREE du tableau : son DOM est masque par pb915 (yearbook-media.js),\r\n            \/\/   la laisser ici la ferait choisir comme \"etape en cours\" sur un bloc\r\n            \/\/   invisible -> plus aucune etape ne paraitrait active.\r\n            \/\/   Revert : window._viaPb915Off = true (ordre et etapes d'origine).\r\n            \/\/ ================================================================\r\n            if (window._viaPb915Off !== true) {\r\n                var _idxDates915 = etapes.findIndex(function (_e) { return _e.id === 'dates'; });\r\n                if (_idxDates915 !== -1) { etapes.splice(_idxDates915, 1); }\r\n                \/\/ ================================================================\r\n                \/\/ pb1072 : DATES APRES FORMAT (demande user, option (a)).\r\n                \/\/   pb915 inserait processDatesDevise AVANT choixFormat. La sonde\r\n                \/\/   pb1071 a montre l'ordre reel :\r\n                \/\/     annonceur > site pays > secteurs > DATES > FORMAT > page web\r\n                \/\/   alors que la regle d'enchainement demandee est :\r\n                \/\/     annonceur > site pays > secteurs > FORMAT > DATES > page web\r\n                \/\/   Cet ordre n'est pas cosmetique : marquerEtapeEnCours choisit\r\n                \/\/   \"la premiere etape non grisee\" DANS CE TABLEAU (pb915 le\r\n                \/\/   documente comme le piege qui avait fait echouer pb907). Le\r\n                \/\/   corriger ici corrige donc a la fois l'enchainement et la\r\n                \/\/   couleur, sans toucher au DOM Elementor \u2014 les blocs y sont deja\r\n                \/\/   dans le bon ordre.\r\n                \/\/   +1 : on insere APRES choixFormat au lieu d'avant.\r\n                \/\/   Revert : window._viaPb1072Off = true (ordre pb915 d'origine).\r\n                \/\/ ================================================================\r\n                \/\/ ================================================================\r\n                \/\/ pb2406 : DATES AVANT FORMAT (demande JF, 12\/09\/2026) \u2014 retour a\r\n                \/\/   l'ordre pb915 : annonceur > site pays > secteur > DATES > FORMAT.\r\n                \/\/   Meme mecanisme que pb1072, dans l'autre sens : on insere AVANT\r\n                \/\/   choixFormat (le +1 de pb1072 n'est plus applique). Les blocs\r\n                \/\/   Elementor sont deplaces par JF ; seul l'ordre LOGIQUE est ici.\r\n                \/\/   Ce tableau est lu par marquerEtapeEnCours, le veilleur pb1076,\r\n                \/\/   le sequenceur pb1099 et la PROPAGATION MONOTONE pb1162 : un\r\n                \/\/   format choisi declarera desormais les dates faites \u2014 d'ou pb2407.\r\n                \/\/   Temoin : la ligne '[pb915] ordre des etapes' ci-dessous.\r\n                \/\/   Revert : window._viaPb2406Off = true (ordre pb1072, dates apres\r\n                \/\/   format).\r\n                \/\/ ================================================================\r\n                var _idxFormat915 = etapes.findIndex(function (_e) { return _e.id === 'choixFormat'; });\r\n                if (_idxFormat915 === -1) { _idxFormat915 = 0; }\r\n                else if (window._viaPb2406Off === true) {\r\n                    if (window._viaPb1072Off !== true) { _idxFormat915 = _idxFormat915 + 1; }\r\n                }\r\n                etapes.splice(_idxFormat915, 0, {\r\n                    id: 'processDatesDevise',\r\n                    titre: '.ProcessDatesDevisetitre',\r\n                    conteneur: '.ProcessDatesDeviseConteneurClass',\r\n                    etape: '#ProcessDatesDeviseEtape',\r\n                    iconeUp: '#ProcessDatesDeviseIconeUp',\r\n                    iconeDown: '#ProcessDatesDeviseIconeDown'\r\n                });\r\n                var _idxPays915 = etapes.findIndex(function (_e) { return _e.id === 'associerPays'; });\r\n                if (_idxPays915 === -1) { _idxPays915 = 0; }\r\n                etapes.splice(_idxPays915, 0, {\r\n                    id: 'processAnnonceur',\r\n                    titre: '.ProcessAnnonceurtitre',\r\n                    conteneur: '.ProcessAnnonceurConteneurClass',\r\n                    etape: '#ProcessAnnonceurEtape',\r\n                    iconeUp: '#ProcessAnnonceurIconeUp',\r\n                    iconeDown: '#ProcessAnnonceurIconeDown'\r\n                });\r\n                console.log('[pb915] ordre des etapes : ' + etapes.map(function (_e) { return _e.id; }).join(' > '));\r\n            }\r\n            \/\/ ================================================================\r\n            \/\/ pb1111 : l'etape PAGE WEB existe AUSSI sur DESKTOP (demande user).\r\n            \/\/   pb907 ne l'enregistrait qu'en dessous de 1000px, ou le conteneur de\r\n            \/\/   page web est reellement affiche. Sur desktop, la page vit dans le\r\n            \/\/   VLP \u2014 mais le TITRE reste utile : il jalonne l'etape \"choisir un\r\n            \/\/   espace publicitaire\" et porte sa phrase.\r\n            \/\/   L'etape est donc enregistree dans les deux cas. Son conteneur n'est\r\n            \/\/   pas affiche sur desktop (le VLP tient ce role) ; seul le titre l'est.\r\n            \/\/   Elle est placee AVANT 'recapitulatif' : c'est l'ordre du parcours \u2014\r\n            \/\/   on choisit l'espace, puis on regarde le recapitulatif.\r\n            \/\/   Revert : window._viaPb907Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb907Off !== true) {\r\n                var _idxPW907 = etapes.findIndex(function(_e) { return _e.id === 'pageWeb'; });\r\n                if (_idxPW907 === -1) {\r\n                    _idxPW907 = etapes.findIndex(function(_e) { return _e.id === 'recapitulatif'; });\r\n                }\r\n                if (_idxPW907 === -1) { _idxPW907 = etapes.length; }\r\n                etapes.splice(_idxPW907, 0, {\r\n                    id: 'pageWebMobile',\r\n                    titre: '.PageWebMobiletitre',\r\n                    conteneur: '.PageWebMobileConteneurClass',\r\n                    etape: '#PageWebMobileEtape',\r\n                    iconeUp: '#PageWebMobileIconeUp',\r\n                    iconeDown: '#PageWebMobileIconeDown'\r\n                });\r\n                console.log('[pb907] \u00e9tape pageWebMobile enregistr\u00e9e (mobile) \u00e0 l\\'index ' + _idxPW907 + ', avant pageWeb');\r\n            }\r\n            \r\n            \/\/ Sauvegarder la config dans state\r\n            this.state.etapesConfig = etapes;\r\n\r\n            \/\/ pb1076 : demarrer le veilleur une fois la config connue.\r\n            if (!window._viaTimerVeil1076) {\r\n                var _self1076 = this;\r\n                window._viaTimerVeil1076 = setInterval(function () {\r\n                    try { _self1076._veilleurEtapes1076(); } catch (_e) {}\r\n                }, 400);\r\n                console.log('[pb1076] veilleur des \u00e9tapes d\u00e9marr\u00e9 (400ms)');\r\n                try { _self1076._armerFinaliser1157(); } catch (_e1157a) {}   \/\/ pb1157\r\n            }\r\n            \r\n            \/\/ Initialiser chaque \u00e9tape\r\n            etapes.forEach(etape => {\r\n                console.log('\ud83d\udd27 Initialisation \u00e9tape:', etape.id);\r\n                \r\n                \/\/ Afficher le conteneur de l'\u00e9tape (pour que le titre soit visible)\r\n                \/\/ \u2705 v2.0.9 : Sur mobile, #EtapeValidations et #EtapePaiement restent masqu\u00e9s\r\n                \/\/ via la r\u00e8gle CSS !important :not(.via-etape-visible) \u2014 .show() est neutralis\u00e9\r\n                \/\/ ================================================================\r\n                \/\/ pb1146 : sur MOBILE, ne PAS reafficher les etapes de la colonne\r\n                \/\/   droite (demande user, cf pb1145\/pb1145b cote regie).\r\n                \/\/   Constat : le HTML montre #PageWebMobileEtape avec style=\"\" \u2014\r\n                \/\/   ni display:none ni display:block. Ce n'est pas un conflit de\r\n                \/\/   priorite mais une SUPPRESSION : c'est la signature de ce\r\n                \/\/   $(etape.etape).show(), qui retire la propriete posee par le\r\n                \/\/   .hide() de pb1145b.\r\n                \/\/   Cette boucle d'init tourne apres, et rend visible chaque etape de\r\n                \/\/   la config. On l'exclut pour les cinq etapes concernees, en mobile\r\n                \/\/   uniquement \u2014 sur desktop le comportement est inchange.\r\n                \/\/   Revert : window._viaPb1146Off = true.\r\n                \/\/ ================================================================\r\n                var _masq1146 = ['pageWebMobile', 'references', 'paiement',\r\n                                 'validations', 'paiementFinal'];\r\n                var _skip1146 = false;\r\n                if (window._viaPb1146Off !== true) {\r\n                    if (window.outerWidth < 1000) {\r\n                        if (_masq1146.indexOf(etape.id) !== -1) { _skip1146 = true; }\r\n                    }\r\n                }\r\n                if (_skip1146) {\r\n                    $(etape.etape).hide();\r\n                    console.log('   - Etape container:', etape.etape, '\u2192 MASQU\u00c9 (pb1146, mobile)');\r\n                } else {\r\n                    $(etape.etape).show();\r\n                    console.log('   - Etape container:', etape.etape, '\u2192 visible');\r\n                }\r\n                \r\n                \/\/ \u2705 v1.9 : Ne pas forcer display sur le titre, laisser Elementor g\u00e9rer\r\n                \/\/ Le titre est d\u00e9j\u00e0 visible via Elementor\r\n                console.log('   - Titre:', etape.titre);\r\n                \r\n                \/\/ \u2705 Afficher TOUS les parents entre le titre et l'\u00e9tape\r\n                const $parents = $(etape.titre).parentsUntil(etape.etape);\r\n                $parents.each(function() {\r\n                    $(this).show();\r\n                    console.log('   - Parent interm\u00e9diaire:', this.className || this.id, '\u2192 visible');\r\n                });\r\n                \r\n                \/\/ \u2705 v1.7 : Tous les menus FERM\u00c9S par d\u00e9faut\r\n                \/\/ Chevron ferm\u00e9 (down visible, up masqu\u00e9)\r\n                $(etape.iconeUp).hide();\r\n                $(etape.iconeDown).show();\r\n                \/\/ Conteneur masqu\u00e9\r\n                $(etape.conteneur).hide();\r\n                \r\n                \/\/ \u2705 v1.10 : Tous les titres sont des accord\u00e9ons cliquables\r\n                const $titre = $(etape.titre);\r\n                \r\n                \/\/ \u2705 v1.10 : TOUS les titres sont cliquables (accord\u00e9ons)\r\n                $titre.css({\r\n                    'cursor': 'pointer'\r\n                }).attr('data-etape-active', 'true');\r\n                \r\n                $titre.each(function() {\r\n                    var is3Col = sessionStorage.getItem('PageWebColonneOpenclose') === 'Open';\r\n                    if (is3Col && $(this).hasClass('elementor-widget-text-editor')) {\r\n                        this.style.setProperty('pointer-events', 'none', 'important');\r\n                        this.style.setProperty('cursor', 'default', 'important');\r\n                    } else {\r\n                        this.style.setProperty('pointer-events', 'auto', 'important');\r\n                    }\r\n                });\r\n                console.log('   \u2705 Titre ACTIF:', etape.id);\r\n            });\r\n            \r\n            \/\/ \u2705 v1.10 : Masquer #ProcederPaiementContenu au d\u00e9part\r\n            $('#ProcederPaiementContenu').hide();\r\n            \r\n            console.log('\u2705 Titres \u00e9tapes initialis\u00e9s (tous cliquables)');\r\n            \r\n            \/\/ \u2705 v1.16.0 : Marquer la premi\u00e8re \u00e9tape non-gris\u00e9e en bleu\r\n            this.marquerEtapeEnCours();\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 Active le titre d'une \u00e9tape sp\u00e9cifique\r\n         * @param {string} etapeId - ID de l'\u00e9tape ('references', 'paiement', 'validations', 'paiementFinal')\r\n         * @param {boolean} ouvrirConteneur - Si true, affiche aussi le conteneur (d\u00e9faut: true)\r\n         *\/\r\n        activerTitreEtape(etapeId, ouvrirConteneur = true) {\r\n            if (!this.state.etapesConfig) return;\r\n            \r\n            const etape = this.state.etapesConfig.find(e => e.id === etapeId);\r\n            if (!etape) {\r\n                console.warn('\u26a0\ufe0f \u00c9tape non trouv\u00e9e:', etapeId);\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 Activer le titre (curseur main, clics autoris\u00e9s)\r\n            const $titre = $(etape.titre);\r\n            $titre.css({\r\n                'cursor': 'pointer'\r\n            }).attr('data-etape-active', 'true');\r\n            \r\n            \/\/ \u2705 R\u00e9activer pointer-events avec !important\r\n            $titre.each(function() {\r\n                var is3Col = sessionStorage.getItem('PageWebColonneOpenclose') === 'Open';\r\n                if (is3Col && $(this).hasClass('elementor-widget-text-editor')) {\r\n                    this.style.setProperty('pointer-events', 'none', 'important');\r\n                    this.style.setProperty('cursor', 'default', 'important');\r\n                } else {\r\n                    this.style.setProperty('pointer-events', 'auto', 'important');\r\n                }\r\n            });\r\n            \r\n            \/\/ \u2705 Afficher le conteneur de l'\u00e9tape (seulement si demand\u00e9)\r\n            if (ouvrirConteneur) {\r\n                \/\/ \u2705 v2.6 : Afficher via setProperty pour passer display:none!important du CSS r\u00e9gie\r\n                \/* ============================================================\r\n                 * pb1717 : LE SECOND OUVREUR D ETAPE, ET IL EST SINGULIER.\r\n                 *   Constat user apres pb1716 : aucun log pb1716, et pourtant\r\n                 *   #ModePaiementLisereBleu porte toujours display:block !important\r\n                 *   \u2014 tandis que les TROIS autres .ChoisirPaiementClass ont\r\n                 *   style=\"\", vid\u00e9 par pb1716. Un seul element reecrit sur quatre :\r\n                 *   la signature d un querySelector, pas d un querySelectorAll.\r\n                 *   C est cet ouvreur-ci, qui ne prend QUE le premier conteneur.\r\n                 *   pb1716 retirait bien la propriete ; celui-ci la reposait juste\r\n                 *   apres. Deux ouvreurs pour une meme etape, et je n en avais\r\n                 *   corrige qu un.\r\n                 *   Meme traitement : on RETIRE le display inline pose a la\r\n                 *   fermeture, et la feuille rend flex a ce qui est flex. Et on\r\n                 *   traite TOUS les conteneurs, pas le premier \u2014 l ecart entre\r\n                 *   querySelector et querySelectorAll est precisement ce qui a\r\n                 *   rendu le defaut visible.\r\n                 *   Filet identique : si l element reste masque par une feuille,\r\n                 *   on force block comme avant et on le dit.\r\n                 *   Revert : window._viaPb1717Off = true.\r\n                 * ============================================================ *\/\r\n                var _tous1717 = document.querySelectorAll(etape.conteneur);\r\n                if (!_tous1717.length) { $(etape.conteneur).show(); }\r\n                for (var _q1717 = 0; _q1717 < _tous1717.length; _q1717++) {\r\n                    var _e1717 = _tous1717[_q1717];\r\n                    if (window._viaPb1717Off === true) {\r\n                        _e1717.style.setProperty('display', 'block', 'important');\r\n                    } else {\r\n                        _e1717.style.removeProperty('display');\r\n                        var _d1717 = '';\r\n                        try { _d1717 = window.getComputedStyle(_e1717).display; } catch (_x1717) {}\r\n                        if (_d1717 === 'none') {\r\n                            _e1717.style.setProperty('display', 'block', 'important');\r\n                            console.log('[pb1717] ' + etapeId + ' : ' + (_e1717.id || etape.conteneur)\r\n                                + ' reste masque par une feuille -> block force');\r\n                        }\r\n                    }\r\n                }\r\n                \r\n                \/\/ \u2705 v2.6 : G\u00e9rer les ic\u00f4nes pour toutes les \u00e9tapes (pas seulement paiementFinal)\r\n                if (etape.iconeUp && etape.iconeDown) {\r\n                    var _icUp = document.querySelector(etape.iconeUp);\r\n                    var _icDn = document.querySelector(etape.iconeDown);\r\n                    if (_icUp) { _icUp.style.setProperty('display', 'block', 'important'); }\r\n                    if (_icDn) { _icDn.style.setProperty('display', 'none', 'important'); }\r\n                }\r\n                \r\n                \/\/ \u2705 v1.10 : Pour paiementFinal, afficher #ProcederPaiementContenu et griser validations\r\n                if (etapeId === 'paiementFinal') {\r\n                    $('#ProcederPaiementContenu').show();\r\n                    $(etape.iconeUp).show();\r\n                    $(etape.iconeDown).hide();\r\n                    \r\n                    \/\/ Griser seulement l'\u00e9tape validations\r\n                    this.griserEtape('validations');\r\n                    \r\n                    \/\/ \u2705 v2.0 : Scroll to bottom dans #ColonneDroite apr\u00e8s ouverture Paiement\r\n                    setTimeout(function() {\r\n                        \/* ====================================================================\r\n                         * pb2354 : UN SEUL DEFILEMENT VERS LE BAS, PARTAGE PAR LES QUATRE APPELS.\r\n                         *   pb2353 a etabli la cause sur un site : le code visait #ColonneDroite,\r\n                         *   qui ne defile pas \u2014 le piege pb1895 montrait une animation dont les\r\n                         *   pas valaient 0,016 px, donc une cible de zero. Le defileur reel est\r\n                         *   .via-col-popup-body (overflow:hidden auto).\r\n                         *   Les trois autres appels sont byte-identiques a celui qui echouait, et\r\n                         *   ils se declenchent sur des CHEMINS DIFFERENTS : ouvrir l etape en\r\n                         *   cliquant le titre passe par Formulaire, pas par Validations. Le meme\r\n                         *   geste marchait ou non selon le chemin.\r\n                         *   Les corriger en recopiant la solution serait refaire la faute que\r\n                         *   pb2346 vient de payer : quatre copies divergent, et l une se fait\r\n                         *   oublier. La fonction est donc definie UNE fois, par le premier fichier\r\n                         *   charge, et les quatre l appellent. Aucun ordre de chargement a tenir.\r\n                         *   Elle cherche le defileur au lieu de le nommer, et attend qu il y ait\r\n                         *   quelque chose a defiler \u2014 un delai fixe ne sait pas quand la mise en\r\n                         *   page est posee.\r\n                         *   Reglages : _viaPb2353Max (1500), _viaPb2353Duree (300).\r\n                         *   Revert : _viaPb2353Off = true -> ancien comportement (#ColonneDroite).\r\n                         * ==================================================================== *\/\r\n                        if (typeof window._viaScrollBas2354 !== 'function') {\r\n                            window._viaScrollBas2354 = function (_origine) {\r\n                                var _dur = (typeof window._viaPb2353Duree === 'number') ? window._viaPb2353Duree : 300;\r\n                                if (window._viaPb2353Off === true) {\r\n                                    var $_cd = jQuery('#ColonneDroite');\r\n                                    if ($_cd.length) { $_cd.animate({ scrollTop: $_cd[0].scrollHeight }, _dur); }\r\n                                    console.log('[pb2354] ' + _origine + ' : DESARME -> ancien comportement #ColonneDroite');\r\n                                    return;\r\n                                }\r\n                                var _cible = document.getElementById('ProcederPaiementTitre')\r\n                                    || document.getElementById('EtapePaiement');\r\n                                var _t0 = Date.now();\r\n                                var _max = (typeof window._viaPb2353Max === 'number') ? window._viaPb2353Max : 1500;\r\n                                var _trouver = function (_el) {\r\n                                    var _n = _el;\r\n                                    while (_n ? (_n !== document.body) : false) {\r\n                                        var _oy = '';\r\n                                        try { _oy = window.getComputedStyle(_n).overflowY; } catch (_e) { _oy = ''; }\r\n                                        if (_oy === 'auto' ? true : _oy === 'scroll') {\r\n                                            if (_n.scrollHeight > _n.clientHeight + 4) { return _n; }\r\n                                        }\r\n                                        _n = _n.parentElement;\r\n                                    }\r\n                                    return null;\r\n                                };\r\n                                var _essayer = function () {\r\n                                    var _ec = Date.now() - _t0;\r\n                                    var _sc = _cible ? _trouver(_cible) : null;\r\n                                    if (_sc) {\r\n                                        var _nom = _sc.tagName + (_sc.id ? ('#' + _sc.id) : '')\r\n                                            + (_sc.classList.length ? ('.' + Array.prototype.join.call(_sc.classList, '.').slice(0, 60)) : '');\r\n                                        console.log('[pb2354] ' + _origine + ' : defileur trouve apres ' + _ec + 'ms : ' + _nom\r\n                                            + ' | scrollHeight=' + _sc.scrollHeight + ' clientHeight=' + _sc.clientHeight\r\n                                            + ' scrollTop=' + Math.round(_sc.scrollTop));\r\n                                        jQuery(_sc).stop(true, false).animate({ scrollTop: _sc.scrollHeight }, _dur);\r\n                                        return;\r\n                                    }\r\n                                    if (_ec >= _max) {\r\n                                        console.log('[pb2354] ' + _origine + ' : aucun ancetre defilant apres ' + _ec + 'ms'\r\n                                            + (_cible ? '' : ' (cible absente)') + ' -> repli sur #ColonneDroite');\r\n                                        var $_r = jQuery('#ColonneDroite');\r\n                                        if ($_r.length) { $_r.animate({ scrollTop: $_r[0].scrollHeight }, _dur); }\r\n                                        return;\r\n                                    }\r\n                                    setTimeout(_essayer, 100);\r\n                                };\r\n                                _essayer();\r\n                            };\r\n                        }\r\n                        window._viaScrollBas2354('\u00e9tape Paiement ouverte');\r\n                    }, 100);\r\n                }\r\n            }\r\n            \r\n            console.log('\u2705 \u00c9tape activ\u00e9e:', etapeId, ouvrirConteneur ? '(conteneur ouvert)' : '(conteneur ferm\u00e9)');\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 D\u00e9sactive le titre d'une \u00e9tape sp\u00e9cifique\r\n         * @param {string} etapeId - ID de l'\u00e9tape\r\n         *\/\r\n        desactiverTitreEtape(etapeId) {\r\n            if (!this.state.etapesConfig) return;\r\n            \r\n            const etape = this.state.etapesConfig.find(e => e.id === etapeId);\r\n            if (!etape) return;\r\n            \r\n            \/\/ \u2705 Griser le titre visuellement \u2014 le titre reste cliquable (toggle accord\u00e9on)\r\n            const $titre = $(etape.titre);\r\n            $titre.css({ 'cursor': 'pointer' }).attr('data-etape-active', 'true');\r\n            \r\n            \/\/ Masquer le conteneur de contenu\r\n            $(etape.conteneur).hide();\r\n            \r\n            \/\/ \u2705 v1.10 : Pour paiementFinal, masquer #ProcederPaiementContenu\r\n            if (etapeId === 'paiementFinal') {\r\n                $('#ProcederPaiementContenu').hide();\r\n            }\r\n            \r\n            \/\/ Chevron ferm\u00e9\r\n            $(etape.iconeUp).hide();\r\n            $(etape.iconeDown).show();\r\n            \r\n            console.log('\ud83d\udd12 \u00c9tape d\u00e9sactiv\u00e9e:', etapeId);\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 R\u00e9initialise toutes les \u00e9tapes (references et paiement actifs, autres d\u00e9sactiv\u00e9s)\r\n         *\/\r\n        reinitialiserTitresEtapes() {\r\n            if (!this.state.etapesConfig) return;\r\n            \r\n            this.state.etapesConfig.forEach(etape => {\r\n                \/\/ \u2705 R\u00e9f\u00e9rences et Mode de paiement restent actifs (mais conteneur ferm\u00e9)\r\n                if (etape.id === 'references' || etape.id === 'paiement') {\r\n                    this.activerTitreEtape(etape.id, false); \/\/ false = ne pas ouvrir le conteneur\r\n                    \/\/ Chevron ferm\u00e9\r\n                    $(etape.iconeUp).hide();\r\n                    $(etape.iconeDown).show();\r\n                } else {\r\n                    this.desactiverTitreEtape(etape.id);\r\n                }\r\n                \r\n                \/\/ \u2705 v1.10 : D\u00e9griser toutes les \u00e9tapes\r\n                this.degriserEtape(etape.id);\r\n            });\r\n            \r\n            \/\/ \u2705 v1.10 : D\u00e9griser aussi l'\u00e9tape Dates (pas dans etapesConfig au moment de l'init)\r\n            $('.DatesDureeCampagneTitre').removeClass('via-etape-grisee via-etape-en-cours');\r\n            $('#DatesDureeCampagneIconeUp, #DatesDureeCampagneIconeDown').removeClass('via-etape-grisee via-etape-en-cours');\r\n            \/\/ \u2705 v1.16.0 : Retirer tous les styles inline forc\u00e9s\r\n            $('.DatesDureeCampagneTitre').find('*').addBack().each(function() { this.style.removeProperty('color'); });\r\n            $('#DatesDureeCampagneIconeUp, #DatesDureeCampagneIconeDown').find('*').addBack().each(function() { this.style.removeProperty('color'); });\r\n            \r\n            console.log('\ud83d\udd04 Toutes les \u00e9tapes r\u00e9initialis\u00e9es');\r\n            \r\n            \/\/ \u2705 v1.16.0 : Recalculer l'\u00e9tape en cours\r\n            this.marquerEtapeEnCours();\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.10 : Grise le titre et les ic\u00f4nes d'une \u00e9tape\r\n         * @param {string} etapeId - ID de l'\u00e9tape\r\n         *\/\r\n        \/\/ ====================================================================\r\n        \/\/ pb1171 : griserEtape pose la couleur des ETAPES COMPLETEES.\r\n        \/\/   Constat user : un titre complete passe en bleu puis revient en gris.\r\n        \/\/   Le log donne l'ordre : \"Etape en cours marquee\" (donc pb1169 a colore)\r\n        \/\/   puis \"Etape grisee: recapitulatif\" \u2014 griserEtape repasse APRES et\r\n        \/\/   reecrit son gris inline #6e6e6e, qui gagne.\r\n        \/\/   Deux ecrivains posaient deux couleurs differentes pour le meme etat.\r\n        \/\/   griserEtape est appele sur les etapes FAITES : sa couleur devient donc\r\n        \/\/   celle de cet etat, #4b689b \u2014 la meme que pb1169. Les deux disent\r\n        \/\/   desormais la meme chose, dans quelque ordre qu'ils passent.\r\n        \/\/   Le gris #6e6e6e demeure disponible via le knob, pour les contextes qui\r\n        \/\/   griseraient une etape NON faite.\r\n        \/\/   Revert : window._viaPb1171Off = true (retour au gris #6e6e6e).\r\n        \/\/ ====================================================================\r\n        griserEtape(etapeId) {\r\n            console.log('\ud83d\udd18 griserEtape appel\u00e9e avec:', etapeId);\r\n            \/\/ pb1171b : couleur capturee dans une VARIABLE, pas appelee dans un\r\n            \/\/   callback. A l'interieur d'un each() jQuery, 'this' est l'element\r\n            \/\/   DOM et la methode de l'objet n'y est plus accessible : d'ou le\r\n            \/\/   \"_grisCouleur1171 is not defined\" du log.\r\n            var _col1171 = (window._viaPb1171Off === true) ? '#6e6e6e' : '#7f7f7f';   \/\/ pb1177\r\n            \r\n            if (!this.state.etapesConfig) {\r\n                console.warn('\u26a0\ufe0f etapesConfig non d\u00e9fini');\r\n                return;\r\n            }\r\n            \r\n            const etape = this.state.etapesConfig.find(e => e.id === etapeId);\r\n            if (!etape) {\r\n                console.warn('\u26a0\ufe0f \u00c9tape non trouv\u00e9e:', etapeId);\r\n                return;\r\n            }\r\n            \r\n            console.log('\ud83d\udd18 \u00c9tape trouv\u00e9e:', etape);\r\n            \r\n            \/\/ \u2705 Injecter le style CSS si pas d\u00e9j\u00e0 fait\r\n            if (!document.getElementById('via-etape-grisee-style')) {\r\n                const style = document.createElement('style');\r\n                style.id = 'via-etape-grisee-style';\r\n                style.textContent = `\r\n                    .via-etape-grisee,\r\n                    .via-etape-grisee *,\r\n                    .via-etape-grisee span,\r\n                    .via-etape-grisee a,\r\n                    .via-etape-grisee i,\r\n                    .via-etape-grisee .elementor-widget-container,\r\n                    .via-etape-grisee .elementor-widget-container *,\r\n                    .via-etape-grisee .elementor-icon-wrapper,\r\n                    .via-etape-grisee .elementor-icon-wrapper * {\r\n                        \/* pb1123 : gris des titres = #6e6e6e (valeur du projet, confirmee\r\n                           par l'utilisateur ; c'est deja celle que rend le DOM :\r\n                           rgb(110,110,110)). Le #999999 utilise ici et dans les writers\r\n                           inline etait plus clair et creait un ecart selon le chemin\r\n                           emprunte. Une seule valeur partout. *\/\r\n                        color: #7f7f7f !important;   \/* pb1177 : etape completee *\/\r\n                        fill: #6e6e6e !important;\r\n                    }\r\n                `;\r\n                document.head.appendChild(style);\r\n                console.log('\u2705 Style CSS via-etape-grisee inject\u00e9');\r\n            }\r\n            \r\n            \/\/ Ajouter la classe au titre et aux ic\u00f4nes\r\n            const $titre = $(etape.titre);\r\n            const $iconeUp = $(etape.iconeUp);\r\n            const $iconeDown = $(etape.iconeDown);\r\n            \r\n            console.log('\ud83d\udd18 \u00c9l\u00e9ments trouv\u00e9s - titre:', $titre.length, 'iconeUp:', $iconeUp.length, 'iconeDown:', $iconeDown.length);\r\n            \r\n            $titre.addClass('via-etape-grisee');\r\n            $iconeUp.addClass('via-etape-grisee');\r\n            $iconeDown.addClass('via-etape-grisee');\r\n            \r\n            \/\/ \u2705 v1.16.0 : Forcer gris sur TOUS les descendants (override les inline bleus)\r\n            \/\/ \u2705 Sauvegarder la couleur originale avant d'\u00e9craser\r\n            $titre.find('*').addBack().each(function() {\r\n                if (!this.hasAttribute('data-original-color')) {\r\n                    this.setAttribute('data-original-color', this.style.color || '');\r\n                }\r\n                this.style.setProperty('color', _col1171, 'important');\r\n            });\r\n            $iconeUp.find('*').addBack().each(function() {\r\n                if (!this.hasAttribute('data-original-color')) {\r\n                    this.setAttribute('data-original-color', this.style.color || '');\r\n                }\r\n                this.style.setProperty('color', _col1171, 'important');\r\n            });\r\n            $iconeDown.find('*').addBack().each(function() {\r\n                if (!this.hasAttribute('data-original-color')) {\r\n                    this.setAttribute('data-original-color', this.style.color || '');\r\n                }\r\n                this.style.setProperty('color', _col1171, 'important');\r\n            });\r\n            \r\n            console.log('\u2705 \u00c9tape gris\u00e9e:', etapeId, '- Classes ajout\u00e9es:', $titre.hasClass('via-etape-grisee'));\r\n            \r\n            \/\/ \u2705 v1.16.0 : Recalculer l'\u00e9tape en cours\r\n            this.marquerEtapeEnCours();\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.10 : D\u00e9grise le titre et les ic\u00f4nes d'une \u00e9tape (remet les couleurs normales)\r\n         * @param {string} etapeId - ID de l'\u00e9tape\r\n         *\/\r\n        degriserEtape(etapeId) {\r\n            if (!this.state.etapesConfig) return;\r\n            \r\n            const etape = this.state.etapesConfig.find(e => e.id === etapeId);\r\n            if (!etape) return;\r\n            \r\n            const $titre = $(etape.titre);\r\n            const $iconeUp = $(etape.iconeUp);\r\n            const $iconeDown = $(etape.iconeDown);\r\n            \r\n            \/\/ Retirer la classe\r\n            $titre.removeClass('via-etape-grisee');\r\n            $iconeUp.removeClass('via-etape-grisee');\r\n            $iconeDown.removeClass('via-etape-grisee');\r\n            \r\n            \/\/ \u2705 v1.16.0 : Restaurer les couleurs d'origine (sauvegard\u00e9es avant grisage)\r\n            $titre.find('*').addBack().each(function() {\r\n                const orig = this.getAttribute('data-original-color');\r\n                this.style.removeProperty('color');\r\n                if (orig) { this.style.color = orig; }\r\n                this.removeAttribute('data-original-color');\r\n            });\r\n            $iconeUp.find('*').addBack().each(function() {\r\n                const orig = this.getAttribute('data-original-color');\r\n                this.style.removeProperty('color');\r\n                if (orig) { this.style.color = orig; }\r\n                this.removeAttribute('data-original-color');\r\n            });\r\n            $iconeDown.find('*').addBack().each(function() {\r\n                const orig = this.getAttribute('data-original-color');\r\n                this.style.removeProperty('color');\r\n                if (orig) { this.style.color = orig; }\r\n                this.removeAttribute('data-original-color');\r\n            });\r\n            \r\n            \/\/ \u2705 Restaurer pointer-events et data-etape-active\r\n            $titre.each(function() {\r\n                this.style.removeProperty('pointer-events');\r\n            });\r\n            $titre.css({ 'cursor': 'pointer' }).attr('data-etape-active', 'true');\r\n\r\n            console.log('\ud83d\udd35 \u00c9tape d\u00e9gris\u00e9e:', etapeId);\r\n            \r\n            \/\/ \u2705 v1.16.0 : Recalculer l'\u00e9tape en cours\r\n            this.marquerEtapeEnCours();\r\n        },\r\n\r\n        \/**\r\n         * v4.9ds : \"R\u00e9activer\" l'\u00e9tape Dates quand son contenu se rouvre\r\n         *   (clic sur titre Dates, clic sur r\u00e9servation pour la modifier, etc.).\r\n         * \u2705 v4.9ds Pb 7 : \u00e9tape Dates supprim\u00e9e d'Elementor \u2014 fonction NEUTRALIS\u00c9E.\r\n         *   Plus de repositionnement DOM (le container DatesDureeTarifContainer ne doit\r\n         *   pas \u00eatre d\u00e9plac\u00e9\/affich\u00e9 entre R\u00e9server et R\u00e9cap).\r\n         *   Le degriserEtape('dates') est conserv\u00e9 par s\u00e9curit\u00e9 (mais sans effet visible\r\n         *   puisque le titre n'existe plus).\r\n         *\/\r\n        _viaActiverEtapeDates() {\r\n            try { this.degriserEtape('dates'); } catch(_eDG) {}\r\n        },\r\n\r\n        \/**\r\n         * \u2705 v1.16.0 : Marque la premi\u00e8re \u00e9tape non-gris\u00e9e comme \"\u00e9tape en cours\" (bleu #4B689B)\r\n         * Applique le style bleu sur le titre, sous-titre et ic\u00f4nes\r\n         *\/\r\n        \/\/ ====================================================================\r\n        \/\/ pb1071 : SONDE du futur sequenceur du process d'achat.\r\n        \/\/   La 1re tentative (pb1069, revertee) s'est greffee sur\r\n        \/\/   marquerEtapeEnCours en ECRIVANT dans le DOM. Erreur d'approche :\r\n        \/\/   cette fonction est appelee depuis une dizaine d'endroits, dont\r\n        \/\/   griserEtape et degriserEtape eux-memes \u2014 que le sequenceur appelait\r\n        \/\/   en retour. Le point d'entree etait au coeur d'un reseau de rappels\r\n        \/\/   croises. Resultat : \"Maximum call stack size exceeded\".\r\n        \/\/   On recommence donc par OBSERVER, sans rien ecrire :\r\n        \/\/     - les completions telles que je propose de les calculer, pour\r\n        \/\/       verifier qu'elles collent aux vrais champs de l'item ;\r\n        \/\/     - l'etape que le sequenceur AURAIT choisie, a comparer a celle que\r\n        \/\/       marquerEtapeEnCours designe reellement ;\r\n        \/\/     - le nombre d'appels et leur PROVENANCE (pile tronquee), pour voir\r\n        \/\/       le graphe de rappels avant de s'y brancher \u2014 c'est precisement ce\r\n        \/\/       qui manquait.\r\n        \/\/   Deux protections contre le bruit : releve seulement si la signature\r\n        \/\/   change, et pile imprimee une fois par appelant distinct.\r\n        \/\/   SONDE PURE : aucune ecriture, aucun appel a griser\/degriser.\r\n        \/\/   Revert : window._viaPb1071Off = true.\r\n        \/\/ ====================================================================\r\n        _sondeSequenceur1071() {\r\n            if (window._viaPb1071Off === true) { return; }\r\n            try {\r\n                const it = (this.state.items || []).find(x => x.id === this.state.itemActif) || null;\r\n                const empl = it ? ((it.donneesIframe ? it.donneesIframe.Commande_Emplacement_Page_Web : '')\r\n                    || it.emplacementPageWeb || '') : '';\r\n                const faits = {\r\n                    processAnnonceur: window._viaAnnonceurFait1713(it),   \/* pb1713 *\/\r\n                    associerPays: it ? !!(it.paysDisplayed || it.linkSecteurPage) : false,\r\n                    associerSecteur: it ? !!(it.selectedPageSecteur || it.commandePage) : false,\r\n                    \/* pb1554a : LA SENTINELLE N'EST PAS UNE ETAPE FAITE.\r\n                       Le log a remonte la chaine complete : \u00ab ChoixFormat ouvert \u00bb,\r\n                       puis completions 0111011 \u2014 4e chiffre = choixFormat a 1 \u2014, puis\r\n                       \u00ab griserEtape appelee avec: choixFormat \u00bb, puis \u00ab ChoixFormat\r\n                       ferme \u00bb. C'est CE calcul qui grise et ferme le bandeau ; le\r\n                       message vert et l'invite corail n'en etaient que les symptomes.\r\n                       !!it.format laisse passer 'a choisir' (chaine non vide). Meme\r\n                       juge que partout ailleurs : _viaFormatValide1513 (pb1513). *\/\r\n                    choixFormat: it ? window._viaChoixFormatFait2099(it.format) : false,   \/* pb2099 *\/\r\n                    processDatesDevise: it ? !!(it.dateDebut && it.dateFin) : false,\r\n                    pageWeb: !!empl, pageWebMobile: !!empl\r\n                };\r\n                const ordre = (this.state.etapesConfig || [])\r\n                    .map(e => e.id).filter(id => faits.hasOwnProperty(id));\r\n                const sig = ordre.map(id => faits[id] ? 1 : 0).join('');\r\n\r\n                \/\/ provenance : une seule fois par appelant distinct\r\n                let appelant = '?';\r\n                try {\r\n                    const pile = (new Error()).stack.split('\\n')\r\n                        .map(l => l.trim())\r\n                        .filter(l => l ? (l.indexOf('_sondeSequenceur1071') === -1) : false);\r\n                    appelant = (pile[2] || pile[1] || '?').substring(0, 110);\r\n                } catch (_eP) {}\r\n                window._viaVus1071 = window._viaVus1071 || {};\r\n                if (!window._viaVus1071[appelant]) {\r\n                    window._viaVus1071[appelant] = 0;\r\n                    console.log('[pb1071] nouvel appelant : ' + appelant);\r\n                }\r\n                window._viaVus1071[appelant]++;\r\n\r\n                if (window._viaSig1071 === sig) { return; }   \/\/ rien de neuf\r\n                window._viaSig1071 = sig;\r\n\r\n                const idxActif = ordre.findIndex(id => !faits[id]);\r\n                const cible = (idxActif === -1) ? 'recapitulatif' : ordre[idxActif];\r\n                const gris = ordre.filter(id => $(\r\n                    (this.state.etapesConfig.find(e => e.id === id) || {}).titre || 'x'\r\n                ).hasClass('via-etape-grisee'));\r\n                const ouvertes = ordre.filter(id => $(\r\n                    (this.state.etapesConfig.find(e => e.id === id) || {}).conteneur || 'x'\r\n                ).is(':visible'));\r\n                console.log('[pb1071] completions ' + sig + ' (' + ordre.join('>') + ')'\r\n                    + '\\n[pb1071]   \u00e9tape que le s\u00e9quenceur choisirait : ' + cible\r\n                    + '\\n[pb1071]   d\u00e9j\u00e0 gris\u00e9es : ' + (gris.length ? gris.join(',') : '(aucune)')\r\n                    + '\\n[pb1071]   d\u00e9j\u00e0 ouvertes : ' + (ouvertes.length ? ouvertes.join(',') : '(aucune)')\r\n                    + '\\n[pb1071]   item : ' + (it\r\n                        ? ('pays=' + (it.pays || '-') + ' site=' + (it.paysDisplayed || '-')\r\n                            + ' page=' + (it.selectedPageSecteur || it.commandePage || '-')\r\n                            + ' format=' + (it.format || '-')\r\n                            + ' dates=' + (it.dateDebut || '-') + '->' + (it.dateFin || '-')\r\n                            + ' espace=' + (empl || '-'))\r\n                        : '(aucun item actif)'));\r\n            } catch (_e1071) { console.warn('[pb1071]', _e1071.message); }\r\n        },\r\n\r\n        \/\/ pb1071 : compter les appels par appelant, a la demande.\r\n        \/\/   Usage console : window._viaBilan1071()\r\n        _bilanSonde1071() {\r\n            const v = window._viaVus1071 || {};\r\n            console.log('[pb1071] BILAN des appels \u00e0 marquerEtapeEnCours :');\r\n            Object.keys(v).forEach(k => console.log('[pb1071]   ' + v[k] + ' x  ' + k));\r\n        },\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb1073 : SEQUENCEUR \u2014 OUVERTURE \/ FERMETURE des etapes du process.\r\n        \/\/   Perimetre volontairement MINIMAL : ce sequenceur ne touche QUE la\r\n        \/\/   visibilite des conteneurs et des chevrons. Il n'appelle NI\r\n        \/\/   griserEtape NI degriserEtape.\r\n        \/\/   Pourquoi : la sonde pb1071 a montre que 14 des 15 appels a\r\n        \/\/   marquerEtapeEnCours viennent de griserEtape. C'est cette boucle qui\r\n        \/\/   a fait exploser pb1069. En ne l'appelant pas, la recursion est\r\n        \/\/   impossible \u2014 pas besoin de verrou, il n'y a plus de cycle.\r\n        \/\/   Le grisage et la couleur fonctionnent DEJA correctement (le log le\r\n        \/\/   montre : \"deja grisees : associerPays,associerSecteur,choixFormat\").\r\n        \/\/   Il n'y a donc rien a reecrire de ce cote \u2014 seul l'enchainement\r\n        \/\/   ouverture\/fermeture manquait.\r\n        \/\/   Ce que le log a etabli et que ce bloc corrige :\r\n        \/\/     - 'processAnnonceur' restait OUVERTE une fois renseignee ;\r\n        \/\/     - a la fin, plus rien n'etait ouvert alors que le recapitulatif\r\n        \/\/       doit l'etre (Q8).\r\n        \/\/   CLIC MANUEL (option B) : _viaManuelProcess1073, pose par le handler\r\n        \/\/   de titre, prime jusqu'au prochain changement de completion.\r\n        \/\/   Revert : window._viaPb1073Off = true.\r\n        \/\/ ====================================================================\r\n        \/\/ ====================================================================\r\n        \/\/ pb1076 : VEILLEUR \u2014 il manquait le DECLENCHEUR.\r\n        \/\/   Constat user : l'etape annonceur ne se referme toujours pas, et les\r\n        \/\/   titres pays\/secteur\/format ne passent jamais en bleu. Le log en donne\r\n        \/\/   la raison par son SILENCE : aucune ligne [pb1071] ni [pb1073] pendant\r\n        \/\/   la saisie de l'annonceur.\r\n        \/\/   Cause : le sequenceur est branche sur marquerEtapeEnCours, qui \u2014 la\r\n        \/\/   sonde pb1071 l'a etabli \u2014 n'est appelee que par griserEtape (14 fois)\r\n        \/\/   et initTitresEtapesDesactives (1 fois). Saisir l'annonceur ne grise\r\n        \/\/   rien, donc n'appelle rien : le sequenceur n'etait jamais reveille.\r\n        \/\/   J'ai construit la mecanique sans verifier ce qui la declenche.\r\n        \/\/   Un VEILLEUR plutot que des hooks : accrocher chaque champ et chaque\r\n        \/\/   clic demanderait une dizaine de points d'entree, qui finiraient par se\r\n        \/\/   contredire \u2014 c'est la lecon de pb1009 et de pb1036. Le veilleur\r\n        \/\/   observe la SIGNATURE des completions et ne reagit qu'a son changement.\r\n        \/\/   Il grise\/degrise ce qui doit l'etre \u2014 ce qui fait passer les titres en\r\n        \/\/   bleu, puisque marquerEtapeEnCours prend \"la premiere non grisee\" \u2014\r\n        \/\/   puis laisse cette derniere faire son travail.\r\n        \/\/   RECURSION : griserEtape rappelle marquerEtapeEnCours, qui appelle le\r\n        \/\/   sequenceur d'ouverture ; celui-ci n'appelle PAS griserEtape (pb1073).\r\n        \/\/   La chaine est donc finie. Le verrou ci-dessous protege en plus contre\r\n        \/\/   une reentree du veilleur lui-meme.\r\n        \/\/   Revert : window._viaPb1076Off = true.\r\n        \/\/ ====================================================================\r\n        \/\/ ====================================================================\r\n        \/\/ pb1157 : apres FINALISER, seule l'etape REFERENCES est ouverte.\r\n        \/\/   Constat user (mobile) : le clic sur .PasserCommandeBouton rouvre\r\n        \/\/   l'etape \"Choisir les espaces publicitaires\", qui redevient active,\r\n        \/\/   alors que le parcours passe aux references.\r\n        \/\/   'references' ne fait pas partie des etapes suivies par le sequenceur\r\n        \/\/   (elle n'a pas de completion) : personne ne la designait comme cible,\r\n        \/\/   et pageWebMobile restait le dernier choix connu.\r\n        \/\/   On pose donc le choix MANUEL sur 'references' au clic : le mecanisme\r\n        \/\/   existe deja (option B) et prime sur le calcul automatique jusqu'au\r\n        \/\/   prochain changement de completion. Aucune regle nouvelle a inventer.\r\n        \/\/   Le handler est delegue sur document : le bouton est recree a chaque\r\n        \/\/   rendu du recapitulatif.\r\n        \/\/   Revert : window._viaPb1157Off = true.\r\n        \/\/ ====================================================================\r\n        _armerFinaliser1157() {\r\n            if (window._viaArme1157) { return; }\r\n            window._viaArme1157 = true;\r\n            var _self = this;\r\n            document.addEventListener('click', function (_e1157) {\r\n                if (window._viaPb1157Off === true) { return; }\r\n                try {\r\n                    var _b = _e1157.target.closest\r\n                        ? _e1157.target.closest('.PasserCommandeBouton, .FinaliserBouton')\r\n                        : null;\r\n                    if (!_b) { return; }\r\n                    window._viaManuelProcess1073 = 'references';\r\n                    console.log('[pb1157] Finaliser cliqu\u00e9 -> \u00e9tape R\u00e9f\u00e9rences ouverte et active');\r\n                    setTimeout(function () {\r\n                        try {\r\n                            _self._sequenceurOuverture1073();\r\n                            var _cfg = _self.state.etapesConfig || [];\r\n                            var _eR = _cfg.filter(function (_x) { return _x.id === 'references'; })[0];\r\n                            if (_eR) {\r\n                                $(_eR.etape).show();\r\n                                $(_eR.conteneur).show();\r\n                                $(_eR.iconeUp).show();\r\n                                $(_eR.iconeDown).hide();\r\n                                _self.degriserEtape('references');\r\n                            }\r\n                            _self.marquerEtapeEnCours();\r\n                        } catch (_e) { console.warn('[pb1157]', _e.message); }\r\n                    }, 60);\r\n                } catch (_eC1157) {}\r\n            }, true);\r\n        },\r\n\r\n        _veilleurEtapes1076() {\r\n            if (window._viaPb1076Off === true) { return; }\r\n            if (window._viaVeil1076EnCours === true) { return; }\r\n            if (!this.state.etapesConfig) { return; }\r\n            window._viaVeil1076EnCours = true;\r\n            try {\r\n                const f = this._completions1076();\r\n                const cfg = this.state.etapesConfig;\r\n                const ordre = cfg.map(e => e.id).filter(id => f.hasOwnProperty(id));\r\n                \/\/ ================================================================\r\n                \/\/ pb1153 : la DUREE entre dans la signature du veilleur.\r\n                \/\/   Constat user : apres un message \"dur\u00e9e minimale\" (3 jours), saisir\r\n                \/\/   210 jours ne met pas le texte a jour \u2014 le message minimum reste.\r\n                \/\/   Cause : les deux durees sont invalides, donc la completion de\r\n                \/\/   l'etape Dates vaut 0 dans les deux cas et la signature ne change\r\n                \/\/   pas. Le veilleur sort, le sequenceur n'est pas rejoue, et le\r\n                \/\/   message \u2014 ecrit par pb1144 dans le sequenceur \u2014 reste tel quel.\r\n                \/\/   On ajoute donc la duree a la signature : deux etats invalides\r\n                \/\/   differents deviennent deux signatures differentes.\r\n                \/\/   Sur les durees valides, la signature ne bouge pas davantage\r\n                \/\/   qu'avant : la completion suffisait deja a les distinguer.\r\n                \/\/   Revert : window._viaPb1153Off = true.\r\n                \/\/ ================================================================\r\n                let sig = ordre.map(id => f[id] ? 1 : 0).join('');\r\n                if (window._viaPb1153Off !== true) {\r\n                    let _dur1153 = '';\r\n                    try {\r\n                        _dur1153 = ($('#form-field-DebutCampagne').val() || '') + '>'\r\n                            + ($('#form-field-FinCampagne').val() || '');\r\n                    } catch (_e1153) { _dur1153 = ''; }\r\n                    sig = sig + '|' + _dur1153;\r\n                }\r\n                if (window._viaSigVeil1076 === sig) { return; }\r\n                window._viaSigVeil1076 = sig;\r\n                console.log('[pb1076] compl\u00e9tions chang\u00e9es -> ' + sig + ' (' + ordre.join('>') + ')');\r\n                let bouge = false;\r\n                ordre.forEach(id => {\r\n                    const e = cfg.find(x => x.id === id);\r\n                    if (!e) { return; }\r\n                    const estGris = $(e.titre).hasClass('via-etape-grisee');\r\n                    if (f[id] ? !estGris : false) { this.griserEtape(id); bouge = true; }\r\n                    if (!f[id] ? estGris : false) { this.degriserEtape(id); bouge = true; }\r\n                });\r\n                \/\/ si rien n'a change cote gris, personne n'a rappele\r\n                \/\/   marquerEtapeEnCours : on la declenche nous-memes.\r\n                if (!bouge) { this.marquerEtapeEnCours(); }\r\n            } catch (_e1076) { console.warn('[pb1076]', _e1076.message); }\r\n            finally { window._viaVeil1076EnCours = false; }\r\n        },\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb1253 : DESKTOP 3 COLONNES \u2014 l'etape ESPACE PUBLICITAIRE quitte le\r\n        \/\/   sequenceur (demande user, option A ; DESKTOP UNIQUEMENT).\r\n        \/\/   Constat : en 3 colonnes le recapitulatif ne devenait jamais l'etape\r\n        \/\/   courante. La cause n'est pas dans l'affichage mais dans le CALCUL DE\r\n        \/\/   LA CIBLE : celle-ci est la premiere etape non faite, et les deux\r\n        \/\/   etapes page web ('pageWebMobile' puis 'pageWeb') partagent le critere\r\n        \/\/   'empl', qui exige une reservation effective (pb1126). Tant qu'aucun\r\n        \/\/   espace n'est reserve, la cible restait donc bloquee sur elles, et le\r\n        \/\/   recapitulatif restait ferme et en couleur \"a venir\".\r\n        \/\/   pb1243, pb1245 et pb1250 ecrivaient APRES ce calcul sans le changer :\r\n        \/\/   d'ou trois tentatives sans effet. On corrige a la source.\r\n        \/\/   En 3 colonnes la page web vit dans le VLP : ces deux etapes n'ont\r\n        \/\/   plus d'objet dans le process. Retirees des completions, elles\r\n        \/\/   disparaissent de 'ordre' \u2014 le filtre hasOwnProperty existe deja dans\r\n        \/\/   le veilleur ET dans le sequenceur \u2014 et la cible tombe sur le\r\n        \/\/   recapitulatif des que les cinq etapes amont sont faites. Aucune autre\r\n        \/\/   regle n'est touchee : couleurs, tailles et marges lisent la cible.\r\n        \/\/   Le mode est mesure sur la PRESENCE D'UN VLP OUVERT, jamais sur\r\n        \/\/   #ColonneCentre : en 3 colonnes regie la colonne centrale est\r\n        \/\/   justement masquee (lecon pb1231c). Les popups de colonne partagent la\r\n        \/\/   classe .via-link-popup : ils sont exclus.\r\n        \/\/   Revert : window._viaPb1253Off = true.\r\n        \/\/ ====================================================================\r\n        \/\/ ====================================================================\r\n        \/\/ pb1255 : \u00ab Une ou plusieurs reservations sont validees \u00bb n'apparait que\r\n        \/\/   si c'est VRAI (demande user).\r\n        \/\/   Constat user (HTML) : #RecapitulatifMessageContainer est en\r\n        \/\/   display:block !important alors qu'aucun espace n'est reserve.\r\n        \/\/   Cause : pb1161 affiche la phrase des que le recapitulatif est ACTIF ou\r\n        \/\/   fait. Le raccourci se tenait avant pb1253 \u2014 le recapitulatif ne pouvait\r\n        \/\/   devenir actif qu'une fois l'espace reserve. Depuis pb1253 il s'ouvre\r\n        \/\/   avant, et la phrase annonce un fait qui n'a pas eu lieu.\r\n        \/\/   Une phrase d'etat doit dependre du FAIT, pas de l'etape ou l'on se\r\n        \/\/   trouve. Le critere existe deja et sert au code couleur comme a pb1126 :\r\n        \/\/   estReserveEffective, ou statut 'complete'. Une seule definition, ici,\r\n        \/\/   partagee par les deux writers de cette propriete (pb1161 dans le\r\n        \/\/   sequenceur, _updateMessagesEtapes a l'ouverture\/fermeture) \u2014 sinon ils\r\n        \/\/   se contrediraient a deux rythmes differents.\r\n        \/\/   Revert : window._viaPb1255Off = true.\r\n        \/\/ ====================================================================\r\n        _resaValidee1255() {\r\n            if (window._viaPb1255Off === true) { return true; }\r\n            try {\r\n                var _it1255 = (this.state ? (this.state.items || []) : []);\r\n                for (var _k1255 = 0; _k1255 < _it1255.length; _k1255++) {\r\n                    var _u1255 = _it1255[_k1255];\r\n                    if (!_u1255) { continue; }\r\n                    if (_u1255.estReserveEffective === true) { return true; }\r\n                    if (_u1255.statut === 'complete') { return true; }\r\n                }\r\n            } catch (_e1255) { return true; }\r\n            return false;\r\n        },\r\n\r\n        \/* ====================================================================\r\n         * pb1991 : UN SEUL CRITERE POUR LA PHRASE \u00ab Une ou plusieurs reservations\r\n         *   sont validees \u00bb.\r\n         *   Constat JF (capture) : la phrase apparait des l'etape \u00ab Choisir un\r\n         *   format \u00bb, cinq etapes trop tot. Mesure console livree par JF :\r\n         *     items = [{ statut: 'en_cours', estReserveEffective: true }]\r\n         *   donc _resaValidee1255() vaut VRAI, et il a raison de valoir vrai : un\r\n         *   espace EST reserve. Le critere n'est pas faux, il ne repond pas a la\r\n         *   bonne question. \u00ab Reserve \u00bb et \u00ab valide \u00bb sont deux faits distincts,\r\n         *   separes par le clic Finaliser. Sur la regie ils semblaient coincider\r\n         *   parce qu'on y reserve depuis le recapitulatif ; sur un site pays la\r\n         *   reservation est le PREMIER geste, avant meme l'ouverture du process.\r\n         *   Meme famille que pb1255, dont le commentaire notait deja \u00ab le\r\n         *   raccourci se tenait avant pb1253 \u00bb : une premisse vraie dans un\r\n         *   contexte, importee dans un autre.\r\n         *   DEUX ECRIVAINS QUI SE CONTREDISAIENT. pb1255 annoncait \u00ab une seule\r\n         *   definition partagee par les deux writers \u00bb ; en fait il n'avait unifie\r\n         *   que la branche RECAP ACTIF. Hors de cette branche ils divergeaient :\r\n         *     _updateMessagesEtapes  : !recapOuvert ET _resaValidee1255()\r\n         *     sequenceur pb1161      : faits.recapitulatif (FinaliserStep)\r\n         *   Le premier montrait, le second cachait ; le dernier passe l'emportait.\r\n         *   C'est la contradiction, pas l'un des deux tests, qui rendait le\r\n         *   symptome intermittent selon le chemin emprunte.\r\n         *   LA DEFINITION EST DONC ICI, UNE FOIS, ET LES DEUX ECRIVAINS L'APPELLENT.\r\n         *   Elle est posee a cote de _resaValidee1255 pour que les deux criteres\r\n         *   du recapitulatif se lisent ensemble et qu'on ne puisse plus en modifier\r\n         *   un en croyant toucher l'autre.\r\n         *   REGLE RETENUE (choix JF : \u00ab partout \u00bb, regie comprise) : la phrase\r\n         *   n'apparait qu'apres le clic Finaliser. On lit FinaliserStep, le meme\r\n         *   temoin que faits.recapitulatif (l.13030) \u2014 pas _viaFinaliserClique,\r\n         *   que pb327 pose aussi quand les references sont validees SANS Finaliser,\r\n         *   et qui dirait donc vrai dans un cas que JF n'a pas demande.\r\n         *   Le terme \u00ab recapitulatif ferme \u00bb est conserve : c'est la forme commune\r\n         *   a toutes les phrases d'etape (cf. Dates, juste au-dessus du writer),\r\n         *   affichees sous un titre replie.\r\n         *   REVERT EXACT, PAS APPROXIMATIF : chaque appelant passe SON ancien\r\n         *   booleen ; sous window._viaPb1991Off = true, chacun retrouve donc son\r\n         *   comportement d'avant, y compris leur divergence.\r\n         * ==================================================================== *\/\r\n        _msgRecapVisible1991(_ancien1991) {\r\n            if (window._viaPb1991Off === true) { return !!_ancien1991; }\r\n            var _fin1991 = false;\r\n            try { _fin1991 = (sessionStorage.getItem('FinaliserStep') === 'Yes'); }\r\n            catch (_eS1991) { _fin1991 = false; }\r\n            var _ouv1991 = this.state ? (this.state.recapOuvert === true) : false;\r\n            var _vis1991 = _fin1991 ? !_ouv1991 : false;\r\n            \/* Une ligne par changement d'etat, pas par passage : ces deux writers\r\n               tournent en continu (regle 5.2 sans inonder le tampon). *\/\r\n            var _sg1991 = (_fin1991 ? 'F' : '-') + (_ouv1991 ? 'O' : '-')\r\n                + (_vis1991 ? '>visible' : '>masquee');\r\n            if (window._viaSig1991 !== _sg1991) {\r\n                window._viaSig1991 = _sg1991;\r\n                console.log('[pb1991] phrase du recapitulatif ' + (_vis1991 ? 'AFFICHEE' : 'masquee')\r\n                    + ' | FinaliserStep=' + (_fin1991 ? 'Yes' : 'non')\r\n                    + ' | recap ' + (_ouv1991 ? 'ouvert' : 'ferme')\r\n                    + ' | ancien critere aurait dit ' + (_ancien1991 ? 'AFFICHEE' : 'masquee'));\r\n            }\r\n            return _vis1991;\r\n        },\r\n\r\n        _pageWebHorsProcess1253() {\r\n            if (window._viaPb1253Off === true) { return false; }\r\n            try {\r\n                \/\/ pb1263c : la sonde pb1263b est retir\u00e9e \u2014 elle a conclu. Elle a\r\n                \/\/   montr\u00e9 que cette fonction bascule par la LARGEUR (largeur=160)\r\n                \/\/   et non par l'absence de VLP, et que la mesure venait bien du\r\n                \/\/   document parent (top=true). Le garde est desormais dans\r\n                \/\/   _viaLargeur1263 : ici, plus rien de special.\r\n                var _lg1253 = (typeof window._viaLargeur1263 === 'function')\r\n                    ? window._viaLargeur1263()\r\n                    : window.outerWidth;\r\n                if (_lg1253 < 1000) { return false; }   \/\/ desktop uniquement\r\n                var _vlps1253 = document.querySelectorAll('.via-link-popup');\r\n                for (var _v1253 = 0; _v1253 < _vlps1253.length; _v1253++) {\r\n                    var _el1253 = _vlps1253[_v1253];\r\n                    if (_el1253.classList.contains('via-col-popup')) { continue; }\r\n                    if (window.getComputedStyle(_el1253).display === 'none') { continue; }\r\n                    return true;\r\n                }\r\n            } catch (_e1253) {}\r\n            return false;\r\n        },\r\n\r\n        \/\/ pb1253 : MASQUAGE de #PageWebMobileEtape par CLASSE SUR <body> + feuille\r\n        \/\/   CSS \u2014 meme motif que pb1183. Un display inline ne tiendrait pas : la\r\n        \/\/   boucle d'initialisation fait $(etape.etape).show() et d'autres writers\r\n        \/\/   repassent ensuite (c'est ce qui a fait echouer pb1181 et pb1182). Une\r\n        \/\/   regle en feuille ne s'oublie pas entre deux passes ; retirer la classe\r\n        \/\/   rend la main aux writers d'origine, donc aucune valeur de base a\r\n        \/\/   memoriser ni a restaurer au retour en 1 colonne.\r\n        \/\/   Le wrapper suffit : titre, chevrons, message et conteneur vivent\r\n        \/\/   dedans (carte DOM pb892).\r\n        _masquePageWeb1253() {\r\n            if (window._viaPb1253Off === true) { return; }\r\n            try {\r\n                if (!document.getElementById('via-masque-pageweb-1253')) {\r\n                    var _st1253 = document.createElement('style');\r\n                    _st1253.id = 'via-masque-pageweb-1253';\r\n                    _st1253.textContent =\r\n                        'body.via-pageweb-masque #PageWebMobileEtape'\r\n                        + '{ display: none !important; }'\r\n                        \/* pb2117b : en finalisation, les DEUX etapes page web sont\r\n                           masquees \u2014 la mobile (#PageWebMobileEtape, pb907) ET la\r\n                           classique (pageWeb -> #PageWebColonne, config l.12393),\r\n                           celle qui restait visible chez le user. Classe distincte\r\n                           pour ne pas toucher au motif historique \"3 colonnes\r\n                           desktop\" (masquer #PageWebColonne y serait faux). *\/\r\n                        + '\\nbody.via-pageweb-masque-fin #PageWebMobileEtape,'\r\n                        + '\\nbody.via-pageweb-masque-fin #PageWebColonne'\r\n                        + '{ display: none !important; }';\r\n                    document.head.appendChild(_st1253);\r\n                    console.log('[pb1253] feuille de masquage de l\\'\u00e9tape page web inject\u00e9e');\r\n                }\r\n                var _doit1253 = this._pageWebHorsProcess1253();\r\n                \/* pb2117 : APRES FINALISER, L'ETAPE PAGE WEB EST MASQUEE (demande\r\n                   user, multi-achat mobile). Meme mecanisme, meme feuille : on\r\n                   ajoute la finalisation au critere. FinaliserStep (sessionStorage,\r\n                   pose au clic Finaliser, survit au rechargement) OU le drapeau de\r\n                   session _viaFinaliserClique. Le retour-modification retire\r\n                   FinaliserStep -> l'etape revient d'elle-meme.\r\n                   Revert : window._viaPb2117Off = true. *\/\r\n                var _fin2117 = false;\r\n                if (window._viaPb2117Off !== true) {\r\n                    if (window._viaFinaliserClique === true) { _fin2117 = true; }\r\n                    try {\r\n                        if (sessionStorage.getItem('FinaliserStep') === 'Yes') { _fin2117 = true; }\r\n                    } catch (_eF2117) {}\r\n                }\r\n                if (_fin2117) { _doit1253 = true; }\r\n                \/* pb2263 : EXCEPTION REGIE MOBILE (demande JF). Apres Finaliser,\r\n                   l'etape page web doit rester VISIBLE sur la regie mobile \u2014\r\n                   grisee\/repliee comme les autres etapes faites, ce que la chaine\r\n                   standard fait deja ([pb1071] la liste dans \"deja grisees\") ; seul\r\n                   le display:none de pb2117 la cachait par-dessus. On leve donc le\r\n                   masquage de finalisation dans CE contexte seulement. Les deux\r\n                   discriminants sont exiges ensemble (regle du carnet) :\r\n                     - PAS body.via-popup-achat (classe posee uniquement dans\r\n                       l'iframe #ViaPopupProcessAchat des sites pays -> la demande\r\n                       d'origine \"multi-achat mobile\" y reste servie) ;\r\n                     - outerWidth < 1000 (mobile ; desktop regie inchange, et\r\n                       outerWidth car innerWidth vaut 0 en iframe mobile).\r\n                   Le masquage \"3 colonnes desktop\" (pb1253) n'est pas touche.\r\n                   Revert : window._viaPb2263Off = true. *\/\r\n                if (_fin2117 ? (window._viaPb2263Off !== true) : false) {\r\n                    var _popup2263 = document.body.classList.contains('via-popup-achat');\r\n                    var _ow2263 = Math.round(window.outerWidth || 0);\r\n                    if (_popup2263 ? false : (_ow2263 > 0 ? _ow2263 < 1000 : false)) {\r\n                        _fin2117 = false;\r\n                        _doit1253 = this._pageWebHorsProcess1253();\r\n                        console.log('[pb2263] finalisation regie mobile -> etape page web laissee VISIBLE'\r\n                            + ' (grisee\/repliee par la chaine standard)'\r\n                            + ' | outerW=' + _ow2263 + ' | via-popup-achat=false'\r\n                            + ' | masque 3col recalcule=' + _doit1253);\r\n                    }\r\n                }\r\n                \/* pb2117b : classe dediee finalisation, geree AVANT le court-circuit\r\n                   d'egalite ci-dessous (sinon jamais retiree au retour-modif). *\/\r\n                var _dejaFin2117 = document.body.classList.contains('via-pageweb-masque-fin');\r\n                if (_fin2117 !== _dejaFin2117) {\r\n                    document.body.classList[_fin2117 ? 'add' : 'remove']('via-pageweb-masque-fin');\r\n                    \/* pb2117c : LA FEUILLE NE SUFFIT PAS \u2014 ECRITURE INLINE.\r\n                       Preuve log : classes posees a 11:24:43.721, et la sonde voit\r\n                       quand meme #PageWebMobileEtape(bot=294.2) rendu. Une feuille\r\n                       !important perd contre un display inline !important (lecon 6),\r\n                       et ce process en pose (pb632 data-display632, pilotage du\r\n                       wrapper l.14828). On ecrit donc display:none inline !important\r\n                       sur les DEUX etapes, en memorisant l'inline anterieur dans\r\n                       data-via-disp2117 pour le restaurer tel quel a la sortie. *\/\r\n                    ['PageWebMobileEtape', 'PageWebColonne'].forEach(function (_id17) {\r\n                        var _el17 = document.getElementById(_id17);\r\n                        if (!_el17) {\r\n                            console.log('[pb2117c] #' + _id17 + ' introuvable');\r\n                            return;\r\n                        }\r\n                        if (_fin2117) {\r\n                            if (_el17.dataset.viaDisp2117 === undefined) {\r\n                                _el17.dataset.viaDisp2117 = _el17.style.getPropertyValue('display')\r\n                                    + '|' + _el17.style.getPropertyPriority('display');\r\n                            }\r\n                            _el17.style.setProperty('display', 'none', 'important');\r\n                        } else {\r\n                            var _mem17 = _el17.dataset.viaDisp2117;\r\n                            if (_mem17 !== undefined) {\r\n                                var _p17 = _mem17.split('|');\r\n                                if (_p17[0]) { _el17.style.setProperty('display', _p17[0], _p17[1] || ''); }\r\n                                else { _el17.style.removeProperty('display'); }\r\n                                delete _el17.dataset.viaDisp2117;\r\n                            }\r\n                        }\r\n                    });\r\n                    console.log('[pb2117b] etapes page web (mobile + classique) -> '\r\n                        + (_fin2117 ? 'MASQUEES (finalisation, inline pb2117c)' : 'affichees (finalisation terminee, inline restaure)'));\r\n                }\r\n                var _deja1253 = document.body.classList.contains('via-pageweb-masque');\r\n                if (_doit1253 === _deja1253) { return; }\r\n                document.body.classList[_doit1253 ? 'add' : 'remove']('via-pageweb-masque');\r\n                console.log('[pb1253] \u00e9tape page web -> '\r\n                    + (_doit1253 ? ('MASQU\u00c9E (' + (_fin2117 ? 'finalisation pb2117' : '3 colonnes desktop') + ')') : 'affich\u00e9e'));\r\n            } catch (_e1253b) { console.warn('[pb1253]', _e1253b.message); }\r\n        },\r\n\r\n        \/\/ pb1076 : calcul des completions, partage par le veilleur, le sequenceur\r\n        \/\/   d'ouverture et la sonde. Une seule definition \u2014 deux copies auraient\r\n        \/\/   fini par diverger.\r\n        _completions1076() {\r\n            const it = (this.state.items || []).find(x => x.id === this.state.itemActif) || null;\r\n            const ss = function (k) { try { return sessionStorage.getItem(k) || ''; } catch (_e) { return ''; } };\r\n            \/* pb1567 : DECLARATION REMONTEE EN TETE. pb1561 avait pose _expr1311 a la\r\n               ligne 236 de cette fonction, alors que `annonceur` l'utilise des la\r\n               ligne 50. Un `const` vit dans sa zone morte temporelle jusqu'a sa\r\n               declaration : chaque appel levait \u00ab Cannot access '_expr1311' before\r\n               initialization \u00bb, donc _completions1076 ne rendait plus rien \u2014 et tout\r\n               ce qui en depend tombait avec, y compris pb1564, pb1565 et pb1566.\r\n               Le raisonnement de pb1561 etait juste ; sa POSITION ne l'etait pas. *\/\r\n            \/* ============================================================\r\n             * pb1561 : L'ITEM EST LA SEULE SOURCE HONNETE \u2014 AUSSI EN POPUP.\r\n             *   Releve pb1560 : faits=111111100000, soit annonceur, format ET dates\r\n             *   declares faits alors qu'aucun ne l'est. La cible tombe donc sur\r\n             *   'recapitulatif', et c'est elle qui pilote la couleur\r\n             *   (_couleurEtapes1169) comme la taille (delta pb1170) : un seul defaut,\r\n             *   tous les symptomes que je poursuivais depuis quatre livraisons.\r\n             *   La sonde pb1071, qui lit l'ITEM, rendait 0110011 \u2014 la verite.\r\n             *   pb1311 a deja diagnostique ce mecanisme et ecrit la regle :\r\n             *   \u00ab quand le catalogue a pris la place du process, l'item est la seule\r\n             *   source honnete... mesurer l'etat reel, pas une cle qui survit \u00bb.\r\n             *   Mais elle n'etait armee que pour l'achat express\r\n             *   (_viaCatalogueDeplace1264). Le process en popup est le meme cas de\r\n             *   figure : SelectedPageSecteur, FormatSelect et Nationalite_Societe\r\n             *   survivent d'une reservation a l'autre et mentent sur l'espace courant.\r\n             *   On etend la condition existante au lieu d'ecrire une seconde regle.\r\n             *   Revert : window._viaPb1561Off = true.\r\n             * ============================================================ *\/\r\n            const _popup1561 = (window._viaPb1561Off === true)\r\n                ? false\r\n                : (function () {\r\n                    try {\r\n                        return new URLSearchParams(window.location.hash.substring(1)\r\n                            || window.location.search).get('mode') === 'popup';\r\n                    } catch (_e) { return false; }\r\n                })();\r\n            const _expr1311 = (window._viaPb1311Off === true)\r\n                ? false\r\n                : (window._viaCatalogueDeplace1264 === true ? true : _popup1561);\r\n            \/\/ ================================================================\r\n            \/\/ pb1126 : l'etape ESPACE PUBLICITAIRE n'est faite qu'une fois l'espace\r\n            \/\/   RESERVE (demande user).\r\n            \/\/   Jusqu'ici la simple presence d'un emplacement suffisait : l'etape se\r\n            \/\/   fermait \u2014 et le recapitulatif s'ouvrait \u2014 des le clic sur un espace,\r\n            \/\/   avant que l'utilisateur ait coche \"Reserver cet espace publicitaire\".\r\n            \/\/   Le critere de reservation effective existe deja et sert au code\r\n            \/\/   couleur : estReserveEffective === true, ou statut === 'complete'\r\n            \/\/   (cf le commentaire de _viaEtapeActiveColorWatchdog). On le reutilise\r\n            \/\/   plutot que d'en inventer un.\r\n            \/\/   Revert : window._viaPb1126Off = true (emplacement seul, comme avant).\r\n            \/\/ ================================================================\r\n            const _emplChoisi = (it ? ((it.donneesIframe ? it.donneesIframe.Commande_Emplacement_Page_Web : '')\r\n                || it.emplacementPageWeb || '') : '') || ss('Commande_Emplacement_Page_Web');\r\n            const _reserve = it\r\n                ? (it.estReserveEffective === true ? true : (it.statut === 'complete'))\r\n                : false;\r\n            const empl = (window._viaPb1126Off === true)\r\n                ? _emplChoisi\r\n                : (_reserve ? _emplChoisi : '');\r\n            \/\/ ================================================================\r\n            \/\/ pb1077 : L'ANNONCEUR N'EST COMPLET QU'APRES VALIDATION.\r\n            \/\/   Constat user (log) : des la 1re lettre \u2014 \"Pays chang\u00e9 dans \u00c9tape 1: f\"\r\n            \/\/   \u2014 la completion passait a 1, l'etape se grisait et se fermait, puis\r\n            \/\/   pb915 la rouvrait et degrisait. D'ou un va-et-vient a chaque frappe.\r\n            \/\/   Le champ est un autocomplete : sa valeur intermediaire n'est pas un\r\n            \/\/   pays. Le log le dit lui-meme : \"Pays non trouve pour mise a jour TVA: f\"\r\n            \/\/   puis \"Saisie en cours, pas de validation\".\r\n            \/\/   Deux criteres, dans cet ordre :\r\n            \/\/     - item.pays fait foi s'il existe (il n'est ecrit qu'apres validation) ;\r\n            \/\/     - sinon la valeur du champ n'est retenue QUE si le champ n'a plus le\r\n            \/\/       focus, c'est-a-dire une fois la saisie terminee.\r\n            \/\/   Tester le focus plutot que la longueur ou une liste de pays : c'est le\r\n            \/\/   seul signal qui vaut pour toutes les langues et toutes les graphies.\r\n            \/\/   Revert : window._viaPb1077Off = true (comportement immediat).\r\n            \/\/ ================================================================\r\n            \/\/ pb1100 : un pays choisi dans la LISTE DEROULANTE compte aussi.\r\n            \/\/   Constat user : selectionner un pays dans la liste ne referme pas\r\n            \/\/   l'etape, alors que le saisir entierement au clavier fonctionne.\r\n            \/\/   Cause : pb1077 n'accepte la valeur du champ que s'il a perdu le\r\n            \/\/   FOCUS. Or l'autocomplete jQuery UI rend le focus au champ apres un\r\n            \/\/   clic dans la liste : la condition n'est jamais remplie.\r\n            \/\/   STATE.selectedCountry n'est pose QUE sur un pays valide, par les\r\n            \/\/   deux chemins (liste et frappe complete) : c'est le signal de\r\n            \/\/   validation qui manquait. Le test du focus reste en repli.\r\n            \/* pb1561b : meme regle pour l'annonceur. Nationalite_Societe survit a la\r\n               reservation precedente ; en popup, seul it.pays fait foi. *\/\r\n            \/* ============================================================\r\n             * pb1714 : EN POPUP, L ANNONCEUR LISAIT LE PAYS DU SITE.\r\n             *   Log user, trois lignes consecutives :\r\n             *     [pb1071] completions 1100000 | item : pays=Congo\r\n             *     [pb773]  annonceur <- item.paysAnnonceur = \"Burkina Faso\"\r\n             *              (item.pays = \"Congo\", site, non utilise)\r\n             *     [pb1076] completions -> 010000000000  -> Etape degrisee\r\n             *   Entre les deux tables, it.pays est nullifie par le reset de\r\n             *   selection d espace (l.4431). Or cette ligne-ci fait reposer\r\n             *   TOUTE la completion annonceur sur it.pays en mode popup :\r\n             *   annonceur devient vide, l etape se rouvre.\r\n             *   pb1561b avait choisi it.pays pour ecarter Nationalite_Societe,\r\n             *   qui survit d une reservation a l autre. Le motif etait bon, le\r\n             *   champ non : pb773 et pb1189 disent tous deux que it.pays porte\r\n             *   le pays du SITE, et que l annonceur est it.paysAnnonceur.\r\n             *   On aligne donc sur pb773 \u2014 meme source, meme lecture \u2014 et on\r\n             *   passe par le predicat de validite pour ne pas conclure sur une\r\n             *   saisie partielle, que pb922 ecrit dans l item au fil de la frappe.\r\n             *   L ecran reste ignore en popup : c est l acquis de pb1561.\r\n             *   Revert : window._viaPb1714Off = true (retour a it.pays).\r\n             * ============================================================ *\/\r\n            var _ann1714 = '';\r\n            if (_expr1311) {\r\n                if (window._viaPb1714Off === true) {\r\n                    _ann1714 = it ? (it.pays || '') : '';\r\n                } else {\r\n                    var _pa1714 = it ? (it.paysAnnonceur || '') : '';\r\n                    if (_pa1714) {\r\n                        if (typeof window._viaPaysValide949 === 'function') {\r\n                            _ann1714 = (window._viaPaysValide949(_pa1714) === true) ? _pa1714 : '';\r\n                        } else {\r\n                            _ann1714 = _pa1714;\r\n                        }\r\n                    }\r\n                    if (!_ann1714) { _ann1714 = it ? (it.pays || '') : ''; }\r\n                    if (window._viaSig1714 !== (_pa1714 + '|' + _ann1714)) {\r\n                        window._viaSig1714 = _pa1714 + '|' + _ann1714;\r\n                        console.log('[pb1714] annonceur retenu = ' + (_ann1714 || '(vide)')\r\n                            + ' | paysAnnonceur=' + (_pa1714 || '(vide)')\r\n                            + ' | pays(site)=' + (it ? (it.pays || '(null)') : 'sans item') + ')');\r\n                    }\r\n                }\r\n            }\r\n            let annonceur = _expr1311\r\n                ? _ann1714\r\n                : ((it ? it.pays : '') || ss('Nationalite_Societe'));\r\n            if (!annonceur) {\r\n                \/\/ pb1101 : le MENU FERME signale la fin de la saisie.\r\n                \/\/   pb1100 lisait window.STATE.selectedCountry \u2014 mais STATE est une\r\n                \/\/   variable locale du formulaire, pas une globale : la condition\r\n                \/\/   etait toujours fausse et le correctif sans effet.\r\n                \/\/   Signal reellement observable : le menu de l'autocomplete. Il est\r\n                \/\/   OUVERT pendant la frappe (propositions affichees) et FERME des\r\n                \/\/   qu'un pays est choisi \u2014 a la souris comme au clavier. Il couvre\r\n                \/\/   donc les deux chemins, la ou le focus n'en couvrait qu'un.\r\n                \/\/ pb1104 : le pays doit etre RECONNU, pas seulement saisi.\r\n                \/\/   Constat user : taper \"fr\" referme l'etape alors que la liste de\r\n                \/\/   propositions vient de s'ouvrir et qu'aucun pays n'est encore choisi.\r\n                \/\/   Les criteres precedents etaient indirects : le focus (pb1077) ne\r\n                \/\/   couvrait pas le choix a la souris, le menu ouvert (pb1101) depend\r\n                \/\/   d'un instant de mesure \u2014 le veilleur passe toutes les 400ms et peut\r\n                \/\/   tomber entre deux etats.\r\n                \/\/   On teste desormais ce qui compte vraiment : la valeur correspond-elle\r\n                \/\/   a un pays connu ? VIA_Countries porte la liste (198 pays, FR\/EN et\r\n                \/\/   alias) et sert deja a l'autocomplete : meme source, meme verdict.\r\n                \/\/   Sans VIA_Countries, on retombe sur le test du focus.\r\n                try {\r\n                    var _val1104 = ($('#form-field-Nationalite_Societe').val() || '').trim();\r\n                    if (_val1104) {\r\n                        \/\/ pb1110 : la methode s'appelle isValidCountry.\r\n                        \/\/   Releve user : VIA_Countries expose normalizeString,\r\n                        \/\/   COUNTRIES_DATA, getCountryByCode, getCountryByLabel,\r\n                        \/\/   searchCountries, getCountriesByGroup, getPHPMapping et\r\n                        \/\/   isValidCountry \u2014 aucune des trois que j'avais devinees.\r\n                        \/\/   J'aurais du demander cette liste avant d'ecrire le test.\r\n                        \/\/   Meme releve : apres un choix dans la liste,\r\n                        \/\/   document.activeElement.id vaut toujours\r\n                        \/\/   'form-field-Nationalite_Societe'. Le champ GARDE donc le\r\n                        \/\/   focus, et le repli ne pouvait pas prendre le relais :\r\n                        \/\/   isValidCountry est le seul signal utilisable ici.\r\n                        var _vc = window.VIA_Countries;\r\n                        var _fn = _vc\r\n                            ? (_vc.isValidCountry || _vc.getCountryByLabel || null)\r\n                            : null;\r\n                        \/\/ pb1106 : les deux signaux sont CUMULATIFS, pas exclusifs.\r\n                        \/\/   Constat user : \"Afrique du Sud\" est valide (log \"Pays\r\n                        \/\/   selectionne\" puis \"Pays valide par blur\") et l'etape ne se\r\n                        \/\/   ferme pas.\r\n                        \/\/   Cause : le repli sur le focus n'etait pris que si la METHODE\r\n                        \/\/   de VIA_Countries etait absente. Si elle existe mais ne\r\n                        \/\/   reconnait pas la graphie exacte, on n'y arrivait jamais.\r\n                        \/\/   Un seul des deux signaux suffit : pays reconnu OU saisie\r\n                        \/\/   terminee (champ sans focus). Les deux sont des preuves\r\n                        \/\/   valables, il n'y a pas de raison de les hierarchiser.\r\n                        \/\/ ================================================================\r\n                        \/\/ pb1193 : le pays doit etre RECONNU, sans repli sur le focus.\r\n                        \/\/   Constat user (capture) : \"Pays de la societe de l'annonceur : f\"\r\n                        \/\/   \u2014 la lettre \"f\" a ete acceptee comme annonceur, et le layout\r\n                        \/\/   s'est ouvert sur une saisie incomplete.\r\n                        \/\/   pb1106 acceptait \"pays reconnu OU champ sans focus\". Le second\r\n                        \/\/   critere etait un repli, ecrit quand je n'avais pas encore le nom\r\n                        \/\/   de la methode de VIA_Countries. Depuis pb1110 je l'ai\r\n                        \/\/   (isValidCountry) : le repli n'a plus lieu d'etre, et il laissait\r\n                        \/\/   passer toute saisie abandonnee en cours de route.\r\n                        \/\/   Le focus ne sert plus que si VIA_Countries est indisponible \u2014\r\n                        \/\/   mieux vaut alors accepter que bloquer le parcours.\r\n                        \/\/   Revert : window._viaPb1193Off = true (repli focus retabli).\r\n                        \/\/ ================================================================\r\n                        var _ok1106 = false;\r\n                        if (typeof _fn === 'function') {\r\n                            try { _ok1106 = !!_fn.call(_vc, _val1104); } catch (_eF) { _ok1106 = false; }\r\n                        } else if (window._viaPb1193Off === true) {\r\n                            var _ch1104 = $('#form-field-Nationalite_Societe')[0] || null;\r\n                            _ok1106 = _ch1104 ? (document.activeElement !== _ch1104) : false;\r\n                        } else {\r\n                            \/\/ VIA_Countries absent : on ne peut pas verifier, on accepte\r\n                            \/\/   la saisie terminee plutot que de bloquer.\r\n                            var _ch1193 = $('#form-field-Nationalite_Societe')[0] || null;\r\n                            _ok1106 = _ch1193 ? (document.activeElement !== _ch1193) : false;\r\n                        }\r\n                        \/* pb1570a : PAS DE RELECTURE DU CHAMP EN POPUP. pb1561b avait mis\r\n                           l'INITIALISATION de `annonceur` sur l'item, mais deux\r\n                           reaffectations suivent et lisent #form-field-Nationalite_Societe,\r\n                           c'est-a-dire l'ECRAN. Elles restauraient donc la valeur que\r\n                           pb1561 voulait ecarter : l'etape annonceur repassait a \u00ab faite \u00bb,\r\n                           la cible glissait, et le titre retombait en #525252 \u00ab a venir \u00bb.\r\n                           Constat : _moins1170 = 0.5 sur ce titre \u2014 le delta \u00ab a faire \u00bb,\r\n                           jamais celui de l'etape active. *\/\r\n                        if (_ok1106 ? !_expr1311 : false) { annonceur = _val1104; }\r\n                    }\r\n                } catch (_e1104) {}\r\n            }\r\n            if (!annonceur) {\r\n                const $ch1077 = $('#form-field-Nationalite_Societe');\r\n                const val1077 = ($ch1077.val() || '');\r\n                const enSaisie1077 = (window._viaPb1077Off === true)\r\n                    ? false\r\n                    : ($ch1077.length ? (document.activeElement === $ch1077[0]) : false);\r\n                \/* pb1570b : seconde reaffectation, meme regle. *\/\r\n                if (_expr1311 ? false : (val1077 ? !enSaisie1077 : false)) { annonceur = val1077; }\r\n            }\r\n            \/\/ ================================================================\r\n            \/\/ pb1330 : LE CONTROLE NE COUVRAIT QUE LA VALEUR VENUE DU CHAMP.\r\n            \/\/   Constat user : la liste des pays ne s'affiche pas et la saisie du\r\n            \/\/   pays ne peut pas etre terminee. Le log enchaine :\r\n            \/\/     \ud83c\udf0d Pays chang\u00e9 dans \u00c9tape 1: fr      <- l'item recoit la saisie partielle\r\n            \/\/     [pb667] ... item.pays (annonceur) = fr\r\n            \/\/     [pb1076] compl\u00e9tions chang\u00e9es -> 1111100000\r\n            \/\/     \u2705 \u00c9tape gris\u00e9e: processAnnonceur\r\n            \/\/     [pb915] processAnnonceur ferm\u00e9   \/   [pb1099] processAnnonceur -> ferm\u00e9\r\n            \/\/   L'etape fermee met .ProcessAnnonceurConteneurClass en display:none :\r\n            \/\/   le champ ET son menu d'autocomplete disparaissent en pleine frappe.\r\n            \/\/   Cause : la validation de pb1104\/pb1110\/pb1193 \u2014 isValidCountry, juste\r\n            \/\/   au-dessus \u2014 vit ENTIEREMENT dans le \u00ab if (!annonceur) \u00bb. Elle ne\r\n            \/\/   s'applique donc qu'a la valeur lue dans le CHAMP. Des que it.pays ou\r\n            \/\/   la cle sessionStorage porte deja la saisie partielle (ce que le log\r\n            \/\/   montre), la valeur traverse sans etre controlee.\r\n            \/\/   Meme trou structurel que pb1328 cote regie : le chemin \u00ab valeur deja\r\n            \/\/   presente \u00bb court-circuite le controle que le chemin \u00ab champ \u00bb subit.\r\n            \/\/   On controle donc la valeur RETENUE, d'ou qu'elle vienne, avec le meme\r\n            \/\/   predicat et la meme source (VIA_Countries).\r\n            \/\/   Sans VIA_Countries, aucun controle : comportement d'avant, on\r\n            \/\/   n'empeche pas le parcours d'avancer.\r\n            \/\/   Revert : window._viaPb1330Off = true.\r\n            \/\/ ================================================================\r\n            if (annonceur ? (window._viaPb1330Off !== true) : false) {\r\n                const _vc1330 = window.VIA_Countries;\r\n                const _fn1330 = _vc1330\r\n                    ? (_vc1330.isValidCountry || _vc1330.getCountryByLabel || null)\r\n                    : null;\r\n                if (typeof _fn1330 === 'function') {\r\n                    let _ok1330 = true;\r\n                    try { _ok1330 = !!_fn1330.call(_vc1330, annonceur); }\r\n                    catch (_e1330) {\r\n                        console.warn('[pb1330] validation impossible : ' + _e1330.message);\r\n                        _ok1330 = true;   \/\/ on n'empeche pas le parcours sur une erreur\r\n                    }\r\n                    if (!_ok1330) {\r\n                        if (window._viaAlerte1330 !== annonceur) {\r\n                            window._viaAlerte1330 = annonceur;\r\n                            console.log('[pb1330] annonceur \"' + annonceur\r\n                                + '\" en cours de saisie -> \u00e9tape NON compl\u00e9t\u00e9e');\r\n                        }\r\n                        annonceur = '';\r\n                    }\r\n                }\r\n            }\r\n            const site = (it ? (it.paysDisplayed || it.linkSecteurPage) : '')\r\n                || ss('ContinentPaysTitreDisplayed') || ss('ContinentPaysTitre') || ss('SitePays');\r\n            \/\/ ================================================================\r\n            \/\/ pb1311 : EN ACHAT EXPRESS, SEUL L'ITEM FAIT FOI POUR PAGE ET FORMAT.\r\n            \/\/   Constat user (log) : sur une nouvelle reservation express,\r\n            \/\/     [pb1076] compl\u00e9tions -> 111110000000\r\n            \/\/     [pb1099] pageWebMobile -> OUVERT\r\n            \/\/   cinq etapes comptees faites, donc la premiere non faite est la\r\n            \/\/   page web : le sequenceur l'ouvre, et l'ANCIENNE page apparait.\r\n            \/\/   Rien ne l'a \u00ab ouverte \u00bb \u2014 c'est l'etape qui s'ouvre sur un\r\n            \/\/   conteneur jamais vide.\r\n            \/\/   Or l'item dit le contraire, dans le meme log :\r\n            \/\/     [pb1071] item : pays=France site=Congo page=- format=-\r\n            \/\/   Secteur et format ne sont comptes faits que par le repli\r\n            \/\/   sessionStorage. Ce repli sert a restaurer une session ; en achat\r\n            \/\/   express il ment, car le catalogue repose ces cles pour SON compte\r\n            \/\/   (SelectedPageSecteur, commandePage, FormatSelect) sans que le\r\n            \/\/   process ait rien recu.\r\n            \/\/   Quand le catalogue a pris la place du process (pb1264\/pb1298),\r\n            \/\/   l'item est la seule source honnete. C'est la lecon pb1196\/pb1222 :\r\n            \/\/   mesurer l'etat reel, pas une cle qui survit.\r\n            \/\/   Le SITE n'est pas touche : il est legitimement choisi dans le\r\n            \/\/   catalogue et l'item le porte (site=Congo ci-dessus).\r\n            \/\/   Revert : window._viaPb1311Off = true.\r\n            \/\/ ================================================================\r\n            const page = _expr1311\r\n                ? (it ? (it.selectedPageSecteur || it.commandePage || '') : '')\r\n                : ((it ? (it.selectedPageSecteur || it.commandePage) : '')\r\n                    || ss('SelectedPageSecteur') || ss('SelectedPageType'));\r\n            const format = _expr1311\r\n                ? (it ? (it.format || '') : '')\r\n                : ((it ? it.format : '') || ss('FormatSelect'));\r\n            if (_expr1311) {\r\n                const _sg1311 = (page ? '1' : '0') + (format ? '1' : '0');\r\n                if (window._viaSig1311 !== _sg1311) {\r\n                    window._viaSig1311 = _sg1311;\r\n                    console.log('[pb1311] achat express : page et format lus sur l\\'item'\r\n                        + ' | page=' + (page || '-') + ' | format=' + (format || '-'));\r\n                }\r\n            }\r\n            \/\/ ================================================================\r\n            \/\/ pb1142 : une duree HORS BORNES ne vaut pas une etape Dates faite.\r\n            \/\/   Constat user : avec 3 jours, l'etape Dates se grise et se ferme \u2014\r\n            \/\/   le log le montre (\"Duree calculee: 3 jours\" puis \"completions\r\n            \/\/   0000100\" puis \"Etape grisee: processDatesDevise\").\r\n            \/\/   La regle des 7 jours existe pourtant : _verifierDureeMin603 pose\r\n            \/\/   window._viaDureeInvalide603 des que la duree sort de [7-200].\r\n            \/\/   Mais la completion ne regardait que la PRESENCE des deux dates, pas\r\n            \/\/   leur validite : deux dates quelconques suffisaient.\r\n            \/\/   On lit donc ce drapeau. Tant que la duree est invalide, l'etape\r\n            \/\/   reste ouverte et en cours \u2014 ce qui rend la regle visible dans le\r\n            \/\/   parcours, meme si le message de pb603 n'apparait pas dans ce\r\n            \/\/   contexte.\r\n            \/\/   Revert : window._viaPb1142Off = true.\r\n            \/\/ ================================================================\r\n            \/* pb1561c : meme regle pour les dates. Le repli sur les champs du\r\n               formulaire lit l'ECRAN, pas l'espace courant : en popup, seules les\r\n               dates portees par l'item comptent. *\/\r\n            const _deuxDates = _expr1311\r\n                ? (it ? (it.dateDebut ? !!it.dateFin : false) : false)\r\n                : ((it ? (it.dateDebut ? !!it.dateFin : false) : false)\r\n                    || !!($('#form-field-DebutCampagne').val() ? $('#form-field-FinCampagne').val() : ''));\r\n            const _dureeOk = (window._viaPb1142Off === true)\r\n                ? true\r\n                : (window._viaDureeInvalide603 !== true);\r\n            const dates = _deuxDates ? _dureeOk : false;\r\n            \/\/ ================================================================\r\n            \/\/ pb1158 : les ETAPES AVAL entrent dans le sequenceur (demande user).\r\n            \/\/   Leurs criteres ne sont PAS reinventes : ils sont repris de\r\n            \/\/   Validation_sequentielle.txt (objet ETAPES), qui les utilise deja\r\n            \/\/   pour autoriser ou bloquer chaque bouton. Une seule definition de\r\n            \/\/   \"cette etape est faite\" pour l'action ET pour l'affichage \u2014 sinon\r\n            \/\/   un bouton pourrait etre actif sur une etape que le sequenceur croit\r\n            \/\/   inachevee, ou l'inverse.\r\n            \/\/     recapitulatif : FinaliserStep === 'Yes'\r\n            \/\/     references    : references_validees_session === 'Yes'\r\n            \/\/     paiement      : mode_paiement (ou VIA_Paiement.state.modePaiement)\r\n            \/\/     validations   : les trois cases cochees\r\n            \/\/     paiementFinal : jamais \"faite\" \u2014 c'est l'aboutissement du parcours\r\n            \/\/   L'espace publicitaire garde MON critere (reservation effective,\r\n            \/\/   pb1126) : c'est ce que l'utilisateur a demande pour l'affichage.\r\n            \/\/ ================================================================\r\n            var _recap1158 = (ss('FinaliserStep') === 'Yes');\r\n            var _ref1158 = (ss('references_validees_session') === 'Yes');\r\n            \/* ============================================================\r\n             * pb1639 : LE MODE DE PAIEMENT SE LIT SUR L'ETAT VIVANT, PAS SUR LA SESSION.\r\n             *   Log user : faits=010000011100 \u2014 la 10e position, 'paiement', vaut 1 alors\r\n             *   que l'utilisateur n'a rien choisi. pb1634 saute donc cette etape et avance\r\n             *   a 'validations', qui s'ouvre a sa place (capture).\r\n             *   Cause : ss('mode_paiement') est une cle de session qui SURVIT d'une\r\n             *   reservation a l'autre. Elle etait lue en PREMIER, l'etat vivant du module\r\n             *   n'etant consulte qu'a defaut \u2014 donc jamais quand la cle persiste.\r\n             *   pb1311 avait deja ecrit la regle pour un cas voisin : \u00ab mesurer l'etat\r\n             *   reel, pas une cle qui survit \u00bb. On l'applique ici en inversant la\r\n             *   priorite : si le module de paiement est charge, son etat fait foi, y\r\n             *   compris quand il dit qu'aucun mode n'est choisi. La session ne sert plus\r\n             *   que de repli, quand le module n'est pas encore la.\r\n             *   Revert : window._viaPb1639Off = true (session prioritaire).\r\n             * ============================================================ *\/\r\n            var _pay1158;\r\n            if (window._viaPb1639Off === true) {\r\n                _pay1158 = !!ss('mode_paiement');\r\n                if (!_pay1158) {\r\n                    try {\r\n                        _pay1158 = !!(window.VIA_Paiement ? (window.VIA_Paiement.state\r\n                            ? window.VIA_Paiement.state.modePaiement : false) : false);\r\n                    } catch (_eP1158) { _pay1158 = false; }\r\n                }\r\n            } else {\r\n                var _mod1639 = null;\r\n                try {\r\n                    _mod1639 = (window.VIA_Paiement ? (window.VIA_Paiement.state || null) : null);\r\n                } catch (_eM1639) { _mod1639 = null; }\r\n                if (_mod1639) {\r\n                    _pay1158 = !!_mod1639.modePaiement;\r\n                    var _sg1639 = _pay1158 ? '1' : '0';\r\n                    if (window._viaSig1639 !== _sg1639) {\r\n                        window._viaSig1639 = _sg1639;\r\n                        console.log('[pb1639] etape paiement = ' + (_pay1158 ? 'faite' : 'a faire')\r\n                            + ' | etat vivant=' + (_mod1639.modePaiement || '(aucun)')\r\n                            + ' | session=' + (ss('mode_paiement') || '(vide)'));\r\n                    }\r\n                } else {\r\n                    _pay1158 = !!ss('mode_paiement');\r\n                }\r\n            }\r\n            \/\/ ================================================================\r\n            \/\/ pb1195 : l'etape VALIDATIONS attend le clic sur VALIDER.\r\n            \/\/   Constat user : des que les trois cases sont cochees, l'etape se\r\n            \/\/   ferme et le paiement s'ouvre \u2014 sans que le bouton \"Valider\" ait\r\n            \/\/   ete clique.\r\n            \/\/   Mon critere reprenait celui de Validation_sequentielle.txt\r\n            \/\/   (validations_cgv = les trois cases cochees). Il y est juste : ce\r\n            \/\/   module verifie des PREREQUIS avant d'autoriser une action. Pour\r\n            \/\/   l'AVANCEMENT du parcours, la validation n'est acquise qu'au clic.\r\n            \/\/   Validations.txt pose alors sessionStorage.validations_completees \u2014\r\n            \/\/   c'est le signal du clic, et c'est lui qu'il faut lire ici.\r\n            \/\/   Les trois cases restent testees en repli, pour les contextes ou ce\r\n            \/\/   drapeau n'aurait pas ete pose (restauration de session).\r\n            \/\/   Revert : window._viaPb1195Off = true (les cases suffisent).\r\n            \/\/ ================================================================\r\n            var _cgv1158 = false;\r\n            try {\r\n                if (window._viaPb1195Off !== true) {\r\n                    _cgv1158 = (ss('validations_completees') === 'true');\r\n                } else {\r\n                    var _c1 = document.querySelector('input[name=\"form_fields[Validation_Commande]\"]');\r\n                    var _c2 = document.querySelector('input[name=\"form_fields[Acceptation_CGV]\"]');\r\n                    var _c3 = document.querySelector('input[name=\"form_fields[Acceptation_Commande]\"]');\r\n                    _cgv1158 = (_c1 ? _c1.checked : false)\r\n                        ? ((_c2 ? _c2.checked : false) ? (_c3 ? _c3.checked : false) : false)\r\n                        : false;\r\n                }\r\n            } catch (_eC1158) { _cgv1158 = false; }\r\n            if (_expr1311) {\r\n                var _sg1570 = (annonceur ? '1' : '0') + '|' + (it ? (it.pays || '-') : 'sans item');\r\n                if (window._viaSig1570 !== _sg1570) {\r\n                    window._viaSig1570 = _sg1570;\r\n                    console.log('[pb1570] annonceur retenu = ' + (annonceur || '(vide)')\r\n                        + ' | item.pays = ' + (it ? (it.pays || '(null)') : 'sans item')\r\n                        + ' | champ ecran ignore en popup');\r\n                }\r\n            }\r\n            var _f1162 = {\r\n                processAnnonceur: !!annonceur, associerPays: !!site,\r\n                \/* pb1570c : trace dedupee \u2014 si l'etape annonceur reste \u00ab faite \u00bb alors\r\n                   que l'item n'a pas de pays, la ligne nomme la source restante. *\/\r\n                \/* pb1554b : meme correction sur la table du SEQUENCEUR \u2014 c'est elle\r\n                   qui decide quelle etape ouvrir ou fermer. Corriger la sonde seule\r\n                   aurait donne un log juste et un comportement inchange. *\/\r\n                associerSecteur: !!page, choixFormat: window._viaChoixFormatFait2099(format),   \/* pb2099 *\/\r\n                processDatesDevise: !!dates, pageWeb: !!empl, pageWebMobile: !!empl,\r\n                recapitulatif: _recap1158, references: _ref1158,\r\n                paiement: _pay1158, validations: _cgv1158, paiementFinal: false\r\n            };\r\n            \/\/ ================================================================\r\n            \/\/ pb1252 : pb1242 RETIRE (demande user) \u2014 l'etape page web redevient une\r\n            \/\/   etape ordinaire en 3 colonnes desktop : visible, non completee, donc\r\n            \/\/   etape courante tant qu'aucun espace n'est reserve.\r\n\r\n            \/\/ pb1253 : ... et elle en SORT de nouveau en 3 colonnes desktop, mais\r\n            \/\/   par la seule voie qui agisse : la SUPPRESSION DES CLES. pb1242 la\r\n            \/\/   declarait \"faite\", ce qui l'affichait completee alors que rien\r\n            \/\/   n'etait reserve ; ici elle n'est simplement plus suivie.\r\n            \/\/   Place AVANT la propagation monotone pb1162, qui filtre sur\r\n            \/\/   hasOwnProperty : les deux cles absentes en sont exclues d'office.\r\n            \/\/   Revert : window._viaPb1253Off = true.\r\n            if (typeof this._pageWebHorsProcess1253 === 'function'\r\n                ? this._pageWebHorsProcess1253() : false) {\r\n                delete _f1162.pageWeb;\r\n                delete _f1162.pageWebMobile;\r\n            }\r\n            \/\/ ================================================================\r\n            \/\/ pb1312 : EN ACHAT EXPRESS, L'ETAPE PAGE WEB N'EXISTE PAS TANT QUE\r\n            \/\/   LA SELECTION N'EST PAS VALIDEE.\r\n            \/\/   Constat user : pb1311 fonctionne \u2014 le log montre page et format\r\n            \/\/   lus sur l'item \u2014 mais l'etape s'ouvre quand meme des que le\r\n            \/\/   catalogue les a renseignes :\r\n            \/\/     [pb1311] page=Homepage | format=Communiqu\u00e9\r\n            \/\/   Et c'est logique : les cinq etapes amont sont alors vraiment\r\n            \/\/   faites, la premiere non faite est la page web, le sequenceur\r\n            \/\/   l'ouvre. pb1311 etait necessaire \u2014 il a supprime le mensonge des\r\n            \/\/   cles \u2014 mais il ne suffit pas.\r\n            \/\/   Ce qui manque est une regle d'ORDRE : en achat express, la page\r\n            \/\/   web ne vient qu'apres le \u00ab Continuer la reservation \u00bb, pas des que\r\n            \/\/   la selection est complete.\r\n            \/\/   On applique donc le mecanisme de pb1253 \u2014 retirer les cles, donc\r\n            \/\/   sortir les etapes du sequenceur \u2014 tant que la selection courante\r\n            \/\/   n'a pas ete validee. Elles reviennent au Continuer, et l'etape\r\n            \/\/   s'ouvre alors normalement : rien n'est masque, donc rien n'est\r\n            \/\/   casse pour la premiere reservation (l'erreur de pb1309).\r\n            \/\/   Le critere est celui de pb1309, defini une seule fois cote\r\n            \/\/   yearbook-media et deja partage avec _pretPageWeb1148.\r\n            \/\/   Revert : window._viaPb1312Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1312Off !== true) {\r\n                var _att1312 = false;\r\n                try {\r\n                    _att1312 = (typeof window._viaExpressEnAttente1309 === 'function')\r\n                        ? window._viaExpressEnAttente1309() : false;\r\n                } catch (_e1312) { _att1312 = false; }\r\n                if (_att1312) {\r\n                    delete _f1162.pageWeb;\r\n                    delete _f1162.pageWebMobile;\r\n                    if (window._viaSig1312 !== 'hors') {\r\n                        window._viaSig1312 = 'hors';\r\n                        console.log('[pb1312] achat express : \u00e9tape page web hors'\r\n                            + ' s\u00e9quenceur jusqu\\'au Continuer');\r\n                    }\r\n                } else if (window._viaSig1312 === 'hors') {\r\n                    window._viaSig1312 = 'ok';\r\n                    console.log('[pb1312] s\u00e9lection valid\u00e9e -> \u00e9tape page web r\u00e9tablie');\r\n                }\r\n            }\r\n\r\n            \/\/ pb1162 : la PROPAGATION MONOTONE remonte dans _completions1076.\r\n            \/\/   Constat user : apres le Finaliser, l'etape References devient bien\r\n            \/\/   active \u2014 puis le veilleur la reprend et repart sur pageWebMobile.\r\n            \/\/   Le log le montre : \"completions changees -> 111110010000\", donc\r\n            \/\/   pageWebMobile a 0 alors que recapitulatif vaut 1.\r\n            \/\/   Cause : pb1159 posait la propagation dans _sequenceurOuverture1073.\r\n            \/\/   Mais le VEILLEUR calcule sa propre signature directement depuis\r\n            \/\/   _completions1076, sans propagation : les deux voyaient un etat\r\n            \/\/   different, et le veilleur \u2014 qui grise et degrise \u2014 imposait le sien.\r\n            \/\/   La regle appartient au calcul des completions, pas a l'un de ses\r\n            \/\/   consommateurs. Placee ici, elle vaut pour tous.\r\n            \/\/   Revert : window._viaPb1159Off = true.\r\n            \/\/ ================================================================\r\n            \/* ============================================================\r\n             * pb1572 : PAS DE PROPAGATION MONOTONE QUAND LE PARCOURS N'EST PAS LINEAIRE.\r\n             *   Mesure user : _completions1076().processAnnonceur === true, alors que\r\n             *   la trace pb1570 rend \u00ab annonceur retenu = (vide) \u00bb trois lignes plus\r\n             *   haut. Les deux sont exacts : la propagation ci-dessous s'execute APRES\r\n             *   la construction de la table et retourne le resultat.\r\n             *   Elle parcourt les etapes A L'ENVERS et, des qu'elle en voit une faite,\r\n             *   declare faites toutes celles qui precedent. La regle suppose un\r\n             *   parcours strictement sequentiel : on ne peut pas avoir fait l'etape 3\r\n             *   sans la 1. C'est vrai sur la regie, ou l'on renseigne l'annonceur, puis\r\n             *   le pays, puis le secteur.\r\n             *   Sur un site pays, l'ordre est inverse : l'espace est RESERVE d'abord \u2014\r\n             *   donc site, secteur et emplacement sont connus \u2014 et l'annonceur se\r\n             *   saisit en dernier. associerPays et associerSecteur etant vrais,\r\n             *   processAnnonceur qui les precede etait marque fait retroactivement.\r\n             *   D'ou la cible 'recapitulatif', le titre en #7f7f7f et le delta pb1170\r\n             *   \u00ab a faire \u00bb \u2014 un seul defaut, tous les symptomes de couleur et de\r\n             *   taille que je poursuivais depuis six livraisons.\r\n             *   On desarme la propagation la ou le parcours n'est pas lineaire ; elle\r\n             *   reste entiere sur la regie, ou son diagnostic pb1162 tient toujours.\r\n             *   Revert : window._viaPb1572Off = true (propagation partout).\r\n             * ============================================================ *\/\r\n            var _lineaire1572 = true;\r\n            if (window._viaPb1572Off !== true) {\r\n                try {\r\n                    _lineaire1572 = !(new URLSearchParams(window.location.hash.substring(1)\r\n                        || window.location.search).get('mode') === 'popup');\r\n                } catch (_e1572) { _lineaire1572 = true; }\r\n            }\r\n            if (!_lineaire1572) {\r\n                var _sg1572 = (_f1162.processAnnonceur ? '1' : '0');\r\n                if (window._viaSig1572 !== _sg1572) {\r\n                    window._viaSig1572 = _sg1572;\r\n                    console.log('[pb1572] propagation monotone desarmee (parcours non lineaire)'\r\n                        + ' | processAnnonceur reste ' + _f1162.processAnnonceur);\r\n                }\r\n            }\r\n            if (window._viaPb1159Off !== true ? _lineaire1572 : false) {\r\n                var _ordre1162 = (this.state.etapesConfig || [])\r\n                    .map(function (_e) { return _e.id; })\r\n                    .filter(function (_id) { return _f1162.hasOwnProperty(_id); });\r\n                var _vu1162 = false;\r\n                for (var _k1162 = _ordre1162.length - 1; _k1162 >= 0; _k1162--) {\r\n                    var _id1162 = _ordre1162[_k1162];\r\n                    if (_f1162[_id1162]) { _vu1162 = true; }\r\n                    else if (_vu1162) { _f1162[_id1162] = true; }\r\n                }\r\n            }\r\n            return _f1162;\r\n        },\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb1335 : ETAT REEL D'UN BANDEAU \u2014 methode partagee.\r\n        \/\/   faits[] ne peut pas repondre \u00ab ce bandeau est-il rempli ? \u00bb : la\r\n        \/\/   PROPAGATION MONOTONE de pb1162 (~l.10995) declare faite toute etape\r\n        \/\/   PRECEDANT une etape faite. Des dates saisies en premier suffisent donc\r\n        \/\/   a marquer pays, secteur et format comme renseignes \u2014 le log l'a montre :\r\n        \/\/     [pb1076] compl\u00e9tions -> 111110000000\r\n        \/\/     [pb1333] closeAssocierSecteur sur un bandeau VIDE\r\n        \/\/   La monotonie reste en place (elle sert au grisage et au parcours en\r\n        \/\/   avant) ; on cesse seulement de la consulter la ou elle ment.\r\n        \/\/   Source : _viaEtatBandeaux1332, exposee cote yearbook-media (pb1332), et\r\n        \/\/   deja utilisee par pb857 pour decider du passage en 3 colonnes \u2014 les deux\r\n        \/\/   decisions restent donc d'accord.\r\n        \/\/   Deux consommateurs : l'ouverture des bandeaux (pb1335) et le seuil\r\n        \/\/   d'ouverture de la page web (pb1336). Une seule definition pour que les\r\n        \/\/   deux ne puissent pas diverger.\r\n        \/\/   Repli : sans la fonction, on retombe sur faits[].\r\n        \/\/   Revert : window._viaPb1335Off = true.\r\n        \/\/ ====================================================================\r\n        _bandeauFait1335(_id1335, _faits1335) {\r\n            const _repli1335 = !!(_faits1335 ? _faits1335[_id1335] : false);\r\n            if (window._viaPb1335Off === true) { return _repli1335; }\r\n            try {\r\n                if (typeof window._viaEtatBandeaux1332 === 'function') {\r\n                    const _cle1335 = (_id1335 === 'associerPays')\r\n                        ? 'pays'\r\n                        : ((_id1335 === 'associerSecteur')\r\n                            ? 'secteur'\r\n                            : ((_id1335 === 'choixFormat') ? 'format' : ''));\r\n                    if (_cle1335) { return !!window._viaEtatBandeaux1332()[_cle1335]; }\r\n                }\r\n            } catch (_e1335) {\r\n                console.warn('[pb1335] \u00e9tat r\u00e9el indisponible (' + _id1335 + ') : '\r\n                    + _e1335.message);\r\n            }\r\n            return _repli1335;\r\n        },\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb1099 : SEQUENCEUR \u2014 REECRITURE COMPLETE (demande user : simplifier).\r\n        \/\/   Remplace pb1073 et ses sept rustines successives (pb1082, pb1084,\r\n        \/\/   pb1085, pb1086, pb1087, pb1089, pb1097). Chacune corrigeait un cas\r\n        \/\/   que la precedente avait manque ; le bloc etait devenu illisible.\r\n        \/\/\r\n        \/\/   UNE SEULE REGLE, en deux familles :\r\n        \/\/     - etapes a BANDEAU (pays, secteur, format) : une seule ouverte a la\r\n        \/\/       fois, la premiere non renseignee. Ces bandeaux sont hauts et se\r\n        \/\/       recouvrent : en ouvrir plusieurs rend le process illisible, c'est\r\n        \/\/       le constat fait au chargement.\r\n        \/\/     - etapes a CHAMPS (annonceur, dates) : ouvertes si non renseignees.\r\n        \/\/       Elles sont courtes et peuvent coexister.\r\n        \/\/     - recapitulatif : ouvert quand tout est renseigne.\r\n        \/\/   Le clic manuel prime toujours (option B).\r\n        \/\/\r\n        \/\/   CHAQUE ETAPE EST PILOTEE PAR SES PROPRES FONCTIONS, celles qui\r\n        \/\/   existent deja : open\/closeAssocierPays & co pour les bandeaux,\r\n        \/\/   _viaOuvrirEtape915 \/ _viaFermerEtape915 pour annonceur et dates,\r\n        \/\/   show\/hide du conteneur pour le reste. On ne reimplante aucun\r\n        \/\/   masquage \u2014 c'etait la source des rustines pb1082\/pb1084.\r\n        \/\/   L'etat courant se lit sur le CHEVRON (offsetParent), comme pb308.\r\n        \/\/   Revert : window._viaPb1073Off = true.\r\n        \/\/ ====================================================================\r\n        _sequenceurOuverture1073() {\r\n            if (window._viaPb1073Off === true) { return; }\r\n            if (!this.state.etapesConfig) { return; }\r\n            try {\r\n                const faits = this._completions1076();\r\n                const cfg = this.state.etapesConfig;\r\n\r\n                \/\/ familles : nom des fonctions natives d'ouverture\/fermeture\r\n                const BANDEAUX = {\r\n                    associerPays:    ['openAssocierPays', 'closeAssocierPays'],\r\n                    associerSecteur: ['openAssocierSecteur', 'closeAssocierSecteur'],\r\n                    choixFormat:     ['openChoixFormat', 'closeChoixFormat']\r\n                };\r\n                const CHAMPS = ['processAnnonceur', 'processDatesDevise'];\r\n\r\n                \/\/ signature : sert au clic manuel et au seuil page web\r\n                const ordre = cfg.map(e => e.id).filter(id => faits.hasOwnProperty(id));\r\n                \/\/ pb1162 : propagation monotone assuree par _completions1076.\r\n                const sig = ordre.map(id => faits[id] ? 1 : 0).join('');\r\n                if (window._viaSigOuv1073 !== sig) {\r\n                    window._viaSigOuv1073 = sig;\r\n                    window._viaManuelProcess1073 = null;\r\n                }\r\n                \/\/ pb1129 : plus de distinction bandeau \/ champs \u2014 l'etape courante\r\n                \/\/   est la premiere non renseignee, et c'est la seule ouverte.\r\n                const toutFait = ordre.every(id => faits[id]);\r\n                \/\/ pb1131 : 'cible' etait declaree dans le bloc supprime par pb1129 \u2014\r\n                \/\/   d'ou l'erreur \"[pb1099] cible is not defined\" au chargement, qui\r\n                \/\/   interrompait tout le sequenceur avant la moindre fermeture.\r\n                \/\/   Elle est l'etape courante : la premiere non renseignee, ou le\r\n                \/\/   recapitulatif quand tout l'est. Une seule definition, ici, et la\r\n                \/\/   valeur publiee pour les veilles (pb1091, pb1130) en decoule.\r\n                \/* ============================================================\r\n                 * pb1586 : LA CIBLE NE SE RECALCULE PAS PENDANT LA FINALISATION.\r\n                 *   Log user, dans l'ordre :\r\n                 *     [pb1560] cible=references | faits=111111110000   <- juste\r\n                 *     Liseres enleves de toutes les commandes\r\n                 *     [pb1560] cible=processAnnonceur | faits=010000010000\r\n                 *     [pb915] processAnnonceur ouvert\r\n                 *     [pb1099] references -> ferme\r\n                 *   La finalisation deselectionne l'item ; _completions1076 lit l'item\r\n                 *   ACTIF, donc tout redevient \u00ab non fait \u00bb et la cible retombe sur la\r\n                 *   premiere etape amont. Le sequenceur ouvre alors l'annonceur et\r\n                 *   referme References \u2014 l'inverse de ce qui est attendu.\r\n                 *   pb1585 avait desarme la regle d'ouverture pb1565, mais ce n'etait\r\n                 *   pas elle qui ouvrait : c'est la CIBLE. Je corrigeais un symptome\r\n                 *   voisin du bon endroit.\r\n                 *   Une fois Finaliser clique, le parcours est descendant et pilote par\r\n                 *   les etapes aval : la cible ne doit plus etre deduite de completions\r\n                 *   devenues vides. On conserve donc la derniere cible connue.\r\n                 *   Revert : window._viaPb1586Off = true (recalcul permanent).\r\n                 * ============================================================ *\/\r\n                \/* pb1587 : GELER SUR LA PERTE DE L'ITEM, PAS SUR LA FINALISATION.\r\n                   Log user : \u00ab [pb1586] finalisation : cible gelee sur recapitulatif (le\r\n                   recalcul aurait donne references) \u00bb. Le gel a fige la valeur d'AVANT le\r\n                   clic et bloque celle d'apres \u2014 j'ai empeche le calcul juste pour\r\n                   conserver le perime.\r\n                   Au clic, les completions sont encore valides (faits=111111110000, cible\r\n                   = references) : il faut donc les laisser s'exprimer. Ce n'est qu'ENSUITE,\r\n                   quand la finalisation deselectionne l'item, qu'elles s'effondrent\r\n                   (faits=010000010000) et deviennent inexploitables.\r\n                   Le bon critere n'est donc pas \u00ab finalisation en cours \u00bb mais \u00ab plus\r\n                   d'item actif pour les calculer \u00bb. *\/\r\n                var _aval1586 = ['recapitulatif', 'references', 'paiement', 'validations', 'paiementFinal'];\r\n                var _sansItem1587 = !this.state.itemActif;\r\n                var _gele1586 = (window._viaPb1586Off === true)\r\n                    ? false\r\n                    : ((window._viaFinaliserClique === true ? _sansItem1587 : false)\r\n                        ? (_aval1586.indexOf(window._viaCibleProcess1091) !== -1)\r\n                        : false);\r\n                \/* ============================================================\r\n                 * pb1634 : LE GEL DOIT SE LEVER QUAND L'ETAPE EST FAITE.\r\n                 *   Log user : clic Valider sur References -> \u00ab griserEtape(references) \u00bb,\r\n                 *   \u00ab Etape grisee: references \u00bb, puis aussitot \u00ab [pb1099] references ->\r\n                 *   OUVERT \u00bb. L'etape se rouvre seule.\r\n                 *   Cause : pb1586 gele la cible sur 'references' pendant la finalisation\r\n                 *   (l'item est deselectionne, les completions deviennent inexploitables).\r\n                 *   Le sequenceur ouvre la cible \u2014 donc References, indefiniment, meme\r\n                 *   une fois validee.\r\n                 *   Un gel sans condition de sortie n'est pas un gel, c'est un blocage.\r\n                 *   On avance donc a l'etape aval suivante des que la cible gelee est\r\n                 *   faite. Le gel protege toujours des completions vides, mais il suit\r\n                 *   la progression.\r\n                 *   Consequence attendue : la cible passe a 'paiement', References se\r\n                 *   ferme, et l'exception de ouvrirEtapePaiement (lecture de .top sur un\r\n                 *   element absent) n'aura plus a etre traversee pour y parvenir.\r\n                 *   Revert : window._viaPb1634Off = true (gel fige, comme pb1586).\r\n                 * ============================================================ *\/\r\n                if (_gele1586 ? (window._viaPb1634Off !== true) : false) {\r\n                    var _cg1634 = window._viaCibleProcess1091;\r\n                    if (faits[_cg1634]) {\r\n                        var _suite1634 = _aval1586.slice(_aval1586.indexOf(_cg1634) + 1)\r\n                            .filter(function (_id) { return faits.hasOwnProperty(_id); })\r\n                            .find(function (_id) { return !faits[_id]; });\r\n                        if (_suite1634) {\r\n                            console.log('[pb1634] cible gelee ' + _cg1634\r\n                                + ' desormais faite -> avance a ' + _suite1634);\r\n                            window._viaCibleProcess1091 = _suite1634;\r\n                        } else {\r\n                            _gele1586 = false;\r\n                            console.log('[pb1634] toutes les etapes aval faites -> gel leve');\r\n                        }\r\n                    }\r\n                }\r\n                \/* ============================================================\r\n                 * pb2116 : PENDANT LA FINALISATION, LA CIBLE NE REMONTE JAMAIS EN AMONT.\r\n                 *   Constat user (multi-achat mobile, log 10:46) : item 2 encore\r\n                 *   \u00ab en_cours \u00bb avec format=\u00ab \u00e0 choisir \u00bb -> faits=111011110000 -> au\r\n                 *   clic Finaliser la cible recalculee retombe sur choixFormat (amont),\r\n                 *   le sequenceur rouvre annonceur+format ([pb1851] annonceur=OUVERT |\r\n                 *   format=OUVERT) par-dessus References qui venait de s'ouvrir : le\r\n                 *   process parait mort sur mobile.\r\n                 *   Le gel pb1586\/1587 ne couvrait que \u00ab plus d'item actif \u00bb ; le\r\n                 *   multi-achat cree le cas jumeau : item ACTIF mais INCOMPLET. Meme\r\n                 *   doctrine (pb1586 : \u00ab une fois Finaliser clique, le parcours est\r\n                 *   descendant \u00bb) : si le recalcul donne une etape amont pendant la\r\n                 *   finalisation, la cible est ramenee a la premiere etape AVAL non\r\n                 *   faite (references dans ce log). pb1634 continue de faire avancer.\r\n                 *   Revert : window._viaPb2116Off = true.\r\n                 * ============================================================ *\/\r\n                var _clamp2116 = null;\r\n                if (window._viaPb2116Off !== true ? (window._viaFinaliserClique === true ? !_gele1586 : false) : false) {\r\n                    var _rec2116 = toutFait ? 'recapitulatif' : (ordre.find(id => !faits[id]) || 'recapitulatif');\r\n                    if (_aval1586.indexOf(_rec2116) === -1) {\r\n                        _clamp2116 = _aval1586\r\n                            .filter(function (_id) { return faits.hasOwnProperty(_id); })\r\n                            .find(function (_id) { return !faits[_id]; }) || 'recapitulatif';\r\n                        if (window._viaSig2116 !== _clamp2116) {\r\n                            window._viaSig2116 = _clamp2116;\r\n                            console.log('[pb2116] finalisation : cible amont (' + _rec2116\r\n                                + ') ecartee -> ' + _clamp2116 + ' (item actif incomplet, parcours descendant)');\r\n                        }\r\n                    } else {\r\n                        window._viaSig2116 = '';\r\n                    }\r\n                }\r\n                \/\/ pb2130 : clamp commercial applique en DERNIER \u2014 quel que soit le\r\n                \/\/   chemin (gel 1586, clamp 2116, recalcul), la cible ne depasse\r\n                \/\/   jamais 'paiement' pour un commercial.\r\n                const cible = window._viaClampCommercial2130(_gele1586\r\n                    ? window._viaCibleProcess1091\r\n                    : (_clamp2116\r\n                        ? _clamp2116\r\n                        : (toutFait\r\n                            ? 'recapitulatif'\r\n                            : (ordre.find(id => !faits[id]) || 'recapitulatif'))));\r\n                if (_gele1586) {\r\n                    if (window._viaSig1586 !== cible) {\r\n                        window._viaSig1586 = cible;\r\n                        console.log('[pb1586] finalisation sans item actif : cible gelee sur ' + cible\r\n                            + ' (le recalcul aurait donne '\r\n                            + (toutFait ? 'recapitulatif' : (ordre.find(id => !faits[id]) || 'recapitulatif')) + ')');\r\n                    }\r\n                }\r\n                \/* ============================================================\r\n                 * pb1560 : TRACEUR \u2014 pourquoi la cible vaut 'recapitulatif'.\r\n                 *   Mesure user : window._viaCibleProcess1091 === 'recapitulatif'\r\n                 *   alors que l'annonceur n'est pas renseigne. C'est CETTE cible qui\r\n                 *   pilote _couleurEtapes1169 (active #fb5e2a \/ completee #7f7f7f \/\r\n                 *   a venir #525252) ET la taille via le delta pb1170 : le titre\r\n                 *   mesure 13.95px = 17 x 0.85 - 0.5, le delta \u00ab a venir \u00bb. Une seule\r\n                 *   cause pour les deux symptomes, et mes trois dernieres livraisons\r\n                 *   visaient des ecrivains situes en aval.\r\n                 *   Trois issues possibles, que ce releve separe :\r\n                 *     - ordre VIDE -> every() sur un tableau vide rend true, donc\r\n                 *       toutFait -> 'recapitulatif'. Cause : les cles de faits ne\r\n                 *       correspondent pas aux ids de etapesConfig.\r\n                 *     - toutFait VRAI a tort -> une entree de faits est mal calculee.\r\n                 *     - find() rend undefined malgre un false present -> impossible,\r\n                 *       mais le releve le montrerait.\r\n                 *   Dedupe par signature : la fonction est appelee tres souvent.\r\n                 *   A retirer une fois la cause identifiee.\r\n                 * ============================================================ *\/\r\n                try {\r\n                    var _sig1560 = cible + '|' + ordre.join(',') + '|'\r\n                        + ordre.map(function (id) { return faits[id] ? 1 : 0; }).join('');\r\n                    if (window._viaSig1560 !== _sig1560) {\r\n                        window._viaSig1560 = _sig1560;\r\n                        console.log('[pb1560] cible=' + cible + ' | toutFait=' + toutFait\r\n                            + ' | ordre(' + ordre.length + ')=' + (ordre.join('>') || '(VIDE)')\r\n                            + ' | faits=' + ordre.map(function (id) { return faits[id] ? 1 : 0; }).join('')\r\n                            + ' | cles de faits=' + Object.keys(faits).join(',')\r\n                            + ' | ids etapesConfig=' + cfg.map(function (e) { return e.id; }).join(','));\r\n                    }\r\n                } catch (_e1560) { console.warn('[pb1560] ' + _e1560.message); }\r\n                window._viaCibleProcess1091 = cible;\r\n\r\n                \/\/ pb1253 : le masquage de l'etape page web suit le meme cycle que la\r\n                \/\/   cible \u2014 meme fonction, meme rythme, aucun veilleur supplementaire.\r\n                try { this._masquePageWeb1253(); } catch (_eM1253) {}\r\n\r\n                \/\/ ================================================================\r\n                \/\/ pb1314 : FERMER LE CONTENU DE L'ETAPE PAGE WEB PENDANT UNE\r\n                \/\/   NOUVELLE SELECTION EXPRESS (demande user).\r\n                \/\/   pb1312 sort l'etape du sequenceur, mais le conteneur inline\r\n                \/\/   garde l'iframe de la reservation precedente : elle reste a\r\n                \/\/   l'ecran sous le catalogue.\r\n                \/\/   pb1309 avait tente ce masquage et casse la PREMIERE\r\n                \/\/   reservation, parce que son critere etait vrai avant tout\r\n                \/\/   Continuer. Le critere est donc STRICT ici : le drapeau doit\r\n                \/\/   valoir explicitement false, ce qui n'arrive qu'apres un\r\n                \/\/   premier Continuer suivi d'une modification (pb1064b). Avant le\r\n                \/\/   tout premier Continuer il vaut undefined, et rien n'est\r\n                \/\/   masque \u2014 l'erreur de pb1309 ne peut pas se reproduire.\r\n                \/\/   Au retour, la propriete est RETIREE : les writers d'origine\r\n                \/\/   reprennent la main, aucune valeur a restaurer.\r\n                \/\/   Revert : window._viaPb1314Off = true.\r\n                \/\/ ================================================================\r\n                if (window._viaPb1314Off !== true) {\r\n                    try {\r\n                        var _resel1314 = (window._viaExpressValide1313 === false);\r\n                        var _cw1314 = document.querySelector('.PageWebMobileConteneurClass');\r\n                        if (_cw1314) {\r\n                            var _cur1314 = _cw1314.style.getPropertyValue('display');\r\n                            \/\/ ====================================================\r\n                            \/\/ pb1317 : NE RENDRE QUE CE QUE L'ON A PRIS.\r\n                            \/\/   Constat user : en process classique mobile, le\r\n                            \/\/   contenu de l'etape page web ne se referme plus \u2014\r\n                            \/\/   ni au choix d'un espace, ni au clic Nouvelle resa.\r\n                            \/\/   Cause : la branche de restauration retirait le\r\n                            \/\/   display des que le conteneur etait ferme, a chaque\r\n                            \/\/   passe du sequenceur. Elle defaisait donc le travail\r\n                            \/\/   des fermetures legitimes, qui posent exactement ce\r\n                            \/\/   meme display:none.\r\n                            \/\/   On marque desormais ce que l'on masque, et on ne\r\n                            \/\/   restaure que cela. Un display pose par un autre\r\n                            \/\/   writer n'est plus touche.\r\n                            \/\/   Revert : window._viaPb1317Off = true.\r\n                            \/\/ ====================================================\r\n                            var _mien1317 = (_cw1314.getAttribute('data-via1314') === '1');\r\n                            if (_resel1314) {\r\n                                if (_cur1314 !== 'none') {\r\n                                    _cw1314.setAttribute('data-via1314', '1');\r\n                                    _cw1314.style.setProperty('display', 'none', 'important');\r\n                                    console.log('[pb1314] contenu page web ferm\u00e9 pendant la'\r\n                                        + ' nouvelle s\u00e9lection express');\r\n                                }\r\n                            } else if (window._viaPb1317Off === true\r\n                                ? (_cur1314 === 'none')\r\n                                : _mien1317) {\r\n                                _cw1314.removeAttribute('data-via1314');\r\n                                _cw1314.style.removeProperty('display');\r\n                                console.log('[pb1314] contenu page web rendu \u00e0 ses writers');\r\n                            }\r\n                        }\r\n                    } catch (_e1314) { console.warn('[pb1314]', _e1314.message); }\r\n                }\r\n\r\n                \/\/ pb1310 : pb1309 RETIRE (demande user). Masquer le conteneur de la\r\n                \/\/   page web empechait aussi son ouverture legitime sur la PREMIERE\r\n                \/\/   reservation : le critere \u00ab selection express non validee \u00bb est\r\n                \/\/   vrai avant tout Continuer, y compris la toute premiere fois.\r\n                \/\/   Le helper window._viaExpressEnAttente1309 reste en place cote\r\n                \/\/   yearbook-media : il sert toujours a _pretPageWeb1148 (pb1304).\r\n\r\n                \/\/ ================================================================\r\n                \/\/ pb1258 : LA NORMALISATION NE DOIT PLUS DEPENDRE D'UN CHEMIN.\r\n                \/\/   Constat user : pb1256 a bien agi \u2014 le HTML montre la zone\r\n                \/\/   Annonceur debarrassee de ses classes elementor-hidden et passee en\r\n                \/\/   display:block !important. La methode a donc tourne. Mais le\r\n                \/\/   recensement reste vide et aucune seconde ligne n'apparait : elle\r\n                \/\/   n'a tourne QU'UNE FOIS, au remplissage, quand la carte n'avait pas\r\n                \/\/   encore de mise en page.\r\n                \/\/   pb1257 avait branche un second appel sur ouvrirRecapitulatif. Il ne\r\n                \/\/   se declenche pas : le sequenceur n'appelle cette fonction que si le\r\n                \/\/   recapitulatif lui parait ferme, et il juge cet etat sur la\r\n                \/\/   visibilite de .VosCampagnesConteneurClass \u2014 deja affichee par un\r\n                \/\/   autre writer. Le rejeu de pb795 ne passe pas davantage : il\r\n                \/\/   retrouve les cartes par $('#' + item.id), et cette resolution\r\n                \/\/   n'aboutit pas ici.\r\n                \/\/   Deux hooks choisis, deux echecs : le probleme n'est pas le choix du\r\n                \/\/   hook, c'est d'en choisir un. On se branche donc sur le seul\r\n                \/\/   battement dont ce projet a la preuve qu'il tourne \u2014 celui du\r\n                \/\/   sequenceur, qui publie la cible et masque l'etape page web (pb1253)\r\n                \/\/   \u2014 et on parcourt le DOM, comme le fait deja la boucle de prefixes\r\n                \/\/   pb794, dont les libelles s'affichent correctement.\r\n                \/\/   Revert : window._viaPb1254Off = true.\r\n                \/\/ ================================================================\r\n                \/\/ ================================================================\r\n                \/\/ pb1283b : LE NETTOYAGE SORT DU BLOC pb1254.\r\n                \/\/   Constat user : pb1283 deploye, aucun effet, et aucune ligne\r\n                \/\/   [pb1283] dans le log.\r\n                \/\/   Deux raisons possibles, toutes deux corrigees ici :\r\n                \/\/     - il vivait sous le garde window._viaPb1254Off et dans le\r\n                \/\/       try\/catch MUET de pb1258 : desactive ou en erreur, il\r\n                \/\/       disparaissait sans un mot \u2014 le meme piege qu'en pb1265c ;\r\n                \/\/     - sa signature globale ne loguait qu'au premier changement\r\n                \/\/       d'etat, donc le silence ne prouvait rien.\r\n                \/\/   Il devient autonome, son catch parle, et chaque retrait est\r\n                \/\/   nomme. Le retrait ne depend d'aucun appariement carte->item :\r\n                \/\/   une passe balaie toutes les invites et ne laisse que celle de\r\n                \/\/   la carte active. Une invite orpheline disparait.\r\n                \/\/   Revert : window._viaPb1283Off = true.\r\n                \/\/ ================================================================\r\n                if (window._viaPb1283Off !== true) {\r\n                    try {\r\n                        var _act1283 = (this.state ? (this.state.itemActif || '') : '');\r\n                        \/\/ ================================================================\r\n                        \/\/ pb1489 : LE RETRAIT NE PEUT PAS DEPENDRE D'UN APPEL.\r\n                        \/\/   pb1488 retirait l'invite dans _inviteEspace1262. Or l'invite\r\n                        \/\/   est posee AVANT le depot de l'annonce, et rien ne garantit\r\n                        \/\/   que cette methode soit rappelee ensuite : elle reste donc\r\n                        \/\/   affichee, comme la capture le montre \u2014 alors meme que le\r\n                        \/\/   libelle \u00ab Espace publicitaire \u2026 a reserver \u00bb en rouge prouve\r\n                        \/\/   que le predicat pb1488 repond bien VRAI sur cet item.\r\n                        \/\/   Ce n'etait donc pas le predicat, c'etait le point d'accroche.\r\n                        \/\/   On se branche ici, sur le balayage pb1283, dont ce projet a\r\n                        \/\/   deja etabli qu'il tourne a chaque battement du sequenceur.\r\n                        \/\/   Meme raisonnement que pb1258 en son temps : ne pas choisir un\r\n                        \/\/   hook, se brancher sur le battement.\r\n                        \/\/   Revert : window._viaPb1489Off = true.\r\n                        \/\/ ================================================================\r\n                        var _dep1489 = false;\r\n                        if (window._viaPb1489Off === true) { _dep1489 = false; }\r\n                        else {\r\n                            if (_act1283) {\r\n                                var _its1489 = (this.state ? (this.state.items || []) : []);\r\n                                for (var _q1489 = 0; _q1489 < _its1489.length; _q1489++) {\r\n                                    if (_its1489[_q1489] ? (_its1489[_q1489].id === _act1283) : false) {\r\n                                        _dep1489 = this._annonceDeposee1488(_its1489[_q1489]);\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n                        var _inv1283 = document.querySelectorAll('.via-invite-haut-1262');\r\n                        for (var _n1283 = _inv1283.length - 1; _n1283 >= 0; _n1283--) {\r\n                            var _e1283 = _inv1283[_n1283];\r\n                            \/\/ ================================================\r\n                            \/\/ pb1283c : IDENTIFIER LA CARTE PAR SON ID, PAS PAR UNE\r\n                            \/\/   CLASSE. Constat user : l'invite ne s'affiche plus du\r\n                            \/\/   tout \u2014 donc elle etait retiree AUSSI de la carte\r\n                            \/\/   active. closest('.CampagneTemplateClass') ne remonte\r\n                            \/\/   pas jusqu'au noeud qui PORTE l'id de la resa : la\r\n                            \/\/   comparaison echouait toujours et tout etait balaye.\r\n                            \/\/   On pose la question directement : cette invite est-\r\n                            \/\/   elle dans la carte de la resa active ? contains()\r\n                            \/\/   repond sans supposer quoi que ce soit de la\r\n                            \/\/   structure.\r\n                            \/\/ ================================================\r\n                            var _carte1283 = _act1283\r\n                                ? document.getElementById(_act1283) : null;\r\n                            var _garder1283 = _carte1283\r\n                                ? _carte1283.contains(_e1283) : false;\r\n                            var _c1283 = _e1283.closest\r\n                                ? _e1283.closest('.CampagneTemplateClass') : null;\r\n                            var _id1283 = _c1283 ? (_c1283.id || '') : '';\r\n                            \/\/ pb1490 : la decision se prend PAR CARTE, plus seulement\r\n                            \/\/   sur l'item actif. _dep1489 dependait de\r\n                            \/\/   state.itemActif ; si l'appariement n'est pas encore\r\n                            \/\/   fait au moment du depot, il repond faux et l'invite\r\n                            \/\/   reste. On interroge donc la carte qui porte CETTE\r\n                            \/\/   invite : son item si on le retrouve, sinon son DOM.\r\n                            var _depC1490 = _dep1489;\r\n                            if (_depC1490 ? false : true) {\r\n                                var _cc1490 = _e1283.closest\r\n                                    ? _e1283.closest('.CampagneTemplateClass') : null;\r\n                                if (!_cc1490) {\r\n                                    var _m1490 = _e1283.parentElement;\r\n                                    var _g1490 = 0;\r\n                                    while (_m1490 ? (_m1490.id ? false : (_g1490 < 8)) : false) {\r\n                                        _m1490 = _m1490.parentElement; _g1490++;\r\n                                    }\r\n                                    _cc1490 = _m1490;\r\n                                }\r\n                                if (_cc1490) {\r\n                                    var _idc1490 = _cc1490.id || '';\r\n                                    if (_idc1490) {\r\n                                        var _itc1490 = (this.state ? (this.state.items || []) : []);\r\n                                        for (var _r1490 = 0; _r1490 < _itc1490.length; _r1490++) {\r\n                                            if (_itc1490[_r1490] ? (_itc1490[_r1490].id === _idc1490) : false) {\r\n                                                if (this._annonceDeposee1488(_itc1490[_r1490], _cc1490)) { _depC1490 = true; }\r\n                                            }\r\n                                        }\r\n                                    }\r\n                                    if (_depC1490 ? false : true) {\r\n                                        \/\/ pb1491 : meme sans item apparie, la carte suffit\r\n                                        if (this._annonceDeposee1488(null, _cc1490)) { _depC1490 = true; }\r\n                                    }\r\n                                }\r\n                            }\r\n                            if (_depC1490) {\r\n                                if (_e1283.parentNode) { _e1283.parentNode.removeChild(_e1283); }\r\n                                if (window._viaVu1489 !== _act1283) {\r\n                                    window._viaVu1489 = _act1283;\r\n                                    console.log('[pb1490] invite retir\u00e9e (annonce d\u00e9pos\u00e9e) | resa = '\r\n                                        + (_act1283 || '(aucune)')\r\n                                        + ' | source = ' + (_dep1489 ? 'etat item' : 'carte (DOM)'));\r\n                                }\r\n                                continue;\r\n                            }\r\n                            if (_garder1283) { continue; }\r\n                            if (_e1283.parentNode) { _e1283.parentNode.removeChild(_e1283); }\r\n                            console.log('[pb1283] invite retir\u00e9e de '\r\n                                + (_id1283 || '(carte inconnue)')\r\n                                + ' | active = ' + (_act1283 || '(aucune)'));\r\n                        }\r\n                    } catch (_e1283b) { console.warn('[pb1283]', _e1283b.message); }\r\n                }\r\n\r\n                if (window._viaPb1254Off !== true) {\r\n                    try {\r\n                        var _self1258 = this;\r\n                        var _its1258 = (this.state ? (this.state.items || []) : []);\r\n                        $('.CampagneTemplateClass').each(function () {\r\n                            var $c1258 = $(this);\r\n                            if ($c1258.attr('id') === 'CampagneTemplate') { return; }\r\n                            var _id1258 = $c1258.attr('id') || '';\r\n                            var _it1258 = null;\r\n                            for (var _k1258 = 0; _k1258 < _its1258.length; _k1258++) {\r\n                                if (_its1258[_k1258] ? (_its1258[_k1258].id === _id1258) : false) {\r\n                                    _it1258 = _its1258[_k1258];\r\n                                    break;\r\n                                }\r\n                            }\r\n                            \/\/ repli : une seule reservation, une seule carte \u2014 pas\r\n                            \/\/   d'ambiguite possible sur l'appariement.\r\n                            if (!_it1258 ? (_its1258.length === 1) : false) { _it1258 = _its1258[0]; }\r\n                            if (!_it1258) { return; }\r\n                            _self1258._normaliserCarte1254($c1258, _it1258);\r\n                            \/\/ pb1262 : meme battement, meme parcours \u2014 l'invite de tete\r\n                            \/\/   suit exactement le meme chemin que la mise en page.\r\n                            \/\/ pb1492 : CE CATCH ETAIT MUET. C'est le seul appel de\r\n                            \/\/   _inviteEspace1262 qui tourne a chaque battement ; une\r\n                            \/\/   erreur dedans faisait echouer la garde pb1491 sans un\r\n                            \/\/   mot, et l'invite restait. \u00ab Tout catch doit loguer \u00bb.\r\n                            try {\r\n                                _self1258._inviteEspace1262($c1258, _it1258);\r\n                            } catch (_eI1262) {\r\n                                console.warn('[pb1492] _inviteEspace1262 a echoue : ' + _eI1262.message);\r\n                            }\r\n                        });\r\n                    } catch (_e1258) { console.warn('[pb1258]', _e1258.message); }\r\n                }\r\n\r\n                cfg.forEach(e => {\r\n                    if (!faits.hasOwnProperty(e.id)) { return; }   \/\/ pb1158 : toutes suivies\r\n\r\n                    \/\/ ============================================================\r\n                    \/\/ pb1129 : UNE SEULE ETAPE OUVERTE \u2014 la premiere non renseignee\r\n                    \/\/   (demande user, remplace pb1097, pb1109 et pb1125).\r\n                    \/\/   Regle finale, en une phrase : au chargement seule l'etape\r\n                    \/\/   Annonceur est ouverte ; des qu'une etape est renseignee elle\r\n                    \/\/   se ferme et la suivante s'ouvre. Bandeaux et etapes a champs\r\n                    \/\/   suivent la MEME regle \u2014 la distinction introduite en pb1099\r\n                    \/\/   n'a plus lieu d'etre.\r\n                    \/\/   Les trois regles precedentes cherchaient a garder ouvertes les\r\n                    \/\/   etapes non renseignees ; a l'usage cela produisait des\r\n                    \/\/   ouvertures multiples et du clignotement. L'enchainement strict\r\n                    \/\/   est plus lisible et plus stable.\r\n                    \/\/   Seules exceptions conservees : le clic manuel prime (option B),\r\n                    \/\/   et le recapitulatif s'ouvre quand tout est renseigne \u2014 ce qui\r\n                    \/\/   est le meme critere, puisqu'il est alors l'etape courante.\r\n                    \/\/   Revert : window._viaPb1129Off = true (regles pb1109\/pb1125).\r\n                    \/\/ ============================================================\r\n                    \/\/ ============================================================\r\n                    \/\/ pb1154 : en MODE 1 COLONNE, les trois BANDEAUX restent ouverts\r\n                    \/\/   tant qu'ils ne sont pas renseignes (demande user, mobile ET\r\n                    \/\/   desktop).\r\n                    \/\/   pb1129 n'ouvrait que l'etape courante \u2014 regle simple mais qui\r\n                    \/\/   oblige l'utilisateur a attendre son tour pour voir les\r\n                    \/\/   vignettes pays, secteurs et formats. En 1 colonne, le process\r\n                    \/\/   est seul a l'ecran : les afficher ensemble donne la vue\r\n                    \/\/   d'ensemble.\r\n                    \/\/   En 3 colonnes, la place est comptee (page web + recap) : la\r\n                    \/\/   regle d'origine s'applique, une seule etape ouverte.\r\n                    \/\/   Les etapes a CHAMPS (annonceur, dates) gardent l'enchainement\r\n                    \/\/   strict dans les deux modes : elles clignotaient sinon (pb1125).\r\n                    \/\/   Revert : window._viaPb1154Off = true.\r\n                    \/\/ ============================================================\r\n                    \/\/ ============================================================\r\n                    \/\/ pb1196 : le mode colonnes se MESURE, il ne se lit pas dans\r\n                    \/\/   sessionStorage. (Reapplique : ce bloc avait ete emporte lors\r\n                    \/\/   du revert de pb1214\/pb1215.)\r\n                    \/\/   Constat user : les bandeaux pays \/ secteur \/ format ne\r\n                    \/\/   s'ouvraient plus, alors qu'en 1 colonne ils doivent rester\r\n                    \/\/   ouverts tant qu'ils ne sont pas renseignes (pb1154).\r\n                    \/\/   Cause : PageWebColonneOpenclose gardait 'Open' d'une session\r\n                    \/\/   precedente \u2014 sessionStorage survit au rechargement. Le code se\r\n                    \/\/   croyait en 3 colonnes alors que l'ecran n'en montrait qu'une.\r\n                    \/\/   On regarde desormais si la colonne centrale est REELLEMENT\r\n                    \/\/   affichee : l'etat visible ne peut pas etre en retard sur\r\n                    \/\/   lui-meme, contrairement a une cle memorisee.\r\n                    \/\/   Revert : window._viaPb1196Off = true (lecture sessionStorage).\r\n                    \/\/ ============================================================\r\n                    var _uneCol1154 = false;\r\n                    if (window._viaPb1154Off !== true) {\r\n                        try {\r\n                            if (window._viaPb1196Off === true) {\r\n                                _uneCol1154 = (sessionStorage.getItem('PageWebColonneOpenclose') !== 'Open');\r\n                            } else {\r\n                                var _cc1196 = document.getElementById('ColonneCentre');\r\n                                _uneCol1154 = _cc1196\r\n                                    ? (window.getComputedStyle(_cc1196).display === 'none')\r\n                                    : true;\r\n                            }\r\n                        } catch (_e1154) { _uneCol1154 = false; }\r\n                    }\r\n                    let ouvrir;\r\n                    \/\/ pb1271 : le RECAPITULATIF reste ouvert apres l'ajout d'une\r\n                    \/\/   reservation (demande user). Exception assumee a la regle\r\n                    \/\/   pb1129 \u00ab une seule etape ouverte \u00bb : la carte qui vient\r\n                    \/\/   d'etre creee doit rester visible pendant qu'on recommence\r\n                    \/\/   la selection. Le drapeau est pose par pb1271 cote\r\n                    \/\/   yearbook-media.js, au clic sur Ajouter une reservation.\r\n                    \/\/   Revert : window._viaRecapOuvert1271 = false.\r\n                    if (window._viaManuelProcess1073 === e.id) { ouvrir = true; }\r\n                    else if (e.id === 'recapitulatif'\r\n                        ? (window._viaRecapOuvert1271 === true) : false) { ouvrir = true; }\r\n                    \/\/ ============================================================\r\n                    \/\/ pb1334 : LA REGLE DE pb1154 VAUT POUR TOUS LES LAYOUTS.\r\n                    \/\/   Demande user : ne refermer un bandeau que s'il est renseigne,\r\n                    \/\/   chacun independamment des deux autres.\r\n                    \/\/   Constat : en saisissant les dates avant le site\/pays, le\r\n                    \/\/   secteur ou le format, les trois bandeaux se referment. Le\r\n                    \/\/   traceur pb1333 a nomme l'appelant :\r\n                    \/\/     [pb1333] closeAssocierPays sur un bandeau VIDE (pays)\r\n                    \/\/              | par ... <- at (index):28154 <- at Array.forEach\r\n                    \/\/   soit cette boucle. pb1154 posait deja exactement la bonne\r\n                    \/\/   regle \u2014 \u00ab ouvrir = pas encore fait \u00bb \u2014 mais UNIQUEMENT en mode\r\n                    \/\/   1 colonne. Partout ailleurs on retombait sur la regle pb1129\r\n                    \/\/   \u00ab une seule etape ouverte, la cible \u00bb : les deux autres\r\n                    \/\/   bandeaux se fermaient sans qu'on regarde s'ils etaient remplis.\r\n                    \/\/   Un bandeau ferme veut dire \u00ab c'est fait \u00bb ; le fermer sur du\r\n                    \/\/   vide dit le contraire de la verite et retire a l'utilisateur\r\n                    \/\/   l'acces a ce qu'il n'a pas encore choisi.\r\n                    \/\/   Les etapes CHAMPS (annonceur, dates) et toutes les autres\r\n                    \/\/   gardent la regle de la cible : seuls les bandeaux changent.\r\n                    \/\/   Revert : window._viaPb1334Off = true (regle restreinte a la\r\n                    \/\/   1 colonne, comportement pb1154 d'origine).\r\n                    \/\/ ============================================================\r\n                    else if (BANDEAUX[e.id]) {\r\n                        if (window._viaPb1334Off === true) {\r\n                            ouvrir = _uneCol1154 ? !faits[e.id] : (e.id === cible);\r\n                        } else {\r\n                            \/\/ pb1335 : etat REEL du bandeau \u2014 voir _bandeauFait1335.\r\n                            const _reel1335 = this._bandeauFait1335(e.id, faits);\r\n                            if (_reel1335 !== !!faits[e.id]) {\r\n                                const _sg1335 = e.id + ':' + (_reel1335 ? 1 : 0)\r\n                                    + (faits[e.id] ? 1 : 0);\r\n                                if (window._viaSig1335 !== _sg1335) {\r\n                                    window._viaSig1335 = _sg1335;\r\n                                    console.log('[pb1335] ' + e.id + ' : r\u00e9el='\r\n                                        + (_reel1335 ? 'renseign\u00e9' : 'VIDE')\r\n                                        + ' | compl\u00e9tions=' + (faits[e.id] ? 'fait' : 'non fait')\r\n                                        + ' (monotonie pb1162) -> on suit le r\u00e9el');\r\n                                }\r\n                            }\r\n                            ouvrir = !_reel1335;\r\n                        }\r\n                    }\r\n                    \/\/ pb2136 : pb2134 RETIRE (JF : sans interet). La boucle reprend\r\n                    \/\/   la regle commune ; pb2132 suffit a refermer l'etape.\r\n                    else { ouvrir = (e.id === cible); }\r\n\r\n                    \/\/ pb1252 : pb1243, pb1243b, pb1245 et pb1250 RETIRES (demande\r\n                    \/\/   user). Le recapitulatif suit de nouveau la regle commune : il\r\n                    \/\/   ne s'ouvre que lorsqu'il devient l'etape courante, c'est-a-dire\r\n                    \/\/   quand tout est renseigne.\r\n\r\n                    \/\/ ============================================================\r\n                    \/\/ pb1134 : le titre du RECAPITULATIF reste GRIS tant qu'il n'est\r\n                    \/\/   pas l'etape courante (reprise de pb1121, perdu dans la\r\n                    \/\/   reecriture pb1129).\r\n                    \/\/   Constat user : en mode 3 colonnes le recapitulatif redevient\r\n                    \/\/   actif \u2014 le correctif de ce matin avait disparu avec le bloc\r\n                    \/\/   que pb1129 a remplace. J'aurais du verifier ce que ce bloc\r\n                    \/\/   contenait avant de le supprimer.\r\n                    \/\/   Le gris signifie ici \"pas encore\", la ou il signifie \"deja\r\n                    \/\/   fait\" pour les autres etapes \u2014 dans les deux cas, \"ce n'est\r\n                    \/\/   pas la que ca se passe\".\r\n                    \/\/   pb1122 revient avec lui : le message \"Une ou plusieurs\r\n                    \/\/   reservations sont validees\" annonce un resultat que\r\n                    \/\/   l'utilisateur n'a pas encore obtenu.\r\n                    \/\/   Revert : window._viaPb1134Off = true.\r\n                    \/\/ ============================================================\r\n                    if (e.id === 'recapitulatif' ? (window._viaPb1134Off !== true) : false) {\r\n                        \/\/ pb1161b : le recapitulatif se grise quand il est FAIT (comme\r\n                        \/\/   toute etape franchie) et reste gris tant qu'il n'est pas\r\n                        \/\/   atteint. Il n'est d\u00e9gris\u00e9 que lorsqu'il est l'etape courante.\r\n                        \/\/   Sans cette nuance, une fois le Finaliser fait, il restait\r\n                        \/\/   d\u00e9gris\u00e9 \u2014 donc visuellement au meme niveau que References,\r\n                        \/\/   qui est pourtant la nouvelle etape active.\r\n                        \/\/ ============================================================\r\n                        \/\/ pb1192 : le recapitulatif NE SE GRISE PLUS quand il n'est pas\r\n                        \/\/   atteint.\r\n                        \/\/   Constat user (capture) : l'etape Recapitulatif s'affiche\r\n                        \/\/   comme une etape COMPLETEE alors qu'elle ne l'est pas.\r\n                        \/\/   Cause : pb1134 posait via-etape-grisee pour signifier \"pas\r\n                        \/\/   encore atteinte\". Or depuis pb1171, cette classe signifie\r\n                        \/\/   \"completee\" \u2014 elle porte la couleur #7f7f7f et, depuis\r\n                        \/\/   pb1180, le -1px. Deux sens opposes pour le meme marqueur :\r\n                        \/\/   le second l'emporte a l'ecran.\r\n                        \/\/   La distinction est desormais faite par _couleurEtapes1169,\r\n                        \/\/   qui lit les completions reelles et applique #525252 aux\r\n                        \/\/   etapes a venir. Le grisage n'a plus lieu d'etre ici.\r\n                        \/\/   On ne conserve que le DEgrisage : si le recapitulatif porte\r\n                        \/\/   encore la classe d'un etat anterieur alors qu'il devient\r\n                        \/\/   l'etape courante, il faut la lui retirer.\r\n                        \/\/   Revert : window._viaPb1134Off = true.\r\n                        \/\/ ============================================================\r\n                        var _actifRec = (cible === 'recapitulatif');\r\n                        var _grisRec = $(e.titre).hasClass('via-etape-grisee');\r\n                        if (_actifRec ? _grisRec : false) { this.degriserEtape(e.id); }\r\n                        if (!_actifRec ? (_grisRec ? !faits.recapitulatif : false) : false) {\r\n                            this.degriserEtape(e.id);\r\n                        }\r\n                        \/\/ pb1161 : la phrase verte du recapitulatif reste affichee une\r\n                        \/\/   fois l'etape FAITE, comme les phrases des autres etapes.\r\n                        \/\/   pb1122 la masquait des que le recapitulatif n'etait plus\r\n                        \/\/   l'etape courante \u2014 donc juste apres le Finaliser, au moment\r\n                        \/\/   ou elle devient justement pertinente : \"Une ou plusieurs\r\n                        \/\/   reservations sont validees\" enonce un fait acquis.\r\n                        \/\/   Elle reste donc masquee tant que l'etape n'est pas atteinte,\r\n                        \/\/   et visible des qu'elle est active OU faite.\r\n                        \/\/ pb1255 : la branche ACTIVE exige desormais qu'une reservation\r\n                        \/\/   existe reellement. La branche FAITE est inchangee :\r\n                        \/\/   faits.recapitulatif suppose deja le Finaliser.\r\n                        var _msgRec = document.getElementById('RecapitulatifMessageContainer');\r\n                        if (_msgRec) {\r\n                            \/* pb1991 : critere unique. L'ancien booleen est passe\r\n                               tel quel pour que le revert soit exact. *\/\r\n                            var _voirMsg1161 = this._msgRecapVisible1991(_actifRec\r\n                                ? this._resaValidee1255()\r\n                                : !!faits.recapitulatif);\r\n                            _msgRec.style.setProperty('display', _voirMsg1161 ? 'block' : 'none', 'important');\r\n                        }\r\n                    }\r\n\r\n                    \/\/ ================================================================\r\n                    \/\/ pb1132 : pour les BANDEAUX, mesurer l'etat sur le BANDEAU.\r\n                    \/\/   Constat user : les bandeaux restent ouverts, et le log ne\r\n                    \/\/   montre aucun \"[pb1099] associerPays -> ferme\" \u2014 le\r\n                    \/\/   court-circuit ci-dessous sort avant.\r\n                    \/\/   Cause : l'etat etait lu sur le CHEVRON (iconeUp). Or au\r\n                    \/\/   chargement le chevron peut etre masque alors que le bandeau est\r\n                    \/\/   deploye : on lisait donc \"ferme\", ce qui correspondait a l'etat\r\n                    \/\/   voulu, et la fonction sortait sans rien faire.\r\n                    \/\/   C'est le meme piege qu'en pb1087, que la reecriture pb1099 avait\r\n                    \/\/   efface : mesurer autre chose que ce qu'on pilote.\r\n                    \/\/   open\/closeAssocierPays & co agissent sur .AssocierPaysClass,\r\n                    \/\/   .AssocierSecteurClass et .ChoixFormatClass : on lit donc l'etat\r\n                    \/\/   sur ces memes elements. Pour les autres etapes, le chevron reste\r\n                    \/\/   le bon indicateur.\r\n                    \/\/   Revert : window._viaPb1132Off = true.\r\n                    \/\/ ================================================================\r\n                    const CLASSES1132 = {\r\n                        associerPays: '.AssocierPaysClass',\r\n                        associerSecteur: '.AssocierSecteurClass',\r\n                        choixFormat: '.ChoixFormatClass'\r\n                    };\r\n                    let estOuvert;\r\n                    if (CLASSES1132[e.id] ? (window._viaPb1132Off !== true) : false) {\r\n                        const b1132 = $(CLASSES1132[e.id])[0] || null;\r\n                        estOuvert = b1132 ? (b1132.offsetParent !== null) : false;\r\n                    } else {\r\n                        const up = $(e.iconeUp)[0] || null;\r\n                        estOuvert = up ? (up.offsetParent !== null) : $(e.conteneur).is(':visible');\r\n                    }\r\n                    \/* ============================================================\r\n                     * pb1722 : LE RECAPITULATIF RESTE FERME APRES FINALISATION.\r\n                     *   pb1720 corrigeait fermerRecapitulatif ; le log user n en\r\n                     *   montre aucune trace : dans ce parcours, c est CE\r\n                     *   sequenceur qui decide, et lui seul \u2014 [pb1099] apparait,\r\n                     *   [pb1720] non.\r\n                     *   (J avais d abord pose la regle dans _ETAPES915 de\r\n                     *   yearbook-media.js ; ce tableau ne contient que\r\n                     *   processAnnonceur et processDatesDevise, la regle y etait\r\n                     *   morte. Retiree.)\r\n                     *   Ici la variable ouvrir commande tout : quand elle est\r\n                     *   fausse, la branche pb1105 appelle fermerRecapitulatif(),\r\n                     *   que pb1720 laisse desormais aboutir. Les deux marqueurs se\r\n                     *   completent : l un ouvre le chemin, l autre l emprunte.\r\n                     *   Le clic de l utilisateur reste souverain :\r\n                     *   _viaManuelProcess1073 et _viaRecapOuvert1271 sont evalues\r\n                     *   avant et forcent ouvrir a true \u2014 masque PAR DEFAUT, pas\r\n                     *   verrouille.\r\n                     *   L etat est lu sur FinaliserStep, pose en session au clic :\r\n                     *   il survit au rechargement, contrairement au drapeau memoire.\r\n                     *   Revert : window._viaPb1722Off = true.\r\n                     * ============================================================ *\/\r\n                    if (e.id === 'recapitulatif' ? (window._viaPb1722Off !== true) : false) {\r\n                        \/* ============================================================\r\n                         * pb1723 : _viaRecapOuvert1271 N EST PAS UN CLIC.\r\n                         *   Log user : [pb1720] ferme le recapitulatif, puis\r\n                         *   [pb1099] recapitulatif -> OUVERT le rouvre \u2014 et aucun\r\n                         *   [pb1722]. Ma garde ne s est donc pas declenchee.\r\n                         *   Cause : je comptais _viaRecapOuvert1271 comme un signal\r\n                         *   manuel. Ce n en est pas un \u2014 pb1271 le pose au clic sur\r\n                         *   \u00ab Ajouter une reservation \u00bb pour garder la carte visible\r\n                         *   pendant la selection suivante, et il n est jamais efface.\r\n                         *   Un drapeau pose une fois et jamais rendu : encore un gel\r\n                         *   sans condition de sortie, et cette fois c est moi qui l ai\r\n                         *   pris pour argent comptant.\r\n                         *   Seul _viaManuelProcess1073 designe une action de\r\n                         *   l utilisateur sur ce titre. Et on donne a pb1271 la fin\r\n                         *   qui lui manquait : son exception s arrete a la\r\n                         *   finalisation, ou il n y a plus de selection suivante.\r\n                         * ============================================================ *\/\r\n                        var _man1722 = (window._viaManuelProcess1073 === e.id);\r\n                        var _fin1722 = (window._viaFinaliserClique === true);\r\n                        if (!_fin1722) {\r\n                            try { _fin1722 = (sessionStorage.getItem('FinaliserStep') === 'Yes'); }\r\n                            catch (_e1722) { _fin1722 = false; }\r\n                        }\r\n                        if (_fin1722 ? !_man1722 : false) {\r\n                            \/* pb1723 : l exception pb1271 prend fin ici *\/\r\n                            if (window._viaRecapOuvert1271 === true) {\r\n                                window._viaRecapOuvert1271 = false;\r\n                                console.log('[pb1723] _viaRecapOuvert1271 rendu a false'\r\n                                    + ' (finalisation : plus de selection suivante)');\r\n                            }\r\n                            if (ouvrir) {\r\n                                if (window._viaSig1722 !== '1') {\r\n                                    window._viaSig1722 = '1';\r\n                                    console.log('[pb1722] commande finalisee -> recapitulatif garde ferme'\r\n                                        + ' (ouverture automatique refusee, clic toujours possible)');\r\n                                }\r\n                            }\r\n                            ouvrir = false;\r\n                        }\r\n                    }\r\n                    if (estOuvert === ouvrir) { return; }\r\n\r\n                    if (BANDEAUX[e.id]) {\r\n                        const fn = window[BANDEAUX[e.id][ouvrir ? 0 : 1]];\r\n                        if (typeof fn === 'function') { fn(); }\r\n                    } else if (CHAMPS.indexOf(e.id) !== -1) {\r\n                        \/* ============================================================\r\n                         * pb1865 : NE PAS FERMER UNE ETAPE QUE pb1565 VA ROUVRIR.\r\n                         *   Constat JF : l etape Dates s ouvre et se referme a la saisie\r\n                         *   de l annonceur. pb1862 puis pb1864 ont tente d absorber le\r\n                         *   clignotement par un delai de grace, porte de 450 a 1200 puis\r\n                         *   3000 ms. Les mesures ont REFUTE cette approche : la derniere\r\n                         *   trace donne \u00ab rouverte 2ms apres fermeture \u00bb. Deux millisecondes\r\n                         *   ne sont pas un rebond que l on amortit, c est une reponse\r\n                         *   immediate \u2014 aucun delai n aurait jamais converge. L anti-rebond\r\n                         *   est retire de yearbook-media.js par le meme pb1865.\r\n                         *\r\n                         *   LA VRAIE CAUSE : DEUX DECIDEURS POUR UN MEME EXECUTEUR.\r\n                         *   Ce sequenceur-ci decide et appelle _viaFermerEtape915 ; la boucle\r\n                         *   _forcerOuvert917 de yearbook-media.js decide de son cote et\r\n                         *   appelle _viaOuvrirEtape915. Le log les distingue : \u00ab [pb1099] X\r\n                         *   -> ferme \u00bb porte les deux lignes, la reouverture n a que\r\n                         *   \u00ab [pb915] X ouvert \u00bb \u2014 elle vient donc de l autre decideur.\r\n                         *   Celui-ci applique pb1565 : \u00ab toute etape NON RENSEIGNEE reste\r\n                         *   ouverte \u00bb. Ce sequenceur-ci ignorait cette regle et fermait\r\n                         *   quand meme. Chacun repassant en boucle, ils se repondaient\r\n                         *   indefiniment \u2014 le commentaire de pb1419 decrit deja ce piege.\r\n                         *\r\n                         *   On applique donc ICI la meme regle, avec la meme source\r\n                         *   (_completions1076). Les deux decideurs cessent de se contredire\r\n                         *   au lieu d etre departages par un chronometre.\r\n                         *   L OUVERTURE n est pas touchee : seule la fermeture est refusee.\r\n                         *   Le clic manuel sur le chevron passe par un autre chemin\r\n                         *   (_ETAPES915 titre, yearbook-media.js) et reste libre.\r\n                         *   Revert : window._viaPb1865Off = true.\r\n                         * ============================================================ *\/\r\n                        let _bloque1865 = false;\r\n                        if (window._viaPb1865Off !== true) {\r\n                            if (!ouvrir) {\r\n                                try {\r\n                                    const _f1865 = (typeof this._completions1076 === 'function')\r\n                                        ? this._completions1076() : null;\r\n                                    if (_f1865 ? _f1865.hasOwnProperty(e.id) : false) {\r\n                                        if (!_f1865[e.id]) {\r\n                                            _bloque1865 = true;\r\n                                            if (window._viaSig1865 !== e.id) {\r\n                                                window._viaSig1865 = e.id;\r\n                                                console.log('[pb1865] fermeture de ' + e.id + ' REFUSEE :'\r\n                                                    + ' etape non renseignee, pb1565 la rouvrirait aussitot');\r\n                                            }\r\n                                        }\r\n                                    }\r\n                                } catch (_e1865) { console.warn('[pb1865] ' + _e1865.message); }\r\n                            }\r\n                        }\r\n                        if (!_bloque1865) {\r\n                            const fn915 = ouvrir ? window._viaOuvrirEtape915 : window._viaFermerEtape915;\r\n                            if (typeof fn915 === 'function') { fn915(e.id); }\r\n                        }\r\n                    } else if (e.id === 'recapitulatif') {\r\n                        \/\/ pb1105 : le recapitulatif a ses propres fonctions, qui tiennent\r\n                        \/\/   le drapeau interne 'recapOuvert'. Le masquer par show\/hide\r\n                        \/\/   laissait ce drapeau a 'true' alors que le bloc etait ferme :\r\n                        \/\/   le 1er clic sur le titre appelait donc fermerRecapitulatif()\r\n                        \/\/   \u2014 sans effet visible \u2014 et il fallait cliquer une 2e fois.\r\n                        \/\/   Meme principe que pour les bandeaux et les etapes 915 :\r\n                        \/\/   piloter par la fonction qui detient l'etat.\r\n                        if (ouvrir) { this.ouvrirRecapitulatif(); }\r\n                        else { this.fermerRecapitulatif(); }\r\n                    } else if (['pageWebMobile', 'references', 'paiement', 'validations',\r\n                                'paiementFinal'].indexOf(e.id) !== -1\r\n                               ? (window.outerWidth < 1000) : false) {\r\n                        \/\/ pb1158b : sur mobile, ces etapes sont masquees au depart\r\n                        \/\/   (pb1145b\/pb1146). Le sequenceur les REVELE une par une\r\n                        \/\/   quand elles deviennent courantes, et les remasque ensuite\r\n                        \/\/   \u2014 demande user. Meme mecanique que pb1147, etendue aux\r\n                        \/\/   quatre etapes aval.\r\n                        \/\/ ============================================================\r\n                        \/\/ pb1147 : MOBILE \u2014 l'etape page web est masquee au depart\r\n                        \/\/   (pb1145b\/pb1146) ; le sequenceur la REVELE quand elle\r\n                        \/\/   devient l'etape courante, et la remasque ensuite.\r\n                        \/\/   Sans cela elle resterait invisible tout le parcours :\r\n                        \/\/   masquer par defaut n'a de sens que si quelqu'un se charge\r\n                        \/\/   de l'afficher au bon moment. C'est le role du sequenceur,\r\n                        \/\/   deja seul juge de l'etape courante.\r\n                        \/\/   On pilote le WRAPPER (#PageWebMobileEtape) en plus des\r\n                        \/\/   chevrons : c'est lui que pb1146 masque.\r\n                        \/\/   Revert : window._viaPb1147Off = true.\r\n                        \/\/ ============================================================\r\n                        \/\/ ============================================================\r\n                        \/\/ pb1160 : une etape DEJA FAITE reste VISIBLE (grisee, fermee).\r\n                        \/\/   Constat user : une fois l'espace reserve, l'etape\r\n                        \/\/   \"choisir les espaces publicitaires\" disparait au lieu de\r\n                        \/\/   rester affichee en gris comme les etapes amont.\r\n                        \/\/   pb1147 masquait des qu'elle n'etait plus courante \u2014 sans\r\n                        \/\/   distinguer \"pas encore atteinte\" de \"deja franchie\". Or le\r\n                        \/\/   masquage ne vaut que pour la premiere : une etape franchie\r\n                        \/\/   doit rester lisible, avec son titre gris et sa phrase verte,\r\n                        \/\/   comme sur desktop.\r\n                        \/\/   Le WRAPPER est donc visible si l'etape est ouverte OU faite ;\r\n                        \/\/   seuls le contenu et les chevrons suivent l'ouverture.\r\n                        \/\/   Revert : window._viaPb1160Off = true.\r\n                        \/\/ ============================================================\r\n                        if (window._viaPb1147Off !== true) {\r\n                            \/\/ ============================================================\r\n                            \/\/ pb1181 : les etapes APRES la page web restent masquees tant\r\n                            \/\/   qu'aucun espace n'est reserve (demande user).\r\n                            \/\/   Constat : quand l'etape \"choisir les espaces\" s'ouvre,\r\n                            \/\/   references \/ paiement \/ validations apparaissent aussi.\r\n                            \/\/   Cause : pb1160 rend visible toute etape \"ouverte OU\r\n                            \/\/   faite\", et pb1159 propage les completions vers l'amont \u2014\r\n                            \/\/   ce qui suffisait a les faire passer pour faites.\r\n                            \/\/   Regle : une etape aval n'apparait que si l'espace\r\n                            \/\/   publicitaire est reserve, c'est-a-dire si pageWebMobile\r\n                            \/\/   est completee. Avant cela, seule l'etape page web est\r\n                            \/\/   visible parmi les cinq.\r\n                            \/\/   Revert : window._viaPb1181Off = true.\r\n                            \/\/ ============================================================\r\n                            var _visible1160 = (window._viaPb1160Off === true)\r\n                                ? ouvrir\r\n                                : (ouvrir ? true : !!faits[e.id]);\r\n                            \/\/ ============================================================\r\n                            \/\/ pb1182 : MOBILE \u2014 tout ou rien apres l'espace publicitaire.\r\n                            \/\/   Constat user (capture) : Recapitulatif, References,\r\n                            \/\/   Paiement, Validations et Bon de commande restent visibles\r\n                            \/\/   alors qu'aucun espace n'est reserve.\r\n                            \/\/   pb1181 ne couvrait pas 'recapitulatif' et posait le\r\n                            \/\/   masquage via .hide() de jQuery, sans priorite : d'autres\r\n                            \/\/   writers (initTitresEtapesDesactives, reinitialiserTitres)\r\n                            \/\/   les reaffichaient ensuite.\r\n                            \/\/   Regle demandee, plus simple : tant que l'espace n'est pas\r\n                            \/\/   RESERVE, aucune de ces cinq etapes n'est visible ; des\r\n                            \/\/   qu'il l'est, elles apparaissent TOUTES d'un bloc \u2014 plus\r\n                            \/\/   de devoilement une par une.\r\n                            \/\/   Le display est pose en !important pour tenir face aux\r\n                            \/\/   autres writers, comme pb1082 l'avait etabli.\r\n                            \/\/   Revert : window._viaPb1181Off = true.\r\n                            \/\/ ============================================================\r\n                            \/\/ pb1183 : masquage des etapes aval assure par une CLASSE sur\r\n                            \/\/   <body> + feuille CSS (voir _masqueAval1183), pas ici.\r\n                            $(e.etape).each(function () {\r\n                                this.style.setProperty('display',\r\n                                    _visible1160 ? 'block' : 'none', 'important');\r\n                            });\r\n                        }\r\n                        $(e.conteneur)[ouvrir ? 'show' : 'hide']();\r\n                        $(e.iconeUp)[ouvrir ? 'show' : 'hide']();\r\n                        $(e.iconeDown)[ouvrir ? 'hide' : 'show']();\r\n                    } else if (e.id === 'pageWebMobile' ? (window.outerWidth >= 1000) : false) {\r\n                        \/\/ pb1111 : desktop \u2014 seul le TITRE de l'etape page web est\r\n                        \/\/   affiche ; son conteneur reste au VLP. On ne pilote donc que\r\n                        \/\/   les chevrons, jamais le conteneur.\r\n                        $(e.iconeUp)[ouvrir ? 'show' : 'hide']();\r\n                        $(e.iconeDown)[ouvrir ? 'hide' : 'show']();\r\n                    } else {\r\n                        $(e.conteneur)[ouvrir ? 'show' : 'hide']();\r\n                        $(e.iconeUp)[ouvrir ? 'show' : 'hide']();\r\n                        $(e.iconeDown)[ouvrir ? 'hide' : 'show']();\r\n                    }\r\n                    console.log('[pb1099] ' + e.id + ' -> ' + (ouvrir ? 'OUVERT' : 'ferm\u00e9'));\r\n                });\r\n\r\n                \/\/ ================================================================\r\n                \/\/ pb1112 : phrase verte sous le titre PAGE WEB une fois un espace\r\n                \/\/   publicitaire choisi (demande user).\r\n                \/\/   Meme forme que les autres phrases d'etape faite : sous le titre,\r\n                \/\/   vert, et retiree si l'espace est deselectionne.\r\n                \/\/ ================================================================\r\n                try {\r\n                    var _ePW1112 = cfg.find(x => x.id === 'pageWebMobile') || null;\r\n                    if (_ePW1112) {\r\n                        \/\/ pb1115 : inserer APRES LE CONTENEUR du titre, pas apres le\r\n                        \/\/   premier element portant la classe .PageWebMobiletitre.\r\n                        \/\/   Constat user (HTML) : la phrase se retrouvait entre le\r\n                        \/\/   chevron et le texte du titre, donc a gauche \u2014 ces elements\r\n                        \/\/   sont cote a cote dans un conteneur flex.\r\n                        \/\/   Le conteneur #PageWebMobileTitreContainer englobe chevrons\r\n                        \/\/   et titre : y ajouter la phrase la place bien EN DESSOUS.\r\n                        var $tPW = $('#PageWebMobileTitreContainer').first();\r\n                        if (!$tPW.length) { $tPW = $(_ePW1112.titre).last(); }\r\n                        if ($tPW.length) {\r\n                            $tPW.nextAll('.v1112-msg').remove();\r\n                            $('.v1112-msg').remove();   \/\/ ancienne position eventuelle\r\n                            if (faits.pageWebMobile) {\r\n                                var _lg1112 = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                                var $m1112 = $('<div class=\"v1112-msg\"><\/div>');\r\n                                $m1112.text(_lg1112 === 'EN'\r\n                                    ? 'One or more advertising spaces are selected'\r\n                                    : 'Un ou des espaces publicitaires sont s\u00e9lectionn\u00e9s');\r\n                                var _st = $m1112[0].style;\r\n                                _st.setProperty('color', '#56be50', 'important');\r\n                                \/\/ pb1184 : taille alignee sur les AUTRES phrases vertes\r\n                                \/\/   (demande user : \"Un ou des espaces publicitaires sont\r\n                                \/\/   selectionnes\" ressortait plus gros que ses voisines).\r\n                                \/\/   Les sous-titres verts des etapes ne sont pas ecrits par\r\n                                \/\/   ce bloc : ils viennent d'Elementor, et pb913 les reduit\r\n                                \/\/   comme le reste. On mesure donc la taille rendue d'un\r\n                                \/\/   sous-titre existant et on s'aligne dessus, plutot que de\r\n                                \/\/   fixer une valeur en dur qui divergerait au prochain\r\n                                \/\/   ajustement de pb913.\r\n                                \/\/   Repli sur 11px si aucun sous-titre n'est trouve.\r\n                                var _ref1184 = document.querySelector('.SousTitre p, .SousTitre');\r\n                                var _fs1184 = _ref1184\r\n                                    ? parseFloat(window.getComputedStyle(_ref1184).fontSize)\r\n                                    : 0;\r\n                                if (!(_fs1184 > 0)) { _fs1184 = 11; }\r\n                                _st.setProperty('font-size', _fs1184 + 'px', 'important');\r\n                                _st.setProperty('font-weight', '600', 'important');\r\n                                _st.setProperty('text-align', 'center', 'important');\r\n                                _st.setProperty('width', '100%', 'important');\r\n                                _st.setProperty('display', 'block', 'important');\r\n                                \/\/ pb1119 : remontee de 25px (demande user). Le conteneur\r\n                                \/\/   du titre reserve une hauteur pour les chevrons ; la\r\n                                \/\/   phrase, placee juste apres (pb1115), heritait de cet\r\n                                \/\/   espace et tombait trop bas.\r\n                                \/\/   Knob : window._viaMt1119 (-25 par defaut).\r\n                                \/\/ pb1127 : marges distinctes desktop \/ mobile (demande user).\r\n                                \/\/   desktop : -29px en haut (les -25 de pb1119 moins 4),\r\n                                \/\/             +10px en bas ;\r\n                                \/\/   mobile  : -15px en haut (les -25 plus 10),\r\n                                \/\/             -10px en bas.\r\n                                \/\/   Knobs : window._viaMt1119 (haut) et window._viaMb1127 (bas)\r\n                                \/\/   forcent les deux valeurs si besoin d'un reglage fin.\r\n                                \/\/ pb1141 : deltas supplementaires (demande user).\r\n                                \/\/   desktop : margin-bottom +5  -> 10 devient 15px\r\n                                \/\/   mobile  : margin-bottom +5  -> -10 devient -5px\r\n                                \/\/             margin-top    +3  -> -15 devient -12px\r\n                                var _mob1127 = window.outerWidth < 1000;\r\n                                \/\/ pb1191 : +2px de margin-top en MOBILE (demande user) \u2014\r\n                                \/\/   -12 devient -10. Desktop inchange (-29).\r\n                                var _mt1127 = (typeof window._viaMt1119 === 'number')\r\n                                    ? window._viaMt1119 : (_mob1127 ? -10 : -29);\r\n                                \/\/ pb1188  : +10px de margin-bottom en DESKTOP -> 25.\r\n                                \/\/ pb1188b : +3px de margin-bottom en MOBILE  -> -2.\r\n                                var _mb1127 = (typeof window._viaMb1127 === 'number')\r\n                                    ? window._viaMb1127 : (_mob1127 ? -2 : 25);\r\n                                _st.setProperty('margin-top', _mt1127 + 'px', 'important');\r\n                                _st.setProperty('margin-bottom', _mb1127 + 'px', 'important');\r\n                                $tPW.after($m1112);\r\n                            }\r\n                        }\r\n                    }\r\n                } catch (_e1112) { console.warn('[pb1112]', _e1112.message); }\r\n\r\n                \/\/ ================================================================\r\n                \/\/ pb1144 : MESSAGE d'alerte sous le titre de l'etape DATES.\r\n                \/\/   pb1143 fait desormais respecter la regle des 7 jours dans le\r\n                \/\/   process (l'etape ne se valide plus), mais le message de pb603\r\n                \/\/   n'y apparait pas : il ecrit dans #MsgDatesText, absent de ce\r\n                \/\/   contexte. L'utilisateur voit donc l'etape rester ouverte sans\r\n                \/\/   savoir pourquoi.\r\n                \/\/   On affiche le meme texte que l'achat express, sous le titre de\r\n                \/\/   l'etape, dans la forme des autres messages d'invite (rouge).\r\n                \/\/   Les bornes viennent des memes sources que pb603\/pb610 : knob,\r\n                \/\/   puis parametres charges, puis defaut.\r\n                \/\/   Retire des que la duree redevient valide.\r\n                \/\/   Revert : window._viaPb1144Off = true.\r\n                \/\/ ================================================================\r\n                try {\r\n                    var _eD1144 = cfg.find(x => x.id === 'processDatesDevise') || null;\r\n                    if (_eD1144) {\r\n                        var $tD1144 = $(_eD1144.titre).last();\r\n                        if ($tD1144.length) {\r\n                            $('.v1144-msg').remove();\r\n                            var _inval1144 = (window._viaPb1144Off === true)\r\n                                ? false : (window._viaDureeInvalide603 === true);\r\n                            if (_inval1144) {\r\n                                var _min1144 = (typeof window._viaDureeMin603 === 'number')\r\n                                    ? window._viaDureeMin603\r\n                                    : (window._viaParams610 ? window._viaParams610.min : 7);\r\n                                var _max1144 = (typeof window._viaDureeMax609 === 'number')\r\n                                    ? window._viaDureeMax609\r\n                                    : (window._viaParams610 ? window._viaParams610.max : 200);\r\n                                var _nb1144 = 0;\r\n                                try {\r\n                                    var _d1 = ($('#form-field-DebutCampagne').val() || '').split('\/');\r\n                                    var _d2 = ($('#form-field-FinCampagne').val() || '').split('\/');\r\n                                    if (_d1.length === 3 ? (_d2.length === 3) : false) {\r\n                                        var _t1 = new Date(+_d1[2], +_d1[1] - 1, +_d1[0]);\r\n                                        var _t2 = new Date(+_d2[2], +_d2[1] - 1, +_d2[0]);\r\n                                        _nb1144 = Math.round((_t2 - _t1) \/ 86400000);\r\n                                    }\r\n                                } catch (_eN) { _nb1144 = 0; }\r\n                                var _lg1144 = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                                \/\/ pb1150 : textes reformules (demande user). Les deux bornes\r\n                                \/\/   sont traitees : le message MAXIMUM existait deja dans le\r\n                                \/\/   code mais ne s'affichait pas, faute d'un _nb1144 fiable \u2014\r\n                                \/\/   il est desormais calcule avant, a partir des deux champs.\r\n                                var _txt1144;\r\n                                if (_nb1144 > _max1144) {\r\n                                    _txt1144 = (_lg1144 === 'EN')\r\n                                        ? 'Please select a campaign lasting no more than ' + _max1144 + ' days'\r\n                                        : 'Merci de s\u00e9lectionner une campagne d\\u2019une dur\u00e9e maximale de ' + _max1144 + ' jours';\r\n                                } else {\r\n                                    _txt1144 = (_lg1144 === 'EN')\r\n                                        ? 'Please select a campaign lasting at least ' + _min1144 + ' days'\r\n                                        : 'Merci de s\u00e9lectionner une campagne d\\u2019une dur\u00e9e minimale de ' + _min1144 + ' jours';\r\n                                }\r\n                                var $m1144 = $('<div class=\"v1144-msg\"><\/div>');\r\n                                $m1144.text(_txt1144);\r\n                                \/\/ pb1150 : marges et taille (demande user).\r\n                                \/\/   desktop + mobile : -5px en haut, 6px en bas\r\n                                \/\/   mobile : 1px de moins sur la taille (13 -> 12px)\r\n                                var _mob1150 = window.outerWidth < 1000;\r\n                                var _s1144 = $m1144[0].style;\r\n                                _s1144.setProperty('color', '#fb5e2a', 'important');\r\n                                _s1144.setProperty('font-size', (_mob1150 ? '12px' : '13px'), 'important');\r\n                                _s1144.setProperty('font-weight', '600', 'important');\r\n                                _s1144.setProperty('text-align', 'center', 'important');\r\n                                _s1144.setProperty('width', '100%', 'important');\r\n                                _s1144.setProperty('display', 'block', 'important');\r\n                                \/\/ pb1150c : MOBILE seul, deltas supplementaires (demande user) :\r\n                                \/\/   -5px de plus en haut (-5 -> -10) et +5px en bas (6 -> 11).\r\n                                \/\/   Desktop inchange (-5 \/ 6).\r\n                                _s1144.setProperty('margin-top', (_mob1150 ? '-10px' : '-5px'), 'important');\r\n                                _s1144.setProperty('margin-bottom', (_mob1150 ? '11px' : '6px'), 'important');\r\n                                \/\/ pb1144b : inserer DANS le conteneur de l'etape, pas apres\r\n                                \/\/   le titre. Constat user (capture) : le message se\r\n                                \/\/   pla\u00e7ait a DROITE du titre et repoussait la mise en\r\n                                \/\/   page \u2014 titre coupe sur trois lignes, popup elargi.\r\n                                \/\/   Le titre vit dans un conteneur flex en ligne : tout\r\n                                \/\/   ce qu'on insere a cote de lui s'aligne dessus. C'est\r\n                                \/\/   le meme piege qu'en pb1115 pour la phrase verte.\r\n                                \/\/   Le conteneur de l'etape, lui, est SOUS le titre et\r\n                                \/\/   occupe la largeur : le message y prend sa place sans\r\n                                \/\/   rien deplacer. L'etape restant ouverte tant que la\r\n                                \/\/   duree est invalide, il est bien visible.\r\n                                var $ctn1144 = $(_eD1144.conteneur).first();\r\n                                \/\/ pb2118 : message en BAS du conteneur (demande user).\r\n                                \/\/   pb1144b l'inserait en TETE (prepend). Le passage en\r\n                                \/\/   queue rend caduc le margin-top negatif de pb1150\/1150c\r\n                                \/\/   (concu pour recoller au titre au-dessus) : en bas, il\r\n                                \/\/   mordrait sur la ligne devise. On le neutralise (6px\r\n                                \/\/   desktop \/ 4px mobile), margin-bottom conserve.\r\n                                \/\/   Revert : window._viaPb2118Off = true (prepend d'origine).\r\n                                if ($ctn1144.length) {\r\n                                    if (window._viaPb2118Off === true) { $ctn1144.prepend($m1144); }\r\n                                    else {\r\n                                        \/\/ pb2118b : desktop -20px (demande user) -> 6 devient -14. Mobile inchange (4).\r\n                                        \/\/ pb2118c : desktop -10px supplementaires -> -14 devient -24. Mobile inchange.\r\n                                        _s1144.setProperty('margin-top', (_mob1150 ? '4px' : '-24px'), 'important');\r\n                                        $ctn1144.append($m1144);\r\n                                        console.log('[pb2118] message v1144 insere en BAS de ' + _eD1144.conteneur);\r\n                                    }\r\n                                }\r\n                                else { $tD1144.after($m1144); }\r\n                            }\r\n                        }\r\n                    }\r\n                } catch (_e1144) { console.warn('[pb1144]', _e1144.message); }\r\n\r\n                \/\/ pb1092 : page web rejouee au franchissement du seuil annonceur+dates\r\n                \/\/   (les gardes pb1083\/pb1090 l'ont differee, il faut la reprendre).\r\n                \/\/ pb1107 : la page web attend TOUTES les etapes amont, pas seulement\r\n                \/\/   annonceur + dates.\r\n                \/\/   Constat user : le mode 3 colonnes s'ouvre mal \u2014 la capture montre\r\n                \/\/   le VLP superpose au popup Process au lieu d'etre a cote.\r\n                \/\/   Cause : pb1092 ouvrait la page web des annonceur + dates. Mais le\r\n                \/\/   layout 3 colonnes, lui, exige aussi pays + secteur + FORMAT\r\n                \/\/   (pb857) \u2014 et le log montre \"format: ''\". Le VLP s'ouvrait donc\r\n                \/\/   alors qu'aucun layout ne pouvait l'accueillir : il se posait par\r\n                \/\/   dessus.\r\n                \/\/   On aligne la condition d'ouverture sur celle du layout : toutes\r\n                \/\/   les etapes amont faites. Les deux decisions portent sur le meme\r\n                \/\/   moment du parcours, elles doivent partager le meme critere.\r\n                \/\/ ================================================================\r\n                \/\/ pb1336 : LE SEUIL LISAIT LUI AUSSI DES COMPLETIONS CONTAMINEES.\r\n                \/\/   Constat user : annonceur, pays, secteur et dates choisis mais PAS\r\n                \/\/   le format \u2014 et la page web s'ouvre quand meme, mal placee. Le log\r\n                \/\/   met les deux verdicts cote a cote :\r\n                \/\/     [pb1092] annonceur + dates r\u00e9unis -> ouverture de la page web\r\n                \/\/     [pb857]  3 colonnes ajourne | pays=Congo secteur=Assurances format=-\r\n                \/\/   pb857 voit l'absence de format et ajourne ; pb1092 ne la voit pas\r\n                \/\/   et ouvre. Le VLP se pose alors sur un layout qui ne peut pas\r\n                \/\/   l'accueillir \u2014 exactement le symptome que pb1107 avait deja decrit\r\n                \/\/   et corrige en ajoutant 'choixFormat' a cette liste.\r\n                \/\/   pb1107 avait donc raison ; ce qui lui manquait, c'est que faits[]\r\n                \/\/   ne dit pas la verite sur les bandeaux : la monotonie pb1162 met\r\n                \/\/   choixFormat a 1 des que les dates \u2014 etape SUIVANTE \u2014 sont saisies.\r\n                \/\/   Le format n'a jamais ete choisi, il est seulement declare tel.\r\n                \/\/   On evalue donc les trois bandeaux sur leur etat reel, annonceur et\r\n                \/\/   dates restant sur faits[] (aucune etape posterieure ne les precede\r\n                \/\/   dans la liste, la monotonie ne les fabrique pas).\r\n                \/\/   Revert : window._viaPb1336Off = true.\r\n                \/\/ ================================================================\r\n                \/\/ ================================================================\r\n                \/\/ pb2407 : LES DATES SE LISENT SUR L'ITEM, PLUS SUR faits[].\r\n                \/\/   pb1336 gardait annonceur et dates sur faits[] au motif\r\n                \/\/   qu'\u00ab aucune etape posterieure ne les precede \u00bb. Depuis pb2406\r\n                \/\/   choixFormat SUIT processDatesDevise : la monotonie pb1162\r\n                \/\/   declare donc les dates faites des qu'un format est choisi, et\r\n                \/\/   ce seuil ouvrirait la page web sans dates \u2014 le symetrique exact\r\n                \/\/   du defaut que pb1336 corrigeait pour le format.\r\n                \/\/   Meme juge que _completions1076 avant propagation :\r\n                \/\/   it.dateDebut ET it.dateFin. L'annonceur reste sur faits[] :\r\n                \/\/   il est toujours premier, rien ne le fabrique.\r\n                \/\/   Revert : window._viaPb2407Off = true (dates sur faits[]).\r\n                \/\/ ================================================================\r\n                var _datesOk2407 = !!faits['processDatesDevise'];\r\n                if (window._viaPb2407Off !== true) {\r\n                    try {\r\n                        var _it2407 = (this.state.items || [])\r\n                            .find(x => x.id === this.state.itemActif) || null;\r\n                        var _reel2407 = _it2407 ? !!(_it2407.dateDebut ? _it2407.dateFin : false) : false;\r\n                        if (_reel2407 !== _datesOk2407) {\r\n                            console.log('[pb2407] dates : faits[]=' + _datesOk2407\r\n                                + ' (monotonie) mais item=' + _reel2407 + ' -> on suit l\\'item');\r\n                        }\r\n                        _datesOk2407 = _reel2407;\r\n                    } catch (_e2407) { console.warn('[pb2407]', _e2407.message); }\r\n                }\r\n                const pretPage = (window._viaPb1336Off === true)\r\n                    ? ['processAnnonceur', 'associerPays', 'associerSecteur',\r\n                       'choixFormat', 'processDatesDevise'].every(id => faits[id])\r\n                    : ((faits['processAnnonceur'] ? _datesOk2407 : false)\r\n                        ? ['associerPays', 'associerSecteur', 'choixFormat']\r\n                            .every(id => this._bandeauFait1335(id, faits))\r\n                        : false);\r\n                if (pretPage ? !window._viaSeuilPage1092 : false) {\r\n                    window._viaSeuilPage1092 = true;\r\n                    \/\/ ================================================================\r\n                    \/\/ pb1128 : RESTAURER LinkSecteurPage avant d'ouvrir la page web.\r\n                    \/\/   Constat user : les 3 colonnes s'ouvrent mal. Le log donne la\r\n                    \/\/   cause a la ligne suivant l'appel :\r\n                    \/\/     [pb65] DisplayPageWeb : LinkSecteurPage vide ou _vlpOpen\r\n                    \/\/            indisponible | link:  | _vlpOpen: function\r\n                    \/\/   _vlpOpen est bien la : c'est l'URL qui manque. L'item la\r\n                    \/\/   connait pourtant (page=Agro-industries), mais la cle globale\r\n                    \/\/   LinkSecteurPage a ete videe entre-temps \u2014 le sequenceur appelle\r\n                    \/\/   DisplayPageWeb depuis son veilleur, hors du chemin de selection\r\n                    \/\/   qui, lui, pose cette cle juste avant d'appeler.\r\n                    \/\/   On la repose donc depuis l'item, source qui fait foi (lecon\r\n                    \/\/   pb1061b), avant d'appeler. Si l'item n'en a pas non plus, on\r\n                    \/\/   n'appelle pas : mieux vaut ne rien ouvrir qu'ouvrir a vide.\r\n                    \/\/   Revert : window._viaPb1128Off = true.\r\n                    \/\/ ================================================================\r\n                    \/\/ ================================================================\r\n                    \/\/ pb1303 : EN ACHAT EXPRESS, LA PAGE WEB ATTEND LE \u00ab CONTINUER \u00bb.\r\n                    \/\/   Constat user (log) : sur une nouvelle reservation express\r\n                    \/\/   mobile, la page web s'ouvre des la saisie des dates \u2014\r\n                    \/\/     [pb1092] annonceur + dates r\u00e9unis -> ouverture de la page web\r\n                    \/\/     [pb1128] aucune URL de page -> ouverture annul\u00e9e\r\n                    \/\/   repete a chaque passe, faute d'URL puisque le site et le\r\n                    \/\/   secteur ne sont pas encore choisis.\r\n                    \/\/   pb1092 applique la regle du process CLASSIQUE : annonceur +\r\n                    \/\/   dates suffisent, le reste se choisit dans la page. En achat\r\n                    \/\/   express l'ordre est inverse \u2014 tout se choisit dans le\r\n                    \/\/   catalogue, et le \u00ab Continuer la reservation \u00bb marque la fin\r\n                    \/\/   de la selection. Ouvrir avant, c'est ouvrir sur rien.\r\n                    \/\/   Le drapeau lu ici est celui de pb1302, pose a la creation de\r\n                    \/\/   la resa express et retire au Continuer (pb1056) : il dit\r\n                    \/\/   exactement \u00ab une selection express est en cours \u00bb.\r\n                    \/\/   Revert : window._viaPb1303Off = true.\r\n                    \/\/ ================================================================\r\n                    if (window._viaPb1303Off !== true) {\r\n                        if (window._viaNouvelleResaExpress1302 === true) {\r\n                            if (window._viaSig1303 !== 'attente') {\r\n                                window._viaSig1303 = 'attente';\r\n                                console.log('[pb1303] achat express en cours -> ouverture'\r\n                                    + ' de la page web diff\u00e9r\u00e9e jusqu\\'au Continuer');\r\n                            }\r\n                            return;\r\n                        }\r\n                        if (window._viaSig1303 === 'attente') { window._viaSig1303 = 'ok'; }\r\n                    }\r\n                    console.log('[pb1092] annonceur + dates r\u00e9unis -> ouverture de la page web');\r\n                    try {\r\n                        var _it1128 = (this.state.items || []).find(x => x.id === this.state.itemActif) || null;\r\n                        var _url1128 = '';\r\n                        try { _url1128 = sessionStorage.getItem('LinkSecteurPage') || ''; } catch (_eS) {}\r\n                        if (window._viaPb1128Off !== true ? !_url1128 : false) {\r\n                            _url1128 = _it1128\r\n                                ? (_it1128.linkSecteurPage\r\n                                    || (_it1128.donneesIframe ? _it1128.donneesIframe.LoadedPageUrl : '') || '')\r\n                                : '';\r\n                            if (_url1128) {\r\n                                try { sessionStorage.setItem('LinkSecteurPage', _url1128); } catch (_eW) {}\r\n                                console.log('[pb1128] LinkSecteurPage restaur\u00e9 depuis l item : ' + _url1128);\r\n                            }\r\n                        }\r\n                        if (window._viaPb1128Off !== true ? !_url1128 : false) {\r\n                            console.warn('[pb1128] aucune URL de page -> ouverture annul\u00e9e');\r\n                            window._viaSeuilPage1092 = false;   \/\/ on retentera\r\n                        } else if (typeof window.DisplayPageWeb === 'function') {\r\n                            window.DisplayPageWeb();\r\n                        }\r\n                    } catch (_e) { console.warn('[pb1092]', _e.message); }\r\n                }\r\n                if (!pretPage) { window._viaSeuilPage1092 = false; }\r\n            } catch (_e1073) { console.warn('[pb1099]', _e1073.message); }\r\n        },\r\n        marquerEtapeEnCours() {\r\n            if (!this.state.etapesConfig) return;\r\n            try { this._sondeSequenceur1071(); } catch (_eS1071) {}\r\n            try { this._sequenceurOuverture1073(); } catch (_eS1073) {}\r\n            \r\n            \/\/ Injecter le style CSS si pas d\u00e9j\u00e0 fait\r\n            \/\/ v4.9ds : la variable --via-etape-active-color et les r\u00e8gles override\r\n            \/\/   sur titres Dates\/R\u00e9cap sont pos\u00e9es dans l'IIFE pr\u00e9coce en d\u00e9but de\r\n            \/\/   fichier (pour s'appliquer d\u00e8s le 1er rendu). Ici on ajoute juste les\r\n            \/\/   r\u00e8gles d\u00e9pendant de la classe .via-etape-en-cours (pos\u00e9e par marquerEtapeEnCours).\r\n            if (!document.getElementById('via-etape-en-cours-style')) {\r\n                const style = document.createElement('style');\r\n                style.id = 'via-etape-en-cours-style';\r\n                style.textContent = `\r\n                    \/* \u00c9tape \"en cours\" (marqu\u00e9e par marquerEtapeEnCours) *\/\r\n                    .via-etape-en-cours,\r\n                    .via-etape-en-cours *,\r\n                    .via-etape-en-cours span,\r\n                    .via-etape-en-cours a,\r\n                    .via-etape-en-cours i,\r\n                    .via-etape-en-cours .elementor-widget-container,\r\n                    .via-etape-en-cours .elementor-widget-container *,\r\n                    .via-etape-en-cours .elementor-heading-title,\r\n                    .via-etape-en-cours .elementor-icon-wrapper,\r\n                    .via-etape-en-cours .elementor-icon-wrapper * {\r\n                        color: var(--via-etape-active-color) !important;\r\n                        fill:  var(--via-etape-active-color) !important;\r\n                    }\r\n                `;\r\n                document.head.appendChild(style);\r\n            }\r\n            \r\n            \/\/ Mapping sous-titres par \u00e9tape\r\n            const sousTitreMap = {\r\n                'associerPays': '.AssocierPaysClass .SousTitre',\r\n                'associerSecteur': '.AssocierSecteurClass .SousTitre',\r\n                'choixFormat': '.ChoixFormatClass .SousTitre',\r\n                'pageWeb': '.PageWebTemplate .SousTitre'\r\n            };\r\n            \r\n            \/\/ Retirer la classe et les styles inline bleus de toutes les \u00e9tapes (hors r\u00e9capitulatif)\r\n            this.state.etapesConfig.forEach(etape => {\r\n                if (etape.id === 'recapitulatif') return;\r\n                const $t = $(etape.titre);\r\n                const $up = $(etape.iconeUp);\r\n                const $dn = $(etape.iconeDown);\r\n                \r\n                $t.removeClass('via-etape-en-cours');\r\n                $up.removeClass('via-etape-en-cours');\r\n                $dn.removeClass('via-etape-en-cours');\r\n                \r\n                \/\/ Retirer les styles inline bleus forc\u00e9s\r\n                \/\/ \u2705 v4.9ds Fix 11 (Pb 5) : retirer aussi le rouge (251, 94, 42) \u2014 l'ancienne\r\n                \/\/   logique nettoyait uniquement le bleu (34, 93, 169) h\u00e9rit\u00e9 d'une version\r\n                \/\/   ant\u00e9rieure, mais depuis _viaEtapeActiveColor() la couleur active est\r\n                \/\/   rouge orang\u00e9. Sans ce nettoyage, les inline styles rouges persistent\r\n                \/\/   d'une ex\u00e9cution \u00e0 l'autre et battent le CSS via-popup-process-achat-spacing.\r\n                $t.find('*').addBack().each(function() {\r\n                    if (this.style && this.style.color && (this.style.color.includes('34, 93, 169') || this.style.color.includes('251, 94, 42'))) {\r\n                        this.style.removeProperty('color');\r\n                    }\r\n                });\r\n                $up.find('i').each(function() { this.style.removeProperty('color'); });\r\n                $dn.find('i').each(function() { this.style.removeProperty('color'); });\r\n                \r\n                if (sousTitreMap[etape.id]) {\r\n                    const $stClean = $(sousTitreMap[etape.id]);\r\n                    $stClean.removeClass('via-etape-en-cours');\r\n                    \/\/ Retirer le bleu\/rouge forc\u00e9, mais conserver le vert de s\u00e9lection\r\n                    $stClean.find('*').addBack().each(function() {\r\n                        if (this.style && this.style.color && (this.style.color.includes('34, 93, 169') || this.style.color.includes('251, 94, 42'))) {\r\n                            this.style.removeProperty('color');\r\n                        }\r\n                    });\r\n                }\r\n            });\r\n            \r\n            \/\/ Trouver la premi\u00e8re \u00e9tape non-gris\u00e9e (hors r\u00e9capitulatif - g\u00e9r\u00e9 ind\u00e9pendamment)\r\n            \/\/ \u2705 v4.9ds Fix 11 v2 (Pb 5) : en mode popup achat, AUCUNE \u00e9tape principale\r\n            \/\/   (associerSecteur, choixFormat, pageWeb) ne doit \u00eatre marqu\u00e9e en cours.\r\n            \/\/   Elles servent uniquement \u00e0 afficher l'\u00e9tat (sous-titre vert \"Le format\r\n            \/\/   choisi est X\", \"Communication associ\u00e9e au site Y\", etc.) \u2014 l'utilisateur\r\n            \/\/   n'agit pas sur ces \u00e9tapes en mode popup achat (il agit sur les sous-\r\n            \/\/   sections : R\u00e9capitulatif, Choisir les dates, R\u00e9f\u00e9rences, etc.).\r\n            \/\/   associerPays n'est pas dans la liste : elle est griseEtape()'d\r\n            \/\/   dynamiquement \u00e0 la s\u00e9lection du pays (yearbook-media.js:2868).\r\n            \/\/ \u2705 v4.9ds Pb 7 : tant que l'user n'a pas cliqu\u00e9 sur FinaliserBouton,\r\n            \/\/   les \u00e9tapes \"references\", \"paiement\", \"validations\", \"paiementFinal\" ne\r\n            \/\/   doivent PAS \u00eatre marqu\u00e9es en cours (rester grises).\r\n            \/\/   Avant : grisage de pageWeb\/Dates \u2192 marquerEtapeEnCours marquait l'\u00e9tape\r\n            \/\/   suivante non-gris\u00e9e (references puis paiement) \u2192 titre passait en rouge.\r\n            \/\/   Demande user : trop t\u00f4t, attendre le clic FinaliserBouton.\r\n            \/\/   Le flag _viaFinaliserClique est pos\u00e9 dans le handler du clic FinaliserBouton.\r\n            var _modePopupMek = (new URLSearchParams(window.location.hash.substring(1) || window.location.search).get('mode') === 'popup');\r\n            var _finaliserCliqueMek = window._viaFinaliserClique === true;\r\n            var _etapesPostFinalisation = ['references', 'paiement', 'validations', 'paiementFinal'];\r\n            \/\/ \u2705 v4.9ds Pb 7 : forcer le GRIS sur les \u00e9tapes post-finalisation tant que\r\n            \/\/   FinaliserBouton n'a pas \u00e9t\u00e9 cliqu\u00e9. Le simple \"continue\" pour skipper ne\r\n            \/\/   suffit pas : un titre d\u00e9j\u00e0 color\u00e9 (par un autre code) reste en couleur.\r\n            \/\/   Ici on retire la classe via-etape-en-cours et on impose #999999 inline\r\n            \/\/   pour battre tout style h\u00e9rit\u00e9.\r\n            if (!_finaliserCliqueMek) {\r\n                _etapesPostFinalisation.forEach(function(_etapeId) {\r\n                    var _etape = (window.VIA_Panier ? (window.VIA_Panier.state ? window.VIA_Panier.state.etapesConfig : null) : null) || [];\r\n                    var _conf = _etape.find ? _etape.find(function(e) { return e.id === _etapeId; }) : null;\r\n                    if (!_conf) { return; }\r\n                    var $_t = $(_conf.titre);\r\n                    var $_iU = $(_conf.iconeUp);\r\n                    var $_iD = $(_conf.iconeDown);\r\n                    $_t.removeClass('via-etape-en-cours');\r\n                    $_iU.removeClass('via-etape-en-cours');\r\n                    $_iD.removeClass('via-etape-en-cours');\r\n                    \/\/ pb1174b : la classe est retiree, la COULEUR ne l'est plus ici.\r\n                    \/\/   Ce bloc imposait #6e6e6e inline sur les etapes post-finalisation\r\n                    \/\/   \"pour battre tout style herite\" \u2014 donc, par construction, pour\r\n                    \/\/   passer devant la regle des trois etats (pb1169).\r\n                    \/\/   Retirer via-etape-en-cours suffit : _couleurEtapes1169 leur\r\n                    \/\/   appliquera #747474 (a venir) ou #4b689b (faites), selon leur\r\n                    \/\/   etat reel. Un seul writer de couleur, comme demande.\r\n                });\r\n            }\r\n            \/* ============================================================\r\n             * pb1557 : UN SEUL CRITERE POUR L'ETAPE EN COURS.\r\n             *   Le log montrait deux calculs concurrents, a 23 lignes d'ecart :\r\n             *     [pb1071] etape que le sequenceur choisirait : processAnnonceur\r\n             *     Etape en cours marquee: processDatesDevise\r\n             *   Le sequenceur prend la premiere etape NON FAITE\r\n             *   (ordre.findIndex(id => !faits[id])) et tombait juste. La boucle\r\n             *   ci-dessous prend la premiere etape NON GRISEE \u2014 un etat d'affichage,\r\n             *   pas un etat logique. Les deux divergent des qu'une etape faite n'a\r\n             *   pas encore ete grisee, ou l'inverse.\r\n             *   On aligne sur le critere du sequenceur : c'est celui qui decrit la\r\n             *   realite (lecon pb734, etat LOGIQUE et non affichage), et il evite une\r\n             *   seconde definition a maintenir.\r\n             *   Le saut de choixFormat en mode popup (ligne suivante) disparait avec :\r\n             *   il datait du popup etroit ou le bandeau format etait toujours ferme.\r\n             *   Depuis pb1555 il reste ouvert, donc l'etape est eligible comme les\r\n             *   autres \u2014 c'est la meme premisse perimee que pb1549 et pb1550.\r\n             *   Revert : window._viaPb1557Off = true.\r\n             * ============================================================ *\/\r\n            var _faits1557 = null;\r\n            if (window._viaPb1557Off !== true) {\r\n                try {\r\n                    var _it1557 = (this.state.items || []).find(function (i) { return i.id === this.state.itemActif; }, this);\r\n                    if (_it1557) {\r\n                        var _empl1557 = (_it1557.donneesIframe ? _it1557.donneesIframe.Commande_Emplacement_Page_Web : '')\r\n                            || _it1557.emplacementPageWeb || '';\r\n                        _faits1557 = {\r\n                            processAnnonceur:   window._viaAnnonceurFait1713(_it1557),   \/* pb1713 *\/\r\n                            associerPays:       !!(_it1557.paysDisplayed || _it1557.linkSecteurPage),\r\n                            associerSecteur:    !!(_it1557.selectedPageSecteur || _it1557.commandePage),\r\n                            choixFormat:        window._viaChoixFormatFait2099(_it1557.format),   \/* pb2099 *\/\r\n                            processDatesDevise: !!(_it1557.dateDebut && _it1557.dateFin),\r\n                            pageWeb:            !!_empl1557,\r\n                            pageWebMobile:      !!_empl1557\r\n                        };\r\n                    }\r\n                } catch (_e1557) { _faits1557 = null; }\r\n            }\r\n\r\n            for (const etape of this.state.etapesConfig) {\r\n                if (etape.id === 'recapitulatif') continue;\r\n                if (_faits1557 === null) {\r\n                    if (_modePopupMek ? (etape.id === 'associerSecteur' || etape.id === 'choixFormat' || etape.id === 'pageWeb') : false) continue;\r\n                }\r\n                if (_etapesPostFinalisation.indexOf(etape.id) !== -1 ? !_finaliserCliqueMek : false) continue;\r\n                const $titre = $(etape.titre);\r\n                \/* pb1557 : etat LOGIQUE quand il est disponible, repli sur l'ancien\r\n                   test d'affichage sinon (etape hors table : references, paiement...). *\/\r\n                var _eligible1557 = (_faits1557 !== null)\r\n                    ? (_faits1557.hasOwnProperty(etape.id) ? !_faits1557[etape.id] : !$titre.hasClass('via-etape-grisee'))\r\n                    : !$titre.hasClass('via-etape-grisee');\r\n                if ($titre.length && _eligible1557) {\r\n                    \/\/ Marquer comme \u00e9tape en cours\r\n                    $titre.addClass('via-etape-en-cours');\r\n                    $(etape.iconeUp).addClass('via-etape-en-cours');\r\n                    $(etape.iconeDown).addClass('via-etape-en-cours');\r\n                    \r\n                    \/\/ \u2705 v1.16.0 : Forcer inline sur TOUS les descendants (Elementor override)\r\n                    \/\/ v4.9ds : couleur lue depuis la variable CSS --via-etape-active-color\r\n                    \/\/ \u2705 v4.9ds : pour les 3 \u00e9tapes structurelles (associerPays \/ associerSecteur \/\r\n                    \/\/   choixFormat), forcer toujours #999999 (gris) au lieu de la couleur\r\n                    \/\/   active dynamique. Demande user : ces titres + leurs chevrons doivent\r\n                    \/\/   rester gris en permanence, ind\u00e9pendamment de l'\u00e9tat de la r\u00e9servation.\r\n                    \/\/   Les textes\/sous-titres sous ces \u00e9tapes (.AssocierPaysClass .SousTitre etc.)\r\n                    \/\/   sont trait\u00e9s s\u00e9par\u00e9ment plus bas et conservent leur couleur dynamique.\r\n                    \/\/ ================================================================\r\n                    \/\/ pb919 : les 3 etapes \"structurelles\" (pays \/ secteur \/ format) etaient\r\n                    \/\/   forcees en GRIS EN PERMANENCE, meme quand elles etaient l'etape en\r\n                    \/\/   cours. Demande user : appliquer a TOUT le process la meme logique de\r\n                    \/\/   progression -> l'etape en cours est BLEUE, les autres grises\r\n                    \/\/   (\"Quand un annonceur est selectionne, l'etape suivante site pays\r\n                    \/\/   passe en bleu tandis que le titre annonceur passe en gris\").\r\n                    \/\/   ATTENTION : ceci REVIENT sur une demande anterieure (gris permanent\r\n                    \/\/   sur ces 3 etapes). Revert : window._viaPb919Off = true.\r\n                    var _grisEtapesStructurelles = (window._viaPb919Off === true)\r\n                        ? ['associerPays', 'associerSecteur', 'choixFormat']\r\n                        : [];\r\n                    \/\/ pb915 : les 2 nouvelles etapes du process suivent la meme regle de\r\n                    \/\/   couleur que pageWebMobile -> BLEU quand en cours (demande user),\r\n                    \/\/   gris une fois faites (via griserEtape, pilote par pb915 cote\r\n                    \/\/   yearbook-media.js : annonceur renseigne \/ dates + devise renseignees).\r\n                    \/\/ pb919 : toutes les etapes du process passent au bleu quand elles sont\r\n                    \/\/   en cours (et non plus a la couleur active orange), pour une\r\n                    \/\/   progression visuelle homogene bleu -> gris.\r\n                    \/\/ pb1163 : les ETAPES AVAL passent au BLEU quand elles sont en cours\r\n                    \/\/   (demande user). Constat : apres le Finaliser, References devient\r\n                    \/\/   bien active mais son titre et son chevron sont rouges (#FB5E2A,\r\n                    \/\/   la couleur active historique) au lieu du bleu #4b689b.\r\n                    \/\/   La liste _bleu915 ne couvrait que les etapes amont : les autres\r\n                    \/\/   retombaient sur window._viaEtapeActiveColor(). Or toutes les\r\n                    \/\/   etapes du parcours suivent desormais la meme regle depuis\r\n                    \/\/   pb1158 \u2014 leur couleur doit l'etre aussi.\r\n                    \/\/   Le recapitulatif garde sa couleur propre : il est traite a part\r\n                    \/\/   par le code couleur des reservations (cf _viaEtapeActiveColor,\r\n                    \/\/   qui bascule selon \"a reserver\" \/ \"reservee\").\r\n                    \/* ============================================================\r\n                     * pb1559 : LA COULEUR ACTIVE REDEVIENT UNIQUE.\r\n                     *   La liste ci-dessous peignait en #4b689b toute etape en cours qui\r\n                     *   y figurait \u2014 et elle avait fini par contenir les ONZE etapes du\r\n                     *   parcours (pb915, puis pb919, puis pb1163 pour les etapes aval).\r\n                     *   Une liste qui contient tout n'est plus une liste : c'est une\r\n                     *   seconde couleur active, concurrente de --via-etape-active-color,\r\n                     *   que v4.9ds avait pourtant posee comme source unique \u2014 \u00ab POUR\r\n                     *   CHANGER LA COULEUR, modifier UNIQUEMENT la valeur de\r\n                     *   --via-etape-active-color \u00bb.\r\n                     *   Effet observe : sur la regie, processAnnonceur n'etait pas marquee\r\n                     *   en cours et gardait le rouge #FB5E2A des regles de surcharge\r\n                     *   (mesure user : rgb(251, 94, 42)). Depuis pb1557 elle est marquee\r\n                     *   active cote site pays, donc repeinte en bleu \u2014 d'ou l'ecart.\r\n                     *   On la vide plutot que d'en retirer une seule entree : une\r\n                     *   exception dans une regle d'homogeneite en ferait deux a maintenir.\r\n                     *   La variable CSS redevient seule maitresse.\r\n                     *   Revert : window._viaPb1559Off = true (retablit la liste et le bleu).\r\n                     * ============================================================ *\/\r\n                    var _bleu915 = (window._viaPb1559Off === true)\r\n                        ? ['pageWebMobile', 'processAnnonceur', 'processDatesDevise',\r\n                           'associerPays', 'associerSecteur', 'choixFormat', 'pageWeb',\r\n                           'references', 'paiement', 'validations', 'paiementFinal']\r\n                        : [];\r\n                    \/\/ pb906 : PageWebMobile (pb892) doit passer en BLEU quand elle est\r\n                    \/\/   l'etape en cours \u2014 pas en couleur active (#FB5E2A orange\/rouge,\r\n                    \/\/   utilisee par les autres etapes). Demande user explicite : \"bleu\r\n                    \/\/   puis redevenir gris\". Le retour au gris est assure par le cycle\r\n                    \/\/   normal griserEtape('pageWebMobile') (appele a la reservation, cf\r\n                    \/\/   yearbook-media.js pb903) -> #999999 via .via-etape-grisee.\r\n                    \/\/   Revert : retirer la branche pageWebMobile ci-dessous.\r\n                    var _vColor = _grisEtapesStructurelles.indexOf(etape.id) !== -1\r\n                        ? '#6e6e6e'   \/\/ pb1123 : gris unique du projet\r\n                        : (_bleu915.indexOf(etape.id) !== -1 ? '#4b689b' : window._viaEtapeActiveColor());\r\n                    $titre.find('*').addBack().each(function() {\r\n                        this.style.setProperty('color', _vColor, 'important');\r\n                    });\r\n                    $(etape.iconeUp).find('*').addBack().each(function() {\r\n                        this.style.setProperty('color', _vColor, 'important');\r\n                    });\r\n                    $(etape.iconeDown).find('*').addBack().each(function() {\r\n                        this.style.setProperty('color', _vColor, 'important');\r\n                    });\r\n                    \r\n                    \/\/ Sous-titre : forcer bleu SAUF si vert (message de s\u00e9lection)\r\n                    if (sousTitreMap[etape.id]) {\r\n                        const $st = $(sousTitreMap[etape.id]);\r\n                        const stColor = $st.find('p').css('color');\r\n                        const isGreen = stColor && (stColor.includes('86, 190, 80') || stColor.includes('56BE50'));\r\n                        if (!isGreen) {\r\n                            $st.addClass('via-etape-en-cours');\r\n                            $st.find('*').addBack().each(function() {\r\n                                this.style.setProperty('color', window._viaEtapeActiveColor(), 'important');\r\n                            });\r\n                        }\r\n                    }\r\n                    \r\n                    console.log('\ud83d\udd35 \u00c9tape en cours marqu\u00e9e:', etape.id);\r\n                    \r\n                    \/\/ \u2705 v2.4.7 : Quand pageWeb est l'\u00e9tape en cours, ic\u00f4ne Recap en bleu \u2014 sauf si gris\u00e9e\r\n                    if (etape.id === 'pageWeb') {\r\n                        var $_recapIcone = $('#RecapitulatifVosCommandesIconeUp');\r\n                        var _recapEstGrise = $_recapIcone.hasClass('via-etape-grisee')\r\n                            || ($_recapIcone.find('*').addBack().filter(function() {\r\n                                return this.style && this.style.color === 'rgb(153, 153, 153)';\r\n                            }).length > 0);\r\n                        if (!_recapEstGrise) {\r\n                            $_recapIcone.find('*').addBack().each(function() {\r\n                                this.style.setProperty('color', window._viaEtapeActiveColor(), 'important');\r\n                            });\r\n                        }\r\n                    }\r\n                    break;\r\n                }\r\n            }\r\n            \/\/ pb1169 : couleurs des trois etats, appliquees EN DERNIER.\r\n            try { this._couleurEtapes1169(); } catch (_e1169) {}\r\n        },\r\n\r\n        \/\/ ====================================================================\r\n        \/\/ pb1169 : TROIS ETATS, TROIS COULEURS (demande user).\r\n        \/\/     active            -> #fb5e2a   (titre + chevrons)\r\n        \/\/     completee         -> #4b689b\r\n        \/\/     a venir, non faite-> #747474\r\n        \/\/   Une seule fonction decide, appelee en DERNIER dans\r\n        \/\/   marquerEtapeEnCours : les writers precedents (griserEtape, boucle\r\n        \/\/   d'etape en cours) ont deja pose leurs couleurs, celle-ci tranche.\r\n        \/\/   Ecrire ailleurs en plus recreerait la concurrence qui a coute pb1045.\r\n        \/\/   L'etat vient du sequenceur : _completions1076 pour \"faite\",\r\n        \/\/   _viaCibleProcess1091 pour \"active\". Memes sources que le reste.\r\n        \/\/   La TAILLE n'est pas touchee ici : elle appartient a pb913, seul\r\n        \/\/   writer de font-size (cf pb1170).\r\n        \/\/   Revert : window._viaPb1169Off = true.\r\n        \/\/ ====================================================================\r\n        \/* ====================================================================\r\n         * pb2046 : LES ETAPES \u00ab A VENIR \u00bb NE S'AFFICHENT PLUS.\r\n         *   Demande JF. Une etape est AFFICHEE si elle est FAITE ou ACTIVE ;\r\n         *   elle est MASQUEE tant qu'elle est \u00ab a venir \u00bb \u2014 le troisieme etat\r\n         *   de pb1169, celui qui rend #525252.\r\n         *   PORTEE : les QUATRE etapes aval, regie ET sites pays, meme regle\r\n         *   des deux cotes. Aucun discriminant de contexte n'est necessaire, et\r\n         *   c'est le point qui rend ce bloc court : tant que FinaliserStep n'est\r\n         *   pas pose, la cible vaut 'recapitulatif' et 'references' reste \u00ab a\r\n         *   venir \u00bb. Le comportement actuel de pb1183 tombe donc tout seul, sans\r\n         *   drapeau de clic. Au clic Finaliser la cible passe a 'references',\r\n         *   qui s'affiche SEULE ; les trois autres suivent chacune a son tour,\r\n         *   portees par pb1634 qui avance la cible des qu'une etape est faite.\r\n         *   ACQUISE POUR LA SESSION (reponse JF) : une etape affichee une fois\r\n         *   le reste. La memoire vit dans window, JAMAIS en sessionStorage \u2014\r\n         *   pb1220 et pb1222 se sont fait pi\u00e9ger par des residus de session, et\r\n         *   une etape \u00ab acquise \u00bb d'une session precedente serait le meme piege.\r\n         *   FEUILLE CSS + CLASSE SUR <body>, jamais d'inline : motif pb1183 et\r\n         *   pb1917, dont la raison est ecrite noir sur blanc \u2014 la boucle d'init\r\n         *   fait $(etape.etape).show() et d'autres writers repassent ensuite ;\r\n         *   un inline serait efface a la passe suivante, une regle en feuille ne\r\n         *   s'oublie pas entre deux passes.\r\n         *   Les SELECTEURS sont ceux de pb1183 : memes cibles, deja eprouvees,\r\n         *   titre et conteneur de titre compris \u2014 ils vivent HORS du wrapper,\r\n         *   comme pb1183b l'avait constate a ses depens.\r\n         *   pb1183 EST RETIRE par ce bloc (voir sa garde) : deux mecanismes\r\n         *   visant les quatre memes elements, c'est la configuration pb1045.\r\n         *   Revert : window._viaPb2046Off = true (pb1183 reprend la main).\r\n         * ==================================================================== *\/\r\n        _masqueAvenir2046(faits, cible) {\r\n            if (window._viaPb2046Off === true) { return; }\r\n            try {\r\n                \/* pb2049 : table et feuille sont definies en tete de fichier, pour\r\n                   etre posables AVANT l init du process. Une seule definition. *\/\r\n                var _E2046 = window._viaTable2046 || [];\r\n                if (!_E2046.length) { return; }\r\n                window._viaFeuille2046();\r\n                if (!document.body) { return; }\r\n                if (!window._viaAcquis2046) { window._viaAcquis2046 = {}; }\r\n                \/* ============================================================\r\n                 * pb2050 : \u00ab FAITE \u00bb NE SE CROIT PAS SUR PAROLE EN AVAL.\r\n                 *   Constat JF, log de pb2049 : le pre-masquage EST pose, et la\r\n                 *   premiere passe de pb2046 rend\r\n                 *     cible=processAnnonceur | paiement=affich\u00e9e\/faite\r\n                 *   puis \u00ab affich\u00e9e\/acquise \u00bb. Ce n etait donc PAS une course :\r\n                 *   pb2046 a decide, et il a decide sur un faux.\r\n                 *   D OU VIENT LE FAUX : faits.paiement vaut _pay1158. pb1639 fait\r\n                 *   autorite sur l etat VIVANT de VIA_Paiement \u2014 mais si le module\r\n                 *   n est pas encore charge, il retombe sur sessionStorage\r\n                 *   mode_paiement, qui SURVIT d une session a l autre. C est le\r\n                 *   residu que pb1220, pb1222 et pb1311 ont deja paye trois fois :\r\n                 *   \u00ab mesurer l etat reel, pas une cle qui survit \u00bb. Et cela\r\n                 *   explique le \u00ab quand je vais trop vite \u00bb de JF : plus la page\r\n                 *   est froide, plus la premiere passe tombe avant VIA_Paiement.\r\n                 *   POURQUOI CA RESTE : l acquis a fige la valeur fausse.\r\n                 *   LA PARADE, sans toucher a _completions1076 \u2014 fonction partagee\r\n                 *   par la couleur, le sequenceur et les tailles : on ne CROIT pas\r\n                 *   un \u00ab faite \u00bb incoherent. En AVAL le parcours est strictement\r\n                 *   sequentiel : on ne choisit pas un mode de paiement avant\r\n                 *   d avoir valide les references, ni sans avoir finalise. Une\r\n                 *   etape aval n est donc \u00ab faite \u00bb que si le recapitulatif l est\r\n                 *   ET si toutes celles qui la precedent le sont.\r\n                 *   C est la propagation monotone de pb1162, mais dans l autre\r\n                 *   sens et bornee a l aval \u2014 la ou pb1572 a etabli qu elle est\r\n                 *   legitime, puisque c est l AMONT qui n est pas lineaire.\r\n                 *   L ecart entre la table brute et la table filtree est\r\n                 *   journalise : il NOMME la cle qui ment, ce qui evitera de\r\n                 *   rechercher la meme cause une quatrieme fois.\r\n                 *   Revert : window._viaPb2050Off = true (on croit faits[] tel quel).\r\n                 * ============================================================ *\/\r\n                var _ordre2050 = ['references', 'paiement', 'validations', 'paiementFinal'];\r\n                var _chaine2050 = {};\r\n                if (window._viaPb2050Off === true) {\r\n                    _ordre2050.forEach(function (_id) {\r\n                        _chaine2050[_id] = faits ? !!faits[_id] : false;\r\n                    });\r\n                } else {\r\n                    \/* pb2051 : racine en MEMOIRE, plus sessionStorage. *\/\r\n                    var _amont2050 = window._viaRacineAval2051(faits);\r\n                    for (var _j2050 = 0; _j2050 < _ordre2050.length; _j2050++) {\r\n                        var _id2050 = _ordre2050[_j2050];\r\n                        var _f2050 = _amont2050 ? (faits ? !!faits[_id2050] : false) : false;\r\n                        _chaine2050[_id2050] = _f2050;\r\n                        if (!_f2050) { _amont2050 = false; }\r\n                    }\r\n                    var _brut2050 = _ordre2050.map(function (_id) {\r\n                        return (faits ? faits[_id] : false) ? '1' : '0';\r\n                    }).join('');\r\n                    var _filt2050 = _ordre2050.map(function (_id) {\r\n                        return _chaine2050[_id] ? '1' : '0';\r\n                    }).join('');\r\n                    if (_brut2050 !== _filt2050) {\r\n                        var _sg2050 = _brut2050 + '->' + _filt2050;\r\n                        if (window._viaSig2050 !== _sg2050) {\r\n                            window._viaSig2050 = _sg2050;\r\n                            console.warn('[pb2050] \u00ab faite \u00bb incoh\u00e9rent en aval, non retenu :'\r\n                                + ' brut=' + _brut2050 + ' filtr\u00e9=' + _filt2050\r\n                                + ' | ordre=' + _ordre2050.join(',')\r\n                                + ' | racine pb2051=' + window._viaRacineAval2051(faits)\r\n                                + ' (clic1222=' + (window._viaFinaliseClique1222 === true)\r\n                                + ' clicListeners=' + (window._viaFinaliserClique === true) + ')'\r\n                                + ' | recapitulatif=' + (faits ? !!faits.recapitulatif : false)\r\n                                + ' | FinaliserStep=' + (function () {\r\n                                    try { return sessionStorage.getItem('FinaliserStep') || '(vide)'; }\r\n                                    catch (_e) { return '(illisible)'; } })()\r\n                                + ' | mode_paiement=' + (function () {\r\n                                    try { return sessionStorage.getItem('mode_paiement') || '(vide)'; }\r\n                                    catch (_e) { return '(illisible)'; } })()\r\n                                + ' | VIA_Paiement=' + (window.VIA_Paiement ? 'charg\u00e9' : 'ABSENT'));\r\n                        }\r\n                    }\r\n                }\r\n                var _etat2046 = [];\r\n                for (var _i2046 = 0; _i2046 < _E2046.length; _i2046++) {\r\n                    var _e2046 = _E2046[_i2046];\r\n                    var _fait2046 = (_chaine2050[_e2046.id] === true);\r\n                    var _actif2046 = (_e2046.id === cible);\r\n                    var _acq2046 = (window._viaAcquis2046[_e2046.id] === true);\r\n                    var _vu2046 = _fait2046 ? true : (_actif2046 ? true : _acq2046);\r\n                    if (_vu2046) { window._viaAcquis2046[_e2046.id] = true; }\r\n                    document.body.classList[_vu2046 ? 'remove' : 'add'](_e2046.cls);\r\n                    \/* pb2034 : journaliser AUSSI le cas affiche, et avec le motif \u2014\r\n                       une sortie muette coute un aller-retour. *\/\r\n                    _etat2046.push(_e2046.id + '='\r\n                        + (_vu2046\r\n                            ? (_fait2046 ? 'affich\u00e9e\/faite'\r\n                                         : (_actif2046 ? 'affich\u00e9e\/active' : 'affich\u00e9e\/acquise'))\r\n                            : 'MASQU\u00c9E'));\r\n                }\r\n                var _sig2046 = _etat2046.join(' | ');\r\n                if (window._viaSig2046 !== _sig2046) {\r\n                    window._viaSig2046 = _sig2046;\r\n                    console.log('[pb2046] cible=' + (cible || '(aucune)') + ' | ' + _sig2046);\r\n                }\r\n            } catch (_e2046) { console.warn('[pb2046] ' + _e2046.message); }\r\n        },\r\n\r\n        \/\/ pb1183 : voir le commentaire dans _couleurEtapes1169.\r\n        _masqueAval1183(faits) {\r\n            if (window._viaPb1183Off === true) { return; }\r\n            \/* pb2046 : CE MECANISME EST RETIRE. Il masquait les quatre etapes\r\n               aval sur un drapeau de CLIC (_viaFinaliseClique1222) ; pb2046 les\r\n               masque sur leur ETAT, ce qui produit le meme resultat avant le clic\r\n               et le bon apres. La classe posee lors d'une passe anterieure est\r\n               retiree ici, sans quoi sa feuille continuerait de masquer.\r\n               Revert : window._viaPb2046Off = true -> ce bloc reprend la main\r\n               entierement, y compris son handler de clic. *\/\r\n            if (window._viaPb2046Off !== true) {\r\n                if (document.body\r\n                        ? document.body.classList.contains('via-aval-masque') : false) {\r\n                    document.body.classList.remove('via-aval-masque');\r\n                    console.log('[pb2046] pb1183 retir\u00e9 \u2014 classe via-aval-masque enlev\u00e9e');\r\n                }\r\n                return;\r\n            }\r\n            try {\r\n                if (!document.getElementById('via-masque-aval-1183')) {\r\n                    var _st = document.createElement('style');\r\n                    _st.id = 'via-masque-aval-1183';\r\n                    _st.textContent =\r\n                        \/\/ pb1183b : #EtapeRecapitulatif s'ajoute a la liste.\r\n                        \/\/   Constat user : toutes les etapes aval sont bien masquees\r\n                        \/\/   sauf le recapitulatif. Sa config designe\r\n                        \/\/   #RecapitulatifVosCommandesContainer \u2014 le bloc TITRE \u2014 mais\r\n                        \/\/   le wrapper de l'etape est #EtapeRecapitulatif, celui que\r\n                        \/\/   v2.0.9 rend visible sur mobile (ligne 12419). C'est lui qui\r\n                        \/\/   restait affiche.\r\n                        \/\/   Les deux sont cibles : le titre et son wrapper.\r\n                        \/\/ pb1213b : le RECAPITULATIF reste visible \u2014 c'est depuis lui\r\n                        \/\/   qu'on clique sur Finaliser ; le masquer rendrait la suite\r\n                        \/\/   du parcours inaccessible.\r\n                        \/\/   Les TITRES sont cibles en plus des wrappers : ils vivent\r\n                        \/\/   hors de #EtapeReferences & co, comme le titre du\r\n                        \/\/   recapitulatif est separe de #EtapeRecapitulatif.\r\n                          'body.via-aval-masque #EtapeReferences,'\r\n                        + 'body.via-aval-masque #EtapeModedePaiement,'\r\n                        + 'body.via-aval-masque #EtapeValidations,'\r\n                        + 'body.via-aval-masque #EtapePaiement,'\r\n                        + 'body.via-aval-masque .ReferencesTitre,'\r\n                        + 'body.via-aval-masque .ChoisirPaiementTitre,'\r\n                        + 'body.via-aval-masque .ValidationsTitre,'\r\n                        + 'body.via-aval-masque .ProcederPaiementTitre,'\r\n                        + 'body.via-aval-masque #ReferencesTitreContainer,'\r\n                        + 'body.via-aval-masque #ChoisirPaiementTitreContainer,'\r\n                        + 'body.via-aval-masque #ValidationsTitreContainer,'\r\n                        + 'body.via-aval-masque #ProcederPaiementTitreContainer'\r\n                        + '{ display: none !important; }';\r\n                    document.head.appendChild(_st);\r\n                    console.log('[pb1183] feuille de masquage des \u00e9tapes aval inject\u00e9e');\r\n                }\r\n                \/\/ ================================================================\r\n                \/\/ pb1213 : les etapes REFERENCES -> PAIEMENT sont masquees tant que\r\n                \/\/   FINALISER n'a pas ete clique, sur MOBILE ET DESKTOP (demande user).\r\n                \/\/ pb1220 : la finalisation se verifie AUSSI sur les items.\r\n                \/\/   faits.recapitulatif repose sur sessionStorage.FinaliserStep, qui\r\n                \/\/   survit au rechargement : une valeur laissee par une session\r\n                \/\/   precedente suffisait a lever le masquage \u2014 meme piege que pb1196\r\n                \/\/   avec PageWebColonneOpenclose.\r\n                \/\/   On exige donc les DEUX : la cle ET au moins un item reellement\r\n                \/\/   finalise. L'etat des items, lui, est reconstruit a chaque session.\r\n                \/\/   Revert : window._viaPb1220Off = true (cle seule).\r\n                \/\/ ================================================================\r\n                \/\/ ================================================================\r\n                \/\/ pb1222 : la finalisation est un CLIC de la session courante.\r\n                \/\/   Constat user : le log ne montre que \"feuille injectee\", jamais\r\n                \/\/   \"etapes aval -> MASQUEES\". La fonction sort donc avant, sur\r\n                \/\/   _doitMasquer === _dejaMasque : elle estime qu'il ne faut PAS\r\n                \/\/   masquer.\r\n                \/\/   Cause : les deux criteres de pb1220 sont satisfaits par des\r\n                \/\/   RESIDUS de session \u2014 FinaliserStep reste 'Yes', et les items sont\r\n                \/\/   restaures depuis sessionStorage avec leur statut 'complete'. Aucun\r\n                \/\/   des deux ne distingue \"finalise maintenant\" de \"finalise un jour\".\r\n                \/\/   On s'appuie donc sur un drapeau pose AU CLIC, en memoire (window),\r\n                \/\/   qui disparait a chaque chargement de page : il ne peut pas etre\r\n                \/\/   perime par construction.\r\n                \/\/   Le handler est delegue sur document \u2014 le bouton est recree a\r\n                \/\/   chaque rendu du recapitulatif.\r\n                \/\/   Revert : window._viaPb1222Off = true (criteres pb1220).\r\n                \/\/ ================================================================\r\n                if (!window._viaArmeFin1222) {\r\n                    window._viaArmeFin1222 = true;\r\n                    document.addEventListener('click', function (_e1222) {\r\n                        try {\r\n                            var _b1222 = _e1222.target.closest\r\n                                ? _e1222.target.closest('.PasserCommandeBouton, .FinaliserBouton')\r\n                                : null;\r\n                            if (!_b1222) { return; }\r\n                            window._viaFinaliseClique1222 = true;\r\n                            console.log('[pb1222] Finaliser cliqu\u00e9 -> \u00e9tapes aval autoris\u00e9es');\r\n                        } catch (_e) {}\r\n                    }, true);\r\n                }\r\n                var _finalise1220;\r\n                if (window._viaPb1222Off === true) {\r\n                    _finalise1220 = !!faits.recapitulatif;\r\n                    if (window._viaPb1220Off !== true ? _finalise1220 : false) {\r\n                        var _items1220 = (this.state ? (this.state.items || []) : []);\r\n                        var _unFinalise1220 = false;\r\n                        for (var _i1220 = 0; _i1220 < _items1220.length; _i1220++) {\r\n                            var _it1220 = _items1220[_i1220];\r\n                            if (!_it1220) { continue; }\r\n                            if (_it1220.statut === 'complete') { _unFinalise1220 = true; break; }\r\n                            if (_it1220.estReserveEffective === true) { _unFinalise1220 = true; break; }\r\n                        }\r\n                        _finalise1220 = _unFinalise1220;\r\n                    }\r\n                } else {\r\n                    _finalise1220 = (window._viaFinaliseClique1222 === true);\r\n                }\r\n                var _doitMasquer = !_finalise1220;\r\n                var _dejaMasque = document.body.classList.contains('via-aval-masque');\r\n                if (_doitMasquer === _dejaMasque) { return; }\r\n                document.body.classList[_doitMasquer ? 'add' : 'remove']('via-aval-masque');\r\n                console.log('[pb1183] \u00e9tapes aval -> ' + (_doitMasquer ? 'MASQU\u00c9ES' : 'affich\u00e9es')\r\n                    + ' (finalis\u00e9=' + (_finalise1220 ? 'oui' : 'non') + ')');\r\n            } catch (_e1183) { console.warn('[pb1183]', _e1183.message); }\r\n        },\r\n\r\n        _couleurEtapes1169() {\r\n            if (window._viaPb1169Off === true) { return; }\r\n            if (!this.state.etapesConfig) { return; }\r\n            const faits = this._completions1076();\r\n            \/* ============================================================\r\n             * pb1568 : LA COULEUR CALCULE SA CIBLE, ELLE NE LA SUBIT PAS.\r\n             *   _couleurEtapes1169 lisait window._viaCibleProcess1091, une valeur\r\n             *   posee ailleurs et qui peut etre perimee : le log montre\r\n             *   \u00ab Etape en cours marquee: processAnnonceur \u00bb (pb1557, qui calcule sur\r\n             *   l'instant) pendant que la couleur rend #525252 \u00ab a venir \u00bb \u2014 les deux\r\n             *   ne parlent pas de la meme etape.\r\n             *   Elle a pourtant deja `faits` sous la main, ligne precedente. On y\r\n             *   applique la meme regle que partout : la premiere etape non faite.\r\n             *   Le repli sur la valeur globale ne sert que si le calcul echoue.\r\n             *   Note : le rouge constate au tour precedent etait ACCIDENTEL \u2014\r\n             *   _completions1076 levait (pb1567), donc cette fonction levait aussi et\r\n             *   n'appliquait plus aucune couleur ; les regles CSS de surcharge\r\n             *   laissaient alors le titre a var(--via-etape-active-color), rouge.\r\n             *   Revert : window._viaPb1568Off = true.\r\n             * ============================================================ *\/\r\n            let cible = window._viaCibleProcess1091 || null;\r\n            \/* pb1586b : meme regle pour la couleur. pb1568 lui fait recalculer sa cible\r\n               a partir de `faits` \u2014 vides pendant la finalisation. On conserve alors la\r\n               cible en cours, comme le sequenceur (pb1586). *\/\r\n            \/* pb1587b : meme critere pour la couleur. *\/\r\n            var _avalC1586 = ['recapitulatif', 'references', 'paiement', 'validations', 'paiementFinal'];\r\n            var _sansItemC1587 = !this.state.itemActif;\r\n            var _geleC1586 = (window._viaPb1586Off === true)\r\n                ? false\r\n                : ((window._viaFinaliserClique === true ? _sansItemC1587 : false)\r\n                    ? (_avalC1586.indexOf(cible) !== -1)\r\n                    : false);\r\n            if (window._viaPb1568Off !== true ? !_geleC1586 : false) {\r\n                try {\r\n                    const _ordre1568 = (this.state.etapesConfig || [])\r\n                        .map(e => e.id).filter(id => faits.hasOwnProperty(id));\r\n                    const _c1568 = _ordre1568.find(id => !faits[id]);\r\n                    const _nouv1568 = _c1568 || 'recapitulatif';\r\n                    if (_nouv1568 !== cible) {\r\n                        if (window._viaSigCible1568 !== _nouv1568) {\r\n                            window._viaSigCible1568 = _nouv1568;\r\n                            console.log('[pb1568] cible couleur recalculee : ' + _nouv1568\r\n                                + ' (globale = ' + cible + ')');\r\n                        }\r\n                    }\r\n                    cible = _nouv1568;\r\n                } catch (_e1568) { console.warn('[pb1568] ' + _e1568.message); }\r\n            }\r\n            this.state.etapesConfig.forEach(e => {\r\n                let _c;\r\n                \/\/ pb1177b : couleurs des trois etats (demande user) \u2014\r\n                \/\/   active #fb5e2a | completee #7f7f7f | a venir #525252.\r\n                \/\/ ============================================================\r\n                \/\/ pb2140 : APRES LA CLOTURE COMMERCIALE, 'paiement' EST GRISEE.\r\n                \/\/   Demande JF : titre + chevron grises une fois l'etape fermee.\r\n                \/\/   griserEtape('paiement') est bien appele (pb2132\/pb2139), mais\r\n                \/\/   CE peintre tranche en DERNIER (pb1169) et rendait #fb5e2a :\r\n                \/\/   la cible vaut 'paiement', figee par pb2130. On corrige donc\r\n                \/\/   ici, au writer gagnant, plutot que d'ecrire une couleur de\r\n                \/\/   plus ailleurs (ce serait la configuration pb1045).\r\n                \/\/   Couleur = celle de l'etat COMPLETEE (#7f7f7f), la meme que\r\n                \/\/   toute etape faite : le parcours EST termine cote commercial.\r\n                \/\/   Drapeau pose par Mode_de_paiement (pb2140b), en window et non\r\n                \/\/   en sessionStorage (pb1220\/1222\/2050).\r\n                \/\/   Revert : window._viaPb2140Off = true.\r\n                \/\/ ============================================================\r\n                var _clos2140 = (window._viaPb2140Off === true)\r\n                    ? false\r\n                    : (window._viaCommercialTermine2140 === true ? (e.id === 'paiement') : false);\r\n                if (_clos2140) {\r\n                    _c = '#7f7f7f';\r\n                    if (window._viaSig2140 !== true) {\r\n                        window._viaSig2140 = true;\r\n                        console.log('[pb2140] cloture commerciale : titre + chevron paiement grises (#7f7f7f)');\r\n                    }\r\n                }\r\n                else if (e.id === cible) { _c = '#fb5e2a'; }\r\n                else if (faits[e.id]) { _c = '#7f7f7f'; }\r\n                else { _c = '#525252'; }\r\n                [e.titre, e.iconeUp, e.iconeDown].forEach(_sel => {\r\n                    if (!_sel) { return; }\r\n                    $(_sel).find('*').addBack().each(function () {\r\n                        this.style.setProperty('color', _c, 'important');\r\n                    });\r\n                });\r\n\r\n                \/\/ pb1203b : RETIRE. Le differe de pb1203 creait un setTimeout a chaque\r\n                \/\/   passage de _couleurEtapes1169 \u2014 appelee tres souvent \u2014 et la\r\n                \/\/   regression du tarif est reapparue avec lui. Un mecanisme qui\r\n                \/\/   accumule des timers ne peut pas etre neutre.\r\n                \/\/   Le titre du recapitulatif garde donc le bleu impose par le\r\n                \/\/   watchdog pb294, comme avant : c'est la seule etape qui ne suit pas\r\n                \/\/   la regle des trois etats, et cela reste sans consequence\r\n                \/\/   fonctionnelle.\r\n\r\n                \/\/ ================================================================\r\n                \/\/ pb1204 : invite du FORMAT en rouge quand l'etape est active.\r\n                \/\/   #ChoixFormatClassMessageCorailText suit l'etat de son titre :\r\n                \/\/   l'invite et le titre forment un tout.\r\n                \/\/   La couleur est posee EN INLINE sur l'element et ses descendants \u2014\r\n                \/\/   une simple classe ne suffit pas, une regle Elementor plus\r\n                \/\/   specifique l'emporte sur une feuille ajoutee.\r\n                \/\/   Revert : window._viaPb1204Off = true.\r\n                \/\/ ================================================================\r\n                \/\/ ================================================================\r\n                \/\/ pb1223 : #DureeMinimaleTexte en ROUGE quand l'etape DATES est active\r\n                \/\/   (demande user).\r\n                \/\/   Meme principe que pb1204 pour l'invite du format : le texte\r\n                \/\/   accompagne son titre, les deux changent d'etat ensemble.\r\n                \/\/   Couleur posee EN INLINE sur l'element et ses descendants \u2014 une\r\n                \/\/   feuille se fait battre par les regles Elementor, c'est ce qui\r\n                \/\/   avait fait echouer pb1198 et pb1214.\r\n                \/\/   Revert : window._viaPb1223Off = true.\r\n                \/\/ ================================================================\r\n                if (e.id === 'processDatesDevise' ? (window._viaPb1223Off !== true) : false) {\r\n                    var _dm1223 = document.getElementById('DureeMinimaleTexte')\r\n                        || document.querySelector('.DureeMinimaleTexte');\r\n                    if (_dm1223) {\r\n                        var _actifDates1223 = (e.id === cible);\r\n                        $(_dm1223).find('*').addBack().each(function () {\r\n                            if (_actifDates1223) {\r\n                                this.style.setProperty('color', '#fb5e2a', 'important');\r\n                            } else {\r\n                                this.style.removeProperty('color');\r\n                            }\r\n                        });\r\n                    }\r\n                }\r\n\r\n                if (e.id === 'choixFormat' ? (window._viaPb1204Off !== true) : false) {\r\n                    var _m1204 = document.getElementById('ChoixFormatClassMessageCorailText');\r\n                    if (_m1204) {\r\n                        var _actifFmt1204 = (e.id === cible);\r\n                        $(_m1204).find('*').addBack().each(function () {\r\n                            if (_actifFmt1204) {\r\n                                this.style.setProperty('color', '#fb5e2a', 'important');\r\n                            } else {\r\n                                this.style.removeProperty('color');\r\n                            }\r\n                        });\r\n                    }\r\n                }\r\n            });\r\n            \/\/ ================================================================\r\n            \/\/ ================================================================\r\n            \/\/ pb1183 : MASQUAGE DES ETAPES AVAL par CLASSE CSS, pas par JS repete.\r\n            \/\/   Constat user : malgre pb1181\/pb1182, les etapes Recapitulatif,\r\n            \/\/   References, Paiement, Validations et Bon de commande restent\r\n            \/\/   visibles tant qu'aucun espace n'est reserve.\r\n            \/\/   Le log explique pourquoi : pb1145\/pb1146 les masquent bien au\r\n            \/\/   depart, mais la boucle d'initialisation les rouvre ensuite\r\n            \/\/   (\"Titre ACTIF: references\", \"Titre ACTIF: paiement\"...), et\r\n            \/\/   d'autres writers font de meme au fil du parcours. Chaque fois que\r\n            \/\/   j'ecrivais display:none, quelqu'un repassait derriere.\r\n            \/\/   Une regle CSS, elle, ne s'oublie pas entre deux passes : elle\r\n            \/\/   s'applique en permanence, quel que soit l'ordre des writers. Les\r\n            \/\/   .show() de jQuery posent un display SANS !important : la feuille\r\n            \/\/   les bat.\r\n            \/\/   L'etat est porte par une classe sur <body>, posee\/retiree ici \u2014 un\r\n            \/\/   seul booleen a tenir, au lieu de cinq elements a surveiller.\r\n            \/\/   MOBILE uniquement, comme demande.\r\n            \/\/   Revert : window._viaPb1183Off = true.\r\n            \/\/ ================================================================\r\n            this._masqueAval1183(faits);\r\n            \/* pb2046 : la regle des trois etats gouverne desormais aussi\r\n               l'AFFICHAGE, pas seulement la couleur. Meme fonction, memes\r\n               `faits` et meme `cible` : un seul calcul, deux consequences.\r\n               Place APRES pb1183 pour que son retrait soit effectif d'abord. *\/\r\n            this._masqueAvenir2046(faits, cible);\r\n\r\n            \/\/ pb1252 : pb1248b RETIRE avec pb1248.\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1234 : +10px de marge haute et basse sur le CONTENEUR de l'etape\r\n            \/\/   active (demande user), desktop et mobile.\r\n            \/\/   Les conteneurs ne sont pas ceux d'etapesConfig : trois etapes\r\n            \/\/   partagent #Etape1Container alors qu'elles ont chacune leur propre\r\n            \/\/   bloc. La correspondance est donc donnee explicitement.\r\n            \/\/   La base est memorisee dans data-viamg1234 a la premiere rencontre,\r\n            \/\/   puis toujours relue depuis elle : le delta ne se cumule jamais,\r\n            \/\/   quel que soit le nombre de passages (lecon pb913\/pb1031).\r\n            \/\/   Un attribut plutot qu'une propriete JS : il survit a cloneNode.\r\n            \/\/   Revert : window._viaPb1234Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1234Off !== true) {\r\n                try {\r\n                    var _CONT1234 = {\r\n                        processAnnonceur:   '#ProcessAnnonceurEtape',\r\n                        associerPays:       '#PaysSecteursChildContainer',\r\n                        associerSecteur:    '#SecteurContainer',\r\n                        choixFormat:        '#FormatContainer',\r\n                        processDatesDevise: '#ProcessDatesDeviseEtape',\r\n                        pageWebMobile:      '#PageWebMobileEtape',\r\n                        pageWeb:            '#PageWebMobileEtape',\r\n                        recapitulatif:      '#EtapeRecapitulatif',\r\n                        references:         '#EtapeReferences',\r\n                        paiement:           '#EtapeModedePaiement',\r\n                        validations:        '#EtapeValidations',\r\n                        paiementFinal:      '#EtapePaiement'\r\n                    };\r\n                    var _cibleMg1234 = window._viaCibleProcess1091 || null;\r\n                    Object.keys(_CONT1234).forEach(function (_id1234) {\r\n                        var _el1234 = document.querySelector(_CONT1234[_id1234]);\r\n                        if (!_el1234) { return; }\r\n                        var _bt1234 = _el1234.getAttribute('data-viamgt1234');\r\n                        var _bb1234 = _el1234.getAttribute('data-viamgb1234');\r\n                        \/* ============================================================\r\n                         * pb1853 : LIRE LA FEUILLE, PAS L ETAT.\r\n                         *   Racine de tout l ecart d espacement regie \/ sites pays.\r\n                         *   pb1234 capturait la base par getComputedStyle SANS neutraliser\r\n                         *   l inline. Sur la regie ce passage tombait a un instant propre ;\r\n                         *   en popup, d autres writers avaient deja pose leurs inline, et\r\n                         *   c est CET ETAT qui etait fige \u2014 definitivement, l attribut\r\n                         *   n etant jamais relu ensuite.\r\n                         *   Releve pb1852 a l appui, meme feuille des deux cotes :\r\n                         *       noeud                       regie   pays\r\n                         *       ProcessAnnonceurEtape        10      20\r\n                         *       PaysSecteursChildContainer   16     -28\r\n                         *       SecteurContainer              9       3\r\n                         *       FormatContainer  mt           9      -8\r\n                         *       FormatContainer  mb         -35       0   <-- la croix du user\r\n                         *       ProcessDatesDeviseEtape      15       8\r\n                         *   Le -35 de FormatContainer annule sur la regie ses 21.5px de\r\n                         *   vide interne (hauteur 45 pour un contenu de 22, mesure pb1852).\r\n                         *   Cote pays la base vaut 0 : le vide reste, plus 7.2px de gap.\r\n                         *   Vingt-huit pixels de blanc, exactement ce qui est marque.\r\n                         *   On neutralise donc l inline le temps de la mesure, puis on le\r\n                         *   restitue a l identique, priorite comprise. La valeur lue est\r\n                         *   celle de la feuille \u2014 identique des deux cotes.\r\n                         *   RECAPTURE FORCEE : les bases corrompues sont deja figees dans\r\n                         *   le DOM et ne seraient jamais relues. data-viamg1853 sert de\r\n                         *   temoin de version : absent, on recapture une fois.\r\n                         *   pb1609 devient inerte de lui-meme \u2014 il ne mord que sur une\r\n                         *   marge haute negative, et il n y en aura plus. Rien a retirer.\r\n                         *   Revert : window._viaPb1853Off = true.\r\n                         * ============================================================ *\/\r\n                        if (window._viaPb1853Off !== true) {\r\n                            if (_el1234.getAttribute('data-viamg1866') === null) {\r\n                                _el1234.setAttribute('data-viamg1866', '1');\r\n                                if (_bt1234 !== null) {\r\n                                    console.log('[pb1855] ' + _id1234 + ' : base a reprendre'\r\n                                        + ' | ancienne ' + _bt1234 + '\/' + _bb1234);\r\n                                }\r\n                                _bt1234 = null;\r\n                                _bb1234 = null;\r\n                            }\r\n                        }\r\n                        \/* ============================================================\r\n                         * pb1855 : BASES DECLAREES, PLUS DE BASES CAPTUREES.\r\n                         *   La sonde pb1854 a tranche : \u00ab 0 regle(s) \u00bb sur CHAQUE noeud,\r\n                         *   des deux cotes. Aucune feuille CSS ne pose ces marges. Elles\r\n                         *   sont entierement pilotees par JS.\r\n                         *   Il n existe donc AUCUNE valeur de reference a retrouver : la\r\n                         *   base n etait que la photographie de ce qu un writer avait\r\n                         *   laisse en inline a l instant ou pb1234 passait pour la\r\n                         *   premiere fois. Cet instant differe entre regie et popup, d ou\r\n                         *   des bases differentes \u2014 et figees a vie, l attribut n etant\r\n                         *   jamais relu. pb1853 avait cherche l inline au mauvais moment ;\r\n                         *   il n y en avait plus quand il regardait.\r\n                         *   Releve pb1854, inline == calcule des deux cotes :\r\n                         *       noeud                      regie      pays\r\n                         *       ProcessAnnonceurEtape      10\/0       20\/0\r\n                         *       PaysSecteursChildContainer 16\/0      -28\/0\r\n                         *       SecteurContainer            9\/0        3\/0\r\n                         *       FormatContainer             9\/-35     -8\/0\r\n                         *       ProcessDatesDeviseEtape    15\/0        8\/0\r\n                         *   La regie rend juste : ses valeurs deviennent la table.\r\n                         *   Ce n est pas une couche de compensation \u2014 c est le\r\n                         *   remplacement d une capture indeterminee par une valeur\r\n                         *   declaree. Sur la regie la table redonne l existant a\r\n                         *   l identique : rien n y bouge.\r\n                         *   Le -35 de choixFormat n est pas decoratif : il annule les\r\n                         *   21.5px de vide interne mesures par pb1852 (hauteur 45 pour\r\n                         *   un contenu de 22). Son absence cote pays EST la premiere\r\n                         *   croix du user.\r\n                         *   Les noeuds hors table gardent la capture : rien ne prouve\r\n                         *   encore quelle valeur leur donner.\r\n                         *   pb1609 devient inerte : plus aucune base haute negative.\r\n                         *   Revert : window._viaPb1855Off = true.\r\n                         * ============================================================ *\/\r\n                        if (_bt1234 === null) {\r\n                            \/* ============================================================\r\n                             * pb1866 : LA TABLE pb1855 EST UNE REFERENCE DESKTOP.\r\n                             *   Constat JF : en mobile le resultat est moins bon qu avant.\r\n                             *   Normal \u2014 les valeurs 10\/16\/9\/9(-35)\/15 ont ete relevees sur la\r\n                             *   REGIE EN DESKTOP. Le mobile a un autre layout : une colonne,\r\n                             *   PageWebMobileEtape visible, hauteurs differentes. Rien ne dit\r\n                             *   que ces marges y soient justes, et pb1855 les appliquait\r\n                             *   pourtant sans distinction. C est la transposition de contexte\r\n                             *   de pb1471, commise une fois de plus.\r\n                             *   En mobile on retombe donc sur la capture getComputedStyle,\r\n                             *   c est-a-dire exactement le comportement d avant pb1855.\r\n                             *   Le temoin passe a data-viamg1866 pour forcer une reprise : les\r\n                             *   appareils mobiles ou pb1855 a deja tourne portent des bases\r\n                             *   desktop figees dans le DOM, elles ne se corrigeraient jamais.\r\n                             *   Critere outerWidth, convention du fichier (pb79, pb501, pb1096).\r\n                             *   Une table mobile viendra quand la regie mobile aura ete relevee.\r\n                             *   Revert : window._viaPb1866Off = true (table appliquee partout).\r\n                             * ============================================================ *\/\r\n                            var _deskRef1866 = (window.outerWidth >= 1000);\r\n                            if (window._viaPb1866Off === true) { _deskRef1866 = true; }\r\n                            if (window._viaPb1855Off === true) { _deskRef1866 = false; }\r\n                            if (!_deskRef1866) {\r\n                                if (window._viaSig1866 !== _id1234) {\r\n                                    window._viaSig1866 = _id1234;\r\n                                    console.log('[pb1866] mobile (outerWidth=' + window.outerWidth + ') :'\r\n                                        + ' table desktop NON appliquee sur ' + _id1234 + ' -> capture d origine');\r\n                                }\r\n                            }\r\n                            if (_deskRef1866) {\r\n                                var _REF1855 = {\r\n                                    processAnnonceur:   [10, 0],\r\n                                    associerPays:       [16, 0],\r\n                                    associerSecteur:    [9, 0],\r\n                                    choixFormat:        [9, -35],\r\n                                    processDatesDevise: [15, 0]\r\n                                };\r\n                                if (_REF1855[_id1234]) {\r\n                                    _bt1234 = String(_REF1855[_id1234][0]);\r\n                                    _bb1234 = String(_REF1855[_id1234][1]);\r\n                                    _el1234.setAttribute('data-viamgt1234', _bt1234);\r\n                                    _el1234.setAttribute('data-viamgb1234', _bb1234);\r\n                                    console.log('[pb1855] ' + _id1234 + ' base declaree = '\r\n                                        + _bt1234 + '\/' + _bb1234 + ' (reference regie)');\r\n                                }\r\n                            }\r\n                        }\r\n                        if (_bt1234 === null) {\r\n                            \/* pb1853 : neutralisation de l inline pendant la mesure. *\/\r\n                            var _svT1853 = '';\r\n                            var _svTp1853 = '';\r\n                            var _svB1853 = '';\r\n                            var _svBp1853 = '';\r\n                            if (window._viaPb1853Off !== true) {\r\n                                _svT1853  = _el1234.style.getPropertyValue('margin-top');\r\n                                _svTp1853 = _el1234.style.getPropertyPriority('margin-top');\r\n                                _svB1853  = _el1234.style.getPropertyValue('margin-bottom');\r\n                                _svBp1853 = _el1234.style.getPropertyPriority('margin-bottom');\r\n                                _el1234.style.removeProperty('margin-top');\r\n                                _el1234.style.removeProperty('margin-bottom');\r\n                            }\r\n                            var _cs1234 = window.getComputedStyle(_el1234);\r\n                            _bt1234 = String(parseFloat(_cs1234.marginTop) || 0);\r\n                            _bb1234 = String(parseFloat(_cs1234.marginBottom) || 0);\r\n                            if (window._viaPb1853Off !== true) {\r\n                                if (_svT1853) { _el1234.style.setProperty('margin-top', _svT1853, _svTp1853); }\r\n                                if (_svB1853) { _el1234.style.setProperty('margin-bottom', _svB1853, _svBp1853); }\r\n                                console.log('[pb1853] ' + _id1234 + ' base feuille = '\r\n                                    + _bt1234 + '\/' + _bb1234\r\n                                    + ' | inline neutralise pendant la mesure : '\r\n                                    + (_svT1853 || '(aucun)') + '\/' + (_svB1853 || '(aucun)'));\r\n                            }\r\n                            \/* pb1543b : la base de marge ne remonte jamais au-dessus du\r\n                               plus petit releve (cf. pb1543). Sans ce plancher, une mesure\r\n                               prise apres le +10 de l'etape active devient la base et\r\n                               l'ecart s'accumule a chaque rebasage. *\/\r\n                            \/* pb1544 : plancher desarme avec pb1543 \u2014 il figeait des\r\n                               marges negatives. window._viaPb1543On = true le remet. *\/\r\n                            var _loT = (window._viaPb1543On === true)\r\n                                ? _el1234.getAttribute('data-viamgt1234min') : null;\r\n                            if (_loT !== null ? (parseFloat(_loT) < parseFloat(_bt1234)) : false) {\r\n                                console.log('[pb1543] marge ramenee a ' + _loT + ' au lieu de ' + _bt1234\r\n                                    + ' | ' + (_el1234.id || '?'));\r\n                                _bt1234 = _loT;\r\n                                _bb1234 = _el1234.getAttribute('data-viamgb1234min') || _bb1234;\r\n                            }\r\n                            _el1234.setAttribute('data-viamgt1234', _bt1234);\r\n                            _el1234.setAttribute('data-viamgb1234', _bb1234);\r\n                        }\r\n                        var _delta1234 = (_id1234 === _cibleMg1234) ? 10 : 0;\r\n                        \/* ============================================================\r\n                         * pb1874 : PAS DE +10 SUR LE RECAPITULATIF EN MOBILE.\r\n                         *   Constat JF : sur mobile l etape recapitulatif est bien placee au\r\n                         *   repos \u2014 pb1872 et pb1873 l ont ramenee a 18 CSS sous les dates,\r\n                         *   la valeur du desktop \u2014 mais elle descend d une dizaine de pixels\r\n                         *   des qu elle devient active.\r\n                         *   Ce n est pas un ecrivain de plus : c est pb1234 lui-meme, dont la\r\n                         *   ligne au-dessus ajoute 10px de marge haute ET basse a l etape\r\n                         *   courante. Le releve le montrait deja sans que j y prete attention :\r\n                         *   cote regie, EtapeRecapitulatif affichait mt=10 mb=10 pour une base\r\n                         *   declaree a 0\/0.\r\n                         *   LE DELTA ENTIER EST ANNULE, pas seulement la moitie haute : ne\r\n                         *   retirer que le mt ferait remonter l etape tout en laissant les 10px\r\n                         *   du bas pousser ce qui suit. En annulant les deux, l activation ne\r\n                         *   deplace plus rien du tout, ce qui est exactement \u00ab compense \u00bb.\r\n                         *   RECAPITULATIF ET MOBILE SEULS : le +10 de pb1234 est une demande\r\n                         *   d origine, il reste en place pour toutes les autres etapes et sur\r\n                         *   desktop, ou aucun decalage n a ete signale.\r\n                         *   Revert : window._viaPb1874Off = true.\r\n                         * ============================================================ *\/\r\n                        if (window._viaPb1874Off !== true) {\r\n                            if (_id1234 === 'recapitulatif') {\r\n                                if (window.outerWidth < 1000) {\r\n                                    var _sig1874 = _id1234 + '|' + _delta1234;\r\n                                    if (window._viaSig1874 !== _sig1874) {\r\n                                        window._viaSig1874 = _sig1874;\r\n                                        console.log('[pb1874] mobile : recapitulatif '\r\n                                            + (_delta1234 ? 'ACTIF -> +10px annule' : 'inactif -> rien a annuler')\r\n                                            + ' | base ' + _bt1234 + '\/' + _bb1234);\r\n                                        \/* ============================================================\r\n                                         * pb1876 : RELEVE DETAILLE DE LA ZONE RECAPITULATIF.\r\n                                         *   \u00ab L ecart est encore trop important \u00bb : le +10 de pb1234\r\n                                         *   n etait donc pas le seul contributeur, et je n ai aucune\r\n                                         *   mesure de cette zone A L ETAT ACTIF \u2014 le releve pb1871\r\n                                         *   part avant que l utilisateur n active l etape.\r\n                                         *   On mesure ici les quatre segments qui composent l ecart,\r\n                                         *   plus la distance titre -> premiere carte, celle ou un\r\n                                         *   espace vient d apparaitre.\r\n                                         *   Differe de 350ms : les marges sont posees par plusieurs\r\n                                         *   passes, mesurer dans la foulee donnerait un etat\r\n                                         *   intermediaire \u2014 l erreur deja faite avec pb1870.\r\n                                         *   Valeurs RENDUES (echelle 0.9 en popup mobile) et valeurs\r\n                                         *   CSS cote a cote, sans aucune conversion.\r\n                                         * ============================================================ *\/\r\n                                        setTimeout(function () {\r\n                                            try {\r\n                                                var _q = function (s) { return document.querySelector(s); };\r\n                                                var _r = function (e) { return e ? e.getBoundingClientRect() : null; };\r\n                                                var _m = function (e, p) {\r\n                                                    if (!e) { return '?'; }\r\n                                                    return Math.round((parseFloat(window.getComputedStyle(e)[p]) || 0) * 10) \/ 10;\r\n                                                };\r\n                                                var _n = function (v) { return (v === null) ? '?' : Math.round(v * 10) \/ 10; };\r\n                                                var _dat = _q('#ProcessDatesDeviseEtape');\r\n                                                var _cd  = _q('#ColonneDroite');\r\n                                                var _er  = _q('#EtapeRecapitulatif');\r\n                                                var _ti  = _q('#RecapitulatifVosCommandestitreContainer');\r\n                                                var _ca  = _q('#EtapeRecapitulatif .CampagneTemplateClass');\r\n                                                var _rd = _r(_dat); var _rc = _r(_cd); var _re = _r(_er);\r\n                                                var _rt = _r(_ti); var _ra = _r(_ca);\r\n                                                console.log('[pb1876] SEGMENTS (rendus)'\r\n                                                    + ' | dates.bot->CD.top=' + ((_rd ? (_rc ? _n(_rc.top - _rd.bottom) : '?') : '?'))\r\n                                                    + ' | CD.top->ER.top=' + ((_rc ? (_re ? _n(_re.top - _rc.top) : '?') : '?'))\r\n                                                    + ' | ER.top->titre.top=' + ((_re ? (_rt ? _n(_rt.top - _re.top) : '?') : '?'))\r\n                                                    + ' | titre.bot->carte.top=' + ((_rt ? (_ra ? _n(_ra.top - _rt.bottom) : 'PAS DE CARTE') : '?'))\r\n                                                    + ' | TOTAL dates.bot->titre.top=' + ((_rd ? (_rt ? _n(_rt.top - _rd.bottom) : '?') : '?')));\r\n                                                console.log('[pb1876] CSS'\r\n                                                    + ' | ColonneDroite mt=' + _m(_cd, 'marginTop')\r\n                                                    + ' | EtapeRecap mt=' + _m(_er, 'marginTop') + ' mb=' + _m(_er, 'marginBottom')\r\n                                                    + ' pt=' + _m(_er, 'paddingTop') + ' pb=' + _m(_er, 'paddingBottom')\r\n                                                    + ' | titre mt=' + _m(_ti, 'marginTop') + ' mb=' + _m(_ti, 'marginBottom')\r\n                                                    + ' pt=' + _m(_ti, 'paddingTop') + ' pb=' + _m(_ti, 'paddingBottom')\r\n                                                    + ' h=' + (_rt ? _n(_rt.height) : '?')\r\n                                                    + ' | carte mt=' + _m(_ca, 'marginTop') + ' pt=' + _m(_ca, 'paddingTop'));\r\n                                                \/* ============================================================\r\n                                                 * pb1878 : TRACER LA CHAINE ENTRE LE TITRE ET LA PREMIERE CARTE.\r\n                                                 *   Le titre a bien remonte de 10px avec le margin-top, mais les\r\n                                                 *   cartes n ont pas bouge avec le margin-bottom. Ce mb n agit\r\n                                                 *   donc PAS sur elles \u2014 et il n agissait deja pas avant, ce qui\r\n                                                 *   invalide aussi l explication que j avais donnee du couple\r\n                                                 *   7\/-7 : les 29 pixels mesures entre titre.bot et carte.top\r\n                                                 *   viennent d ailleurs.\r\n                                                 *   Le titre et la carte ne sont visiblement pas freres : le\r\n                                                 *   margin-bottom du titre pousse son frere a lui, pas la carte.\r\n                                                 *   Plutot que d essayer un troisieme reglage, on remonte la\r\n                                                 *   chaine des ancetres de la carte jusqu a EtapeRecapitulatif et\r\n                                                 *   on journalise chaque niveau : le noeud qui porte les 29px se\r\n                                                 *   nommera de lui-meme.\r\n                                                 * ============================================================ *\/\r\n                                                if (_ca) {\r\n                                                    var _ch1878 = [];\r\n                                                    var _cur1878 = _ca;\r\n                                                    var _garde1878 = 0;\r\n                                                    while (_cur1878 ? (_garde1878 < 12) : false) {\r\n                                                        var _cs1878 = window.getComputedStyle(_cur1878);\r\n                                                        var _rr1878 = _cur1878.getBoundingClientRect();\r\n                                                        var _nom1878 = _cur1878.id ? ('#' + _cur1878.id) : ('.' + String(_cur1878.className || '?').split(' ').slice(0, 2).join('.'));\r\n                                                        var _prev1878 = _cur1878.previousElementSibling;\r\n                                                        var _pn1878 = '-';\r\n                                                        if (_prev1878) {\r\n                                                            _pn1878 = _prev1878.id ? ('#' + _prev1878.id) : ('.' + String(_prev1878.className || '?').split(' ')[0]);\r\n                                                            _pn1878 = _pn1878 + '(bot=' + _n(_prev1878.getBoundingClientRect().bottom) + ')';\r\n                                                        }\r\n                                                        _ch1878.push('  ' + _garde1878 + ' ' + _nom1878\r\n                                                            + ' top=' + _n(_rr1878.top)\r\n                                                            + ' mt=' + _m(_cur1878, 'marginTop')\r\n                                                            + ' mb=' + _m(_cur1878, 'marginBottom')\r\n                                                            + ' pt=' + _m(_cur1878, 'paddingTop')\r\n                                                            + ' gap=' + (_cs1878.rowGap || _cs1878.gap || '-')\r\n                                                            + ' disp=' + _cs1878.display\r\n                                                            + ' | frere precedent : ' + _pn1878);\r\n                                                        if (_cur1878.id === 'EtapeRecapitulatif') { break; }\r\n                                                        _cur1878 = _cur1878.parentElement;\r\n                                                        _garde1878 = _garde1878 + 1;\r\n                                                    }\r\n                                                    console.log('[pb1878] chaine carte -> EtapeRecapitulatif (du bas vers le haut) :'\r\n                                                        + String.fromCharCode(10) + _ch1878.join(String.fromCharCode(10)));\r\n                                                } else {\r\n                                                    console.log('[pb1878] SORTIE : aucune .CampagneTemplateClass dans #EtapeRecapitulatif');\r\n                                                }\r\n                                            } catch (_e1876) { console.log('[pb1876] releve impossible : ' + _e1876.message); }\r\n                                        }, 350);\r\n                                    }\r\n                                    _delta1234 = 0;\r\n                                }\r\n                            }\r\n                        }\r\n                        \/* pb1601b : pb1558 RETIRE. Il ramenait a 0 les marges hautes\r\n                           negatives ; sans le rebasage qui les creait, il n'a plus d'objet.\r\n                           Une compensation de moins a maintenir. *\/\r\n                        var _mgt1234 = parseFloat(_bt1234) + _delta1234;\r\n                        \/* ============================================================\r\n                         * pb1609 : SECOND ECRIVAIN NOMME PAR LE PIEGE pb1607.\r\n                         *   Pile livree : \u00ab PaysSecteursChildContainer <- margin-top -28px \u00bb\r\n                         *   et \u00ab FormatContainer <- margin-top -8px \u00bb, at _couleurEtapes1169\r\n                         *   \u2014 c'est-a-dire ce bloc pb1234.\r\n                         *   CE COMMENTAIRE ETAIT FAUX, corrige par pb1853 : il affirmait que\r\n                         *   ces bases venaient du CSS du site pays. La sonde TABLE-REF puis\r\n                         *   pb1852 ont montre que la FEUILLE est identique des deux cotes \u2014\r\n                         *   le popup charge d ailleurs la page regie. Les -28 et -8 n etaient\r\n                         *   pas des valeurs CSS mais des CAPTURES CORROMPUES, prises apres\r\n                         *   qu un autre writer avait pose son inline. pb1853 corrige la\r\n                         *   lecture ; ce bloc-ci ne devrait donc plus jamais se declencher.\r\n                         *   En popup, une marge haute negative n'a pas de sens sur un\r\n                         *   conteneur d'etape : on la ramene a 0. Les marges BASSES ne sont\r\n                         *   pas touchees (-35 sur FormatContainer existe aussi sur la regie).\r\n                         *   Revert : window._viaPb1609Off = true.\r\n                         * ============================================================ *\/\r\n                        var _mtF1609 = _mgt1234;\r\n                        if (window._viaPb1609Off !== true ? (_mgt1234 < 0) : false) {\r\n                            try {\r\n                                if (new URLSearchParams(window.location.hash.substring(1)\r\n                                    || window.location.search).get('mode') === 'popup') {\r\n                                    if (window._viaSig1609 !== _id1234) {\r\n                                        window._viaSig1609 = _id1234;\r\n                                        console.log('[pb1609] ' + _id1234 + ' : marge haute '\r\n                                            + _mgt1234 + 'px ramenee a 0 (popup pleine largeur)');\r\n                                    }\r\n                                    _mtF1609 = 0;\r\n                                }\r\n                            } catch (_e1609) { _mtF1609 = _mgt1234; }\r\n                        }\r\n                        \/* ============================================================\r\n                         * pb1989 : #EtapeRecapitulatif REMONTE DE 15px APRES\r\n                         *   FINALISATION, SITE PAYS MOBILE SEULEMENT.\r\n                         *   Demande JF : \u00ab site pays mobile uniquement, quand les\r\n                         *   reservations sont finalisees (clic sur FinaliserBouton),\r\n                         *   remonter l'etape Vos reservations de 15px \u00bb.\r\n                         *   PAS D'ECRIVAIN DE PLUS. La marge haute de\r\n                         *   #EtapeRecapitulatif a deja son ecrivain : c'est la ligne\r\n                         *   juste en dessous, pb1234, qui la pose pour les douze\r\n                         *   conteneurs d'etape. Poser un second setProperty ailleurs,\r\n                         *   ou un veilleur, aurait cree une valeur a deux ecrivains \u2014\r\n                         *   et pb1234 passe tres souvent, il aurait gagne une fois sur\r\n                         *   deux. Le -15 est donc un TERME de plus dans le calcul de\r\n                         *   cet ecrivain, applique au dernier moment.\r\n                         *   APRES pb1609, PAS AVANT : pb1609 ramene a 0 toute marge\r\n                         *   haute negative en mode popup. Or c'est exactement le mode\r\n                         *   ou cette demande s'applique, et la base du recapitulatif\r\n                         *   est proche de zero : place avant, le -15 aurait ete rabote\r\n                         *   sans bruit. pb1609 protege contre une base corrompue,\r\n                         *   celui-ci execute une demande \u2014 ils ne se contredisent pas,\r\n                         *   ils s'ordonnent.\r\n                         *   LA BASE N'EST PAS TOUCHEE : data-viamgt1234 reste l'origine,\r\n                         *   le terme est recalcule a chaque passage depuis elle. Aucun\r\n                         *   cumul possible, quel que soit le nombre d'appels.\r\n                         *   LES TROIS DISCRIMINANTS SONT NOMMES, aucun n'est devine\r\n                         *   (regle 5.3, celle que pb1988 vient de payer) :\r\n                         *     site pays -> body.via-popup-achat, posee uniquement dans\r\n                         *                  l'iframe du popup d'achat pays (cf. pb220,\r\n                         *                  l.971 de ce fichier). La regie ne l'a pas.\r\n                         *     mobile    -> outerWidth < 1000, le meme seuil et la meme\r\n                         *                  propriete que pb1874 vingt lignes plus haut ;\r\n                         *                  innerWidth vaut 0 dans une iframe masquee.\r\n                         *     finalise  -> l'idiome de pb1720 : le drapeau de fenetre\r\n                         *                  d'abord, sessionStorage FinaliserStep ensuite,\r\n                         *                  qui survit a un re-rendu de l'iframe.\r\n                         *   Les trois sont relus A CHAQUE PASSAGE, jamais figes (regle\r\n                         *   5.4) : l'utilisateur finalise longtemps apres le chargement.\r\n                         *   Une seule ligne de log par changement d'etat, motif de refus\r\n                         *   compris (regle 5.2) : cette fonction passe trop souvent pour\r\n                         *   journaliser chaque tour.\r\n                         *   Reglage : window._viaPb1989Delta = 20\r\n                         *   Revert  : window._viaPb1989Off = true\r\n                         * ============================================================ *\/\r\n                        var _mtF1989 = _mtF1609;\r\n                        if (window._viaPb1989Off !== true) {\r\n                            if (_id1234 === 'recapitulatif') {\r\n                                var _pays1989 = document.body\r\n                                    ? document.body.classList.contains('via-popup-achat')\r\n                                    : false;\r\n                                var _mob1989 = (window.outerWidth < 1000);\r\n                                var _fin1989 = false;\r\n                                try {\r\n                                    _fin1989 = (window._viaFinaliserClique === true)\r\n                                        ? true\r\n                                        : (sessionStorage.getItem('FinaliserStep') === 'Yes');\r\n                                } catch (_eS1989) {\r\n                                    _fin1989 = (window._viaFinaliserClique === true);\r\n                                }\r\n                                var _d1989 = (typeof window._viaPb1989Delta === 'number')\r\n                                    ? window._viaPb1989Delta : 15;\r\n                                var _ok1989 = false;\r\n                                if (_pays1989) {\r\n                                    if (_mob1989) {\r\n                                        if (_fin1989) { _ok1989 = true; }\r\n                                    }\r\n                                }\r\n                                if (_ok1989) { _mtF1989 = _mtF1609 - _d1989; }\r\n                                var _sig1989 = (_pays1989 ? 'P' : '-')\r\n                                    + (_mob1989 ? 'M' : '-')\r\n                                    + (_fin1989 ? 'F' : '-') + '|' + _mtF1989;\r\n                                if (window._viaSig1989 !== _sig1989) {\r\n                                    window._viaSig1989 = _sig1989;\r\n                                    console.log('[pb1989] #EtapeRecapitulatif : '\r\n                                        + (_ok1989\r\n                                            ? ('remonte de ' + _d1989 + 'px | mt '\r\n                                                + _mtF1609 + ' -> ' + _mtF1989)\r\n                                            : 'inchange')\r\n                                        + ' | pays=' + _pays1989 + ' mobile=' + _mob1989\r\n                                        + ' (outerW=' + window.outerWidth + ')'\r\n                                        + ' finalise=' + _fin1989\r\n                                        + ' | base ' + _bt1234 + ' delta1234 ' + _delta1234);\r\n                                }\r\n                            }\r\n                        }\r\n                        \/* ====================================================================\r\n                         * pb1996 : LA MARGE NE POUVAIT RIEN POUSSER \u2014 FUSION DES MARGES.\r\n                         *   Capture HTML de JF, sur PM-pb1995d :\r\n                         *     #EtapeRecapitulatif  style=\"... margin-top: 11px !important ...\"\r\n                         *   L'ecriture avait donc bien lieu, aux trois paliers, et rien ne\r\n                         *   bougeait. Le voisinage explique tout :\r\n                         *     #ColonneDroite   display: block !important ; margin-top: 18px\r\n                         *       #PageWebMobileEtape   display: none !important   <- hors flux\r\n                         *       #EtapeRecapitulatif   margin-top: 11px\r\n                         *   Le premier frere etant hors flux, le recapitulatif est le PREMIER\r\n                         *   ENFANT EN FLUX de la colonne. Sa marge haute fusionne donc avec\r\n                         *   celle du parent, et la marge resultante vaut max(18, 11) = 18 :\r\n                         *   exactement ce qui etait deja la. 5, 8 et 11 donnaient le meme\r\n                         *   resultat, et c'est pourquoi aucun palier ne se voyait.\r\n                         *   POURQUOI ICI ET PAS AILLEURS : la fusion suppose que le parent\r\n                         *   n'etablit pas de contexte de formatage. #ColonneDroite en avait\r\n                         *   un tant qu'il portait overflow auto\/hidden ; pb1689 l'a passe a\r\n                         *   overflow-x: clip \/ overflow-y: visible pour supprimer la seconde\r\n                         *   barre de defilement \u2014 et clip, contrairement a hidden, n'etablit\r\n                         *   PAS de contexte. La fusion est un effet de bord de pb1689,\r\n                         *   invisible jusqu'a ce qu'on essaie d'y poser une marge.\r\n                         *   LE PADDING NE FUSIONNE JAMAIS. C'est le bon levier, et il a\r\n                         *   deja son ecrivain : pb1581 pose padding-top INLINE sur\r\n                         *   #EtapeRecapitulatif, en lisant la variable --via-padtop-1580\r\n                         *   (defaut 0 en popup desktop depuis pb1868\/pb1872). On ne pose\r\n                         *   donc pas un second inline \u2014 on ecrit la VARIABLE et on rappelle\r\n                         *   l'ecrivain, window._viaPadTopRecap1581, qu'il expose exactement\r\n                         *   pour ca. Un seul ecrivain du padding, avant comme apres.\r\n                         *   RETOUR AUTOMATIQUE : quand l'etape n'est plus a faire, la\r\n                         *   variable est RETIREE et l'ecrivain retombe sur son defaut. Rien\r\n                         *   a memoriser, rien a soustraire, aucun cumul possible.\r\n                         *   Ecriture idempotente : on ne rappelle l'ecrivain que si la\r\n                         *   valeur change (lecon pb1971 \u2014 pb1234 repasse en continu).\r\n                         *   Reglage : window._viaPb1995Delta = 14\r\n                         *   Revert  : window._viaPb1995Off = true\r\n                         * ==================================================================== *\/\r\n                        if (window._viaPb1995Off !== true) {\r\n                            if (_id1234 === 'recapitulatif') {\r\n                                var _d1996 = 0;\r\n                                \/* pb2045 : appel garde. Une fonction absente ici\r\n                                   levait une TypeError qui emportait tout le bloc,\r\n                                   pb1989 compris. Deux des cinq appels l'etaient\r\n                                   deja ; les trois autres ne l'etaient pas, sans\r\n                                   raison. La garde ne masque pas l'absence : elle\r\n                                   la journalise une fois. *\/\r\n                                if (typeof window._viaPaysDesktop1994 !== 'function') {\r\n                                    if (!window._viaDit2045) {\r\n                                        window._viaDit2045 = true;\r\n                                        console.warn('[pb2045] _viaPaysDesktop1994 absente'\r\n                                            + ' -> pb1996 neutralise (pb1989 preserve)');\r\n                                    }\r\n                                }\r\n                                if ((typeof window._viaPaysDesktop1994 === 'function')\r\n                                        ? window._viaPaysDesktop1994() : false) {\r\n                                    if ((typeof window._viaRecapAFaire1994 === 'function')\r\n                                            ? window._viaRecapAFaire1994() : false) {\r\n                                        \/* pb1996b : 3 px vers le HAUT demandes une fois\r\n                                           le decalage visible, soit 11 - 3 = 8. Paliers,\r\n                                           tous sur le seul defaut : pb1995 +5, pb1995b\r\n                                           +8 et pb1995c +11 etaient poses en MARGE et\r\n                                           n ont donc rien produit (fusion, voir ci-\r\n                                           dessus) ; pb1996 +11 en PADDING a enfin agi,\r\n                                           pb1996b le ramene a 8. *\/\r\n                                        _d1996 = (typeof window._viaPb1995Delta === 'number')\r\n                                            ? window._viaPb1995Delta : 8;\r\n                                    }\r\n                                }\r\n                                var _vou1996 = (_d1996 > 0) ? (_d1996 + 'px') : '';\r\n                                var _cur1996 = document.documentElement.style\r\n                                    .getPropertyValue('--via-padtop-1580');\r\n                                if (_cur1996 !== _vou1996) {\r\n                                    if (_vou1996) {\r\n                                        document.documentElement.style\r\n                                            .setProperty('--via-padtop-1580', _vou1996);\r\n                                    } else {\r\n                                        document.documentElement.style\r\n                                            .removeProperty('--via-padtop-1580');\r\n                                    }\r\n                                    if (typeof window._viaPadTopRecap1581 === 'function') {\r\n                                        var _r1996 = window._viaPadTopRecap1581();\r\n                                        console.log('[pb1996] #EtapeRecapitulatif : padding-top'\r\n                                            + ' \"' + (_cur1996 || 'defaut') + '\" -> \"'\r\n                                            + (_vou1996 || 'defaut') + '\" | ' + _r1996\r\n                                            + ' | a faire='\r\n                                            + ((typeof window._viaRecapAFaire1994 === 'function')\r\n                                                ? window._viaRecapAFaire1994() : 'absente')\r\n                                            + ' pays-desktop='\r\n                                            + ((typeof window._viaPaysDesktop1994 === 'function')\r\n                                                ? window._viaPaysDesktop1994() : 'absente'));\r\n                                    } else {\r\n                                        \/* Aucune sortie muette : sans l'ecrivain de\r\n                                           yearbook-media.js, la variable seule ne peut pas\r\n                                           battre le padding inline deja pose (lecon pb1581). *\/\r\n                                        console.warn('[pb1996] variable posee a \"'\r\n                                            + (_vou1996 || 'defaut') + '\" mais'\r\n                                            + ' _viaPadTopRecap1581 est absente : le padding'\r\n                                            + ' inline de pb1581 reste en place');\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n                        \/* ============================================================\r\n                         * pb2410 : EN 3 COLONNES DESKTOP, REMONTER DEUX ETAPES\r\n                         *   (demande JF, 12\/09\/2026) :\r\n                         *     #ProcessDatesDeviseEtape  -10px\r\n                         *     #SecteurContainer          -5px\r\n                         *   PAS D'ECRIVAIN DE PLUS (motif pb1989, quinze lignes plus\r\n                         *   haut) : la marge haute de ces deux conteneurs a deja son\r\n                         *   ecrivain, c'est pb1234 \u2014 la ligne juste en dessous. Un\r\n                         *   second setProperty ailleurs, ou un veilleur, aurait cree\r\n                         *   une valeur a deux ecrivains, et pb1234 passe toutes les\r\n                         *   400 ms (veilleur pb1076 -> marquerEtapeEnCours) : il\r\n                         *   aurait gagne une fois sur deux. Le decalage est donc un\r\n                         *   TERME de plus dans le calcul, applique au dernier moment.\r\n                         *   APRES pb1609 ET pb1989, comme pb1989 l'est apres pb1609 :\r\n                         *   ces deux-la protegent ou executent sur d'autres criteres,\r\n                         *   ils ne se contredisent pas, ils s'ordonnent. Les bases\r\n                         *   desktop viennent de _REF1855 (9 pour associerSecteur,\r\n                         *   15 pour processDatesDevise) : apres retrait elles restent\r\n                         *   positives, aucun ecretage possible.\r\n                         *   LA BASE N'EST PAS TOUCHEE : data-viamgt1234 reste\r\n                         *   l'origine, le terme est recalcule a chaque passage depuis\r\n                         *   elle. Aucun cumul, quel que soit le nombre d'appels.\r\n                         *   LES DEUX DISCRIMINANTS SONT NOMMES (regle 5.3), aucun\r\n                         *   n'est devine :\r\n                         *     desktop   -> outerWidth >= 1000, convention du fichier\r\n                         *                  (pb79, pb501, pb1096, pb1866, pb1874,\r\n                         *                  pb1989) ; innerWidth vaut 0 en iframe.\r\n                         *     3 colonnes -> window._viaMode3col943(), LA definition du\r\n                         *                  projet (pb943\/pb945), deja partagee par\r\n                         *                  pb1327, pb1399 et pb1400. On ne la reecrit\r\n                         *                  pas ici : body.via-mode-3col n'est pas\r\n                         *                  toujours posee \u2014 sur la regie les colonnes\r\n                         *                  sortent en popups et c'est via-layout-open\r\n                         *                  qui marque l'ouverture.\r\n                         *   Les deux sont relus A CHAQUE PASSAGE, jamais figes\r\n                         *   (regle 5.4) : ouvrir ou fermer les 3 colonnes se repercute\r\n                         *   de soi-meme en 400 ms au plus.\r\n                         *   REPLI NOMME, jamais muet : sans _viaMode3col943 (absence\r\n                         *   de yearbook-media.js), aucun decalage n'est applique et le\r\n                         *   fait est journalise une fois.\r\n                         *   Une seule ligne de log par changement d'etat, motif de\r\n                         *   refus compris (regle 5.2) : cette fonction passe trop\r\n                         *   souvent pour journaliser chaque tour.\r\n                         *   Reglage : window._viaPb2410Deltas =\r\n                         *               { processDatesDevise: 10, associerSecteur: 5 }\r\n                         *   Revert  : window._viaPb2410Off = true\r\n                         * ============================================================ *\/\r\n                        var _mtF2410 = _mtF1989;\r\n                        if (window._viaPb2410Off !== true) {\r\n                            var _DEF2410 = { processDatesDevise: 10, associerSecteur: 5 };\r\n                            if (_DEF2410.hasOwnProperty(_id1234)) {\r\n                                var _kn2410 = window._viaPb2410Deltas || {};\r\n                                var _d2410 = (typeof _kn2410[_id1234] === 'number')\r\n                                    ? _kn2410[_id1234] : _DEF2410[_id1234];\r\n                                var _desk2410 = (window.outerWidth >= 1000);\r\n                                var _fn2410 = (typeof window._viaMode3col943 === 'function');\r\n                                var _col2410 = _fn2410 ? window._viaMode3col943() : false;\r\n                                var _ok2410 = _desk2410 ? _col2410 : false;\r\n                                if (_ok2410) { _mtF2410 = _mtF1989 - _d2410; }\r\n                                var _sig2410 = _id1234 + '|' + (_desk2410 ? 'D' : '-')\r\n                                    + (_fn2410 ? (_col2410 ? '3' : '1') : '?') + '|' + _mtF2410;\r\n                                if (window._viaSig2410 !== _sig2410) {\r\n                                    window._viaSig2410 = _sig2410;\r\n                                    console.log('[pb2410] ' + _id1234 + ' : '\r\n                                        + (_ok2410\r\n                                            ? ('remonte de ' + _d2410 + 'px | mt '\r\n                                                + _mtF1989 + ' -> ' + _mtF2410)\r\n                                            : ('aucun decalage | mt ' + _mtF2410))\r\n                                        + ' | outerWidth=' + window.outerWidth\r\n                                        + ' (' + (_desk2410 ? 'desktop' : 'mobile') + ')'\r\n                                        + ' | 3 colonnes=' + (_fn2410\r\n                                            ? (_col2410 ? 'oui' : 'non')\r\n                                            : '_viaMode3col943 ABSENTE -> repli sans decalage'));\r\n                                }\r\n                            }\r\n                        }\r\n                        _el1234.style.setProperty('margin-top', _mtF2410 + 'px', 'important');\r\n                        _el1234.style.setProperty('margin-bottom',\r\n                            (parseFloat(_bb1234) + _delta1234) + 'px', 'important');\r\n                    });\r\n                } catch (_e1234) {}\r\n            }\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1219 : SCROLL EN BAS a l'ouverture de l'etape PAIEMENT (demande user).\r\n            \/\/   Le popup a sa propre zone scrollable (.via-col-popup-body) : c'est\r\n            \/\/   elle qu'il faut faire defiler. Le popup est en position:fixed, un\r\n            \/\/   scroll de la fenetre n'aurait aucun effet sur son contenu.\r\n            \/\/   Declenche une SEULE FOIS par arrivee sur l'etape : cette fonction\r\n            \/\/   passe tres souvent, defiler a chaque passage empecherait\r\n            \/\/   l'utilisateur de remonter dans le popup. Le drapeau se rearme des\r\n            \/\/   qu'on quitte l'etape, donc un retour ulterieur redeclenche le scroll.\r\n            \/\/   Differe de 250 ms : l'etape vient d'etre revelee par pb1213, sa\r\n            \/\/   hauteur n'est pas encore prise en compte dans scrollHeight.\r\n            \/\/   Repli sur scrollIntoView si le popup n'est pas trouve \u2014 cas du\r\n            \/\/   process affiche hors popup.\r\n            \/\/   Revert : window._viaPb1219Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1219Off !== true) {\r\n                try {\r\n                    var _surPaiement1219 = (window._viaCibleProcess1091 === 'paiementFinal');\r\n                    if (_surPaiement1219 ? !window._viaScrollFait1219 : false) {\r\n                        window._viaScrollFait1219 = true;\r\n                        setTimeout(function () {\r\n                            try {\r\n                                var _eP1219 = document.getElementById('EtapePaiement');\r\n                                var _body1219 = (_eP1219 ? _eP1219.closest('.via-col-popup-body') : null)\r\n                                    || document.querySelector('.via-col-popup-body');\r\n                                if (_body1219) {\r\n                                    _body1219.scrollTop = _body1219.scrollHeight;\r\n                                    console.log('[pb1219] \u00e9tape Paiement ouverte -> scroll en bas du popup');\r\n                                } else if (_eP1219) {\r\n                                    _eP1219.scrollIntoView({ block: 'end' });\r\n                                    console.log('[pb1219] \u00e9tape Paiement ouverte -> scrollIntoView');\r\n                                }\r\n                            } catch (_e) {}\r\n                        }, 250);\r\n                    }\r\n                    if (!_surPaiement1219) { window._viaScrollFait1219 = false; }\r\n                } catch (_e1219) {}\r\n            }\r\n\r\n            \/\/ ================================================================\r\n            \/\/ pb1218 : CENTRAGE de l'etape Validations, pose EN INLINE.\r\n            \/\/   Deux tentatives par feuille CSS (pb1194, pb1214) sont restees sans\r\n            \/\/   effet. Le style inline est la seule ecriture qui ait fonctionne dans\r\n            \/\/   ce projet face aux regles d'Elementor \u2014 c'est ce qui a resolu la\r\n            \/\/   couleur des titres (pb1174b) et l'invite du format (pb1204).\r\n            \/\/   Structure ciblee, d'apres le HTML : #ValidationsConteneur est en\r\n            \/\/   display:block INLINE (les proprietes flex y sont inertes) ; le\r\n            \/\/   contenu vit dans #ValidationsSubConteneur, en flex.\r\n            \/\/   On centre donc le SubConteneur en flex, et on donne aux widgets une\r\n            \/\/   largeur ajustee au contenu avec marges automatiques : le bloc se\r\n            \/\/   centre sans centrer chaque ligne, ce qui resterait lisible pour des\r\n            \/\/   libelles de cases a cocher.\r\n            \/\/   Revert : window._viaPb1218Off = true.\r\n            \/\/ ================================================================\r\n            if (window._viaPb1218Off !== true) {\r\n                try {\r\n                    \/\/ pb1218b : PLUS DE fit-content \u2014 le bloc est centre par le flex.\r\n                    \/\/   Constat user (capture) : \"(voir CGV)\" s'affiche lettre par\r\n                    \/\/   lettre a la verticale. C'est fit-content qui comprime ces\r\n                    \/\/   conteneurs a la largeur du mot le plus court ; le texte ne\r\n                    \/\/   trouve plus la place de tenir sur une ligne.\r\n                    \/\/   #ValidationsSubConteneur est un flex en COLONNE : align-items\r\n                    \/\/   center suffit a centrer chaque enfant selon sa largeur\r\n                    \/\/   naturelle. fit-content etait non seulement inutile, mais\r\n                    \/\/   nuisible.\r\n                    \/\/   Le texte reste aligne a GAUCHE a l'interieur des blocs\r\n                    \/\/   (demande user) : seuls les blocs sont centres, pas leur\r\n                    \/\/   contenu ligne a ligne.\r\n                    var _sub1218 = document.getElementById('ValidationsSubConteneur');\r\n                    if (_sub1218) {\r\n                        _sub1218.style.setProperty('align-items', 'center', 'important');\r\n                        _sub1218.style.setProperty('justify-content', 'center', 'important');\r\n                        var _kids1218 = _sub1218.children;\r\n                        for (var _k1218 = 0; _k1218 < _kids1218.length; _k1218++) {\r\n                            var _w1218 = _kids1218[_k1218];\r\n                            _w1218.style.removeProperty('width');\r\n                            _w1218.style.removeProperty('max-width');\r\n                            _w1218.style.removeProperty('margin-left');\r\n                            _w1218.style.removeProperty('margin-right');\r\n                            _w1218.style.setProperty('text-align', 'left', 'important');\r\n                        }\r\n                        var _grp1218 = _sub1218.querySelectorAll(\r\n                            '.elementor-form-fields-wrapper, .elementor-field-group');\r\n                        for (var _g1218 = 0; _g1218 < _grp1218.length; _g1218++) {\r\n                            _grp1218[_g1218].style.removeProperty('width');\r\n                            _grp1218[_g1218].style.removeProperty('max-width');\r\n                            _grp1218[_g1218].style.removeProperty('margin-left');\r\n                            _grp1218[_g1218].style.removeProperty('margin-right');\r\n                            _grp1218[_g1218].style.removeProperty('justify-content');\r\n                            _grp1218[_g1218].style.setProperty('text-align', 'left', 'important');\r\n                        }\r\n                    }\r\n                } catch (_e1218) {}\r\n            }\r\n\r\n            \/\/ pb1176 : RECALCULER LES TAILLES juste apres les couleurs.\r\n            \/\/   Constat user (HTML) : les couleurs sont desormais justes, mais les\r\n            \/\/   tailles restent inversees \u2014 l'etape active a 13.95px (reduite) et\r\n            \/\/   l'annonceur, complete, garde 14.45px.\r\n            \/\/   Cause : pb913 tourne sur son propre timer (500ms). Il lit la classe\r\n            \/\/   via-etape-en-cours a SON rythme, donc parfois avant que\r\n            \/\/   marquerEtapeEnCours ne l'ait deplacee : il applique alors la regle a\r\n            \/\/   l'ancienne etape active, et ne repasse pas ensuite puisque rien ne le\r\n            \/\/   redeclenche.\r\n            \/\/   La taille depend du meme etat que la couleur : elle doit etre\r\n            \/\/   recalculee au meme moment. On appelle donc pb913 ici, juste apres\r\n            \/\/   avoir pose les couleurs \u2014 la classe est alors a jour.\r\n            \/\/   _appliquer913 est idempotent (il repart toujours de _viaFsBase913) :\r\n            \/\/   l'appeler plus souvent ne cumule rien.\r\n            \/\/ ================================================================\r\n            if (typeof window._viaAppliquerTailleTitres913 === 'function') {\r\n                try { window._viaAppliquerTailleTitres913(); } catch (_e1176) {}\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.10 : Grise toutes les \u00e9tapes jusqu'\u00e0 une \u00e9tape donn\u00e9e (INCLUSE)\r\n         * @param {string} etapeIdFin - ID de l'\u00e9tape jusqu'\u00e0 laquelle griser (INCLUSE)\r\n         *\/\r\n        griserEtapesJusquA(etapeIdFin) {\r\n            if (!this.state.etapesConfig) return;\r\n            \r\n            console.log('\ud83d\udd18 Griser toutes les \u00e9tapes jusqu\\'\u00e0 (inclus):', etapeIdFin);\r\n            \r\n            for (const etape of this.state.etapesConfig) {\r\n                this.griserEtape(etape.id);\r\n                if (etape.id === etapeIdFin) {\r\n                    break; \/\/ Arr\u00eater APR\u00c8S avoir gris\u00e9 l'\u00e9tape de fin\r\n                }\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * G\u00e8re le mode r\u00e9duit\/\u00e9tendu des commandes apr\u00e8s finalisation\r\n         * \u2705 v1.7 : Ne plus masquer les croix de suppression\r\n         *\/\r\n        gererModeFinalisationCommandes() {\r\n            const finaliserStep = sessionStorage.getItem('FinaliserStep');\r\n            \r\n            if (finaliserStep === 'Yes') {\r\n                console.log('\ud83d\udd12 Mode finalisation activ\u00e9');\r\n                \r\n                \/\/ \u2705 Sur desktop, ne rien masquer\r\n                const isMobile = window.innerWidth <= 767;\r\n                \r\n                if (isMobile) {\r\n                    \/\/ \u2705 v1.8 : Garder #Etape1Container visible pour afficher le titre et message\r\n                    \/\/ Masquer seulement le formulaire #ProcessAchatInside\r\n                    $('#Etape1Container').show();\r\n                    $('#ProcessAchatInside').hide();\r\n                    if (window.location.search.indexOf('mode=popup') === -1) {\r\n                        var _e1c = document.getElementById('Etape1MessageContainer');\r\n                        var _e1t = document.getElementById('Etape1MessageTexte');\r\n                        if (_e1c) { _e1c.classList.remove('elementor-hidden-desktop','elementor-hidden-tablet','elementor-hidden-mobile'); _e1c.style.setProperty('display','block','important'); }\r\n                        if (_e1t) { _e1t.classList.remove('elementor-hidden-desktop','elementor-hidden-tablet','elementor-hidden-mobile'); _e1t.style.setProperty('display','block','important'); }\r\n                    }\r\n                    console.log('\ud83d\udcf1 Mobile: Etape1Container visible, ProcessAchatInside masqu\u00e9');\r\n                    \r\n                    \/\/ \u2705 v1.7 : NE PLUS masquer les croix de suppression\r\n                    \/\/ $('.CampagneCloseButton').hide(); \/\/ SUPPRIM\u00c9\r\n                    \r\n                    this.state.items.forEach(item => {\r\n                        this.etendreCommande(item.id);\r\n                    });\r\n                    \r\n                    $(this.config.templateItem).css({\r\n                        'border': 'none'\r\n                    });\r\n                    \r\n                    console.log('\ud83d\udcf1 Mobile : Mode \u00e9tendu appliqu\u00e9 \u00e0 toutes les commandes');\r\n                } else {\r\n                    console.log('\ud83d\udda5\ufe0f Desktop : Rien masqu\u00e9');\r\n                }\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.4 : Recalcule tous les tarifs des items du panier\r\n         *\/\r\n        async recalculerTousTarifs() {\r\n            console.log('\ud83d\udd04 Recalcul de tous les tarifs...');\r\n            \r\n            if (!window.VIA_App || !window.VIA_App.calculerTarifAPI) {\r\n                console.warn('\u26a0\ufe0f VIA_App.calculerTarifAPI non disponible');\r\n                return;\r\n            }\r\n            \r\n            const items = this.state.items;\r\n            \r\n            for (const item of items) {\r\n                \/\/ pb1513d : idem \u2014 pas de recalcul global sur un format sentinelle.\r\n                if (_viaFormatValide1513(item.format) && item.position && item.duree && item.pays) {\r\n                    try {\r\n                        const country = window.VIA_Countries?.getCountryByLabel(item.pays);\r\n                        \r\n                        if (country && window.VIA_App.calculerTarifAPI) {\r\n                            console.log('\ud83d\udd04 Recalcul tarif pour:', item.reference);\r\n                            \r\n                            const resultat = await window.VIA_App.calculerTarifAPI(\r\n                                item.format,\r\n                                item.position,\r\n                                item.duree,\r\n                                country.code\r\n                            );\r\n                            \r\n                            if (resultat.success) {\r\n                                item.tarifHT = resultat.tarif_ht;\r\n                                item.tarifTTC = resultat.tarif_ttc;\r\n                                \r\n                                if (sessionStorage.getItem('CommercialConnected') !== 'Yes') {\r\n                                    item.tarifHT_initial = resultat.tarif_ht;\r\n                                }\r\n                                \r\n                                console.log('\u2705 Tarif recalcul\u00e9:', item.reference, '-', resultat.tarif_ht, 'EUR');\r\n                                \r\n                                this.rafraichirItemHTML(item.id);\r\n                            }\r\n                        }\r\n                    } catch (error) {\r\n                        console.error('\u274c Erreur recalcul tarif pour', item.reference, ':', error);\r\n                    }\r\n                }\r\n            }\r\n            \r\n            this.calculerTotalPanier();\r\n            \r\n            \/\/ \u2705 Rafra\u00eechir les montants de l'\u00e9tape paiement\r\n            if (window.VIA_Paiement && typeof window.VIA_Paiement.rafraichirMontants === 'function') {\r\n                window.VIA_Paiement.rafraichirMontants();\r\n            }\r\n            \r\n            console.log('\u2705 Tous les tarifs recalcul\u00e9s');\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.4 : G\u00e8re le retour \u00e0 l'\u00e9tape 1 pour modification\r\n         * \u2705 v1.7 : Protection d\u00e9plac\u00e9e dans le listener de clic sur commande\r\n         *\/\r\n        async retourModificationCommande() {\r\n            console.log('\ud83d\udd19 Retour \u00e0 l\\'\u00e9tape 1 pour modification...');\r\n            \r\n            const isMobile = window.innerWidth <= 767;\r\n            \r\n            $('.RetourModifCommande')\r\n                .addClass('elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile')\r\n                .hide();\r\n            \r\n            \/\/ Masquer les \u00e9tapes\r\n            $('#EtapeReferences').hide();\r\n            $('#EtapeModedePaiement').hide();\r\n            $('#EtapeValidations').hide();\r\n            \r\n            \/\/ Masquer les conteneurs\r\n            $('.ReferencesConteneur').hide();\r\n            $('.ChoisirPaiementClass').hide();\r\n            $('#ValidationsConteneur').hide();\r\n            $('#ProcederPaiementConteneur').hide();\r\n            $('#DataFacturationForm').hide();\r\n            $('#ProcederPaiementContenu').hide();  \/\/ \u2705 v1.10 : Masquer #ProcederPaiementContenu\r\n            \r\n            \/\/ Refermer les titres\r\n            $('#ReferencesTitreIconeUp').hide();\r\n            $('#ReferencesTitreIconeDown').show();\r\n            \r\n            $('#ChoisirPaiementTitreIconeUp').hide();\r\n            $('#ChoisirPaiementTitreIconeDown').show();\r\n            \r\n            $('#ValidationsTitreIconeUp').hide();\r\n            $('#ValidationsTitreIconeDown').show();\r\n            \r\n            $('#ProcederPaiementTitreIconeUp').hide();\r\n            $('#ProcederPaiementTitreIconeDown').show();\r\n            \r\n            \/\/ \u2705 v1.10 : D\u00e9griser toutes les \u00e9tapes\r\n            \/\/ \u00c9tape Dates (pas dans etapesConfig au moment de l'init)\r\n            $('.DatesDureeCampagneTitre').removeClass('via-etape-grisee');\r\n            $('#DatesDureeCampagneIconeUp, #DatesDureeCampagneIconeDown').removeClass('via-etape-grisee');\r\n            \/\/ Retirer le style inline forc\u00e9\r\n            $('.DatesDureeCampagneTitre').find('span[style*=\"color\"]').css('color', '');\r\n            $('#DatesDureeCampagneIconeUp, #DatesDureeCampagneIconeDown').find('i').css('color', '');\r\n            \r\n            \/\/ Autres \u00e9tapes via etapesConfig\r\n            if (this.state.etapesConfig) {\r\n                this.state.etapesConfig.forEach(etape => {\r\n                    this.degriserEtape(etape.id);\r\n                });\r\n            }\r\n            \r\n            \/\/ Masquer les messages\r\n            $('#MsgCompleterFormulaireOKConteneur').hide();\r\n            $('#DeviseModedePaiementMsgConteneur').hide();\r\n            $('#MsgCommandeValidee').hide();\r\n            \r\n            \/\/ R\u00e9initialiser le flag\r\n            sessionStorage.setItem('FinaliserStep', 'No');\r\n            \r\n            \/\/ \u2705 v1.8 : Ouvrir le r\u00e9capitulatif (inclut SyntheseConteneur)\r\n            this.ouvrirRecapitulatif();\r\n            \r\n            \/\/ Activer la premi\u00e8re commande en mode \u00e9dition\r\n            if (this.state.items.length > 0) {\r\n                const premiereCommande = this.state.items[0];\r\n                \r\n                this.state.items.forEach(item => {\r\n                    const $item = $(`#${item.id}`);\r\n                    \r\n                    $item.find('.CampagneCloseButton').show();\r\n                    $item.find('.CampagneBoutonModifier').show();\r\n                    $item.find('.CampagneBoutonSupprimer').show();\r\n                    \/\/ \u2705 Injecter bouton R\u00e9duire\/Agrandir si absent\r\n                    if (!$item.find('.CampagneReduceButton').length) {\r\n                        const $reduceBtn = $('<button class=\"CampagneReduceButton\" data-reduit=\"false\" style=\"font-size:10px;font-weight:bold;color:#4B689B;background:none;border:1px solid #4B689B;border-radius:3px;padding:1px 6px;cursor:pointer;margin-right:4px;\">R\u00e9duire<\/button>');\r\n                        $item.find('.CampagneCloseButton').before($reduceBtn);\r\n                    }\r\n                    \r\n                    \r\n                    $item.css('border', '');\r\n                    \r\n                    $item.find('.CampagneDatesContainer').show();\r\n                    $item.find('.TarifClosedClass').hide();\r\n                    \r\n                    $item.removeClass('mode-finalisation');\r\n                    $item.attr('data-etat', 'etendu');\r\n                    \r\n                    this.etendreCommande(item.id);\r\n                    \r\n                });\r\n                \r\n                $('#Etape1Container').show();\r\n                \r\n                this.setItemActif(premiereCommande.id);\r\n                \r\n                this.afficherEtape1DansItem(premiereCommande.id);\r\n                \r\n                \/\/ \u2705 v2.4.3 : D\u00e9l\u00e9guer \u00e0 setItemActif qui g\u00e8re le liser\u00e9 correctement\r\n                this.setItemActif(premiereCommande.id);\r\n                \r\n                console.log('\u2705 Premi\u00e8re commande activ\u00e9e:', premiereCommande.reference);\r\n            }\r\n            \r\n            \/\/ Afficher la colonne PageWeb\r\n            if (typeof window.PageWebColonneOpen === 'function') {\r\n                window.PageWebColonneOpen();\r\n                console.log('\u2705 PageWebColonneOpen() appel\u00e9');\r\n            } else {\r\n                $('.PageWebTemplate').show();\r\n                $('#MobileMsgReserverMSgDefaut').removeClass('via-msg-visible');\r\n                $('.PageWebColonneClass').show();\r\n                console.log('\u26a0\ufe0f PageWebColonneOpen non disponible, fallback utilis\u00e9');\r\n            }\r\n            \r\n            \/\/ R\u00e9initialiser les validations\r\n            $('#Validation_Commande').prop('checked', false);\r\n            $('#Acceptation_CGV').prop('checked', false);\r\n            $('#Acceptation_Commande').prop('checked', false);\r\n            \r\n            $('#MsgValidation_Commande').hide();\r\n            $('#MsgAcceptation_CGV').hide();\r\n            $('#MsgAcceptation_Commande').hide();\r\n            \r\n            sessionStorage.removeItem('validations_completees');\r\n            sessionStorage.removeItem('validation_commande');\r\n            sessionStorage.removeItem('acceptation_cgv');\r\n            sessionStorage.removeItem('acceptation_commande');\r\n            \r\n            \/\/ Scroll sur mobile (r\u00e9utilise isMobile d\u00e9clar\u00e9 en haut de la fonction)\r\n            const MOBILE_SCROLL_RETOUR = 250;\r\n            \r\n            if (isMobile) {\r\n                $('html, body').animate({ scrollTop: MOBILE_SCROLL_RETOUR }, 500);\r\n            } else {\r\n                $('html, body').animate({ scrollTop: 0 }, 500);\r\n            }\r\n            \r\n            \/\/ Recalculer tous les tarifs\r\n            await this.recalculerTousTarifs();\r\n            \r\n            console.log('\u2705 Retour \u00e0 l\\'\u00e9tape 1 effectu\u00e9');\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 NOUVEAU : G\u00e8re une tentative de modification de la commande\r\n         * - Si bon de commande d\u00e9j\u00e0 cr\u00e9\u00e9 \u2192 message d'alerte + proposition de nouvelle commande\r\n         * - Sinon \u2192 r\u00e9initialiser les 3 validations\r\n         * @param {string} typeModification - Type de modification ('campagne', 'references', 'paiement')\r\n         * @param {boolean} estVisualisation - Si true, permet l'ouverture sans bloquer (d\u00e9faut: false)\r\n         * @returns {boolean} - true si modification autoris\u00e9e, false sinon\r\n         *\/\r\n        gererModificationCommande(typeModification = 'campagne', estVisualisation = false) {\r\n            const bonCommandeCree = sessionStorage.getItem('BonCommandeCree') === 'Yes';\r\n            \r\n            console.log('\ud83d\udd04 Gestion modification commande:', { typeModification, bonCommandeCree, estVisualisation });\r\n            \r\n            if (bonCommandeCree) {\r\n                \/\/ \u2705 v1.10 : Si c'est juste une visualisation, permettre l'ouverture sans message\r\n                if (estVisualisation) {\r\n                    console.log('\ud83d\udc41\ufe0f Visualisation autoris\u00e9e (bon de commande cr\u00e9\u00e9 mais pas de modification)');\r\n                    return true;\r\n                }\r\n                \r\n                \/\/ \u2705 Bon de commande d\u00e9j\u00e0 cr\u00e9\u00e9 \u2192 bloquer et afficher message\r\n                console.log('\ud83d\udd12 Modification bloqu\u00e9e - Bon de commande d\u00e9j\u00e0 cr\u00e9\u00e9');\r\n                this.afficherMessageNouvelleCommande();\r\n                return false;\r\n            } else {\r\n                \/\/ \u2705 Bon de commande pas encore cr\u00e9\u00e9 \u2192 r\u00e9initialiser les validations\r\n                this.reinitialiserValidations();\r\n                return true;\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 NOUVEAU : R\u00e9initialise les 3 checkboxes de validation\r\n         *\/\r\n        reinitialiserValidations() {\r\n            console.log('\ud83d\udd04 R\u00e9initialisation des validations (modification d\u00e9tect\u00e9e)...');\r\n            \r\n            \/\/ D\u00e9cocher les 3 checkboxes\r\n            $('input[name=\"form_fields[Validation_Commande]\"]').prop('checked', false);\r\n            $('input[name=\"form_fields[Acceptation_CGV]\"]').prop('checked', false);\r\n            $('input[name=\"form_fields[Acceptation_Commande]\"]').prop('checked', false);\r\n            \r\n            \/\/ Masquer les messages d'erreur\r\n            $('#MsgElementsCommande').hide();\r\n            $('#MsgCGVText').hide();\r\n            $('#MsgAcceptationCommandeConteneur').hide();\r\n            \r\n            \/\/ Supprimer les flags de validation du sessionStorage\r\n            sessionStorage.removeItem('validations_completees');\r\n            sessionStorage.removeItem('validation_commande');\r\n            sessionStorage.removeItem('acceptation_cgv');\r\n            sessionStorage.removeItem('acceptation_commande');\r\n            \r\n            \/\/ Appeler aussi VIA_RecapValidation si disponible\r\n            if (window.VIA_RecapValidation && typeof window.VIA_RecapValidation.reinitialiserValidations === 'function') {\r\n                window.VIA_RecapValidation.reinitialiserValidations();\r\n            }\r\n            \r\n            console.log('\u2705 Validations r\u00e9initialis\u00e9es');\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.8 : V\u00e9rifie si un bon de commande est cr\u00e9\u00e9 et affiche le message si oui\r\n         * @returns {boolean} true si bloqu\u00e9 (bon de commande cr\u00e9\u00e9), false sinon\r\n         *\/\r\n        verifierBonCommandeCreeLock() {\r\n            if (sessionStorage.getItem('BonCommandeCree') === 'Yes') {\r\n                console.log('\ud83d\udd12 Modification bloqu\u00e9e - bon de commande cr\u00e9\u00e9');\r\n                this.afficherMessageNouvelleCommande();\r\n                return true;\r\n            }\r\n            return false;\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 NOUVEAU : Affiche le message pour effectuer une nouvelle commande\r\n         * v1.7 : Nouveau design avec fond blanc et bordure bleu clair #A2C6F3\r\n         *\/\r\n        bloquerInteractionsApresFinalisation() {\r\n            \/\/ \u2705 v2.4.3 : Bloquer ColonneGauche + ColonneCentre enti\u00e8res + R\u00e9cap + Dates\r\n            \/\/ Note : titre R\u00e9capitulatif (titreTexte, IconeUp, MessageContainer) exclus \u2014 restent actifs\r\n            var _zones = [\r\n                '#ColonneGauche',\r\n                '#ColonneCentre',\r\n                '#RecapitulatifVosCommandesContainer',\r\n                '.VosCampagnesConteneurClass',\r\n                '#SyntheseConteneur',\r\n                '#Etape1Container',\r\n                '.DatesDureeCampagneTitre',\r\n                '#DatesDureeCampagneIconeUp',\r\n                '#DatesDureeCampagneIconeDown',\r\n                '.DatesDureeCampagneClass'\r\n            ];\r\n            _zones.forEach(function(sel) {\r\n                var $el = $(sel);\r\n                if ($el.length) {\r\n                    $el[0].style.setProperty('pointer-events', 'none', 'important');\r\n                    $el[0].style.setProperty('user-select', 'none', 'important');\r\n                    $el[0].style.setProperty('opacity', '0.6', 'important');\r\n                }\r\n            });\r\n            if (!document.getElementById('via-finaliser-lock-style')) {\r\n                var _style = document.createElement('style');\r\n                _style.id = 'via-finaliser-lock-style';\r\n                _style.textContent = [\r\n                    '#ColonneGauche, #ColonneGauche *, #ColonneCentre, #ColonneCentre *,',\r\n                    '#RecapitulatifVosCommandesContainer, #RecapitulatifVosCommandesContainer *,',\r\n                    '.VosCampagnesConteneurClass, .VosCampagnesConteneurClass *,',\r\n                    '#SyntheseConteneur, #SyntheseConteneur *,',\r\n                    '#Etape1Container, #Etape1Container *,',\r\n                    '.DatesDureeCampagneTitre, .DatesDureeCampagneTitre *,',\r\n                    '#DatesDureeCampagneIconeUp, #DatesDureeCampagneIconeUp *,',\r\n                    '#DatesDureeCampagneIconeDown, #DatesDureeCampagneIconeDown *,',\r\n                    '.DatesDureeCampagneClass, .DatesDureeCampagneClass * {',\r\n                    'pointer-events: none !important;',\r\n                    'user-select: none !important;',\r\n                    'cursor: default !important;',\r\n                    '}',\r\n                    '\/* Exceptions : titre R\u00e9cap + titre R\u00e9f\u00e9rences restent actifs *\/',\r\n                    '#RecapitulatifVosCommandestitreTexte, #RecapitulatifVosCommandestitreTexte *,',\r\n                    '#RecapitulatifVosCommandesIconeUp, #RecapitulatifVosCommandesIconeUp *,',\r\n                    '#RecapitulatifMessageContainer, #RecapitulatifMessageContainer *,',\r\n                    '.ReferencesTitre, .ReferencesTitre *,',\r\n                    '#ReferencesTitreIconeUp, #ReferencesTitreIconeUp *,',\r\n                    '#ReferencesTitreIconeDown, #ReferencesTitreIconeDown * {',\r\n                    'pointer-events: auto !important;',\r\n                    'opacity: 1 !important;',\r\n                    'cursor: pointer !important;',\r\n                    '}',\r\n                    \/* \u2705 v4.9ds Pb 2 : exception pour le bouton Agrandir\/R\u00e9duire des items.\r\n                       Sans \u00e7a, .VosCampagnesConteneurClass * \u00e9crasait pointer-events sur le\r\n                       bouton + son SVG enfant \u2192 toute la r\u00e9servation \u00e9tait inerte (pas\r\n                       cliquable pour agrandir\/r\u00e9duire). Demande user : le bouton doit rester\r\n                       fonctionnel apr\u00e8s finalisation pour permettre de visualiser les\r\n                       r\u00e9servations en grand. *\/\r\n                    '.via-reduire-btn, .via-reduire-btn * {',\r\n                        'pointer-events: auto !important;',\r\n                        'opacity: 1 !important;',\r\n                        'cursor: pointer !important;',\r\n                    '}',\r\n                    \/* ====================================================================\r\n                     * pb2351 : LA CROIX DOIT RESTER CLIQUABLE APRES FINALISATION.\r\n                     *   pb2350 lui a donne un nouveau role \u2014 refermer l etape Vos\r\n                     *   reservations \u2014 mais le verrou via-finaliser-lock-style coupait\r\n                     *   pointer-events sur .VosCampagnesConteneurClass * , donc sur elle.\r\n                     *   Le nouveau comportement etait ecrit et inatteignable.\r\n                     *   L exception existait deja pour .via-reduire-btn, posee pour la meme\r\n                     *   raison et par le meme constat (v4.9ds Pb 2). On l etend a la croix\r\n                     *   plutot que d en ecrire une seconde : une seule regle, un seul endroit\r\n                     *   a lire le jour ou la liste des exceptions changera.\r\n                     *   Le SVG enfant est inclus, sans quoi le clic tombe sur lui et meurt.\r\n                     *   Revert : window._viaPb2351Off = true (recharger la page).\r\n                     * ==================================================================== *\/\r\n                    (window._viaPb2351Off === true ? '' :\r\n                        '.CampagneCloseButton, .CampagneCloseButton * {'\r\n                        + ' pointer-events: auto !important;'\r\n                        + ' opacity: 1 !important;'\r\n                        + ' cursor: pointer !important; }')\r\n                ].join(' ');\r\n                document.head.appendChild(_style);\r\n            }\r\n            console.log('\\uD83D\\uDD12 [FinaliserStep] Interactions bloqu\\u00e9es : ColonneGauche + ColonneCentre + R\\u00e9cap + Dates');\r\n        },\r\n\r\n        afficherMessageFinaliser() {\r\n            \/\/ \u2705 v2.4.3 : Message contextuel selon l'\u00e9tape active\r\n            if (window.VIA_Panier_ResizeEnCours) { return; }\r\n            var _existingMsg = document.getElementById('MsgFinaliser');\r\n            if (_existingMsg) { if (_existingMsg.style.display !== 'none') { return; } }\r\n\r\n            \/\/ D\u00e9terminer l'\u00e9tape active \u2014 premi\u00e8re \u00e9tape post-r\u00e9cap visible\r\n            var _etapeSuffix = 'd\\'indiquer vos r\u00e9f\u00e9rences';\r\n            var _etapesPostRecap = [\r\n                { selector: '#EtapeReferences', msg: 'd\\'indiquer vos r\u00e9f\u00e9rences' },\r\n                { selector: '#EtapeModedePaiement', msg: 'de choisir un mode de paiement' },\r\n                { selector: '#EtapeValidations', msg: 'de valider les CGV' },\r\n                { selector: '#EtapePaiement', msg: 'de proc\u00e9der au paiement' }\r\n            ];\r\n            for (var _i = 0; _i < _etapesPostRecap.length; _i++) {\r\n                var _el = document.querySelector(_etapesPostRecap[_i].selector);\r\n                if (_el) { if (_el.offsetParent !== null) { if ($(_el).is(':visible')) { _etapeSuffix = _etapesPostRecap[_i].msg; break; } } }\r\n            }\r\n\r\n            var _msg = 'Les r\\u00e9servations ne sont plus modifiables,<br>Merci de ' + _etapeSuffix + '.';\r\n            var _isMobile = window.innerWidth <= 767;\r\n\r\n            var $overlay = $('<div id=\"MsgFinaliser\" style=\"position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:#fff;border:3px solid #A2C6F3;border-radius:12px;padding:' + (_isMobile ? '25px 20px' : '30px 40px') + ';text-align:center;z-index:99999;font-family:Arial,sans-serif;font-size:' + (_isMobile ? '15px' : '16px') + ';color:#213864;max-width:' + (_isMobile ? '90%' : '420px') + ';box-shadow:0 8px 32px rgba(0,0,0,0.18);\">' +\r\n                '<p style=\"margin:0 0 20px;line-height:1.5;\">' + _msg + '<\/p>' +\r\n                '<button style=\"background:#4B689B;color:#fff;border:none;border-radius:6px;padding:10px 24px;font-size:14px;cursor:pointer;\">OK<\/button>' +\r\n                '<\/div>');\r\n            var $overlay2 = $('<div id=\"MsgFinaliserOverlay\" style=\"position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.35);z-index:99998;\"><\/div>');\r\n            $('body').append($overlay2).append($overlay);\r\n            $overlay.find('button').on('click', function() { $overlay.remove(); $overlay2.remove(); });\r\n            $overlay2.on('click', function() { $overlay.remove(); $overlay2.remove(); });\r\n            console.log('\\uD83D\\uDD12 [FinaliserStep] Message affich\\u00e9 \u2014 \\u00e9tape:', _etapeSuffix);\r\n        },\r\n\r\n        afficherMessageNouvelleCommande() {\r\n            \/* ============================================================\r\n             * pb1729 : QUI APPELLE CE MESSAGE ?\r\n             *   Constat user : le message \u00ab Votre bon de commande a ete cree \u00bb\r\n             *   apparait juste apres la validation et masque l acces aux bons de\r\n             *   commande.\r\n             *   Ce texte n existe qu ici, l.14893 \u2014 pas dans\r\n             *   Validation_sequentielle.txt, dont le popup est un autre\r\n             *   mecanisme (#VIA_PopupValidation, messages \u00ab Merci de ... \u00bb).\r\n             *   La fonction a NEUF appelants, dont chacun journalise sa propre\r\n             *   ligne \u00ab verrou \u00bb \u2014 et AUCUNE de ces lignes n est dans le log\r\n             *   fourni. L un d eux se declenche donc sans laisser de trace, ou\r\n             *   le log s arrete avant.\r\n             *   Plutot que d en suspecter un dixieme, la fonction dit elle-meme\r\n             *   d ou elle vient. Les cadres de bibliotheque sont ecartes, comme\r\n             *   dans pb1671.\r\n             *   Traceur : a retirer une fois l appelant nomme.\r\n             * ============================================================ *\/\r\n            try {\r\n                var _l1729 = new Error().stack.split('\\n').slice(2);\r\n                var _n1729 = [];\r\n                var _s1729 = 0;\r\n                for (var _i1729 = 0; _i1729 < _l1729.length; _i1729++) {\r\n                    var _f1729 = _l1729[_i1729].trim();\r\n                    if (!_f1729) { continue; }\r\n                    if (_f1729.toLowerCase().indexOf('jquery') !== -1) { _s1729++; continue; }\r\n                    _n1729.push(_f1729);\r\n                    if (_n1729.length >= 5) { break; }\r\n                }\r\n                console.log('[pb1729] message nouvelle commande demande par :'\r\n                    + NL_1729 + _n1729.join(NL_1729)\r\n                    + '   [' + _s1729 + ' cadres jquery sautes]');\r\n            } catch (_e1729) {\r\n                console.log('[pb1729] message nouvelle commande demande \u2014 pile indisponible');\r\n            }\r\n            \/\/ \u2705 v1.7 : Ne pas afficher pendant un resize (flag actif pendant 500ms apr\u00e8s resize)\r\n            if (window.VIA_Panier_ResizeEnCours) {\r\n                console.log('\u2139\ufe0f Message nouvelle commande ignor\u00e9 (resize en cours)');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v1.10 : Ne pas afficher si on est en mode visualisation d'\u00e9tape\r\n            if (this.state.enVisualisationEtape) {\r\n                console.log('\u2139\ufe0f Message nouvelle commande ignor\u00e9 (visualisation \u00e9tape en cours)');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v1.7 : Ne pas r\u00e9afficher si le message est d\u00e9j\u00e0 visible\r\n            const $existingMessage = $('#MsgNouvelleCommande');\r\n            if ($existingMessage.length > 0 && $existingMessage.is(':visible')) {\r\n                console.log('\u2139\ufe0f Message nouvelle commande d\u00e9j\u00e0 visible, pas de r\u00e9affichage');\r\n                return;\r\n            }\r\n            \r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const isMobile = window.innerWidth <= 767;\r\n            \r\n            \/\/ \u2705 v1.7 : Messages adapt\u00e9s pour mobile (sans <br> forc\u00e9s)\r\n            let message;\r\n            if (isMobile) {\r\n                message = lang === 'EN'\r\n                    ? 'Your order has been successfully created.<br><br>This order can no longer be modified, but you can create a new one by clicking here.'\r\n                    : 'Votre bon de commande a \u00e9t\u00e9 cr\u00e9\u00e9 avec succ\u00e8s.<br><br>Cette commande ne peut plus \u00eatre modifi\u00e9e, mais vous avez la possibilit\u00e9 d\\'en cr\u00e9er une nouvelle en cliquant ici.';\r\n            } else {\r\n                message = lang === 'EN'\r\n                    ? 'Your order has been successfully<br>created.<br><br>This order can no longer be modified, but you can create a new one by clicking here.'\r\n                    : 'Votre bon de commande a \u00e9t\u00e9 cr\u00e9\u00e9<br>avec succ\u00e8s.<br><br>Cette commande ne peut plus \u00eatre modifi\u00e9e, mais vous avez la possibilit\u00e9 d\\'en cr\u00e9er une nouvelle en cliquant ici.';\r\n            }\r\n            \r\n            const btnText = lang === 'EN' ? 'Create a new order' : 'Cr\u00e9er une nouvelle commande';\r\n            \r\n            \/\/ Cr\u00e9er ou afficher le message\r\n            let $messageContainer = $('#MsgNouvelleCommande');\r\n            \r\n            if ($messageContainer.length === 0) {\r\n                \/\/ \u2705 v1.7 : Styles adapt\u00e9s pour mobile\r\n                const popupWidth = isMobile ? '90%' : '450px';\r\n                const popupPadding = isMobile ? '25px 20px' : '30px 40px';\r\n                const fontSize = isMobile ? '15px' : '16px';\r\n                const btnPadding = isMobile ? '12px 20px' : '12px 25px';\r\n                const btnFontSize = isMobile ? '15px' : '16px';\r\n                \r\n                \/\/ Cr\u00e9er le conteneur s'il n'existe pas\r\n                $messageContainer = $(`\r\n                    <div id=\"MsgNouvelleCommande\" style=\"\r\n                        position: fixed;\r\n                        top: 50%;\r\n                        left: 50%;\r\n                        transform: translate(-50%, -50%);\r\n                        background: #FFFFFF;\r\n                        border: 3px solid #A2C6F3;\r\n                        border-radius: 10px;\r\n                        padding: ${popupPadding};\r\n                        z-index: 99999;\r\n                        box-shadow: 0 10px 30px rgba(0,0,0,0.3);\r\n                        width: ${popupWidth};\r\n                        max-width: 450px;\r\n                        text-align: center;\r\n                        box-sizing: border-box;\r\n                    \">\r\n                        <a href=\"#\" id=\"BtnFermerMessage\" style=\"\r\n                            position: absolute;\r\n                            top: 10px;\r\n                            right: 15px;\r\n                            color: #333;\r\n                            font-size: 24px;\r\n                            font-weight: bold;\r\n                            text-decoration: none;\r\n                            line-height: 1;\r\n                        \">&times;<\/a>\r\n                        <p style=\"margin-bottom: 20px; font-size: ${fontSize}; color: #333; line-height: 1.5;\">${message}<\/p>\r\n                        <a href=\"#\" id=\"BtnNouvelleCommande\" style=\"\r\n                            display: inline-block;\r\n                            background: #A2C6F3;\r\n                            color: #4B689B;\r\n                            padding: ${btnPadding};\r\n                            border-radius: 5px;\r\n                            text-decoration: none;\r\n                            font-weight: bold;\r\n                            font-size: ${btnFontSize};\r\n                        \">${btnText}<\/a>\r\n                    <\/div>\r\n                    <div id=\"MsgNouvelleCommandeOverlay\" style=\"\r\n                        position: fixed;\r\n                        top: 0;\r\n                        left: 0;\r\n                        right: 0;\r\n                        bottom: 0;\r\n                        background: rgba(0,0,0,0.5);\r\n                        z-index: 99998;\r\n                    \"><\/div>\r\n                `);\r\n                \r\n                $('body').append($messageContainer);\r\n                \r\n                \/\/ Gestionnaire pour le bouton \"Nouvelle commande\"\r\n                const self = this;\r\n                $(document).on('click', '#BtnNouvelleCommande', function(e) {\r\n                    e.preventDefault();\r\n                    \/\/ \u2705 v1.7 : Simplement recharger la page\r\n                    location.reload();\r\n                });\r\n                \r\n                \/\/ Gestionnaire pour fermer le message\r\n                $(document).on('click', '#BtnFermerMessage, #MsgNouvelleCommandeOverlay', function(e) {\r\n                    e.preventDefault();\r\n                    $('#MsgNouvelleCommande, #MsgNouvelleCommandeOverlay').remove();\r\n                });\r\n            } else {\r\n                $messageContainer.show();\r\n                $('#MsgNouvelleCommandeOverlay').show();\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 NOUVEAU : R\u00e9initialise compl\u00e8tement le process d'achat pour une nouvelle commande\r\n         *\/\r\n        reinitialiserProcessComplet() {\r\n            console.log('\ud83d\udd04 R\u00e9initialisation compl\u00e8te du process d\\'achat...');\r\n            \r\n            \/\/ Fermer le message\r\n            $('#MsgNouvelleCommande, #MsgNouvelleCommandeOverlay').remove();\r\n            \r\n            \/\/ \u2705 Supprimer le flag de bon de commande\r\n            sessionStorage.removeItem('BonCommandeCree');\r\n            sessionStorage.removeItem('commande_id');\r\n            sessionStorage.removeItem('commande_ref');\r\n            sessionStorage.removeItem('commande_ref_url');\r\n            sessionStorage.removeItem('paiement_id');\r\n            \r\n            \/\/ \u2705 Supprimer toutes les commandes du panier\r\n            const itemsASupprimer = [...this.state.items];\r\n            itemsASupprimer.forEach(item => {\r\n                this.supprimerCommande(item.id, false, true);\r\n            });\r\n            \r\n            \/\/ \u2705 R\u00e9initialiser les validations\r\n            this.reinitialiserValidations();\r\n            \r\n            \/\/ \u2705 R\u00e9initialiser les r\u00e9f\u00e9rences\r\n            if (window.VIA_References && typeof window.VIA_References.effacerReferences === 'function') {\r\n                window.VIA_References.effacerReferences();\r\n            }\r\n            \/\/ \u2705 v1.8 : Supprimer le flag de validation des r\u00e9f\u00e9rences\r\n            sessionStorage.removeItem('references_validees_session');\r\n            \r\n            \/\/ \u2705 R\u00e9initialiser le mode de paiement\r\n            sessionStorage.removeItem('mode_paiement');\r\n            sessionStorage.removeItem('nb_echeances');\r\n            sessionStorage.removeItem('montant_total');\r\n            sessionStorage.removeItem('devise_paiement');\r\n            \r\n            \/\/ \u2705 R\u00e9initialiser le flag FinaliserStep\r\n            sessionStorage.setItem('FinaliserStep', 'No');\r\n            \r\n            \/\/ \u2705 Masquer toutes les \u00e9tapes sauf l'\u00e9tape 1\r\n            $('#EtapeReferences').hide();\r\n            $('#EtapeModedePaiement').hide();\r\n            $('#EtapeValidations').hide();\r\n            $('#EtapePaiement').hide();\r\n            \r\n            \/\/ \u2705 R\u00e9initialiser les titres des \u00e9tapes (d\u00e9sactiv\u00e9s)\r\n            this.reinitialiserTitresEtapes();\r\n            \r\n            $('.ReferencesConteneur').hide();\r\n            $('.ChoisirPaiementClass').hide();\r\n            $('#ValidationsConteneur').hide();\r\n            $('#ProcederPaiementConteneur').hide();\r\n            \r\n            \/\/ \u2705 Masquer les messages\r\n            $('#MsgCompleterFormulaireOKConteneur').hide();\r\n            $('#DeviseModedePaiementMsgConteneur').hide();\r\n            $('#MsgCommandeValidee').hide();\r\n            $('#AssocierPaysMessageContainer').hide();  \/\/ \u2705 v1.9\r\n            $('#SecteursMessageContainer').hide();  \/\/ \u2705 v1.9\r\n            $('#FormatMessageContainer').hide();  \/\/ \u2705 v1.9\r\n            $('#PageWebMessageContainer').hide();  \/\/ \u2705 v1.9\r\n            $('#Etape1MessageContainer').hide();  \/\/ \u2705 v1.9\r\n            $('#RecapitulatifMessageContainer').hide();\r\n            this._updateMessagesEtapes();  \/\/ \u2705 v1.9\r\n            \r\n            \/\/ \u2705 Masquer le bouton RetourModifCommande\r\n            $('.RetourModifCommande')\r\n                .addClass('elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile')\r\n                .hide();\r\n            \r\n            \/\/ \u2705 v1.8 : Ouvrir le r\u00e9capitulatif (inclut SyntheseConteneur)\r\n            this.ouvrirRecapitulatif();\r\n            \r\n            \/\/ \u2705 Ouvrir la colonne PageWeb\r\n            if (typeof window.PageWebColonneOpen === 'function') {\r\n                window.PageWebColonneOpen();\r\n            }\r\n            \r\n            \/\/ \u2705 Mettre \u00e0 jour le r\u00e9capitulatif\r\n            this.updateRecapitulatif();\r\n            \r\n            \/\/ \u2705 Scroll vers le haut\r\n            const isMobile = window.innerWidth <= 767;\r\n            if (isMobile) {\r\n                $('html, body').animate({ scrollTop: 0 }, 500);\r\n            } else {\r\n                $('html, body').animate({ scrollTop: 0 }, 500);\r\n            }\r\n            \r\n            console.log('\u2705 Process d\\'achat r\u00e9initialis\u00e9 pour nouvelle commande');\r\n        },\r\n        \r\n        \/**\r\n         * R\u00e9duit une commande (affichage minimal)\r\n         *\/\r\n        reduireCommande(itemId) {\r\n            const $item = $(`#${itemId}`);\r\n            \r\n            const tarifComplet = $item.find('.CampagneTarifClass').text();\r\n            const tarifResume = this.extraireTarifResume(tarifComplet);\r\n            $item.find('.TarifClosedClass').html(tarifResume).show();\r\n            \r\n            $item.find('.CampagneDatesContainer').hide();\r\n            \r\n            $item.find('.CampagneEnvoiUlterieurClass').hide();\r\n            $item.find('.CampagneAnnonceDeposeClass').hide();\r\n            \r\n            \r\n            $item.attr('data-etat', 'reduit');\r\n            \r\n            console.log('\ud83d\udd3d Commande r\u00e9duite:', itemId);\r\n        },\r\n        \r\n        \/**\r\n         * \u00c9tend une commande (affichage complet)\r\n         *\/\r\n        etendreCommande(itemId) {\r\n            const $item = $(`#${itemId}`);\r\n            const item = this.state.items.find(i => i.id === itemId);\r\n            \r\n            $item.find('.TarifClosedClass').hide();\r\n            \r\n            $item.find('.CampagneDatesContainer').show();\r\n            \r\n            \/\/ \u2705 V\u00e9rifier EnvoiUlterieur (string ou boolean) et FileReceived\r\n            const envoiUlterieur = item?.donneesIframe?.EnvoiUlterieur;\r\n            const isEnvoiDiffere = envoiUlterieur === 'true' || envoiUlterieur === true;\r\n            const hasFile = item?.donneesIframe?.FileReceived === 'Yes';\r\n            \r\n            \/\/ pb69 : annonce d\u00e9pos\u00e9e \u2192 CampagneAnnonceDeposeClass ; envoi diff\u00e9r\u00e9 \u2192 CampagneEnvoiUlterieurClass\r\n            if (hasFile) {\r\n                $item.find('.CampagneEnvoiUlterieurClass').hide();\r\n                $item.find('.CampagneAnnonceDeposeClass').show();\r\n            } else if (isEnvoiDiffere) {\r\n                $item.find('.CampagneEnvoiUlterieurClass').show();\r\n                $item.find('.CampagneAnnonceDeposeClass').hide();\r\n            } else {\r\n                $item.find('.CampagneEnvoiUlterieurClass').hide();\r\n                $item.find('.CampagneAnnonceDeposeClass').hide();\r\n            }\r\n            \r\n            \r\n            $item.attr('data-etat', 'etendu');\r\n            \r\n            console.log('\ud83d\udd3c Commande \u00e9tendue:', itemId);\r\n        },\r\n        \r\n        \/**\r\n         * Extrait le tarif r\u00e9sum\u00e9 depuis le tarif complet\r\n         *\/\r\n        extraireTarifResume(tarifComplet) {\r\n            if (!tarifComplet) return '-';\r\n            \r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            tarifComplet = tarifComplet\r\n                .replace(\/Tarif\\s+H\\.T\\.\\s*\/i, '')\r\n                .replace(\/Price\\s+excl\\.\\s+VAT\\s*\/i, '')\r\n                .trim();\r\n            \r\n            const match = tarifComplet.match(\/([\\d\\s,\\.]+)\\s*(EUR|USD|GBP|CHF|XAF|XOF|CDF|MGA)\/i);\r\n            \r\n            if (match) {\r\n                const montant = match[1].trim();\r\n                const devise = match[2].toUpperCase();\r\n                \r\n                const symboles = {\r\n                    'EUR': '\u20ac',\r\n                    'USD': '$',\r\n                    'GBP': '\u00a3',\r\n                    'CHF': 'CHF',\r\n                    'XAF': 'FCFA',\r\n                    'XOF': 'FCFA',\r\n                    'CDF': 'FC',\r\n                    'MGA': 'Ar'\r\n                };\r\n                \r\n                const symbole = symboles[devise] || devise;\r\n                const labelHT = lang === 'EN' ? 'excl. VAT' : 'H.T.';\r\n                \r\n                return `${montant} ${symbole} ${labelHT}`;\r\n            }\r\n            \r\n            return tarifComplet;\r\n        },\r\n        \r\n        \/**\r\n         * Toggle entre mode r\u00e9duit et \u00e9tendu\r\n         *\/\r\n        toggleCommande(itemId) {\r\n            const $item = $(`#${itemId}`);\r\n            const etat = $item.attr('data-etat');\r\n            \r\n            if (etat === 'reduit') {\r\n                this.etendreCommande(itemId);\r\n            } else {\r\n                this.reduireCommande(itemId);\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.8 : Ferme la section PageWeb (desktop et mobile)\r\n         * \u2705 v1.10 : D\u00e9lai 300ms pour laisser le temps aux donn\u00e9es d'\u00eatre enregistr\u00e9es\r\n         *\/\r\n        fermerPageWeb(showMessage) {\r\n            const isDesktop = window.outerWidth >= 1000;\r\n            \/\/ v4.9ds : detection mode=popup via search OU hash (Elementor pousse parfois en hash)\r\n            var _fpHash = window.location.hash || '';\r\n            var _fpSearch = window.location.search || '';\r\n            const _isPopupModeFP = (_fpSearch.indexOf('mode=popup') !== -1) ? true : (_fpHash.indexOf('mode=popup') !== -1);\r\n            \r\n            \/\/ \u2705 v2.0 : Sur desktop (r\u00e9gie 3 colonnes), ne pas masquer PageWebTemplate\r\n            \/\/ \u2705 v2.7.3 : Exception mode=popup (sites pays) \u2014 masquer comme sur mobile\r\n            if (!isDesktop ? true : _isPopupModeFP) {\r\n                $('.PageWebTemplate').hide();\r\n            }\r\n            \r\n            $('#PageWebTitreIconeUp').hide();\r\n            $('#PageWebTitreIconeDown').show();\r\n            \/\/ \u2705 v1.16.0 : Marquer l'\u00e9tat Close pour emp\u00eacher setupPageWebContainer de r\u00e9ouvrir\r\n            \/\/ \u2705 v4.9ds+ Pb5\/6 : Sur desktop non-popup, NE PAS poser 'Close' ici.\r\n            \/\/   Sur desktop, les 3 colonnes doivent rester ouvertes \u2014 seul PageWebColonneClose()\r\n            \/\/   ferme explicitement les colonnes. Poser 'Close' ici casse _applyLayoutModeChange\r\n            \/\/   lors du reload iframe apr\u00e8s transition mobile\u2192desktop.\r\n            if (!isDesktop || _isPopupModeFP) {\r\n                sessionStorage.setItem('PageWebColonneOpenclose', 'Close');\r\n            }\r\n            \r\n            const isMobile = window.innerWidth <= 767;\r\n            if (isMobile) {\r\n                \/\/ $('#Etape1Container').css('margin-top', '-90px');\r\n            }\r\n            \r\n            \/\/ \u2705 v1.11 : Fermeture syst\u00e8me (showMessage === true)\r\n            if (showMessage === true) {\r\n                this.griserEtape('pageWeb');\r\n                \/\/ \u2705 v2.0 : Afficher le message seulement sur mobile\r\n                if (!isDesktop) {\r\n                    $('#PageWebMessageContainer').show();\r\n                }\r\n                console.log('\ud83d\udcc1 PageWeb ferm\u00e9 + gris\u00e9 + message affich\u00e9 (syst\u00e8me)');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v1.11 : Fermeture manuelle \u2192 v\u00e9rifier si espace pub d\u00e9j\u00e0 s\u00e9lectionn\u00e9\r\n            var hasEspacePub = false;\r\n            if (window.VIA_Panier && window.VIA_Panier.state && window.VIA_Panier.state.items) {\r\n                hasEspacePub = window.VIA_Panier.state.items.some(function(item) {\r\n                    return item.donneesIframe && \r\n                           (item.donneesIframe.FileReceived === 'Yes' || \r\n                            item.donneesIframe.EnvoiUlterieur === 'true' || \r\n                            item.donneesIframe.EnvoiUlterieur === true);\r\n                });\r\n            }\r\n            \r\n            if (hasEspacePub) {\r\n                this.griserEtape('pageWeb');\r\n                \/\/ \u2705 v2.0 : Afficher le message seulement sur mobile\r\n                if (!isDesktop) {\r\n                    $('#PageWebMessageContainer').show();\r\n                }\r\n                console.log('\ud83d\udcc1 PageWeb ferm\u00e9 (manuel) + gris\u00e9 + message (espace pub d\u00e9j\u00e0 choisi)');\r\n            } else {\r\n                console.log('\ud83d\udcc1 PageWeb ferm\u00e9 (manuel, titre reste dor\u00e9)');\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.10 : V\u00e9rifie et affiche le message PageWeb si n\u00e9cessaire\r\n         * @returns {boolean} true si trouv\u00e9 et affich\u00e9\r\n         *\/\r\n        verifierEtAfficherPageWebMessage() {\r\n            let hasAnnonceOuEnvoiDiffere = false;\r\n            \r\n            \/\/ 1. V\u00e9rifier sessionStorage courant (sans index)\r\n            const currentFileReceived = sessionStorage.getItem('FileReceived');\r\n            const currentEnvoiUlterieur = sessionStorage.getItem('EnvoiUlterieur');\r\n            console.log('\ud83d\udd0d verifierPageWebMessage - sessionStorage courant:', { \r\n                FileReceived: currentFileReceived, \r\n                EnvoiUlterieur: currentEnvoiUlterieur \r\n            });\r\n            if (currentFileReceived === 'Yes' || currentEnvoiUlterieur === 'true') {\r\n                hasAnnonceOuEnvoiDiffere = true;\r\n                console.log('\u2705 Trouv\u00e9 via sessionStorage courant');\r\n            }\r\n            \r\n            \/\/ 2. V\u00e9rifier dans les items du panier\r\n            if (!hasAnnonceOuEnvoiDiffere && window.VIA_Panier?.state?.items) {\r\n                const items = window.VIA_Panier.state.items;\r\n                console.log('\ud83d\udd0d verifierPageWebMessage - Items panier:', items.map(item => ({\r\n                    id: item.id,\r\n                    statut: item.statut,\r\n                    FileReceived: item.donneesIframe?.FileReceived,\r\n                    EnvoiUlterieur: item.donneesIframe?.EnvoiUlterieur\r\n                })));\r\n                hasAnnonceOuEnvoiDiffere = items.some(item => {\r\n                    if (item.donneesIframe) {\r\n                        const hasFile = item.donneesIframe.FileReceived === 'Yes';\r\n                        const isEnvoiDiffere = item.donneesIframe.EnvoiUlterieur === 'true' || \r\n                                               item.donneesIframe.EnvoiUlterieur === true ||\r\n                                               item.donneesIframe.EnvoiUlterieur === 'Yes';\r\n                        return hasFile || isEnvoiDiffere;\r\n                    }\r\n                    return false;\r\n                });\r\n                if (hasAnnonceOuEnvoiDiffere) {\r\n                    console.log('\u2705 Trouv\u00e9 via items panier');\r\n                }\r\n            }\r\n            \r\n            \/\/ 3. V\u00e9rifier dans sessionStorage index\u00e9\r\n            if (!hasAnnonceOuEnvoiDiffere) {\r\n                const campagneIndex = parseInt(sessionStorage.getItem('CampagneIndex') || '0');\r\n                for (let i = 1; i <= campagneIndex; i++) {\r\n                    const fileReceived = sessionStorage.getItem('FileReceived' + i);\r\n                    const envoiUlterieur = sessionStorage.getItem('EnvoiUlterieur' + i);\r\n                    console.log('\ud83d\udd0d verifierPageWebMessage - sessionStorage index ' + i + ':', { \r\n                        FileReceived: fileReceived, \r\n                        EnvoiUlterieur: envoiUlterieur \r\n                    });\r\n                    if (fileReceived === 'Yes' || envoiUlterieur === 'true' || envoiUlterieur === 'Yes') {\r\n                        hasAnnonceOuEnvoiDiffere = true;\r\n                        console.log('\u2705 Trouv\u00e9 via sessionStorage index:', i);\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n            \r\n            if (hasAnnonceOuEnvoiDiffere) {\r\n                $('#PageWebMessageContainer').show();\r\n                console.log('\u2705 PageWebMessage AFFICH\u00c9');\r\n            } else {\r\n                console.log('\u274c Aucune annonce\/envoi diff\u00e9r\u00e9 trouv\u00e9 (retry possible)');\r\n            }\r\n            \r\n            return hasAnnonceOuEnvoiDiffere;\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.8 : Ouvre la section PageWeb (desktop et mobile)\r\n         *\/\r\n        ouvrirPageWeb(force) {\r\n            \/\/ pb45 : item VLP actif \u2192 ne pas ouvrir la colonne centre\r\n            if (window._vlpSkipPageWeb45 === true) {\r\n                console.log('[pb45] ouvrirPageWeb bloqu\u00e9 \u2014 item VLP actif');\r\n                return;\r\n            }\r\n            \/\/ \u2705 Bloquer sur sites pays si item actif issu d'un site pays\r\n            if (window.location.search.indexOf('mode=popup') !== -1) {\r\n                var _activeIdPW = this.state && this.state.itemActif;\r\n                var _activeItemPW = _activeIdPW && this.state.items && this.state.items.find(function(i) { return i.id === _activeIdPW; });\r\n                if (_activeItemPW && _activeItemPW.pays) {\r\n                    console.log('\ud83d\udd12 ouvrirPageWeb bloqu\u00e9 - item actif sites pays:', _activeItemPW.pays);\r\n                    return;\r\n                }\r\n            }\r\n            \/\/ \u2705 v1.16.0 : Bloquer la r\u00e9ouverture automatique pendant le traitement d'un espace pub\r\n            if (!force && sessionStorage.getItem('PageWebColonneOpenclose') === 'Close' \r\n                && sessionStorage.getItem('TraitementEspacePubEnCours') === 'Yes') {\r\n                console.log('\ud83d\udd12 ouvrirPageWeb bloqu\u00e9 - traitement espace pub en cours');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v1.16.0 : Bloquer pendant le preselector actif uniquement\r\n            if (!force && sessionStorage.getItem('PageWebColonneOpenclose') === 'Pending'\r\n                && sessionStorage.getItem('UrlPreselectorActive') === 'Yes') {\r\n                console.log('\ud83d\udd12 ouvrirPageWeb bloqu\u00e9 - preselector en cours');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v1.16.0 : Bloquer si Pending et pas de format s\u00e9lectionn\u00e9 (hors preselector)\r\n            if (!force && sessionStorage.getItem('PageWebColonneOpenclose') === 'Pending'\r\n                && !sessionStorage.getItem('FormatSelect')\r\n                && sessionStorage.getItem('CreationFormatActive') !== 'Yes') {   \/\/ pb2096 : la Creation vaut un format (equivalence pb858)\r\n                console.log('\ud83d\udd12 ouvrirPageWeb bloqu\u00e9 - format pas encore s\u00e9lectionn\u00e9');\r\n                return;\r\n            }\r\n            \r\n            \/\/ ================================================================\r\n            \/\/ pb1075 : LES 3 COLONNES ATTENDENT L'ANNONCEUR ET LES DATES.\r\n            \/\/   Constat user : le mode 3 colonnes s'ouvrait des la selection d'un\r\n            \/\/   FORMAT. Regle demandee : annonceur ET dates sont obligatoires \u2014 la\r\n            \/\/   page web n'a de sens qu'une fois la campagne definie.\r\n            \/\/   Le garde v1.16.0 juste au-dessus ne testait que FormatSelect ; on\r\n            \/\/   ajoute les deux conditions manquantes, lues comme en pb1074 :\r\n            \/\/   l'item d'abord s'il existe, les champs de saisie sinon (au moment\r\n            \/\/   ou l'utilisateur choisit son format, aucun item n'existe encore).\r\n            \/\/   'force' reste prioritaire : les appels explicites (restauration\r\n            \/\/   d'une resa complete, clic direct) ne sont pas bloques.\r\n            \/\/   Revert : window._viaPb1075Off = true.\r\n            \/\/ ================================================================\r\n            if (!force ? (window._viaPb1075Off !== true) : false) {\r\n                var _ss1075 = function (_k) {\r\n                    try { return sessionStorage.getItem(_k) || ''; } catch (_e) { return ''; }\r\n                };\r\n                var _it1075 = (this.state.items || []).find(function (_x) {\r\n                    return _x.id === this.state.itemActif;\r\n                }, this) || null;\r\n                var _ann1075 = (_it1075 ? _it1075.pays : '')\r\n                    || ($('#form-field-Nationalite_Societe').val() || '')\r\n                    || _ss1075('Nationalite_Societe');\r\n                var _dat1075 = (_it1075 ? (_it1075.dateDebut ? !!_it1075.dateFin : false) : false)\r\n                    || !!($('#form-field-DebutCampagne').val() ? $('#form-field-FinCampagne').val() : '');\r\n                if (!_ann1075 || !_dat1075) {\r\n                    console.log('[pb1075] ouvrirPageWeb diff\u00e9r\u00e9 : annonceur='\r\n                        + (_ann1075 || 'MANQUANT') + ' | dates=' + (_dat1075 ? 'ok' : 'MANQUANTES'));\r\n                    return;\r\n                }\r\n            }\r\n\r\n            \/\/ \u2705 v1.16.0 : Marquer l'\u00e9tat Open pour permettre setupPageWebContainer d'afficher\r\n            sessionStorage.setItem('PageWebColonneOpenclose', 'Open');\r\n            \r\n            \/\/ pb2096 : equivalent mobile de l'ouverture des colonnes (garde pb1075\r\n            \/\/   passee : annonceur + dates presents) -> ouvrir le kit Creation s'il\r\n            \/\/   est en attente. Idempotent (latch CreationKitPending2096).\r\n            if (typeof window._viaOuvrirKitCreation2096 === 'function') { window._viaOuvrirKitCreation2096('ouvrirPageWeb'); }\r\n            \r\n            const isMobile = window.innerWidth <= 767;\r\n            \/\/ v4.9ds : distinguer \"vrai mobile\" du \"popup desktop etroit\" (mode=popup).\r\n            \/\/   Le popup d'achat dans la regie a une largeur souvent <= 767px, ce qui faisait\r\n            \/\/   passer isMobile a true et appliquait max-height:335px sur .PageWebTemplate\r\n            \/\/   -> iframe coupee a 335px -> les espaces pub etaient mal rendus.\r\n            \/\/   En mode=popup, on traite comme desktop (.show() sans contrainte de hauteur).\r\n            var _pwHash = window.location.hash || '';\r\n            var _pwSearch = window.location.search || '';\r\n            const isPopupMode = (_pwHash.indexOf('mode=popup') !== -1) ? true : (_pwSearch.indexOf('mode=popup') !== -1);\r\n            \r\n            if (isPopupMode ? false : isMobile) {\r\n                $('.PageWebTemplate').css({\r\n                    'max-height': '335px',\r\n                    'overflow-y': 'hidden'\r\n                }).show();\r\n                $('#MobileMsgReserverMSgDefaut').removeClass('via-msg-visible');\r\n                \/\/ $('#Etape1Container').css('margin-top', '-20px');\r\n            } else {\r\n                \/\/ v4.9ds : en mode=popup, le CSS injecte applique `.PageWebTemplate { display:none !important }`.\r\n                \/\/   jQuery .show() pose `display:block` SANS !important -> CSS gagne, template reste masque.\r\n                \/\/   Il faut forcer display:block avec priorite important pour outrepasser le CSS.\r\n                $('.PageWebTemplate').each(function() {\r\n                    this.style.setProperty('display', 'block', 'important');\r\n                });\r\n            }\r\n            \r\n            $('#PageWebTitreIconeUp').show();\r\n            $('#PageWebTitreIconeDown').hide();\r\n            \r\n            \/\/ \u2705 v1.9 : Masquer le message quand PageWeb est ouvert\r\n            $('#PageWebMessageContainer').hide();\r\n            \r\n            \/\/ \u2705 v1.9 : Activer le titre PageWeb (cliquable)\r\n            $('.PageWebTitre').css({\r\n                'cursor': 'pointer'\r\n            }).attr('data-etape-active', 'true').each(function() {\r\n                var is3Col = sessionStorage.getItem('PageWebColonneOpenclose') === 'Open';\r\n                if (is3Col && $(this).hasClass('elementor-widget-text-editor')) {\r\n                    this.style.setProperty('pointer-events', 'none', 'important');\r\n                    this.style.setProperty('cursor', 'default', 'important');\r\n                } else {\r\n                    this.style.setProperty('pointer-events', 'auto', 'important');\r\n                }\r\n            });\r\n            \r\n            console.log('\ud83d\udcc2 PageWeb ouvert');\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.8 : Toggle la section PageWeb (desktop et mobile)\r\n         *\/\r\n        togglePageWeb() {\r\n            const isVisible = $('.PageWebTemplate').is(':visible');\r\n            \r\n            if (isVisible) {\r\n                this.fermerPageWeb();\r\n            } else {\r\n                \/\/ \u2705 v1.16.0 : force=true pour permettre la r\u00e9ouverture manuelle\r\n                this.ouvrirPageWeb(true);\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.10 : Toggle la section R\u00e9f\u00e9rences\r\n         * Permet la visualisation m\u00eame si bon de commande cr\u00e9\u00e9 (pas de message)\r\n         *\/\r\n        toggleEtapeReferences() {\r\n            \/\/ \u2705 v1.10 : Flag temporaire pour emp\u00eacher l'affichage du message\r\n            this.state.enVisualisationEtape = true;\r\n            \r\n            const isVisible = $('.ReferencesConteneur').is(':visible');\r\n            \r\n            if (isVisible) {\r\n                \/\/ Fermer\r\n                $('.ReferencesConteneur').hide();\r\n                $('#ReferencesTitreIconeUp').hide();\r\n                $('#ReferencesTitreIconeDown').show();\r\n                console.log('\ud83d\udcc1 \u00c9tape R\u00e9f\u00e9rences ferm\u00e9e');\r\n            } else {\r\n                \/\/ Ouvrir - pas de blocage pour visualisation\r\n                $('.ReferencesConteneur').show();\r\n                $('#ReferencesTitreIconeUp').show();\r\n                $('#ReferencesTitreIconeDown').hide();\r\n                console.log('\ud83d\udcc2 \u00c9tape R\u00e9f\u00e9rences ouverte (visualisation)');\r\n            }\r\n            this._updateMessagesEtapes();\r\n            \r\n            \/\/ \u2705 v1.10 : Retirer le flag apr\u00e8s un court d\u00e9lai\r\n            setTimeout(() => {\r\n                this.state.enVisualisationEtape = false;\r\n            }, 500);\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.10 : Toggle la section Paiement\r\n         * Permet la visualisation m\u00eame si bon de commande cr\u00e9\u00e9 (pas de message)\r\n         *\/\r\n        toggleEtapePaiement() {\r\n            \/\/ \u2705 v1.10 : Flag temporaire pour emp\u00eacher l'affichage du message\r\n            this.state.enVisualisationEtape = true;\r\n            \r\n            const isVisible = $('.ChoisirPaiementClass').is(':visible');\r\n            \r\n            if (isVisible) {\r\n                \/\/ Fermer\r\n                $('.ChoisirPaiementClass').hide();\r\n                $('#ChoisirPaiementTitreIconeUp').hide();\r\n                $('#ChoisirPaiementTitreIconeDown').show();\r\n                console.log('\ud83d\udcc1 \u00c9tape Paiement ferm\u00e9e');\r\n            } else {\r\n                \/\/ Ouvrir - pas de blocage pour visualisation\r\n                $('.ChoisirPaiementClass').show();\r\n                $('#ChoisirPaiementTitreIconeUp').show();\r\n                $('#ChoisirPaiementTitreIconeDown').hide();\r\n                console.log('\ud83d\udcc2 \u00c9tape Paiement ouverte (visualisation)');\r\n            }\r\n            this._updateMessagesEtapes();\r\n            \r\n            \/\/ \u2705 v1.10 : Retirer le flag apr\u00e8s un court d\u00e9lai\r\n            setTimeout(() => {\r\n                this.state.enVisualisationEtape = false;\r\n            }, 500);\r\n        },\r\n\r\n        \/**\r\n         * \u2705 pb58 : Toggle la section Validations et CGV\r\n         * Handler manquant \u2014 identique au pattern References\/Paiement\r\n         *\/\r\n        toggleEtapeValidations() {\r\n            this.state.enVisualisationEtape = true;\r\n\r\n            const isVisible = $('#ValidationsConteneur').is(':visible');\r\n\r\n            if (isVisible) {\r\n                $('#ValidationsConteneur').hide();\r\n                $('#ValidationsTitreIconeUp').hide();\r\n                $('#ValidationsTitreIconeDown').show();\r\n                console.log('\ud83d\udcc1 \u00c9tape Validations ferm\u00e9e');\r\n            } else {\r\n                $('#ValidationsConteneur').show();\r\n                $('#ValidationsTitreIconeUp').show();\r\n                $('#ValidationsTitreIconeDown').hide();\r\n                console.log('\ud83d\udcc2 \u00c9tape Validations ouverte (visualisation)');\r\n            }\r\n            this._updateMessagesEtapes();\r\n\r\n            setTimeout(() => {\r\n                this.state.enVisualisationEtape = false;\r\n            }, 500);\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.10 : Toggle l'\u00e9tape Paiement Final (#ProcederPaiementTitre)\r\n         * Ouvre\/ferme l'\u00e9l\u00e9ment #ProcederPaiementContenu\r\n         *\/\r\n        toggleEtapePaiementFinal() {\r\n            \/\/ V\u00e9rifier si l'\u00e9tape est active\r\n            const isActive = $('#ProcederPaiementTitre').attr('data-etape-active') === 'true';\r\n            if (!isActive) {\r\n                console.log('\ud83d\udd12 \u00c9tape Paiement Final d\u00e9sactiv\u00e9e, clic ignor\u00e9');\r\n                return;\r\n            }\r\n            \r\n            const isVisible = $('#ProcederPaiementContenu').is(':visible');\r\n            \r\n            if (isVisible) {\r\n                \/\/ Fermer\r\n                $('#ProcederPaiementContenu').hide();\r\n                $('#ProcederPaiementTitreIconeUp').hide();\r\n                $('#ProcederPaiementTitreIconeDown').show();\r\n                console.log('\ud83d\udcc1 \u00c9tape Paiement Final ferm\u00e9e (#ProcederPaiementContenu masqu\u00e9)');\r\n            } else {\r\n                \/\/ Ouvrir\r\n                $('#ProcederPaiementContenu').show();\r\n                $('#ProcederPaiementTitreIconeUp').show();\r\n                $('#ProcederPaiementTitreIconeDown').hide();\r\n                console.log('\ud83d\udcc2 \u00c9tape Paiement Final ouverte (#ProcederPaiementContenu affich\u00e9)');\r\n                \r\n                \/\/ \u2705 v2.0 : Scroll to bottom dans #ColonneDroite apr\u00e8s ouverture Paiement\r\n                setTimeout(function() {\r\n                    window._viaScrollBas2354('toggle Paiement Final');\r\n                }, 100);\r\n            }\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.8 : Ferme le r\u00e9capitulatif des commandes\r\n         * @param {boolean} afficherMessage - Si true, affiche le message r\u00e9capitulatif (d\u00e9faut: true)\r\n         *\/\r\n        \/**\r\n         * \u2705 v2.7.3 : Met \u00e0 jour les messages d'info de chaque \u00e9tape\r\n         * R\u00e8gle : message visible si \u00e9tape COMPL\u00c8TE et FERM\u00c9E\r\n         * Appel\u00e9 \u00e0 chaque ouverture\/fermeture d'\u00e9tape\r\n         *\/\r\n        _updateMessagesEtapes() {\r\n            \/* pb2350 : le libelle de la croix suit l etat. Pose ici parce que\r\n               _updateMessagesEtapes est rappelee a chaque transition (sept points\r\n               d appel) : le titre ne peut pas rester en retard sur l etat. *\/\r\n            if (window._viaPb2350Off === true ? false : true) {\r\n                try {\r\n                    var _finT2350 = (typeof window._viaRacineAval2051 === 'function')\r\n                        ? window._viaRacineAval2051(null) : false;\r\n                    var _lib2350 = _finT2350 ? 'Fermer' : 'Supprimer';\r\n                    var _cx2350 = document.querySelectorAll('.CampagneCloseButton');\r\n                    for (var _i2350 = 0; _i2350 < _cx2350.length; _i2350++) {\r\n                        _cx2350[_i2350].setAttribute('title', _lib2350);\r\n                        _cx2350[_i2350].setAttribute('aria-label', _lib2350);\r\n                    }\r\n                    if (window._viaPb2350Lib !== _lib2350) {\r\n                        window._viaPb2350Lib = _lib2350;\r\n                        console.log('[pb2350] libelle de la croix : \"' + _lib2350 + '\" sur ' + _cx2350.length + ' bouton(s) | finalisee=' + _finT2350);\r\n                    }\r\n                } catch (_et2350) { console.warn('[pb2350] libelle : ' + _et2350.message); }\r\n            }\r\n\r\n            \/* ====================================================================\r\n             * pb2346 : UNE SEULE DEFINITION POUR LES QUATRE ECRIVAINS.\r\n             *   pb2345 avait ferme la porte de Panier_manage en affirmant qu il n y\r\n             *   en avait qu une. C etait faux : la verification ne portait que sur le\r\n             *   corpus alors fourni. Les JS d etape en ont trois autres \u2014\r\n             *     References.txt   l.1409  $msgOK.show()\r\n             *     Mode_de_paiement l.1327  DeviseModedePaiementMsgConteneur\r\n             *     Validations.txt  l.214   MsgCommandeValidee\r\n             *   Recopier la regle a quatre endroits serait refaire l erreur d origine :\r\n             *   quatre copies divergent. La porte est donc definie UNE fois, par le\r\n             *   premier fichier charge, et les autres la reutilisent. Aucun ordre de\r\n             *   chargement a respecter.\r\n             *   Regle (identique a pb2345) : masquer si ordinateur ET site pays.\r\n             *     largeur   _viaLargeur1263() sinon outerWidth (regle 5.4)\r\n             *     site pays la regie est yearbook-media.com EN TOP ; dans l iframe\r\n             *               popup d un site pays window.top diff\u00e8re -> pays.\r\n             *   Revert : window._viaPb2345Off = true (meme knob que pb2345).\r\n             * ==================================================================== *\/\r\n            if (typeof window._viaMasquerMsg2346 !== 'function') {\r\n                window._viaMasquerMsg2346 = function () {\r\n                    if (window._viaPb2345Off === true) { return false; }\r\n                    try {\r\n                        var _lg = (typeof window._viaLargeur1263 === 'function')\r\n                            ? window._viaLargeur1263() : window.outerWidth;\r\n                        var _rg = (window === window.top)\r\n                            ? \/^(?:www\\.)?yearbook-media\\.com$\/.test(window.location.hostname || '') : false;\r\n                        var _m = (_lg >= 1000) ? !_rg : false;\r\n                        if (window._viaPb2346Dit !== true) {\r\n                            window._viaPb2346Dit = true;\r\n                            console.log('[pb2346] phrases vertes des 4 dernieres etapes : ' + (_m ? 'MASQUEES' : 'conservees')\r\n                                + ' | largeur=' + _lg + ' | regie=' + _rg + ' (top=' + (window === window.top) + ')');\r\n                        }\r\n                        return _m;\r\n                    } catch (_e2346) { return false; }\r\n                };\r\n            }\r\n\r\n            var _pb2345 = window._viaMasquerMsg2346();   \/\/ pb2346 : une seule definition, partagee avec les JS d etape\r\n\r\n            \r\n            \/\/ \u2500\u2500 Helper : forcer display block sur conteneur + enfant (passe les !important Elementor) \u2500\u2500\r\n            function _showMsg(conteneurId, enfantId) {\r\n                var _cont = document.getElementById(conteneurId);\r\n                \/\/ enfantId peut \u00eatre un ID string ou null (\u2192 fallback premier widget enfant)\r\n                var _enf = enfantId ? document.getElementById(enfantId)\r\n                         : (_cont ? _cont.querySelector('.elementor-widget') : null);\r\n                if (_cont) {\r\n                    _cont.classList.remove('elementor-hidden-desktop', 'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                    _cont.style.setProperty('display', 'block', 'important');\r\n                }\r\n                if (_enf) {\r\n                    _enf.classList.remove('elementor-hidden-desktop', 'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                    _enf.style.setProperty('display', 'block', 'important');\r\n                }\r\n            }\r\n            function _hideMsg(conteneurId, enfantId) {\r\n                var _cont = document.getElementById(conteneurId);\r\n                var _enf = enfantId ? document.getElementById(enfantId)\r\n                         : (_cont ? _cont.querySelector('.elementor-widget') : null);\r\n                if (_cont) { _cont.style.setProperty('display', 'none', 'important'); }\r\n                if (_enf)  { _enf.style.setProperty('display', 'none', 'important'); }\r\n            }\r\n\r\n            \/\/ \u2500\u2500 \u00c9tape Dates \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            \/\/ v4.9ds : d\u00e9tection mode=popup robuste \u2014 lire HASH d'abord (le mode popup\r\n            \/\/   moderne utilise URL hash #mode=popup&...) puis fallback sur SEARCH.\r\n            const _isPopupMsgUD = (function() {\r\n                try {\r\n                    var _h = window.location.hash || '';\r\n                    if (_h && _h.indexOf('mode=popup') !== -1) return true;\r\n                    return window.location.search.indexOf('mode=popup') !== -1;\r\n                } catch(_e) { return false; }\r\n            })();\r\n            const datesOuvert  = $('.DatesDureeCampagneClass').is(':visible');\r\n            const datesComplet = this.state.items.some(function(i) { return i.tarifHT && i.tarifHT > 0; });\r\n            if (!datesOuvert && datesComplet) {\r\n                _showMsg('Etape1MessageContainer', 'Etape1MessageTexte');\r\n            } else {\r\n                if (!_isPopupMsgUD) { _hideMsg('Etape1MessageContainer', 'Etape1MessageTexte'); }\r\n            }\r\n\r\n            \/\/ \u2500\u2500 \u00c9tape R\u00e9capitulatif \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            const recapOuvert  = this.state.recapOuvert;\r\n            \/\/ pb1255 : la presence d'un item ne vaut pas reservation validee \u2014 un\r\n            \/\/   item partiel existe des le choix du pays. Meme critere que dans le\r\n            \/\/   sequenceur, pour que les deux writers de cette propriete disent la\r\n            \/\/   meme chose.\r\n            const recapComplet = (typeof this._resaValidee1255 === 'function')\r\n                ? this._resaValidee1255()\r\n                : (this.state.items.length > 0);\r\n            \/* pb1632 : pb1631 RETIRE \u2014 la phrase verte doit s'afficher (user).\r\n               Les deux ecrivains reprennent leur comportement d'origine ; c'est\r\n               l'empilement sous le titre (pb1632b, feuille popup) qui traite la\r\n               superposition, pas le masquage. *\/\r\n            \/* pb1991 : meme critere unique que le sequenceur. recapComplet reste\r\n               calcule pour servir d'ancien booleen au revert. *\/\r\n            if (this._msgRecapVisible1991(!recapOuvert ? recapComplet : false)) {\r\n                if (_pb2345) { _hideMsg('RecapitulatifMessageContainer', 'RecapitulatifMessageTexte'); }   \/\/ pb2345 : pays + ordinateur -> pas de phrase verte\r\n                else { _showMsg('RecapitulatifMessageContainer', 'RecapitulatifMessageTexte'); }\r\n            } else {\r\n                _hideMsg('RecapitulatifMessageContainer', 'RecapitulatifMessageTexte');\r\n            }\r\n            \/* ====================================================================\r\n             * pb2347 : DESCENDRE LE TITRE << Vos reservations >> DE 10 px QUAND\r\n             *   L ETAPE EST RENSEIGNEE (demande JF).\r\n             *   Mesure JF dans la console :\r\n             *     RecapitulatifVosCommandestitreContainer | margin-top calcule = 0px\r\n             *                                             | inline = (vide) | top = 223\r\n             *   Donc AUCUNE des deux regles de yearbook-media.js ne gouverne ici (elles\r\n             *   donneraient 7px ou -13px) : la marge vient d Elementor et vaut zero. Il\r\n             *   n y a rien a combattre, seulement une valeur a poser. On l ecrit en\r\n             *   INLINE avec !important : c est le seul niveau qui batte a coup sur les\r\n             *   feuilles injectees si l une d elles se reveillait dans un autre contexte.\r\n             *\r\n             *   << RENSEIGNEE >> n est pas devine : on reprend _resaValidee1255(), la\r\n             *   definition unique deja utilisee par cette meme etape pour decider de sa\r\n             *   phrase d etat. pb1255 l a posee precisement pour qu il n y ait pas deux\r\n             *   criteres qui se contredisent a deux rythmes. On ne s en ecarte pas.\r\n             *\r\n             *   La marge est RETIREE quand l etape ne l est plus : une valeur posee doit\r\n             *   savoir se retirer, sinon elle se cumule au fil des transitions.\r\n             *   Reglage : window._viaPb2347Px (pb2348 : defaut 8, etait 10 \u2014 ajuste sur le\r\n             * ==================================================================== *\/\r\n            if (window._viaPb2347Off === true ? false : true) {\r\n                try {\r\n                    var _tc2347 = document.getElementById('RecapitulatifVosCommandestitreContainer');\r\n                    if (_tc2347) {\r\n                        var _px2347 = (typeof window._viaPb2347Px === 'number') ? window._viaPb2347Px : 8;   \/\/ pb2348 : 10 -> 8 (mesure JF sur rendu)\r\n                        var _rens2347 = this._resaValidee1255();\r\n                        if (_rens2347) { _tc2347.style.setProperty('margin-top', _px2347 + 'px', 'important'); }\r\n                        else { _tc2347.style.removeProperty('margin-top'); }\r\n                        if (window._viaPb2347Etat !== _rens2347) {\r\n                            window._viaPb2347Etat = _rens2347;\r\n                            console.log('[pb2347] titre Vos reservations : etape ' + (_rens2347 ? 'RENSEIGNEE -> margin-top ' + _px2347 + 'px' : 'vide -> marge retiree')\r\n                                + ' | calcule=' + window.getComputedStyle(_tc2347).marginTop\r\n                                + ' | top=' + Math.round(_tc2347.getBoundingClientRect().top));\r\n                        }\r\n                    }\r\n                } catch (_e2347) { console.warn('[pb2347] ' + _e2347.message); }\r\n            }\r\n\r\n\r\n            \/\/ \u2500\u2500 \u00c9tape R\u00e9f\u00e9rences \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            const refOuvert  = $('.ReferencesConteneur').is(':visible');\r\n            const refComplet = sessionStorage.getItem('ReferencesValidees') === 'Yes';\r\n            \/\/ v4.9ds : en mode popup (sites pays), ce message ne doit JAMAIS s'afficher\r\n            \/\/   (sinon _showMsg pose un style inline display:block !important qui bat\r\n            \/\/   notre CSS via-popup-process-achat-spacing).\r\n            \/\/ \u2705 v4.9ds Pb 7 : ce message ne doit pas s'afficher avant le clic FinaliserBouton.\r\n            \/\/   Avant : un sessionStorage r\u00e9siduel (ReferencesValidees=Yes) d'une session\r\n            \/\/   pr\u00e9c\u00e9dente faisait appara\u00eetre \"Les r\u00e9f\u00e9rences sont indiqu\u00e9es\" d\u00e8s l'ouverture\r\n            \/\/   du recap, ce qui n'a pas de sens pour une nouvelle r\u00e9servation.\r\n            var _finaliserCliqueMsg = window._viaFinaliserClique === true;\r\n            \/* pb1719 : la garde popup tombe \u2014 voir le bandeau de la feuille *\/\r\n            var _popMsg1719 = (window._viaPb1719Off === true) ? _isPopupMsgUD : false;\r\n            if (!refOuvert && refComplet && !_popMsg1719 && _finaliserCliqueMsg) {\r\n                if (_pb2345) { _hideMsg('MsgCompleterFormulaireOKConteneur', 'MsgCompleterFormulaireOK'); }   \/\/ pb2345 : pays + ordinateur -> pas de phrase verte\r\n                else { _showMsg('MsgCompleterFormulaireOKConteneur', 'MsgCompleterFormulaireOK'); }\r\n            } else {\r\n                _hideMsg('MsgCompleterFormulaireOKConteneur', 'MsgCompleterFormulaireOK');\r\n            }\r\n\r\n            \/\/ \u2500\u2500 \u00c9tape Mode de paiement \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            const paiementOuvert  = $('.ChoisirPaiementClass').is(':visible');\r\n            const paiementComplet = sessionStorage.getItem('ModePaiementChoisi') === 'Yes';\r\n            \/\/ v4.9ds : idem mode popup\r\n            \/\/ \u2705 v4.9ds Pb 7 : idem \u2014 ne pas afficher avant clic FinaliserBouton.\r\n            if (!paiementOuvert && paiementComplet && !_popMsg1719 && _finaliserCliqueMsg) {\r\n                if (_pb2345) { _hideMsg('DeviseModedePaiementMsgConteneur', 'DeviseModedePaiementMsg'); }   \/\/ pb2345 : pays + ordinateur -> pas de phrase verte\r\n                else { _showMsg('DeviseModedePaiementMsgConteneur', 'DeviseModedePaiementMsg'); }\r\n            } else {\r\n                _hideMsg('DeviseModedePaiementMsgConteneur', 'DeviseModedePaiementMsg');\r\n            }\r\n\r\n            \/\/ \u2500\u2500 \u00c9tape Validation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n            const validationOuvert  = $('#ValidationsConteneur').is(':visible');\r\n            \/\/ \u2705 BonCommandeCree plut\u00f4t que FinaliserStep (pos\u00e9 trop t\u00f4t au clic 'Passer commande')\r\n            const validationComplet = sessionStorage.getItem('BonCommandeCree') === 'Yes';\r\n            if (!validationOuvert && validationComplet) {\r\n                if (_pb2345) { _hideMsg('MsgCommandeValidee', null); }   \/\/ pb2345 : pays + ordinateur -> pas de phrase verte\r\n                else { _showMsg('MsgCommandeValidee', null); }\r\n            } else {\r\n                _hideMsg('MsgCommandeValidee', null);\r\n            }\r\n        },\r\n\r\n        fermerRecapitulatif(afficherMessage = true) {\r\n            \/\/ ================================================================\r\n            \/\/ pb1419 : NE PAS REFERMER QUAND LA PAGE WEB EST OUVERTE.\r\n            \/\/   Le log a nomme la sequence exacte :\r\n            \/\/     [pb1417] r\u00e9capitulatif ouvert, process classique (apr\u00e8s 700 ms)\r\n            \/\/     \ud83d\udcc1 R\u00e9capitulatif ferm\u00e9\r\n            \/\/     [pb1099] recapitulatif -> ferm\u00e9          <- 5 ms plus tard\r\n            \/\/   Le sequenceur pb1099 fait son travail : il ouvre l'etape COURANTE et\r\n            \/\/   ferme les autres. Avec \u00ab faits=001000 \u00bb l'annonceur n'est pas\r\n            \/\/   renseigne, l'etape courante est donc l'annonceur \u2014 et le\r\n            \/\/   recapitulatif se referme aussitot apres chacune de mes ouvertures.\r\n            \/\/   Ouvrir plus fort ou plus tard n'aurait rien change : les deux writers\r\n            \/\/   se seraient repondus indefiniment, comme pb1412 et pb841 tout a\r\n            \/\/   l'heure. C'est la fermeture qui doit connaitre le contexte.\r\n            \/\/   Une fois la page web affichee, le recapitulatif est justement ce que\r\n            \/\/   l'utilisateur doit voir : la reservation s'y lit et s'y poursuit. La\r\n            \/\/   regle du sequenceur reste juste pendant la saisie, elle ne l'est plus\r\n            \/\/   apres.\r\n            \/\/   Mobile uniquement, via le critere partage : sur desktop les 3 colonnes\r\n            \/\/   montrent deja tout et le sequenceur garde la main.\r\n            \/\/   Revert : window._viaPb1419Off = true.\r\n            \/\/ ================================================================\r\n            \/* ============================================================\r\n             * pb1720 : L EXCEPTION pb1419 S ARRETE A LA FINALISATION.\r\n             *   Constat user : apres l ajout d une reservation et la finalisation\r\n             *   de la commande, le contenu de l etape \u00ab Vos reservations \u00bb reste\r\n             *   affiche sur les sites pays. Le HTML le confirme :\r\n             *   .VosCampagnesConteneurClass porte opacity 0.6 et pointer-events\r\n             *   none \u2014 il est GRISE, donc pas masque.\r\n             *   fermerRecapitulatif fait pourtant le hide qu il faut (l.15680).\r\n             *   Mais pb1419 le fait sortir avant, quand une page web est ouverte :\r\n             *     \u00ab le recapitulatif est justement ce que l utilisateur doit voir :\r\n             *       la reservation s y lit et s y poursuit \u00bb\r\n             *   Ce motif est juste PENDANT la saisie. Apres la finalisation, plus\r\n             *   rien ne s y poursuit : la commande est passee, les reservations ne\r\n             *   sont plus modifiables (FinaliserStep=Yes est pose au meme clic).\r\n             *   L exception avait un debut et pas de fin ; on lui en donne une.\r\n             *   Revert : window._viaPb1720Off = true (pb1419 vaut aussi apres).\r\n             * ============================================================ *\/\r\n            var _finalise1720 = false;\r\n            if (window._viaPb1720Off !== true) {\r\n                try {\r\n                    _finalise1720 = (window._viaFinaliserClique === true)\r\n                        ? true : (sessionStorage.getItem('FinaliserStep') === 'Yes');\r\n                } catch (_eF1720) { _finalise1720 = (window._viaFinaliserClique === true); }\r\n            }\r\n            if (window._viaPb1419Off !== true ? !_finalise1720 : false) {\r\n                try {\r\n                    var _mob1419 = (navigator.maxTouchPoints > 0)\r\n                        ? true : (window.innerWidth < 1000);\r\n                    var _pw1419 = (typeof window._viaInfosDansResa1402 === 'function')\r\n                        ? window._viaInfosDansResa1402() : false;\r\n                    if (_mob1419 ? _pw1419 : false) {\r\n                        if (window._viaSig1419 !== 'bloque') {\r\n                            window._viaSig1419 = 'bloque';\r\n                            console.log('[pb1419] fermeture du r\u00e9capitulatif ignor\u00e9e'\r\n                                + ' \u2014 page web ouverte (mobile)');\r\n                        }\r\n                        return;\r\n                    }\r\n                    if (window._viaSig1419 === 'bloque') { window._viaSig1419 = null; }\r\n                } catch (_e1419) {\r\n                    console.warn('[pb1419] crit\u00e8re illisible : ' + _e1419.message);\r\n                }\r\n            }\r\n            if (_finalise1720) {\r\n                if (window._viaSig1720 !== 'ferme') {\r\n                    window._viaSig1720 = 'ferme';\r\n                    console.log('[pb1720] commande finalisee -> recapitulatif ferme'\r\n                        + ' (exception pb1419 levee)');\r\n                }\r\n            }\r\n            const _mode3Colonnes = sessionStorage.getItem('PageWebColonneOpenclose') === 'Open';\r\n            $('.VosCampagnesConteneurClass').hide();\r\n            $('#SyntheseConteneur').hide();\r\n            $('#PayableText').hide();\r\n            \/\/ \u2705 En mode 3 colonnes : ne pas toucher aux ic\u00f4nes (g\u00e9r\u00e9es par PageWebColonneOpen\/Close)\r\n            if (!_mode3Colonnes) {\r\n            }\r\n            \/\/ Stocker l'\u00e9tat\r\n            this.state.recapOuvert = false;\r\n            \r\n            \/\/ \u2705 v1.8 : Afficher le message si des commandes existent ET si demand\u00e9\r\n            if (afficherMessage && this.state.items.length > 0 && sessionStorage.getItem('FinaliserStep') === 'Yes') {\r\n                \/* pb2345 : meme regle qu au-dessus \u2014 sur un site pays en ordinateur, cette\r\n                   phrase ne doit plus apparaitre. La garde est recalculee ici parce que ce\r\n                   chemin ne passe pas par _updateMessagesEtapes. *\/\r\n                var _pays2345b = window._viaMasquerMsg2346();   \/\/ pb2346 : meme porte\r\n                var _rmc = document.getElementById('RecapitulatifMessageContainer');\r\n                if (_rmc ? _pays2345b : false) { _rmc.style.setProperty('display', 'none', 'important'); _rmc = null; }\r\n                if (_rmc) { _rmc.classList.remove('elementor-hidden-desktop','elementor-hidden-tablet','elementor-hidden-mobile'); _rmc.style.setProperty('display','block','important'); }\r\n                console.log('\u2705 RecapitulatifMessage affich\u00e9');\r\n            }\r\n            \r\n            console.log('\ud83d\udcc1 R\u00e9capitulatif ferm\u00e9');\r\n            this._updateMessagesEtapes();\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.8 : Ouvre le r\u00e9capitulatif des commandes\r\n         *\/\r\n        ouvrirRecapitulatif() {\r\n            \/\/ \u2705 v1.10 : Ne pas ouvrir le r\u00e9capitulatif si \u00e9tape R\u00e9f\u00e9rences ou Paiement est ouverte\r\n            const referencesOuvert = $('.ReferencesConteneur').is(':visible');\r\n            const paiementOuvert = $('.ChoisirPaiementClass').is(':visible');\r\n            const validationsOuvert = $('#ValidationsConteneur').is(':visible');\r\n            \r\n            \/\/ \u2705 Fermer l'\u00e9tape Date, Dur\u00e9e et Tarif de campagne\r\n            $('.DatesDureeCampagneClass').hide();\r\n            $('#DatesDureeCampagneIconeUp').hide();\r\n            $('#DatesDureeCampagneIconeDown').show();\r\n            \r\n            \/\/ v2.9 : Sites pays (mode=popup) \u2014 r\u00e9ouvrir les Dates apr\u00e8s recap (desktop + mobile)\r\n            \/\/ v4.9ds : d\u00e9tection mode popup via HASH + search (params en hash dans v4.9ds)\r\n            var _isPopupModeRecap = (new URLSearchParams(window.location.hash.substring(1) || window.location.search).get('mode') === 'popup');\r\n            if (_isPopupModeRecap) {\r\n                var _selfPMR = this;\r\n                setTimeout(function() {\r\n                    \/\/ \u2705 v2.7.3 : Ne pas rouvrir si le tarif a \u00e9t\u00e9 valid\u00e9 (clic sur Etape1BoutonValider)\r\n                    if (sessionStorage.getItem('etape1_tarif_valide') === 'Yes') {\r\n                        console.log('\ud83d\udcc5 [sites pays] DatesDureeCampagneClass NON r\u00e9ouverte \u2014 tarif valid\u00e9');\r\n                        return;\r\n                    }\r\n                    $('.DatesDureeCampagneClass').show();\r\n                    $('#DatesDureeCampagneIconeUp').show();\r\n                    $('#DatesDureeCampagneIconeDown').hide();\r\n                    \/\/ v4.9ds : replacer Dates apr\u00e8s R\u00e9cap + activer titre (rouge)\r\n                    if (typeof _selfPMR._viaActiverEtapeDates === 'function') { _selfPMR._viaActiverEtapeDates(); }\r\n                    console.log('\ud83d\udcc5 [sites pays] DatesDureeCampagneClass r\u00e9ouverte apr\u00e8s recap');\r\n                    \/\/ [pb231-dbg] snapshot de l'etat reel des dates apres settling (500ms apres reouverture)\r\n                    setTimeout(function() {\r\n                        function _pb231st(el) {\r\n                            if (!el) { return 'ABSENT'; }\r\n                            var cs = getComputedStyle(el);\r\n                            var par = el.parentElement ? (el.parentElement.id || el.parentElement.className || '?') : '?';\r\n                            return 'display=' + cs.display + ' vis=' + cs.visibility + ' opacity=' + cs.opacity + ' offH=' + el.offsetHeight + ' parent=' + String(par).slice(0, 50);\r\n                        }\r\n                        var _pb231d = document.querySelector('.DatesDureeCampagneClass');\r\n                        var _pb231p = document.getElementById('ProcessAchatInside');\r\n                        var _pb231a = _selfPMR.state.items.find(function(i) { return i.id === _selfPMR.state.itemActif; });\r\n                        console.log('[pb231-dbg] DatesDureeCampagneClass:', _pb231st(_pb231d));\r\n                        console.log('[pb231-dbg] ProcessAchatInside :', _pb231st(_pb231p));\r\n                        console.log('[pb231-dbg] itemActif:', _pb231a ? JSON.stringify({ id: _pb231a.id, statut: _pb231a.statut, empl: _pb231a.emplacementPageWeb, reserve: _pb231a.estReserveEffective, tarif: _pb231a.tarifHT, dateDebut: _pb231a.dateDebut, dateFin: _pb231a.dateFin }) : 'NULL');\r\n                        console.log('[pb231-dbg] etape1_tarif_valide:', sessionStorage.getItem('etape1_tarif_valide'));\r\n                    }, 500);\r\n                }, 350);\r\n            }\r\n            \r\n            \/\/ \u2705 v2.4.5 : Ne pas griser Dates ici \u2014 seulement au clic sur Finaliser\r\n            console.log('\ud83d\udcc1 \u00c9tape DatesDureeCampagne ferm\u00e9e');\r\n            \r\n            \/\/ \u2705 v1.9 : Afficher le message Etape1 si un tarif est d\u00e9fini \u2014 masqu\u00e9 en mode=popup\r\n            var _isPopupModeOR = window.location.search.indexOf('mode=popup') !== -1;\r\n            if (!_isPopupModeOR) {\r\n                if (this.state.items.some(item => item.tarifHT && item.tarifHT > 0)) {\r\n                    var _e1c2 = document.getElementById('Etape1MessageContainer');\r\n                    var _e1t2 = document.getElementById('Etape1MessageTexte');\r\n                    if (_e1c2) { _e1c2.classList.remove('elementor-hidden-desktop','elementor-hidden-tablet','elementor-hidden-mobile'); _e1c2.style.setProperty('display','block','important'); }\r\n                    if (_e1t2) { _e1t2.classList.remove('elementor-hidden-desktop','elementor-hidden-tablet','elementor-hidden-mobile'); _e1t2.style.setProperty('display','block','important'); }\r\n                    console.log('\u2705 Etape1Message affich\u00e9');\r\n                }\r\n            } else {\r\n                $('#Etape1MessageContainer').hide();\r\n                console.log('\ud83d\ude48 [mode=popup] Etape1MessageContainer masqu\u00e9');\r\n            }\r\n            \r\n            \/\/ \u2705 v1.9 : Masquer le message r\u00e9capitulatif quand ouvert\r\n            $('#RecapitulatifMessageContainer').hide();\r\n            \r\n            \/\/ Ouvrir le r\u00e9capitulatif\r\n            console.log('\ud83d\udcc2 [ouvrirRecap] state.items count:', this.state.items.length);\r\n            console.log('\ud83d\udcc2 [ouvrirRecap] items:', JSON.stringify(this.state.items.map(i => ({id:i.id, statut:i.statut, tarifHT:i.tarifHT, emplacementPageWeb:i.emplacementPageWeb}))));\r\n            console.log('\ud83d\udcc2 [ouvrirRecap] VosCampagnesConteneurClass length:', $('.VosCampagnesConteneurClass').length);\r\n            console.log('\ud83d\udcc2 [ouvrirRecap] CampagneTemplateClass (hors template) length:', $('.CampagneTemplateClass').not('#CampagneTemplate').length);\r\n            \/\/ \u2705 v2.0.9 : Mobile \u2014 rendre #EtapeRecapitulatif visible (masqu\u00e9 par d\u00e9faut via CSS)\r\n            $('#EtapeRecapitulatif').addClass('via-etape-visible');\r\n            \/\/ \u2705 En mode=popup, PageWebColonneOpen n'est pas appel\u00e9 \u2192 ajouter via-etape-visible manuellement\r\n            $('#EtapeReferences, #EtapeModedePaiement, #EtapeValidations, #EtapePaiement').addClass('via-etape-visible');\r\n            console.log('[ouvrirRecap] via-etape-visible ajout\u00e9 \u00e0 toutes les \u00e9tapes');\r\n            console.log('[ouvrirRecap] EtapeReferences visible:', $('#EtapeReferences').is(':visible'), '| classe:', $('#EtapeReferences').hasClass('via-etape-visible'));\r\n            $('.VosCampagnesConteneurClass').show();\r\n            console.log('[ouvrirRecap] VosCampagnesConteneurClass shown | length:', $('.VosCampagnesConteneurClass').length);\r\n            \/\/ pb1257 : les cartes viennent d'acquerir une mise en page \u2014 c'est ici,\r\n            \/\/   et seulement ici, qu'on peut les mesurer. Le .show() ci-dessus rend\r\n            \/\/   la lecture de geometrie exacte : elle force le calcul du layout.\r\n            if (window._viaPb1254Off !== true) {\r\n                try {\r\n                    var _selfN1257 = this;\r\n                    (this.state.items || []).forEach(function (_itN1257) {\r\n                        var $cN1257 = $('#' + _itN1257.id);\r\n                        if (!$cN1257.length) { return; }\r\n                        _selfN1257._normaliserCarte1254($cN1257, _itN1257);\r\n                    });\r\n                } catch (_eN1257) { console.warn('[pb1257]', _eN1257.message); }\r\n            }\r\n            \/\/ \u2705 v2.7.3 : Ajustements positionnement sites pays (mode=popup)\r\n            \/\/ setProperty inline > tout Elementor !important\r\n            if (window.location.search.indexOf('mode=popup') !== -1) {\r\n                $('.VosCampagnesConteneurClass').each(function() {\r\n                    this.style.setProperty('margin-top', '6px', 'important');\r\n                });\r\n                var _paiEl = document.getElementById('ProcessAchatInside');\r\n                if (_paiEl) { _paiEl.style.setProperty('margin-top', '-10px', 'important'); }\r\n            }\r\n            \/\/ \u2705 v2.5 : Message info multi-r\u00e9servation \u2014 mode=popup uniquement (pas sur la r\u00e9gie)\r\n            if (window.location.search.indexOf('mode=popup') !== -1) (function() {\r\n                var _msgId = 'via-multi-resa-info';\r\n                if (document.getElementById(_msgId)) { return; }\r\n                var _lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                var _txt = _lang === 'EN'\r\n                    ? 'You can reserve multiple advertising spaces on this page.'\r\n                    : 'Vous pouvez r\u00e9server plusieurs espaces publicitaires sur cette page';\r\n                var _anchor = document.getElementById('RecapitulatifVosCommandestitreContainer');\r\n                if (_anchor) {\r\n                    var _msg = document.createElement('div');\r\n                    _msg.id = _msgId;\r\n                    _msg.style.cssText = 'margin-top:-15px;margin-bottom:10px;margin-left:0;margin-right:0;padding:6px 10px;background:#EBF3FF;border-radius:4px;font-family:Roboto,Arial,sans-serif;font-size:12px;font-weight:500;color:#4B689B;line-height:1.4;text-align:center;';\r\n                    _msg.textContent = _txt;\r\n                    _anchor.parentNode.insertBefore(_msg, _anchor);\r\n                }\r\n            })();\r\n            $('#SyntheseConteneur').show();\r\n            if (sessionStorage.getItem('FinaliserStep') === 'Yes') { $('#SyntheseConteneur').hide(); }\r\n            $('#PayableText').show();\r\n            \/\/ \u2705 En mode 3 colonnes : forcer couleur \u00e9tape en cours sur titre r\u00e9capitulatif\r\n            \/\/ v4.9ds : couleur lue depuis la variable CSS --via-etape-active-color\r\n            if (sessionStorage.getItem('PageWebColonneOpenclose') === 'Open') {\r\n                var _vColorRC = window._viaEtapeActiveColor();\r\n                $('#RecapitulatifVosCommandestitreTexte').find('*').addBack().each(function() {\r\n                    this.style.setProperty('color', _vColorRC, 'important');\r\n                });\r\n            }\r\n            \/\/ Stocker l'\u00e9tat\r\n            this.state.recapOuvert = true;\r\n\r\n            console.log('\ud83d\udcc2 R\u00e9capitulatif ouvert');\r\n        },\r\n        \r\n        \/**\r\n         * \u2705 v1.8 : Toggle le r\u00e9capitulatif des commandes\r\n         *\/\r\n        toggleRecapitulatif() {\r\n            \/\/ \u2705 Source de v\u00e9rit\u00e9 : this.state.recapOuvert (en m\u00e9moire, ind\u00e9pendant du DOM)\r\n            const estOuvert = this.state.recapOuvert === true;\r\n            console.log('\ud83d\udd04 toggleRecapitulatif - recapOuvert:', this.state.recapOuvert, '| \u2192 estOuvert:', estOuvert);\r\n            \r\n            if (estOuvert) {\r\n                console.log('\ud83d\udd04 \u2192 fermerRecapitulatif()');\r\n                this.fermerRecapitulatif();\r\n            } else {\r\n                console.log('\ud83d\udd04 \u2192 ouvrirRecapitulatif()');\r\n                this.ouvrirRecapitulatif();\r\n            }\r\n            console.log('\ud83d\udd04 apr\u00e8s toggle \u2014 recapOuvert:', this.state.recapOuvert);\r\n        },\r\n    };\r\n    \r\n    \/**\r\n     * Auto-initialisation au chargement\r\n     *\/\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', () => {\r\n            setTimeout(() => {\r\n                if (typeof jQuery !== 'undefined') {\r\n                    jQuery(function() {\r\n                        window.VIA_Panier.init();\r\n                    });\r\n                }\r\n            }, 500);\r\n        });\r\n    } else {\r\n        setTimeout(() => {\r\n            if (typeof jQuery !== 'undefined') {\r\n                jQuery(function() {\r\n                    window.VIA_Panier.init();\r\n                });\r\n            }\r\n        }, 500);\r\n    }\r\n    \r\n    console.log('\u2705 Panier Manager v1.7 charg\u00e9 (MOBILE FIX + ANTI-REBOND)');\r\n\r\n})();\r\n\r\n\/**\r\n * VIA Agency - Adaptateur Bidirectionnel Items \u2194 SessionStorage\r\n * Version 1.0 - Pont entre nouveau et ancien syst\u00e8me\r\n *\/\r\n\r\n(function() {\r\n    'use strict';\r\n\r\n    console.log('\ud83d\udd17 Initialisation Adaptateur Items \u2194 SessionStorage v1.0');\r\n\r\n    window.VIA_Adaptateur = {\r\n        \r\n        \/**\r\n         * Mapping complet des propri\u00e9t\u00e9s\r\n         *\/\r\n        mappings: {\r\n            'emplacementPageWeb': 'Commande_Emplacement_Page_Web',\r\n            'format': 'Commande_Format_Transmis',\r\n            'position': 'PositionDataVosCampagnes',\r\n            'pays': 'NationaliteDataVosCampagnes',\r\n            'dateDebut': 'Debut_de_campagne',\r\n            'dateFin': 'Fin_de_campagne',\r\n            'duree': 'Duree_de_la_campagne',\r\n            'tarifHT': 'TarifHTDataVosCampagnes',\r\n            'tarifTTC': 'TarifTTCDataVosCampagnes',\r\n            'devise': 'selected_currency_visuels',\r\n            'donneesIframe.AddNewRefInVosCampagnes': 'AddNewRefInVosCampagnes',\r\n            'donneesIframe.Commande_Emplacement_Page_Web': 'Commande_Emplacement_Page_Web',\r\n            'donneesIframe.Commande_Format_Transmis': 'Commande_Format_Transmis',\r\n            'donneesIframe.EnvoiUlterieur': 'EnvoiUlterieur',\r\n            'donneesIframe.FileReceived': 'FileReceived',\r\n            'donneesIframe.FullPathAdFile': 'FullPathAdFileOnly',\r\n            'donneesIframe.codePage': 'codePage',\r\n            'donneesIframe.LoadedPageUrl': 'LoadedPageUrl',\r\n            'donneesIframe.Rank_Emplacement_Page_Web': 'Rank_Emplacement_Page_Web',\r\n            'donneesIframe.Upload_File_Name': 'Upload_File_Name',\r\n            'donneesIframe.EspPubLienAnnonce': 'EspPubLienAnnonce',\r\n            \/\/ v4.9ds (estReserveEffective) : flag de r\u00e9servation effective persist\u00e9\r\n            \/\/   pour survivre aux refresh. Pos\u00e9 \u00e0 true uniquement par les 3 sites de\r\n            \/\/   r\u00e9servation effective (yearbook-media:11611, 11657, Formulaire:2223).\r\n            'estReserveEffective': 'EstReserveEffective',\r\n            'selectedPage': 'SelectedPage',\r\n            'selectedPageType': 'SelectedPageType',\r\n            'selectedPageSecteur': 'SelectedPageSecteur',\r\n            'commandePage': 'commandePage',\r\n            'linkSecteurPage': 'LinkSecteurPage',\r\n            'continentPaysTitre': 'ContinentPaysTitre',\r\n            'selectedPageSecteurDisplayed': 'SelectedPageSecteurDisplayed'\r\n        },\r\n        \r\n        \/**\r\n         * R\u00e9cup\u00e8re l'index d'un item depuis sessionStorage\r\n         *\/\r\n        getItemIndex(itemId) {\r\n            const item = window.VIA_Panier.state.items.find(i => i.id === itemId);\r\n            if (!item) return null;\r\n            \r\n            \/\/ \u2705 v2.1.2 : Utiliser sessionStorageIndex m\u00e9moris\u00e9 (fiable apr\u00e8s premi\u00e8re sync)\r\n            if (item.sessionStorageIndex) {\r\n                return item.sessionStorageIndex;\r\n            }\r\n            \r\n            const maxIndex = parseInt(sessionStorage.getItem('CampagneIndex') || '0');\r\n            \r\n            for (let i = 1; i <= maxIndex; i++) {\r\n                \/\/ v4.9ds : skip si un AUTRE item du panier occupe d\u00e9j\u00e0 cet index.\r\n                \/\/   Sans \u00e7a, le fallback URL ci-dessous matche le linkSecteurPage commun \u00e0\r\n                \/\/   plusieurs Ele*A sur la m\u00eame page \u2192 un nouvel item se voit attribuer\r\n                \/\/   l'index d'un item existant \u2192 \u00e9crasement des donn\u00e9es du voisin et\r\n                \/\/   doublon DOM dans le r\u00e9capitulatif.\r\n                const _otherItemSameIdx = window.VIA_Panier.state.items.find(\r\n                    it => it.id !== itemId && it.sessionStorageIndex === i\r\n                );\r\n                if (_otherItemSameIdx) continue;\r\n                \r\n                const storedEmplacement = sessionStorage.getItem(`Commande_Emplacement_Page_Web${i}`);\r\n                if (storedEmplacement && storedEmplacement === item.emplacementPageWeb) {\r\n                    return i;\r\n                }\r\n                \/\/ \u2705 v2.1.2 : Fallback par URL si emplacementPageWeb pas encore stock\u00e9\r\n                if (!storedEmplacement || storedEmplacement === 'null') {\r\n                    const storedUrl = sessionStorage.getItem(`LinkSecteurPage${i}`);\r\n                    if (storedUrl && item.linkSecteurPage && storedUrl === item.linkSecteurPage) {\r\n                        return i;\r\n                    }\r\n                }\r\n            }\r\n            \r\n            return null;\r\n        },\r\n        \r\n        \/**\r\n         * Cr\u00e9e un nouvel index dans sessionStorage\r\n         *\/\r\n        createNewIndex() {\r\n            const currentIndex = parseInt(sessionStorage.getItem('CampagneIndex') || '0');\r\n            const newIndex = currentIndex + 1;\r\n            sessionStorage.setItem('CampagneIndex', newIndex);\r\n            console.log(`\ud83d\udcca Nouvel index cr\u00e9\u00e9: ${newIndex}`);\r\n            return newIndex;\r\n        },\r\n        \r\n        \/**\r\n         * Lit une propri\u00e9t\u00e9 nested\r\n         *\/\r\n        getNestedProperty(obj, path) {\r\n            return path.split('.').reduce((current, prop) => current?.[prop], obj);\r\n        },\r\n        \r\n        \/**\r\n         * D\u00e9finit une propri\u00e9t\u00e9 nested\r\n         *\/\r\n        setNestedProperty(obj, path, value) {\r\n            const parts = path.split('.');\r\n            const last = parts.pop();\r\n            const target = parts.reduce((current, prop) => {\r\n                if (!current[prop]) current[prop] = {};\r\n                return current[prop];\r\n            }, obj);\r\n            target[last] = value;\r\n        },\r\n        \r\n        \/**\r\n         * SYNCHRONISATION : Item \u2192 SessionStorage\r\n         *\/\r\n        syncItemToSessionStorage(itemId, forceNewIndex = false) {\r\n            const item = window.VIA_Panier.state.items.find(i => i.id === itemId);\r\n            if (!item) {\r\n                console.warn('\u26a0\ufe0f Item introuvable pour sync:', itemId);\r\n                return null;\r\n            }\r\n            \r\n            let index = forceNewIndex ? null : this.getItemIndex(itemId);\r\n            \r\n            if (!index) {\r\n                index = this.createNewIndex();\r\n                console.log(`\u2705 Nouvel index assign\u00e9 \u00e0 item ${itemId}: ${index}`);\r\n            }\r\n            \r\n            item.sessionStorageIndex = index;\r\n            \r\n            console.log(`\ud83d\udd04 Sync item \u2192 sessionStorage (index ${index})`, item);\r\n            \r\n            Object.entries(this.mappings).forEach(([itemPath, sessionKey]) => {\r\n                const value = this.getNestedProperty(item, itemPath);\r\n                \r\n                if (value !== undefined && value !== null) {\r\n                    sessionStorage.setItem(`${sessionKey}${index}`, value);\r\n                    console.log(`  \u2713 ${sessionKey}${index} = ${value}`);\r\n                }\r\n            });\r\n            \r\n            this.syncAdditionalData(item, index);\r\n            \r\n            console.log(`\u2705 Item ${itemId} synchronis\u00e9 \u2192 sessionStorage (index ${index})`);\r\n            \r\n            return index;\r\n        },\r\n        \r\n        \/**\r\n         * Synchronise les donn\u00e9es additionnelles\r\n         *\/\r\n        syncAdditionalData(item, index) {\r\n            \/\/ \u2705 Extraire le pays depuis LinkSecteurPage{index} (source fiable, ind\u00e9pendante de la s\u00e9lection courante)\r\n            var _linkUrl = sessionStorage.getItem('LinkSecteurPage' + index) || '';\r\n            var _urlMatch = _linkUrl.match(\/https?:\\\/\\\/([^.]+)\\.yearbook-media\\.com\/);\r\n            var _paysFromUrl = _urlMatch ? _urlMatch[1] : null;\r\n            var _continentPaysTitreDisp = _paysFromUrl ? (_paysFromUrl.charAt(0).toUpperCase() + _paysFromUrl.slice(1)) : null;\r\n            const continentPaysTitre = _paysFromUrl || sessionStorage.getItem('ContinentPaysTitre');\r\n            if (continentPaysTitre) {\r\n                sessionStorage.setItem(`ContinentPaysTitre${index}`, continentPaysTitre);\r\n            }\r\n            const continentPaysTitreDisplayed = _continentPaysTitreDisp || sessionStorage.getItem('ContinentPaysTitreDisplayed');\r\n            if (continentPaysTitreDisplayed) {\r\n                sessionStorage.setItem(`ContinentPaysTitreDisplayed${index}`, continentPaysTitreDisplayed);\r\n            }\r\n            \r\n            if (item.selectedPageType) {\r\n                sessionStorage.setItem(`SelectedPageType${index}`, item.selectedPageType);\r\n                console.log(`\u2705 SelectedPageType${index} = ${item.selectedPageType}`);\r\n            }\r\n            \r\n            if (item.commandePage) {\r\n                sessionStorage.setItem(`commandePage${index}`, item.commandePage);\r\n                console.log(`\u2705 commandePage${index} = ${item.commandePage}`);\r\n            }\r\n            \r\n            if (item.selectedPageSecteur) {\r\n                sessionStorage.setItem(`SelectedPageSecteur${index}`, item.selectedPageSecteur);\r\n            }\r\n            \r\n            if (item.selectedPageSecteurDisplayed) {\r\n                sessionStorage.setItem(`SelectedPageSecteurDisplayed${index}`, item.selectedPageSecteurDisplayed);\r\n                console.log(`\u2705 SelectedPageSecteurDisplayed${index} = ${item.selectedPageSecteurDisplayed}`);\r\n            }\r\n            \r\n            const commandeSecteur = sessionStorage.getItem('Commande_Secteur');\r\n            if (commandeSecteur) {\r\n                sessionStorage.setItem(`Commande_Secteur${index}`, commandeSecteur);\r\n            }\r\n            \r\n            if (item.donneesIframe?.LoadedPageUrl) {\r\n                sessionStorage.setItem(`LinkSecteurPage${index}`, item.donneesIframe.LoadedPageUrl);\r\n                console.log(`\u2705 LinkSecteurPage${index} = ${item.donneesIframe.LoadedPageUrl}`);\r\n            }\r\n            \r\n            if (item.format) {\r\n                sessionStorage.setItem(`FormatDataVosCampagnes${index}`, item.format);\r\n            }\r\n            \r\n            if (item.donneesIframe?.FullPathAdFile) {\r\n                sessionStorage.setItem(`FullPathAdFileOnly${index}`, item.donneesIframe.FullPathAdFile);\r\n                console.log(`\u2705 FullPathAdFileOnly${index} = ${item.donneesIframe.FullPathAdFile}`);\r\n            } else {\r\n                \/\/ \u2705 Bug 10 : effacer la valeur p\u00e9rim\u00e9e (ancien item \u00e0 cet index)\r\n                sessionStorage.removeItem(`FullPathAdFileOnly${index}`);\r\n                console.warn(`\u26a0\ufe0f Pas de FullPathAdFile pour index ${index} \u2014 cl\u00e9 effac\u00e9e`);\r\n            }\r\n            \r\n            if (item.donneesIframe?.FileReceived) {\r\n                sessionStorage.setItem(`FileReceived${index}`, item.donneesIframe.FileReceived);\r\n                console.log(`\u2705 FileReceived${index} = ${item.donneesIframe.FileReceived}`);\r\n            } else {\r\n                \/\/ \u2705 Bug 10 : effacer la valeur p\u00e9rim\u00e9e\r\n                sessionStorage.removeItem(`FileReceived${index}`);\r\n            }\r\n            \r\n            if (item.donneesIframe?.EnvoiUlterieur) {\r\n                sessionStorage.setItem(`EnvoiUlterieur${index}`, item.donneesIframe.EnvoiUlterieur);\r\n                console.log(`\u2705 EnvoiUlterieur${index} = ${item.donneesIframe.EnvoiUlterieur}`);\r\n            }\r\n            \r\n            console.log(`\u2705 Donn\u00e9es additionnelles synchronis\u00e9es pour index ${index}`);\r\n        },\r\n        \r\n        \/**\r\n         * SYNCHRONISATION : SessionStorage \u2192 Item\r\n         *\/\r\n        syncSessionStorageToItem(index, itemId) {\r\n            if (!itemId) {\r\n                console.warn('\u26a0\ufe0f itemId requis pour sync sessionStorage \u2192 item');\r\n                return null;\r\n            }\r\n            \r\n            const item = window.VIA_Panier.state.items.find(i => i.id === itemId);\r\n            if (!item) {\r\n                console.warn('\u26a0\ufe0f Item introuvable:', itemId);\r\n                return null;\r\n            }\r\n            \r\n            console.log(`\ud83d\udd04 Sync sessionStorage (index ${index}) \u2192 item ${itemId}`);\r\n            \r\n            Object.entries(this.mappings).forEach(([itemPath, sessionKey]) => {\r\n                const value = sessionStorage.getItem(`${sessionKey}${index}`);\r\n                \r\n                if (value !== null) {\r\n                    this.setNestedProperty(item, itemPath, value);\r\n                    console.log(`  \u2713 ${itemPath} = ${value}`);\r\n                }\r\n            });\r\n            \r\n            item.sessionStorageIndex = index;\r\n            \r\n            console.log(`\u2705 SessionStorage (index ${index}) synchronis\u00e9 \u2192 item ${itemId}`);\r\n            \r\n            if (window.VIA_Panier) {\r\n                window.VIA_Panier.rafraichirItemHTML(itemId);\r\n            }\r\n            \r\n            return item;\r\n        },\r\n        \r\n        \/**\r\n         * SYNCHRONISATION AUTOMATIQUE\r\n         *\/\r\n        enableAutoSync() {\r\n            console.log('\ud83d\udd04 Activation synchronisation automatique');\r\n            \r\n            const originalMettreAJour = window.VIA_Panier.mettreAJourItem;\r\n            \r\n            window.VIA_Panier.mettreAJourItem = (itemId, donnees) => {\r\n                originalMettreAJour.call(window.VIA_Panier, itemId, donnees);\r\n                this.syncItemToSessionStorage(itemId);\r\n            };\r\n            \r\n            const originalCreer = window.VIA_Panier.creerNouvelItem;\r\n            \r\n            window.VIA_Panier.creerNouvelItem = async function(donnees) {\r\n                const item = await originalCreer.call(window.VIA_Panier, donnees);\r\n                \r\n                if (item) {\r\n                    \/\/ v4.9ds : forceNewIndex=false. Le creerNouvelItem original appelle\r\n                    \/\/   setItemActif \u2192 syncItemToSessionStorage qui a d\u00e9j\u00e0 attribu\u00e9 un index\r\n                    \/\/   et l'a m\u00e9moris\u00e9 dans item.sessionStorageIndex. Avec forceNewIndex=true,\r\n                    \/\/   ce post-hook cr\u00e9ait un SECOND index pour le m\u00eame item \u2192 doublon DOM\r\n                    \/\/   dans le r\u00e9cap (un par index sessionStorage).\r\n                    window.VIA_Adaptateur.syncItemToSessionStorage(item.id, false);\r\n                }\r\n                \r\n                return item;\r\n            };\r\n            \r\n            console.log('\u2705 Synchronisation automatique activ\u00e9e');\r\n        },\r\n        \r\n        \/**\r\n         * Nettoie les donn\u00e9es sessionStorage pour un index\r\n         *\/\r\n        cleanSessionStorageIndex(index) {\r\n            console.log(`\ud83e\uddf9 Nettoyage sessionStorage index ${index}`);\r\n            \r\n            Object.values(this.mappings).forEach(sessionKey => {\r\n                sessionStorage.removeItem(`${sessionKey}${index}`);\r\n            });\r\n            \r\n            const additionalKeys = [\r\n                'ContinentPaysTitre',\r\n                'SelectedPage',\r\n                'SelectedPageType',\r\n                'SelectedPageSecteur',\r\n                'commandePage',\r\n                'LinkSecteurPage',\r\n                'FormatDataVosCampagnes',\r\n                'FullPathAdFileOnly'\r\n            ];\r\n            \r\n            additionalKeys.forEach(key => {\r\n                sessionStorage.removeItem(`${key}${index}`);\r\n            });\r\n        },\r\n        \r\n        \/**\r\n         * SYNCHRONISATION GLOBALE\r\n         *\/\r\n        syncAllItemsToSessionStorage() {\r\n            console.log('\ud83d\udd04 Synchronisation globale items \u2192 sessionStorage');\r\n            \r\n            window.VIA_Panier.state.items.forEach(item => {\r\n                this.syncItemToSessionStorage(item.id);\r\n            });\r\n            \r\n            console.log('\u2705 Synchronisation globale termin\u00e9e');\r\n        },\r\n        \r\n        syncAllSessionStorageToItems() {\r\n            console.log('\ud83d\udd04 Synchronisation globale sessionStorage \u2192 items');\r\n            \r\n            const maxIndex = parseInt(sessionStorage.getItem('CampagneIndex') || '0');\r\n            \r\n            for (let i = 1; i <= maxIndex; i++) {\r\n                const emplacement = sessionStorage.getItem(`Commande_Emplacement_Page_Web${i}`);\r\n                \r\n                if (emplacement) {\r\n                    const item = window.VIA_Panier.state.items.find(\r\n                        item => item.emplacementPageWeb === emplacement\r\n                    );\r\n                    \r\n                    if (item) {\r\n                        this.syncSessionStorageToItem(i, item.id);\r\n                    }\r\n                }\r\n            }\r\n            \r\n            console.log('\u2705 Synchronisation globale termin\u00e9e');\r\n        },\r\n        \r\n        \/**\r\n         * COMPATIBILIT\u00c9 AVEC GetURLCommande\r\n         *\/\r\n        prepareForGetURLCommande(itemId) {\r\n            const item = window.VIA_Panier.state.items.find(i => i.id === itemId);\r\n            if (!item) return;\r\n            \r\n            const index = item.sessionStorageIndex || this.getItemIndex(itemId);\r\n            if (!index) {\r\n                console.warn('\u26a0\ufe0f Aucun index trouv\u00e9 pour item:', itemId);\r\n                return;\r\n            }\r\n            \r\n            sessionStorage.setItem('SelectedCampagneIndex', index);\r\n            sessionStorage.setItem('Commande_Format_Transmis', item.format || ''); \/\/ \u2705 v2.3.3 : \u00e9viter que null devienne la string \"null\"\r\n            \r\n            console.log(`\u2705 Variables pr\u00e9par\u00e9es pour GetURLCommande (index ${index})`);\r\n        },\r\n        \r\n        \/**\r\n         * UTILITAIRES DEBUG\r\n         *\/\r\n        logMapping(itemId) {\r\n            const item = window.VIA_Panier.state.items.find(i => i.id === itemId);\r\n            if (!item) {\r\n                console.warn('\u26a0\ufe0f Item introuvable:', itemId);\r\n                return;\r\n            }\r\n            \r\n            const index = this.getItemIndex(itemId);\r\n            \r\n            console.group(`\ud83d\udcca Mapping item ${itemId} \u2194 sessionStorage (index ${index})`);\r\n            \r\n            Object.entries(this.mappings).forEach(([itemPath, sessionKey]) => {\r\n                const itemValue = this.getNestedProperty(item, itemPath);\r\n                const sessionValue = sessionStorage.getItem(`${sessionKey}${index}`);\r\n                \r\n                const match = itemValue == sessionValue ? '\u2705' : '\u274c';\r\n                \r\n                console.log(`${match} ${itemPath} \u2192 ${sessionKey}${index}`);\r\n                console.log(`   Item: ${itemValue}`);\r\n                console.log(`   Session: ${sessionValue}`);\r\n            });\r\n            \r\n            console.groupEnd();\r\n        },\r\n        \r\n        \/**\r\n         * Initialisation\r\n         *\/\r\n        init() {\r\n            console.log('\ud83d\udd17 Initialisation adaptateur...');\r\n            \r\n            const checkReady = setInterval(() => {\r\n                if (window.VIA_Panier && window.VIA_Panier.state) {\r\n                    clearInterval(checkReady);\r\n                    this.enableAutoSync();\r\n                    console.log('\u2705 Adaptateur pr\u00eat');\r\n                }\r\n            }, 100);\r\n        }\r\n    };\r\n    \r\n    \/**\r\n     * Auto-initialisation\r\n     *\/\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', () => {\r\n            setTimeout(() => window.VIA_Adaptateur.init(), 1000);\r\n        });\r\n    } else {\r\n        setTimeout(() => window.VIA_Adaptateur.init(), 1000);\r\n    }\r\n    \r\n    console.log('\u2705 Adaptateur Items \u2194 SessionStorage v1.0 charg\u00e9');\r\n\r\n})();\r\n\r\n\/\/ v4.9ds : Synchronisation MsgSecteurStep3 \u2194 .AssocierSecteurClass .SousTitre\r\n\/\/   Sur sites pays popup d'achat (UNIQUEMENT), quand un pays est s\u00e9lectionn\u00e9 mais\r\n\/\/   pas encore de secteur, l'\u00e9tape \"associerSecteur\" devient en cours \u2192\r\n\/\/   marquerEtapeEnCours pose via-etape-en-cours sur le SousTitre (\"Publier vos\r\n\/\/   annonces dans les pages web\u2026\"). Parall\u00e8lement, yearbook-media.js affiche\r\n\/\/   #MsgSecteurStep3 (\"Merci de s\u00e9lectionner un th\u00e8me ou un secteur\") \u2192 les 2\r\n\/\/   messages se chevauchent visuellement.\r\n\/\/   Solution : MutationObserver sur #MsgSecteurStep3 qui synchronise une classe\r\n\/\/   CSS d\u00e9di\u00e9e .via-st-cache-msg sur le SousTitre. Pas d'utilisation de\r\n\/\/   .hide()\/.show() pour ne pas \u00e9craser les logiques de display inline existantes.\r\n\/\/   P\u00c9RIM\u00c8TRE : strictement sites pays mode popup (mode=popup dans hash\/search OU\r\n\/\/   AchatEspaceCall='Yes'). Sur le site r\u00e9gie, le SousTitre reste visible normalement.\r\n(function _viaSyncMsgSecteurSousTitre() {\r\n    function _isPopupModeAchat() {\r\n        try {\r\n            if (sessionStorage.getItem('AchatEspaceCall') === 'Yes') { return true; }\r\n            if (window.location.search.indexOf('mode=popup') !== -1) { return true; }\r\n            if (window.location.hash.indexOf('mode=popup') !== -1) { return true; }\r\n        } catch(_e) {}\r\n        return false;\r\n    }\r\n    function _sync() {\r\n        var $msg = jQuery('#MsgSecteurStep3');\r\n        var $st = jQuery('.AssocierSecteurClass .SousTitre');\r\n        if (!$msg.length ? true : !$st.length) { return; }\r\n        if ($msg.is(':visible')) {\r\n            $st.addClass('via-st-cache-msg');\r\n        } else {\r\n            $st.removeClass('via-st-cache-msg');\r\n        }\r\n    }\r\n    function _install() {\r\n        \/\/ Garde : ne s'active que sur sites pays popup d'achat\r\n        if (!_isPopupModeAchat()) { return; }\r\n        \/\/ Injecter CSS d\u00e9di\u00e9 (display:none priorit\u00e9 maximum)\r\n        if (!document.getElementById('via-st-cache-msg-style')) {\r\n            var _s = document.createElement('style');\r\n            _s.id = 'via-st-cache-msg-style';\r\n            _s.textContent = 'html body .via-st-cache-msg{display:none !important}';\r\n            document.head.appendChild(_s);\r\n        }\r\n        var _el = document.getElementById('MsgSecteurStep3');\r\n        if (!_el) {\r\n            \/\/ DOM pas encore pr\u00eat \u2192 retry\r\n            setTimeout(_install, 500);\r\n            return;\r\n        }\r\n        try {\r\n            var _obs = new MutationObserver(_sync);\r\n            _obs.observe(_el, { attributes: true, attributeFilter: ['style', 'class'] });\r\n        } catch(_e) {}\r\n        _sync(); \/\/ sync initial\r\n    }\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', function() { setTimeout(_install, 500); });\r\n    } else {\r\n        setTimeout(_install, 500);\r\n    }\r\n})();\r\n\r\n\/\/ v4.9ds : Scroll automatique de #EtapeRecapitulatif en haut quand le popup d'achat\r\n\/\/   s'ouvre (sites pays mode=popup, desktop ET mobile).\r\n\/\/   Approche par observation : on ne sait pas exactement quel chemin appelle\r\n\/\/   ouvrirRecapitulatif (Panier:5191\/5635\/4163, yearbook-media.js:1395\/2939\/7630, etc.).\r\n\/\/   On observe donc directement EtapeRecapitulatif via MutationObserver \u2014 d\u00e8s que\r\n\/\/   l'\u00e9l\u00e9ment re\u00e7oit la classe via-etape-visible OU devient visible, on d\u00e9clenche\r\n\/\/   le scroll. Cela couvre tous les chemins d'ouverture sans avoir \u00e0 les modifier.\r\n\/\/   Plusieurs retries (jusqu'\u00e0 4s) car le DOM peut continuer \u00e0 se rendre apr\u00e8s\r\n\/\/   le d\u00e9clenchement initial (autres \u00e9tapes apparaissent sous, hauteur change).\r\n(function _viaSetupScrollRecapTop() {\r\n    var _isPopupSR = (new URLSearchParams(window.location.hash.substring(1) || window.location.search).get('mode') === 'popup');\r\n    if (!_isPopupSR) { return; }\r\n    var _scrolledOnce = false;\r\n    var _userScrolled = false;\r\n\r\n    \/* ============================================================\r\n     * pb1663 : CE SCROLL A CHANGE DE CONTENEUR SOUS LUI.\r\n     *   Nomme par le piege pb1660, sans ambiguite :\r\n     *     [pb1660] scrollIntoView SUR DIV#EtapeRecapitulatif\r\n     *              at _doScroll (yearbook-media.com\/:34378)\r\n     *   Le mecanisme date de l architecture ou le recapitulatif vivait dans le\r\n     *   FLUX du document : le remonter en haut avait un sens.\r\n     *   Depuis pb1647, #ColonneDroite \u2014 qui contient #EtapeRecapitulatif \u2014 est\r\n     *   deplacee DANS .via-col-popup-body, qui porte overflow:auto.\r\n     *   scrollIntoView agit sur le plus proche ancetre defilable : ce n est plus\r\n     *   le document, c est le corps du popup. Et comme le recapitulatif y est le\r\n     *   DERNIER enfant, l amener en block:'start' revient a mettre le popup en\r\n     *   butee basse \u2014 scrollTop=456.67 pour un maximum de 457, mesure user.\r\n     *   Le mecanisme n a pas change ; son conteneur, si. C est pourquoi la garde\r\n     *   ne teste pas un drapeau de mise en forme mais le FAIT : le recapitulatif\r\n     *   est-il, ou non, a l interieur du popup de colonne. Un drapeau se desynch-\r\n     *   ronise, une containment se mesure.\r\n     *   La volee de sept relances (T+50 a T+4000) continuait par ailleurs a tirer\r\n     *   alors que top restait bloque a 77 px : sept tentatives sans effet et sans\r\n     *   condition d arret. La garde les eteint toutes.\r\n     *   Revert : window._viaPb1663Off = true.\r\n     * ============================================================ *\/\r\n    var _dejaDit1663 = false;\r\n    \/* ============================================================\r\n     * pb1898 : NE PLUS SCROLLER DES QUE L UTILISATEUR SAISIT.\r\n     *   Constat JF : \u00ab des qu on commence a saisir un champ, un scroll\r\n     *   top se produit \u00bb. Le piege pb1895 a nomme l ecrivain sans\r\n     *   ambiguite \u2014 je ne l avais pas trouve par lecture :\r\n     *     [pb1895] scrollIntoView sur #EtapeRecapitulatif\r\n     *              << _doScroll << ...:35659\r\n     *   L ouverture du recapitulatif programme SEPT relances, de T+50 a\r\n     *   T+4000 (_scheduleRetries). Pendant ces quatre secondes, un focus\r\n     *   sur un champ n arrete rien : la volee continue et ramene la page\r\n     *   sur le recapitulatif, en plein milieu de la frappe.\r\n     *   Le log du user le montre a la seconde pres : focus a 34.437,\r\n     *   scrolls a 34.476, 34.602, 35.038, 35.594, 36.859, 38.411.\r\n     *   DEUX GARDES, pas une :\r\n     *     - immediate, sur activeElement, pour la volee deja lancee ;\r\n     *     - persistante, des le premier focus, pour que le scroll ne\r\n     *       reparte pas si l utilisateur quitte le champ avant T+4000.\r\n     *   Sans la seconde, il suffirait de cliquer ailleurs pour que la\r\n     *   page saute a nouveau. C est la meme intention que _userScrolled,\r\n     *   deja present : quand l utilisateur agit, on ne le deplace plus.\r\n     *   Le scroll d ouverture, lui, n est pas touche : il tire avant\r\n     *   qu aucun champ n ait le focus.\r\n     *   Revert : window._viaPb1898Off = true\r\n     * ============================================================ *\/\r\n    var _saisie1898 = false;\r\n    var _ditSaisie1898 = false;\r\n    function _estChamp1898(_n) {\r\n        if (!_n) { return false; }\r\n        var _tg = String(_n.tagName || '').toLowerCase();\r\n        if (_tg === 'input') { return true; }\r\n        if (_tg === 'textarea') { return true; }\r\n        if (_tg === 'select') { return true; }\r\n        return false;\r\n    }\r\n    try {\r\n        document.addEventListener('focusin', function (_ev) {\r\n            if (window._viaPb1898Off === true) { return; }\r\n            if (!_estChamp1898(_ev.target)) { return; }\r\n            if (_saisie1898) { return; }\r\n            _saisie1898 = true;\r\n            console.log('[pb1898] saisie commencee (' + (_ev.target.id || '?')\r\n                + ') -> scroll Recap desarme pour cette session');\r\n        }, true);\r\n    } catch (_e1898) { console.log('[pb1898] ecoute impossible : ' + _e1898.message); }\r\n    function _doScroll(_label) {\r\n        var _el = document.getElementById('EtapeRecapitulatif');\r\n        if (!_el) { return false; }\r\n        if (_userScrolled) { return false; }\r\n        if (window._viaPb1898Off !== true) {\r\n            if (_saisie1898 ? true : _estChamp1898(document.activeElement)) {\r\n                if (!_ditSaisie1898) {\r\n                    _ditSaisie1898 = true;\r\n                    console.log('[pb1898] scroll Recap annule (' + _label + ') \u2014 l utilisateur saisit');\r\n                }\r\n                return true;\r\n            }\r\n        }\r\n        if (window._viaPb1663Off !== true) {\r\n            var _colPop1663 = document.getElementById('via-col-ColonneGauche');\r\n            if (_colPop1663 ? _colPop1663.contains(_el) : false) {\r\n                if (!_dejaDit1663) {\r\n                    _dejaDit1663 = true;\r\n                    console.log('[pb1663] recapitulatif dans le popup de colonne'\r\n                        + ' -> scroll Recap neutralise (etait la cause de la butee basse)');\r\n                }\r\n                return true;\r\n            }\r\n        }\r\n        var _rect = _el.getBoundingClientRect();\r\n        \/\/ Skip si d\u00e9j\u00e0 bien align\u00e9 en haut\r\n        if (_rect.top >= 0 ? _rect.top < 30 : false) { return true; }\r\n        try {\r\n            _el.scrollIntoView({ behavior: 'auto', block: 'start' });\r\n            console.log('[v4.9ds scroll Recap ' + _label + '] top \u00e9tait ' + Math.round(_rect.top) + 'px');\r\n        } catch (_eSc) {\r\n            try {\r\n                var _docTop = window.scrollY + _rect.top;\r\n                window.scrollTo(0, _docTop);\r\n            } catch(_e2) {}\r\n        }\r\n        return true;\r\n    }\r\n\r\n    function _scheduleRetries(_origin) {\r\n        \/\/ Plusieurs retries pour attraper le bon \u00e9tat du DOM\r\n        [50, 200, 500, 900, 1500, 2500, 4000].forEach(function(_t) {\r\n            setTimeout(function() { _doScroll(_origin + ' T+' + _t); }, _t);\r\n        });\r\n    }\r\n\r\n    function _installObserver() {\r\n        var _el = document.getElementById('EtapeRecapitulatif');\r\n        if (!_el) {\r\n            \/\/ DOM pas encore pr\u00eat \u2192 retry\r\n            setTimeout(_installObserver, 300);\r\n            return;\r\n        }\r\n\r\n        \/\/ Observer la classe + style (apparition de via-etape-visible \/ display non-none)\r\n        try {\r\n            var _obs = new MutationObserver(function(_muts) {\r\n                if (_userScrolled) { return; }\r\n                var _hasVisible = _el.classList.contains('via-etape-visible');\r\n                var _displayed = _el.offsetParent !== null;\r\n                if (_hasVisible ? _displayed : false) {\r\n                    if (!_scrolledOnce) {\r\n                        _scrolledOnce = true;\r\n                        console.log('[v4.9ds scroll Recap] EtapeRecapitulatif devient visible \u2014 scroll programm\u00e9');\r\n                        _scheduleRetries('OBS');\r\n                    }\r\n                }\r\n            });\r\n            _obs.observe(_el, { attributes: true, attributeFilter: ['class', 'style'] });\r\n        } catch(_e) {}\r\n\r\n        \/\/ Si d\u00e9j\u00e0 visible au moment de l'install, d\u00e9clencher imm\u00e9diatement\r\n        if (_el.classList.contains('via-etape-visible') ? _el.offsetParent !== null : false) {\r\n            _scrolledOnce = true;\r\n            console.log('[v4.9ds scroll Recap] EtapeRecapitulatif d\u00e9j\u00e0 visible \u00e0 l\\'install \u2014 scroll programm\u00e9');\r\n            _scheduleRetries('INIT');\r\n        }\r\n\r\n        \/\/ Polling de s\u00e9curit\u00e9 \u2014 si visibilit\u00e9 passe inaper\u00e7ue par MutationObserver\r\n        \/\/ (changement de classe sur anc\u00eatre, CSS h\u00e9rit\u00e9, etc.), on v\u00e9rifie toutes les 500ms\r\n        \/\/ pendant 5s\r\n        var _pollStart = Date.now();\r\n        var _poll = setInterval(function() {\r\n            if (_scrolledOnce) { clearInterval(_poll); return; }\r\n            if (Date.now() - _pollStart > 5000) { clearInterval(_poll); return; }\r\n            if (_el.offsetParent !== null) {\r\n                if (_el.classList.contains('via-etape-visible')) {\r\n                    _scrolledOnce = true;\r\n                    console.log('[v4.9ds scroll Recap] d\u00e9tect\u00e9 via polling \u2014 scroll programm\u00e9');\r\n                    _scheduleRetries('POLL');\r\n                    clearInterval(_poll);\r\n                }\r\n            }\r\n        }, 500);\r\n    }\r\n\r\n    \/\/ D\u00e9tection du scroll utilisateur \u2014 si l'user scrolle, on arr\u00eate nos retries\r\n    function _onUserScroll() {\r\n        if (_scrolledOnce) {\r\n            \/\/ Si on a d\u00e9j\u00e0 scroll\u00e9 au moins une fois, consid\u00e9rer les scrolls suivants comme user-initiated\r\n            \/\/   apr\u00e8s un d\u00e9lai court pour laisser nos retries s'encha\u00eener\r\n            setTimeout(function() { _userScrolled = true; }, 100);\r\n        }\r\n    }\r\n    window.addEventListener('wheel', _onUserScroll, { passive: true });\r\n    window.addEventListener('touchmove', _onUserScroll, { passive: true });\r\n\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', _installObserver);\r\n    } else {\r\n        _installObserver();\r\n    }\r\n})();\r\n    \/\/ ========================================================================\r\n    \/\/ pb913 : reduire de 30% la taille des titres d'etapes ET de leurs chevrons\r\n    \/\/   dans le layout 3 colonnes (demande user).\r\n    \/\/   Cible : les selecteurs deja declares dans etapesConfig (titre \/ iconeUp \/\r\n    \/\/   iconeDown) -> aucune etape oubliee, et ca suit automatiquement toute\r\n    \/\/   evolution de la config.\r\n    \/\/   Pourquoi en JS et pas 'font-size:70%' en CSS : un pourcentage est relatif\r\n    \/\/   au PARENT, pas a la taille reelle de l'element. Elementor posant des\r\n    \/\/   tailles explicites (souvent inline), le resultat serait faux. On lit donc\r\n    \/\/   la taille CALCULEE, on memorise l'originale sur l'element (_viaFsBase913)\r\n    \/\/   et on applique toujours 0.7 x originale -> IDEMPOTENT, jamais cumulatif,\r\n    \/\/   meme si Elementor reimpose et qu'on repasse (cf lecon pb505\/pb309).\r\n    \/\/   Les chevrons Elementor sont soit des icon-fonts (pilotes par font-size),\r\n    \/\/   soit des SVG (pilotes par width\/height) : les deux sont traites.\r\n    \/\/   Desktop uniquement (>=1000) : le mobile n'est pas concerne par ce layout.\r\n    \/\/   Knob : window._viaPb913Ratio (defaut 0.7). Revert : window._viaPb913Off = true.\r\n    \/\/ ========================================================================\r\n    (function _viaReduireTitresEtapes913() {\r\n        \/* ================================================================\r\n         * pb1541 : REBASER pb913 QUAND LE MODE DE LAYOUT CHANGE.\r\n         *   Comparaison des deux HTML de #ProcessAnnonceurEtape :\r\n         *\r\n         *                          REGIE       SITE PAYS\r\n         *     icone  data-viafs913    20            17\r\n         *     titre  data-viafs913    17            14\r\n         *     titre  rendu         13.45px       11.4px\r\n         *\r\n         *   data-viafs913 est la taille ORIGINALE memorisee par pb913 au tout\r\n         *   premier passage, et tout en decoule : _cible913 = base x 0.85 moins le\r\n         *   delta pb1170. Une base fausse donne un rendu faux POUR TOUJOURS \u2014 la\r\n         *   memorisation est definitive par construction, elle existe justement pour\r\n         *   rendre la fonction idempotente.\r\n         *\r\n         *   Dans l'iframe du process, ce premier passage a lieu AVANT que le parent\r\n         *   ne dimensionne le popup : la police lue est celle du layout etroit, 14\r\n         *   au lieu de 17. Meme piege que pb1539 \u2014 une mesure prise avant que la\r\n         *   valeur existe \u2014 mais ici elle est en plus GELEE, d'ou un ecart qui\r\n         *   survit a tous les correctifs de largeur.\r\n         *\r\n         *   Rebasage : on efface la taille inline ecrite par pb913, on oublie la\r\n         *   base (propriete ET attribut), le navigateur recalcule depuis le CSS,\r\n         *   puis pb913 rejoue. L'ORDRE COMPTE : effacer l'inline AVANT de relire,\r\n         *   sinon on re-memorise la valeur reduite et la police descend a chaque\r\n         *   appel. Sans effet si aucune base n'a ete posee.\r\n         *   Revert : window._viaPb1541Off = true.\r\n         * ================================================================ *\/\r\n        \/* ================================================================\r\n         * pb1545 : MESURER LE CHEVAUCHEMENT AU LIEU DE LE DEDUIRE.\r\n         *   Releve, pour chaque conteneur d'etape, de sa position reelle et de son\r\n         *   ecart avec le precedent. Ecart negatif = chevauchement, et la ligne\r\n         *   nomme l'element. A retirer une fois la cause identifiee.\r\n         * ================================================================ *\/\r\n        window._viaDiagEtapes1545 = function () {\r\n            var _ids = ['ProcessAnnonceurEtape', 'AssocierPaysEtape', 'PaysSecteursChildContainer',\r\n                'SecteurContainer', 'FormatContainer', 'ProcessDatesDeviseEtape',\r\n                'PageWebMobileEtape', 'EtapeRecapitulatif'];\r\n            var _prev = null;\r\n            console.log('[pb1545] geometrie des etapes | fenetre ' + window.innerWidth + 'x' + window.innerHeight);\r\n            _ids.forEach(function (_id) {\r\n                var _e = document.getElementById(_id);\r\n                if (!_e) { console.log('[pb1545]   ' + _id + ' : ABSENT'); return; }\r\n                var _r = _e.getBoundingClientRect();\r\n                var _cs = window.getComputedStyle(_e);\r\n                var _ecart = _prev ? Math.round(_r.top - _prev.bas) : null;\r\n                \/* pb1548 : la comparaison change de reference \u2014 la cible est la mise en\r\n                   forme du process en UNE colonne, pas la colonne droite du mode 3\r\n                   colonnes que les deux premiers releves ont mesuree. Les deux modes\r\n                   different d'abord par la TYPOGRAPHIE, que ce releve ignorait : on\r\n                   ajoute la taille de police du titre de chaque etape et sa base\r\n                   memorisee pb913, pour que le prochain croisement regie \/ site pays\r\n                   couvre positions ET texte. *\/\r\n                var _t1548 = _e.querySelector('[id$=\"titreTexte\"], .elementor-heading-title, h4, h3');\r\n                var _fs1548 = _t1548 ? window.getComputedStyle(_t1548).fontSize : '-';\r\n                var _bs1548 = _t1548 ? (_t1548.getAttribute('data-viafs913') || '-') : '-';\r\n                console.log('[pb1545]   ' + _id\r\n                    + ' | top=' + Math.round(_r.top) + ' bas=' + Math.round(_r.bottom)\r\n                    + ' h=' + Math.round(_r.height)\r\n                    + ' | mgTop=' + _cs.marginTop + ' mgBot=' + _cs.marginBottom\r\n                    + ' | display=' + _cs.display\r\n                    + ' | titre fs=' + _fs1548 + ' (base913=' + _bs1548 + ')'\r\n                    + (_ecart === null ? '' : (' | ecart avec le precedent=' + _ecart + 'px'\r\n                        + (_ecart < 0 ? '  <-- CHEVAUCHEMENT' : ''))));\r\n                _prev = { bas: _r.bottom };\r\n            });\r\n            \/* ========================================================\r\n             * pb1547 : REMONTER LA CHAINE DES ANCETRES.\r\n             *   Le releve croise regie \/ site pays a isole le dernier ecart :\r\n             *   ProcessAnnonceurEtape demarre a top=-27 dans l'iframe, au-dessus\r\n             *   de sa propre zone visible. Ce -27 est une SOMME : defilement du\r\n             *   document + marges et paddings des conteneurs au-dessus \u2014 dont les\r\n             *   compensations posees en mode=popup uniquement (feuille\r\n             *   via-popup-force-desktop : ColonneGauche -20px, ColonneDroite\r\n             *   -10px, reglees pour l'ancien popup de 480 px).\r\n             *   Plutot que d'ajuster ces valeurs au juge, on imprime chaque terme\r\n             *   de la somme : defilements, puis chaque ancetre jusqu'au body avec\r\n             *   sa position et ses marges\/paddings verticaux. La ligne fautive se\r\n             *   lira directement.\r\n             * ======================================================== *\/\r\n            console.log('[pb1547] defilement | window.scrollY=' + Math.round(window.scrollY || 0)\r\n                + ' html.scrollTop=' + Math.round(document.documentElement.scrollTop || 0)\r\n                + ' body.scrollTop=' + Math.round(document.body.scrollTop || 0));\r\n            var _dep = document.getElementById('ProcessAnnonceurEtape');\r\n            var _anc = _dep ? _dep.parentElement : null;\r\n            var _niv = 0;\r\n            while (_anc ? (_niv < 14) : false) {\r\n                var _ra = _anc.getBoundingClientRect();\r\n                var _ca = window.getComputedStyle(_anc);\r\n                var _mt = parseFloat(_ca.marginTop) || 0;\r\n                var _pt = parseFloat(_ca.paddingTop) || 0;\r\n                var _nom = _anc.id ? ('#' + _anc.id)\r\n                    : (_anc.className ? String(_anc.className).split(' ').slice(0, 2).join('.') : _anc.tagName);\r\n                \/* n'imprimer que les niveaux qui pesent : marge ou padding non nul,\r\n                   ou position remarquable *\/\r\n                var _pese = (_mt !== 0) ? true : ((_pt !== 0) ? true : (_niv < 3));\r\n                if (_pese) {\r\n                    console.log('[pb1547]   niv' + _niv + ' ' + _nom\r\n                        + ' | top=' + Math.round(_ra.top)\r\n                        + ' | mgTop=' + _ca.marginTop + ' padTop=' + _ca.paddingTop\r\n                        + ' | position=' + _ca.position);\r\n                }\r\n                if (_anc === document.body) { break; }\r\n                _anc = _anc.parentElement;\r\n                _niv++;\r\n            }\r\n        };\r\n\r\n        \/* ============================================================\r\n         * pb1607 : PIEGE \u2014 QUI POSE LA MARGE NEGATIVE ?\r\n         *   Quinze iterations sur ce chevauchement sans progres : a chaque tour j'ai\r\n         *   DEDUIT un ecrivain probable au lieu de le faire avouer. pb1546, pb1558,\r\n         *   pb1569, pb1596, pb1598, pb1599, pb1601 \u2014 tous poses sur une hypothese.\r\n         *   On arrete de deviner. Ce piege remplace setProperty sur les conteneurs\r\n         *   concernes : des qu'une marge haute negative est ecrite, il journalise la\r\n         *   valeur ET LA PILE D'APPEL. L'ecrivain se nomme lui-meme.\r\n         *   A retirer des qu'il a parle.\r\n         *   Reactivation manuelle : window._viaPiege1607() dans la console de l'iframe.\r\n         * ============================================================ *\/\r\n        window._viaPiege1607 = function () {\r\n            \/* pb1615 : le piege s'etend au recapitulatif. Le titre \u00ab Vos reservations \u00bb\r\n               est recouvert par le message vert \u00ab Une ou plusieurs reservations sont\r\n               validees \u00bb \u2014 superposition franche, donc marge negative importante.\r\n               On surveille les deux conteneurs, et desormais margin-bottom et top en\r\n               plus de margin-top : la superposition peut venir de l'un ou de l'autre. *\/\r\n            var _ids = ['PaysSecteursChildContainer', 'SecteurContainer', 'FormatContainer',\r\n                        'ProcessAnnonceurEtape', 'ProcessDatesDeviseEtape',\r\n                        'RecapitulatifVosCommandestitreContainer', 'RecapitulatifMessageContainer',\r\n                        'RecapitulatifMessageTexte'];\r\n            var _n = 0;\r\n            _ids.forEach(function (_id) {\r\n                var _e = document.getElementById(_id);\r\n                if (!_e) { return; }\r\n                if (_e._viaPiege1607) { return; }\r\n                _e._viaPiege1607 = true;\r\n                var _sty = _e.style;\r\n                var _orig = _sty.setProperty.bind(_sty);\r\n                _sty.setProperty = function (_prop, _val, _prio) {\r\n                    var _neg1615 = (_prop === 'margin-top' ? true\r\n                        : (_prop === 'margin-bottom' ? true : (_prop === 'top')));\r\n                    if (_neg1615 ? (parseFloat(_val) < 0) : false) {\r\n                        console.log('[pb1607] ' + _id + ' <- ' + _prop + ' ' + _val\r\n                            + (_prio ? (' ' + _prio) : '') + '\\n' + (new Error()).stack);\r\n                    }\r\n                    return _orig(_prop, _val, _prio);\r\n                };\r\n                _n++;\r\n            });\r\n            if (_n > 0) {\r\n                console.log('[pb1607] piege arme sur ' + _n + ' conteneur(s) \u2014 reproduis le chevauchement');\r\n            }\r\n            return _n;\r\n        };\r\n        (function () {\r\n            var _k1607 = 0;\r\n            var _t1607 = setInterval(function () {\r\n                _k1607++;\r\n                if (window._viaPiege1607() > 0) { clearInterval(_t1607); return; }\r\n                if (_k1607 >= 20) { clearInterval(_t1607); }\r\n            }, 500);\r\n        })();\r\n\r\n        window._viaRebaser913 = function (_pourquoi) {\r\n            if (window._viaPb1541Off === true) { return 0; }\r\n            \/* pb1575b : garde partagee avec le declencheur (yearbook-media.js). Tant\r\n               qu'un redimensionnement est en cours, les largeurs sont transitoires :\r\n               remesurer maintenant figerait des bases prises au milieu du mouvement.\r\n               Le declencheur rejouera 350 ms apres le dernier evenement. *\/\r\n            if (window._viaResizeEnCours1575 === true) {\r\n                console.log('[pb1575] rebasage differe : redimensionnement en cours | ' + (_pourquoi || '?'));\r\n                return 0;\r\n            }\r\n            var _els = document.querySelectorAll('[data-viafs913]');\r\n            var _n = 0;\r\n            Array.prototype.forEach.call(_els, function (_e) {\r\n                \/* pb1542b : ANTI-CLIQUET. Constate dans le HTML apres pb1541 :\r\n                   <a class=\"elementor-icon\"> est passe de data-viafs913=\"17\" a \"15.45\".\r\n                   La base avait BAISSE. Cause : la taille d'un element dont le CSS est\r\n                   relatif se lit sur son parent ; si celui-ci porte encore une taille\r\n                   reduite au moment ou l'enfant est remesure, la nouvelle base est plus\r\n                   petite que l'originale \u2014 et le phenomene se repete a chaque rebasage.\r\n                   La base etant censee etre la taille D'ORIGINE, on retient la plus\r\n                   grande jamais vue : elle ne peut plus que remonter. *\/\r\n                var _av = _e.getAttribute('data-viafs913');\r\n                if (_av !== null) {\r\n                    var _hi = parseFloat(_e.getAttribute('data-viafs913max') || '0');\r\n                    var _cur = parseFloat(_av);\r\n                    if (_cur > _hi) { _e.setAttribute('data-viafs913max', String(_cur)); }\r\n                }\r\n                _e.style.removeProperty('font-size');\r\n                try { delete _e._viaFsBase913; } catch (_x) { _e._viaFsBase913 = undefined; }\r\n                _e.removeAttribute('data-viafs913');\r\n                _n++;\r\n            });\r\n            \/* ============================================================\r\n             * pb1543 : LES MARGES SONT MEMORISEES COMME LES POLICES.\r\n             *   Meme constat sur tes deux HTML de #ProcessAnnonceurEtape :\r\n             *     data-viamgt1234 = 20 (site pays)  contre  10 (regie).\r\n             *   pb1234 fige marginTop\/marginBottom au premier passage, dans la meme\r\n             *   forme exactement que pb913 : \u00ab si l'attribut est null, mesurer et\r\n             *   enregistrer \u00bb. Et il AJOUTE 10 px a l'etape active. Une capture faite\r\n             *   apres qu'un delta a deja ete pose enregistre donc 20 au lieu de 10,\r\n             *   et l'ecart se reporte a chaque passage.\r\n             *   Le cliquet joue ici DANS L'AUTRE SENS que pour les polices : les\r\n             *   deltas n'ajoutent que du positif, la vraie base est donc la plus\r\n             *   PETITE jamais relevee. Polices : on garde le maximum (pb1542).\r\n             *   Marges : le minimum. Les deux gardes sont symetriques.\r\n             * ============================================================ *\/\r\n            \/* ============================================================\r\n             * pb1601 : LE REBASAGE NE TOUCHE PLUS AUX MARGES \u2014 C'EST LUI LA CAUSE.\r\n             *   Constat user, deux releves du meme log :\r\n             *     avant  SecteurContainer mgTop=9px   FormatContainer mgTop=9px\r\n             *     apres  SecteurContainer mgTop=-10px FormatContainer mgTop=-21px\r\n             *   pb1234 releve la marge depuis le CSS UNE SEULE FOIS (data-viamgt1234)\r\n             *   puis la reapplique : c'etait stable, 9 px de chaque cote.\r\n             *   pb1546 \u2014 ce bloc \u2014 effacait ces attributs pour forcer une remesure.\r\n             *   pb1234 recapturait alors dans l'etat du moment, accordeon replie, et\r\n             *   figeait -10 et -21 pour tous les passages suivants. La cause n'etait pas\r\n             *   une marge parasite a corriger : c'etait mon propre rebasage.\r\n             *   Les polices, elles, ont besoin du rebasage (pb1542, valide) : il reste.\r\n             *   On retire donc SEULEMENT la partie marges \u2014 retour au comportement de\r\n             *   pb1544, qui avait deja desarme cette moitie pour une raison voisine.\r\n             *   Consequence directe : pb1599 et pb1558, qui compensaient l'effet,\r\n             *   deviennent inutiles et sont retires.\r\n             *   Revert : window._viaPb1601Off = true (rebasage des marges retabli).\r\n             * ============================================================ *\/\r\n            var _mg = (window._viaPb1601Off === true)\r\n                ? document.querySelectorAll('[data-viamgt1234]')\r\n                : [];\r\n            var _nm = 0;\r\n            Array.prototype.forEach.call(_mg, function (_e) {\r\n                _e.style.removeProperty('margin-top');\r\n                _e.style.removeProperty('margin-bottom');\r\n                _e.removeAttribute('data-viamgt1234');\r\n                _e.removeAttribute('data-viamgb1234');\r\n                _e.removeAttribute('data-viamgt1234min');\r\n                _e.removeAttribute('data-viamgb1234min');\r\n                _nm++;\r\n            });\r\n            if (_n ? true : (_nm > 0)) {\r\n                console.log('[pb1541] ' + _n + ' base(s) de police et ' + _nm + ' base(s) de marge oubliee(s) | '\r\n                    + (_pourquoi || '?') + ' - pb913 et pb1234 vont remesurer depuis le CSS');\r\n            }\r\n            \/* pb1545b : releve differe, le temps que pb913 et pb1234 aient rejoue. *\/\r\n            setTimeout(function () {\r\n                try { window._viaDiagEtapes1545(); } catch (_e1545) { console.warn('[pb1545] ' + _e1545.message); }\r\n            }, 1500);\r\n            return _n;\r\n        };\r\n\r\n        function _appliquer913() {\r\n            if (window._viaPb913Off === true) { return; }\r\n            \/\/ ================================================================\r\n            \/\/ pb1179 : sur MOBILE, ce bloc s'arretait ici \u2014 d'ou l'absence de\r\n            \/\/   gestion des tailles constatee par l'utilisateur.\r\n            \/\/   pb913 a ete ecrit pour le layout DESKTOP : il reduit les titres a\r\n            \/\/   85% \"le mobile n'est pas concerne par ce layout\". Mais depuis\r\n            \/\/   pb1170, il porte aussi le delta de 0.5px entre l'etape active et\r\n            \/\/   les autres \u2014 une regle qui, elle, vaut dans les deux contextes.\r\n            \/\/   On ne sort donc plus sur mobile ; on y neutralise seulement le\r\n            \/\/   RATIO (1 au lieu de 0.85), pour ne pas toucher aux tailles\r\n            \/\/   d'origine du layout mobile. Seul le delta s'applique.\r\n            \/\/   Revert : window._viaPb1179Off = true (mobile ignore, comme avant).\r\n            \/\/ ================================================================\r\n            \/\/ pb1263 : largeur lue par l'accesseur garde (yearbook-media.js).\r\n            var _lg1179 = (typeof window._viaLargeur1263 === 'function')\r\n                ? window._viaLargeur1263() : window.outerWidth;\r\n            var _mob1179 = (_lg1179 < 1000);\r\n            if (_mob1179 ? (window._viaPb1179Off === true) : false) { return; }\r\n            var _cfg913 = (window.VIA_Panier ? (window.VIA_Panier.state ? window.VIA_Panier.state.etapesConfig : null) : null);\r\n            if (!_cfg913) { return; }\r\n            \/\/ pb913c : ratio par defaut 0.7 -> 0.85 (demande user).\r\n            var _ratio913 = (typeof window._viaPb913Ratio === 'number') ? window._viaPb913Ratio : 0.85;\r\n            if (_mob1179) { _ratio913 = 1; }   \/\/ pb1179 : pas de reduction sur mobile\r\n            var _n913 = 0;\r\n            \/\/ --- Phase 0 : COLLECTE des elements cibles (aucune ecriture ici) -------\r\n            var _tous913 = [];\r\n            _cfg913.forEach(function (_et913) {\r\n                var _sels913 = [];\r\n                if (_et913.titre) { _sels913.push(_et913.titre); }\r\n                if (_et913.iconeUp) { _sels913.push(_et913.iconeUp); }\r\n                if (_et913.iconeDown) { _sels913.push(_et913.iconeDown); }\r\n                _sels913.forEach(function (_sel913) {\r\n                    var _racines913;\r\n                    try { _racines913 = document.querySelectorAll(_sel913); } catch (_eSel913) { return; }\r\n                    for (var _i913 = 0; _i913 < _racines913.length; _i913++) {\r\n                        _tous913.push(_racines913[_i913]);\r\n                        var _desc913 = _racines913[_i913].getElementsByTagName('*');\r\n                        for (var _d913 = 0; _d913 < _desc913.length; _d913++) { _tous913.push(_desc913[_d913]); }\r\n                    }\r\n                });\r\n            });\r\n            \/\/ --- Phase 1 : MESURE de toutes les tailles d'origine, AVANT toute ecriture\r\n            \/\/   pb913b : c'est le coeur du correctif. En mesurant\/ecrivant element par\r\n            \/\/   element (version precedente), un descendant etait mesure APRES que son\r\n            \/\/   parent ait ete reduit : sa taille calculee HERITAIT deja de la reduction,\r\n            \/\/   qu'on appliquait donc une 2e fois, puis une 3e au petit-enfant...\r\n            \/\/   Constat user (HTML) : 17 -> 11.9 -> 8.33 -> 5.83 -> 4.08, soit 0.7 a chaque\r\n            \/\/   niveau. Les chevrons etaient corrects car sans descendants imbriques.\r\n            \/\/   En figeant TOUTES les mesures d'abord, chaque element est reduit une seule\r\n            \/\/   fois par rapport a SA taille d'origine -> facteur uniforme 0.7 sur l'arbre.\r\n            \/\/ pb913c : la taille d'origine est memorisee dans un ATTRIBUT data-, pas\r\n            \/\/   seulement dans une propriete JS. Motif (constat user, HTML des clones du\r\n            \/\/   mode 1 colonne) : cloneNode copie les styles INLINE \u2014 donc la taille DEJA\r\n            \/\/   reduite \u2014 mais PAS les proprietes JS. Le clone arrivait donc sans base\r\n            \/\/   connue, etait remesure sur une valeur deja reduite, et re-reduit :\r\n            \/\/   17 -> 14.45 -> 12.28... (avec l'ancien 0.7 : 17 -> 11.9 -> 8.33, valeur\r\n            \/\/   exacte vue dans #PageWebTitreContainerClone).\r\n            \/\/   Un attribut, lui, EST copie par cloneNode -> le clone herite de la base\r\n            \/\/   d'origine et converge vers la meme taille que l'original.\r\n            \/\/   C'est la meme famille de piege que la lecon projet sur les clones\r\n            \/\/   ($('#id') ne voit pas les clones qui dupliquent l'id).\r\n            for (var _m913 = 0; _m913 < _tous913.length; _m913++) {\r\n                var _elM913 = _tous913[_m913];\r\n                var _attr913 = _elM913.getAttribute('data-viafs913');\r\n                if (_attr913 !== null) {\r\n                    _elM913._viaFsBase913 = parseFloat(_attr913);\r\n                } else if (_elM913._viaFsBase913 === undefined) {\r\n                    var _fs913 = parseFloat(window.getComputedStyle(_elM913).fontSize);\r\n                    \/* pb1542c : la base ne redescend jamais sous le plus haut releve\r\n                       (voir pb1542b), sinon chaque rebasage rabote la police. *\/\r\n                    \/* ============================================================\r\n                     * pb1579 : MEMORISER LE MAXIMUM A LA CAPTURE, PAS SEULEMENT AU REBASAGE.\r\n                     *   Mesure user sur #ProcessAnnonceurtitreTexte :\r\n                     *     data-viafs913 = 14  et  data-viafs913max = 14\r\n                     *   La base vaut donc 14 la ou la regie en a 17, et le calcul est\r\n                     *   juste : 14 x 0.85 + 1 + 1 = 13.9 px \u2014 exactement le rendu mesure.\r\n                     *   Le delta pb1566 s'applique bien ; il s'applique sur une mauvaise\r\n                     *   base.\r\n                     *   pb1542 ne relevait le plafond qu'AU MOMENT DU REBASAGE, a partir\r\n                     *   de la valeur deja enregistree. Si la seule capture a eu lieu dans\r\n                     *   un etat etroit, 14 devient a la fois la base ET le plafond, et\r\n                     *   l'anti-cliquet ne peut plus jamais remonter a 17 : il se protege\r\n                     *   contre une baisse qu'il a lui-meme ent\u00e9rin\u00e9e.\r\n                     *   On enregistre donc le maximum a CHAQUE mesure : toute valeur plus\r\n                     *   haute vue une fois devient le plancher definitif.\r\n                     *   Revert : window._viaPb1579Off = true.\r\n                     * ============================================================ *\/\r\n                    var _hi913 = parseFloat(_elM913.getAttribute('data-viafs913max') || '0');\r\n                    if (window._viaPb1579Off !== true ? (_fs913 > _hi913) : false) {\r\n                        _elM913.setAttribute('data-viafs913max', String(_fs913));\r\n                        _hi913 = _fs913;\r\n                    }\r\n                    if (_hi913 > _fs913) {\r\n                        console.log('[pb1542] base remontee a ' + _hi913 + ' au lieu de ' + _fs913\r\n                            + ' | ' + (_elM913.id || _elM913.className || '?'));\r\n                        _fs913 = _hi913;\r\n                    }\r\n                    _elM913._viaFsBase913 = (_fs913 > 0) ? _fs913 : 0;\r\n                    _elM913.setAttribute('data-viafs913', _elM913._viaFsBase913);\r\n                }\r\n                if (_elM913.tagName ? (_elM913.tagName.toLowerCase() === 'svg') : false) {\r\n                    var _attrW913 = _elM913.getAttribute('data-viasvgw913');\r\n                    var _attrH913 = _elM913.getAttribute('data-viasvgh913');\r\n                    if (_attrW913 !== null) {\r\n                        _elM913._viaSvgBase913 = { w: parseFloat(_attrW913), h: parseFloat(_attrH913) };\r\n                    } else if (_elM913._viaSvgBase913 === undefined) {\r\n                        var _r913 = _elM913.getBoundingClientRect();\r\n                        _elM913._viaSvgBase913 = { w: _r913.width, h: _r913.height };\r\n                        _elM913.setAttribute('data-viasvgw913', _r913.width);\r\n                        _elM913.setAttribute('data-viasvgh913', _r913.height);\r\n                    }\r\n                }\r\n            }\r\n            \/* ====================================================================\r\n             * pb1990 : \u00ab Vos reservations \u00bb PREND LA TAILLE DE \u00ab Choisir un format \u00bb.\r\n             *   Constat JF (capture) : les deux etapes sont A FAIRE, et le titre du\r\n             *   recapitulatif est plus petit.\r\n             *   CE N'EST PAS LA REGLE DE STATUT QUI DIVERGE. pb913 est le seul\r\n             *   ecrivain de font-size sur ces titres, et sa formule est commune :\r\n             *       taille = base x ratio - _moins1170 + _plus1566\r\n             *   avec _moins1170 = -1 actif \/ +0.5 a faire \/ +1 complete (pb1180,\r\n             *   pb1233). Les deux titres sont dans etapesConfig (choixFormat l.11727,\r\n             *   recapitulatif l.11751), donc tous deux traites par cette passe et\r\n             *   tous deux credites du meme delta quand ils sont dans le meme etat.\r\n             *   CE QUI DIVERGE, C'EST LA BASE. _viaFsBase913 est capturee element par\r\n             *   element sur le rendu Elementor : deux titres qui ne portent pas la\r\n             *   meme taille d'origine restent decales de cet ecart a TOUS les statuts,\r\n             *   quelle que soit la justesse de la regle. C'est exactement le cas\r\n             *   documente par pb1579 (\u00ab la base vaut 14 la ou la regie en a 17, et le\r\n             *   calcul est juste ; le delta s'applique sur une mauvaise base \u00bb).\r\n             *   ON CORRIGE DONC LA BASE, PAS LA TAILLE FINALE. Ecrire une taille\r\n             *   ailleurs serait efface au passage suivant \u2014 c'est ce qui a fait echouer\r\n             *   pb1164, et pb1170 le rappelle vingt lignes plus bas. En reglant la\r\n             *   base, les deux titres se suivent automatiquement dans les trois etats,\r\n             *   et un futur ajustement du ratio ou des deltas les garde alignes.\r\n             *   AUCUNE VALEUR EN DUR : la reference est MESUREE sur le titre du format,\r\n             *   comme pb1184 mesure un sous-titre existant au lieu de fixer 11px. Les\r\n             *   deux selecteurs sont lus dans etapesConfig, jamais recopies ici : une\r\n             *   seule source pour la table des etapes.\r\n             *   RAPPORT plutot que valeur absolue : le titre porte plusieurs noeuds\r\n             *   imbrique (conteneur, texte, <p> Elementor). Multiplier toutes leurs\r\n             *   bases par un meme facteur preserve leurs proportions internes ; poser\r\n             *   la meme valeur partout les ecraserait.\r\n             *   IDEMPOTENT PAR CONSTRUCTION : la base alignee est reecrite dans\r\n             *   data-viafs913, donc relue telle quelle au passage suivant, ou le\r\n             *   rapport vaut 1 et plus rien n'est ecrit. Aucun emballement possible,\r\n             *   alors que cette passe est rejouee en continu.\r\n             *   data-viafs913max suit (pb1579) : apres un rebasage pb1541, la nouvelle\r\n             *   capture ne pourra pas redescendre sous la valeur alignee.\r\n             *   PAS DE GARDE DE CONTEXTE, ET C'EST VOULU : la correction ne fait\r\n             *   quelque chose que la ou les deux bases different. La ou elles sont\r\n             *   deja egales \u2014 la regie, si c'est le cas \u2014 le rapport vaut 1 et la passe\r\n             *   est inerte. Un discriminant ajouterait un risque sans rien retirer.\r\n             *   Reglage : window._viaPb1990Ref = 'processDatesDevise' pour aligner sur\r\n             *             une autre etape.\r\n             *   Revert  : window._viaPb1990Off = true.\r\n             * ==================================================================== *\/\r\n            if (window._viaPb1990Off !== true) {\r\n                try {\r\n                    var _selEtape1990 = function (_idE1990) {\r\n                        for (var _c1990 = 0; _c1990 < _cfg913.length; _c1990++) {\r\n                            if (_cfg913[_c1990].id === _idE1990) {\r\n                                return _cfg913[_c1990].titre || '';\r\n                            }\r\n                        }\r\n                        return '';\r\n                    };\r\n                    var _noeuds1990 = function (_s1990) {\r\n                        var _out1990 = [];\r\n                        if (!_s1990) { return _out1990; }\r\n                        var _rs1990;\r\n                        try { _rs1990 = document.querySelectorAll(_s1990); }\r\n                        catch (_eQ1990) { return _out1990; }\r\n                        for (var _r1990 = 0; _r1990 < _rs1990.length; _r1990++) {\r\n                            _out1990.push(_rs1990[_r1990]);\r\n                            var _dd1990 = _rs1990[_r1990].getElementsByTagName('*');\r\n                            for (var _k1990 = 0; _k1990 < _dd1990.length; _k1990++) {\r\n                                _out1990.push(_dd1990[_k1990]);\r\n                            }\r\n                        }\r\n                        return _out1990;\r\n                    };\r\n                    \/* ================================================================\r\n                     * pb1992 : LE MAXIMUM DU SOUS-ARBRE N'EST PAS LA TAILLE DU TITRE.\r\n                     *   Verdict JF apres deploiement : \u00ab [pb1990] rien a faire : deja\r\n                     *   aligne (20px) \u00bb \u2014 alors que les deux titres restent visiblement\r\n                     *   de tailles differentes. La mesure disait vrai et ne mesurait pas\r\n                     *   ce qu'on regarde.\r\n                     *   _maxBase1990 prenait le MAXIMUM des bases du sous-arbre. Or un\r\n                     *   titre Elementor empile conteneur -> texte -> <p>, et pb913\r\n                     *   conserve la base PROPRE de chaque noeud. Deux titres dont les\r\n                     *   CONTENEURS valent 20 tous les deux donnent donc le meme maximum,\r\n                     *   quelles que soient les tailles des noeuds qui portent le texte.\r\n                     *   Le maximum masquait exactement l'ecart cherche.\r\n                     *   C'est la lecon deja payee ailleurs dans ce projet sous une autre\r\n                     *   forme (querySelector rend la premiere copie, pas la copie\r\n                     *   rendue) : quand plusieurs noeuds repondent, il faut nommer CELUI\r\n                     *   QUI REND, pas agreger la famille.\r\n                     *   On retient donc le noeud qui porte reellement du TEXTE \u2014 un\r\n                     *   enfant direct de type texte, non vide \u2014 et parmi ceux-la le plus\r\n                     *   grand. C'est celui que l'oeil compare.\r\n                     * ================================================================ *\/\r\n                    var _porteTexte1990 = function (_eT1990) {\r\n                        var _cn1990 = _eT1990.childNodes;\r\n                        for (var _t1990 = 0; _t1990 < _cn1990.length; _t1990++) {\r\n                            if (_cn1990[_t1990].nodeType === 3) {\r\n                                var _v1990 = '' + (_cn1990[_t1990].nodeValue || '');\r\n                                if (_v1990.replace(\/\\s+\/g, '') !== '') { return true; }\r\n                            }\r\n                        }\r\n                        return false;\r\n                    };\r\n                    var _feuilles1990 = function (_lst1990) {\r\n                        var _out1990 = [];\r\n                        for (var _p1990 = 0; _p1990 < _lst1990.length; _p1990++) {\r\n                            if (!(_lst1990[_p1990]._viaFsBase913 > 0)) { continue; }\r\n                            if (!_porteTexte1990(_lst1990[_p1990])) { continue; }\r\n                            _out1990.push(_lst1990[_p1990]);\r\n                        }\r\n                        return _out1990;\r\n                    };\r\n                    var _baseTexte1990 = function (_lst1990) {\r\n                        var _mx1990 = 0;\r\n                        for (var _p1990 = 0; _p1990 < _lst1990.length; _p1990++) {\r\n                            var _b1990 = _lst1990[_p1990]._viaFsBase913;\r\n                            if (_b1990 > _mx1990) { _mx1990 = _b1990; }\r\n                        }\r\n                        return _mx1990;\r\n                    };\r\n                    \/* pb1992 : le statut de chaque titre est journalise avec les\r\n                       bases. Si les deux textes sont a la meme base, l'ecart restant\r\n                       ne peut venir que du delta de statut (-1 actif \/ +0.5 a faire \/\r\n                       +1 complete, pb1180) \u2014 la ligne le dira sans un tour de plus. *\/\r\n                    var _statut1990 = function (_lst1990) {\r\n                        if (!_lst1990.length) { return '?'; }\r\n                        var _e0 = _lst1990[0];\r\n                        if (!_e0.closest) { return '?'; }\r\n                        return _e0.closest('.via-etape-grisee') ? 'grisee'\r\n                            : (_e0.closest('.via-etape-en-cours') ? 'en-cours' : 'a-faire');\r\n                    };\r\n                    var _idRef1990 = (typeof window._viaPb1990Ref === 'string')\r\n                        ? window._viaPb1990Ref : 'choixFormat';\r\n                    var _nRef1990 = _noeuds1990(_selEtape1990(_idRef1990));\r\n                    var _nCib1990 = _noeuds1990(_selEtape1990('recapitulatif'));\r\n                    var _fRef1990 = _feuilles1990(_nRef1990);\r\n                    var _fCib1990 = _feuilles1990(_nCib1990);\r\n                    var _bRef1990 = _baseTexte1990(_fRef1990);\r\n                    var _bCib1990 = _baseTexte1990(_fCib1990);\r\n                    \/* Aucune sortie muette : chaque abandon dit pourquoi, une fois\r\n                       par motif (regle 5.2). Sans cela, \u00ab la taille n'a pas bouge \u00bb\r\n                       ne distinguerait pas un titre absent d'un rapport de 1. *\/\r\n                    var _motif1990 = '';\r\n                    if (!(_bRef1990 > 0)) {\r\n                        _motif1990 = 'aucun noeud portant du texte sous le titre de'\r\n                            + ' reference (' + _idRef1990 + ')';\r\n                    } else if (!(_bCib1990 > 0)) {\r\n                        _motif1990 = 'aucun noeud portant du texte sous le titre du'\r\n                            + ' recapitulatif';\r\n                    } else if (Math.abs(_bRef1990 - _bCib1990) < 0.05) {\r\n                        _motif1990 = 'bases de texte deja egales (' + _bCib1990 + 'px)'\r\n                            + ' | statuts : ' + _idRef1990 + '=' + _statut1990(_fRef1990)\r\n                            + ' recapitulatif=' + _statut1990(_fCib1990)\r\n                            + ' -> si l ecart persiste a l ecran, il vient du delta de'\r\n                            + ' statut, pas de la base';\r\n                    }\r\n                    if (_motif1990) {\r\n                        if (window._viaSig1990 !== _motif1990) {\r\n                            window._viaSig1990 = _motif1990;\r\n                            console.log('[pb1992] rien a faire : ' + _motif1990);\r\n                        }\r\n                    } else {\r\n                        var _fac1990 = _bRef1990 \/ _bCib1990;\r\n                        var _nb1990 = 0;\r\n                        \/* pb1992 : on n'ecrit QUE sur les noeuds qui portent du texte.\r\n                           Multiplier aussi les conteneurs ferait grossir une boite qui\r\n                           ne rend rien, et un conteneur a 28px changerait les hauteurs\r\n                           de ligne pour un gain nul. *\/\r\n                        for (var _w1990 = 0; _w1990 < _fCib1990.length; _w1990++) {\r\n                            var _e1990 = _fCib1990[_w1990];\r\n                            if (!(_e1990._viaFsBase913 > 0)) { continue; }\r\n                            var _new1990 = Math.round(_e1990._viaFsBase913 * _fac1990 * 100) \/ 100;\r\n                            _e1990._viaFsBase913 = _new1990;\r\n                            _e1990.setAttribute('data-viafs913', _new1990);\r\n                            var _hx1990 = parseFloat(_e1990.getAttribute('data-viafs913max') || '0');\r\n                            if (_new1990 > _hx1990) {\r\n                                _e1990.setAttribute('data-viafs913max', String(_new1990));\r\n                            }\r\n                            _nb1990++;\r\n                        }\r\n                        var _sg1990 = 'pose|' + _bCib1990 + '->' + _bRef1990;\r\n                        if (window._viaSig1990 !== _sg1990) {\r\n                            window._viaSig1990 = _sg1990;\r\n                            console.log('[pb1992] base TEXTE du titre Vos reservations'\r\n                                + ' alignee sur ' + _idRef1990 + ' : ' + _bCib1990\r\n                                + ' -> ' + _bRef1990 + 'px (facteur '\r\n                                + (Math.round(_fac1990 * 1000) \/ 1000) + ', '\r\n                                + _nb1990 + ' noeud(s) porteurs de texte)'\r\n                                + ' | statuts : ' + _idRef1990 + '=' + _statut1990(_fRef1990)\r\n                                + ' recapitulatif=' + _statut1990(_fCib1990)\r\n                                + ' | la regle -1\/+0.5\/+1 s applique ensuite a l identique');\r\n                        }\r\n                    }\r\n                } catch (_e1990) {\r\n                    console.warn('[pb1990] abandon : ' + _e1990.message);\r\n                }\r\n            }\r\n            \/\/ --- Phase 2 : APPLICATION -------------------------------------------\r\n            for (var _a913 = 0; _a913 < _tous913.length; _a913++) {\r\n                var _el913 = _tous913[_a913];\r\n                if (_el913._viaFsBase913 > 0) {\r\n                    \/\/ ================================================================\r\n                    \/\/ pb1170 : -0.5px sur les etapes QUI NE SONT PAS ACTIVES (demande\r\n                    \/\/   user : l'active garde la taille standard, les autres sont\r\n                    \/\/   reduites de 0.5px).\r\n                    \/\/   Le delta est applique ICI parce que pb913 est le SEUL writer\r\n                    \/\/   de font-size sur ces elements : il repasse regulierement et\r\n                    \/\/   recalcule tout depuis _viaFsBase913. Ecrire ailleurs serait\r\n                    \/\/   efface au passage suivant \u2014 c'est ce qui a fait echouer pb1164.\r\n                    \/\/   Aucun cumul possible : la valeur repart toujours de la base.\r\n                    \/\/   L'etape active vient de _viaCibleProcess1091, publie par le\r\n                    \/\/   sequenceur \u2014 meme source que les couleurs de pb1169.\r\n                    \/\/   Revert : window._viaPb1170Off = true.\r\n                    \/\/ ================================================================\r\n                    \/\/ ================================================================\r\n                    \/\/ pb1173 : l'etape active se reconnait a sa CLASSE, pas a la cible\r\n                    \/\/   memorisee.\r\n                    \/\/   Constat user (HTML) : les tailles sont inversees \u2014 l'annonceur,\r\n                    \/\/   complete, garde 14.45px (taille standard) tandis que le secteur,\r\n                    \/\/   ACTIF, est a 13.95px (reduit). Exactement le contraire de la\r\n                    \/\/   regle.\r\n                    \/\/   Cause : pb1170 comparait avec _viaCibleProcess1091, une valeur\r\n                    \/\/   memorisee. pb913 tourne sur son propre rythme et pouvait la lire\r\n                    \/\/   AVANT sa mise a jour : il appliquait alors la regle a l'ancienne\r\n                    \/\/   etape active.\r\n                    \/\/   marquerEtapeEnCours pose deja la classe via-etape-en-cours sur le\r\n                    \/\/   titre courant \u2014 le HTML le confirme. C'est un marqueur DOM,\r\n                    \/\/   synchrone avec l'affichage : on le lit au lieu d'une variable qui\r\n                    \/\/   peut etre en retard.\r\n                    \/\/   Revert : window._viaPb1170Off = true.\r\n                    \/\/ ================================================================\r\n                    \/\/ pb1180 : TROIS tailles, une par etat (demande user) \u2014\r\n                    \/\/     active     : taille standard\r\n                    \/\/     completee  : -1px\r\n                    \/\/     a venir    : -0.5px\r\n                    \/\/   L'etat se lit sur les CLASSES posees par le panier, comme la\r\n                    \/\/   couleur : via-etape-en-cours pour l'active, via-etape-grisee\r\n                    \/\/   pour la completee. Meme source pour les deux proprietes, donc\r\n                    \/\/   pas de divergence possible entre couleur et taille.\r\n                    var _moins1170 = 0;\r\n                    if (window._viaPb1170Off !== true) {\r\n                        try {\r\n                            \/\/ pb1190 : l'etape ACTIVE se reconnait a la CIBLE, comme la\r\n                            \/\/   couleur. Constat user (HTML) : le titre\r\n                            \/\/   PageWebMobiletitreTexte est bien rouge (donc actif pour\r\n                            \/\/   _couleurEtapes1169) mais mesure 13.95px, soit la taille\r\n                            \/\/   d'une etape reduite \u2014 parce qu'il ne porte PAS la classe\r\n                            \/\/   via-etape-en-cours. Toutes les etapes ne la recoivent\r\n                            \/\/   pas ; la cible, elle, vaut pour toutes.\r\n                            \/\/   pb1173 etait passe a la classe parce que la cible etait\r\n                            \/\/   parfois en retard ; pb1176 a supprime ce decalage en\r\n                            \/\/   appelant pb913 juste apres la pose des couleurs. Les\r\n                            \/\/   deux proprietes lisent de nouveau la meme source.\r\n                            var _cibleAct1190 = window._viaCibleProcess1091 || null;\r\n                            var _stAct1190 = window.VIA_Panier ? window.VIA_Panier.state : null;\r\n                            var _eAct1190 = (_cibleAct1190 && _stAct1190)\r\n                                ? (_stAct1190.etapesConfig || []).filter(function (_x) {\r\n                                    return _x.id === _cibleAct1190; })[0]\r\n                                : null;\r\n                            var _selAct1190 = _eAct1190\r\n                                ? [_eAct1190.titre, _eAct1190.iconeUp, _eAct1190.iconeDown]\r\n                                    .filter(Boolean).join(',')\r\n                                : '';\r\n                            var _act1180 = _selAct1190\r\n                                ? (_el913.closest ? !!_el913.closest(_selAct1190) : false)\r\n                                : false;\r\n                            var _fait1180 = _el913.closest\r\n                                ? !!_el913.closest('.via-etape-grisee') : false;\r\n                            \/\/ pb1233 : l'etape ACTIVE gagne 1px (demande user) \u2014 elle\r\n                            \/\/   etait a taille standard. Les deux autres etats sont\r\n                            \/\/   inchanges : completee -1px, a venir -0.5px.\r\n                            if (_act1180) { _moins1170 = -1; }\r\n                            else if (_fait1180) { _moins1170 = 1; }\r\n                            else { _moins1170 = 0.5; }\r\n                        } catch (_e1170) { _moins1170 = 0; }\r\n                    }\r\n                    \/* ============================================================\r\n                     * pb1566 : +1 PX SUR LES SITES PAYS (demande user).\r\n                     *   La regle de taille est _cible913 = base x 0.85 - _moins1170, avec\r\n                     *   _moins1170 = -1 (actif) \/ +0.5 (a faire) \/ +1 (complete), soit\r\n                     *   15.45 \/ 13.95 \/ 13.45 px sur une base de 17.\r\n                     *   Dans le popup des sites pays, ces tailles sont jugees trop petites :\r\n                     *   on ajoute 1 px A TOUS LES STATUTS, ce qui decale l'echelle sans\r\n                     *   toucher aux ECARTS entre statuts \u2014 1.5 px entre actif et a faire,\r\n                     *   0.5 px entre a faire et complete restent inchanges.\r\n                     *   Le decalage s'applique apres la regle commune plutot que sur la\r\n                     *   base : agir sur la base aurait multiplie l'ecart par 0.85 et\r\n                     *   contamine la regie, dont les bases sont les memes.\r\n                     *   Reglable a chaud : window._viaPb1566Delta = 2 (ou 0 pour annuler).\r\n                     *   Revert : window._viaPb1566Off = true.\r\n                     * ============================================================ *\/\r\n                    var _plus1566 = 0;\r\n                    if (window._viaPb1566Off !== true) {\r\n                        try {\r\n                            var _pop1566 = new URLSearchParams(window.location.hash.substring(1)\r\n                                || window.location.search).get('mode') === 'popup';\r\n                            if (_pop1566) {\r\n                                _plus1566 = (typeof window._viaPb1566Delta === 'number')\r\n                                    ? window._viaPb1566Delta : 1;\r\n                            }\r\n                        } catch (_e1566) { _plus1566 = 0; }\r\n                    }\r\n                    \/* ============================================================\r\n                     * pb1994 : + 3 PX SUR LE TITRE \u00ab Vos reservations \u00bb.\r\n                     *   Constat JF, apres deux mesures qui ont ferme les autres\r\n                     *   pistes : bases egales, statuts egaux \u2014 pb913 calcule donc\r\n                     *   deja la meme taille pour les deux titres, et l'ecart\r\n                     *   visible ne vient ni de la base ni du delta de statut.\r\n                     *   La demande devient un CHOIX D'APPARENCE, pas une\r\n                     *   correction d'ecart, exactement comme pb1877 l'assumait\r\n                     *   pour le calage mobile du titre et des cartes. On ne\r\n                     *   cherche donc plus a expliquer, on regle.\r\n                     *   Le terme s'ajoute dans la formule de pb913, seul ecrivain\r\n                     *   de font-size sur ces noeuds : il repasse en continu et\r\n                     *   recalcule tout depuis _viaFsBase913. Ecrire ailleurs\r\n                     *   serait efface au tour suivant (echec de pb1164).\r\n                     *   Aucun cumul : la base n'est pas touchee.\r\n                     *   _moins1170 === 0.5 EST la branche \u00ab a faire \u00bb de pb1180 \u2014\r\n                     *   on la relit plutot que de recalculer le statut, pour que\r\n                     *   la taille ne puisse pas dire autre chose que le delta\r\n                     *   pose deux lignes plus haut. Si le try de pb1180 a echoue,\r\n                     *   _moins1170 vaut 0 et le supplement ne s'applique pas :\r\n                     *   l'echec est silencieux dans le bon sens.\r\n                     *   Reglage a chaud : window._viaPb1994Delta = 2\r\n                     *   Revert : window._viaPb1994Off = true\r\n                     * ============================================================ *\/\r\n                    var _plus1994 = 0;\r\n                    if (_moins1170 === 0.5) {\r\n                        if (!_mob1179) {\r\n                            \/* pb2045 : appel garde, meme raison. *\/\r\n                            if ((typeof window._viaPaysDesktop1994 === 'function')\r\n                                    ? window._viaPaysDesktop1994() : false) {\r\n                                if (_el913.closest) {\r\n                                    if (_el913.closest('.RecapitulatifVosCommandestitre, #RecapitulatifVosCommandestitreContainer')) {\r\n                                        \/* Paliers valides a l ecran par JF, sur le\r\n                                           seul defaut : pb1994 +3 (trop grand),\r\n                                           pb1994b +2 (trop grand), pb1994c +1\r\n                                           (trop grand), pb1994d +0.785 (trop\r\n                                           grand), pb1994e +0.75 (trop grand),\r\n                                           pb1994f +0.5.\r\n                                           L encadrement est desormais net : a +0 le\r\n                                           titre etait juge trop PETIT, a +0.75 trop\r\n                                           grand. La valeur juste est entre les deux et\r\n                                           se cherche au knob, pas par livraison \u2014\r\n                                           window._viaPb1994Delta se lit a chaque\r\n                                           passage de pb913, qui repasse tout seul.\r\n                                           Valeur non entiere assumee : le seuil\r\n                                           d ecriture de pb1178 est a 0.1 px et la\r\n                                           cible est arrondie au centieme, donc le\r\n                                           supplement passe bien.\r\n                                           Le mecanisme et le knob ne changent pas.\r\n                                           Note : a +1 le supplement est du meme ordre\r\n                                           que le delta de statut lui-meme (0.5). Si\r\n                                           c est encore trop, ce n est plus la taille\r\n                                           qu il faut regler mais le noeud vise \u2014 deux\r\n                                           bases, 17 et 20, recoivent aujourd hui le\r\n                                           supplement, et rien ne dit que les deux\r\n                                           portent du texte visible. *\/\r\n                                        _plus1994 = (typeof window._viaPb1994Delta === 'number')\r\n                                            ? window._viaPb1994Delta : 0.5;\r\n                                    }\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                    var _cible913 = Math.round((_el913._viaFsBase913 * _ratio913 - _moins1170 + _plus1566 + _plus1994) * 100) \/ 100;\r\n                    \/* pb1994 : une ligne par changement d'etat, pas par noeud ni\r\n                       par passage \u2014 pb913 traite des dizaines d'elements en\r\n                       continu. Le compte de noeuds credites dit tout de suite si\r\n                       le supplement atteint bien le texte visible. *\/\r\n                    if (_plus1994 !== 0) {\r\n                        window._viaN1994 = (window._viaN1994 || 0) + 1;\r\n                        \/* ============================================================\r\n                         * pb1994b : LE JOURNAL INONDAIT LA CONSOLE.\r\n                         *   Capture JF : la meme ligne repetee sans fin, alternant\r\n                         *   17.95 et 20.5, compteur montant a 613 en quelques\r\n                         *   secondes. La cause est dans la ligne elle-meme : le titre\r\n                         *   porte DEUX noeuds de bases differentes, 17 et 20. Une\r\n                         *   signature a un seul creneau basculait de l un a l autre a\r\n                         *   chaque passage et se croyait donc toujours nouvelle.\r\n                         *   UNE VALEUR UNIQUE NE PEUT PAS DEDUPLIQUER UNE FAMILLE.\r\n                         *   L idiome _viaSigXXXX employe partout dans ce fichier n est\r\n                         *   valable que pour un etat SCALAIRE ; des qu on journalise\r\n                         *   plusieurs noeuds, il faut un dictionnaire.\r\n                         *   Chaque base parle donc une fois, puis se tait. La clef est\r\n                         *   la BASE et non la taille calculee : c est elle qui\r\n                         *   distingue les noeuds, et elle ne bouge plus une fois\r\n                         *   capturee. Le compteur cumule reste, lu dans la ligne \u2014 il\r\n                         *   reste le temoin que le supplement atteint bien des noeuds.\r\n                         * ============================================================ *\/\r\n                        window._viaVus1994 = window._viaVus1994 || {};\r\n                        var _sg1994 = 'a-faire|' + _plus1994 + '|' + _el913._viaFsBase913;\r\n                        if (!window._viaVus1994[_sg1994]) {\r\n                            window._viaVus1994[_sg1994] = true;\r\n                            console.log('[pb1994] titre Vos reservations, etape a faire,'\r\n                                + ' site pays desktop : +' + _plus1994 + 'px'\r\n                                + ' | base ' + _el913._viaFsBase913 + ' x ' + _ratio913\r\n                                + ' - ' + _moins1170 + ' + ' + _plus1566 + ' + ' + _plus1994\r\n                                + ' = ' + _cible913 + 'px'\r\n                                + ' | noeuds credites depuis le chargement : ' + window._viaN1994);\r\n                        }\r\n                    }\r\n                    \/* pb1566b : journaliser une fois le delta reellement applique \u2014 sans\r\n                       quoi \u00ab les tailles n'ont pas augmente \u00bb ne distingue pas un delta\r\n                       nul d'un pb913 qui ne rejoue pas. *\/\r\n                    if (window._viaSig1566 !== _plus1566) {\r\n                        window._viaSig1566 = _plus1566;\r\n                        console.log('[pb1566] delta taille = +' + _plus1566 + 'px'\r\n                            + ' | exemple : base ' + _el913._viaFsBase913\r\n                            + ' x ' + _ratio913 + ' - ' + _moins1170 + ' + ' + _plus1566\r\n                            + ' = ' + _cible913 + 'px');\r\n                    }\r\n                    \/\/ pb1178 : SEUIL D'ECRITURE abaisse de 0.5 a 0.1px.\r\n                    \/\/   Constat user (HTML) : les tailles restent inversees \u2014 l'etape\r\n                    \/\/   active a 13.95px et l'annonceur complete 14.45px, malgre\r\n                    \/\/   pb1176 qui rejoue bien pb913 au bon moment.\r\n                    \/\/   Cause : ce seuil valait 0.5px, soit EXACTEMENT le delta de\r\n                    \/\/   pb1170. Passer de 14.45 a 13.95 fait un ecart de 0.5, qui n'est\r\n                    \/\/   pas STRICTEMENT superieur a 0.5 : l'ecriture etait donc\r\n                    \/\/   toujours refusee, dans les deux sens.\r\n                    \/\/   Le seuil existe pour eviter des reecritures inutiles a chaque\r\n                    \/\/   passe ; 0.1px remplit ce role sans bloquer un delta de 0.5.\r\n                    if (Math.abs(parseFloat(window.getComputedStyle(_el913).fontSize) - _cible913) > 0.1) {\r\n                        _el913.style.setProperty('font-size', _cible913 + 'px', 'important');\r\n                        _n913++;\r\n                    }\r\n                }\r\n                if (_el913._viaSvgBase913 ? (_el913._viaSvgBase913.w > 0) : false) {\r\n                    _el913.style.setProperty('width', Math.round(_el913._viaSvgBase913.w * _ratio913) + 'px', 'important');\r\n                    _el913.style.setProperty('height', Math.round(_el913._viaSvgBase913.h * _ratio913) + 'px', 'important');\r\n                }\r\n            }\r\n            if (_n913 > 0) { console.log('[pb913] titres\/chevrons etapes reduits a ' + Math.round(_ratio913 * 100) + '% (' + _n913 + ' element(s))'); }\r\n        }\r\n        \/\/ Elementor peut reimposer ses tailles apres coup (lecon pb505\/pb309) :\r\n        \/\/   on repasse periodiquement. _appliquer913 est idempotent (recalcul depuis\r\n        \/\/   la taille ORIGINALE memorisee) et n'ecrit que si l'ecart depasse 0.5px,\r\n        \/\/   donc aucune boucle d'ecriture ni thrashing.\r\n        var _essais913 = 0;\r\n        var _t913 = setInterval(function () {\r\n            _essais913++;\r\n            if (_essais913 > 40) { clearInterval(_t913); return; }   \/\/ 40 x 500ms = 20 s\r\n            try { _appliquer913(); } catch (_e913) { console.warn('[pb913]', _e913.message); }\r\n        }, 500);\r\n        window._viaAppliquerTailleTitres913 = _appliquer913;\r\n    })();\r\n\r\n    \/* ====================================================================\r\n     * pb1895 : QUI SCROLLE QUAND ON SAISIT UN CHAMP ?\r\n     *   Constat JF : des qu on commence a saisir, la page remonte en haut.\r\n     *   Je n ai pas trouve l ecrivain par lecture \u2014 aucun des scrollTo(0),\r\n     *   scrollTop=0 ni scrollIntoView du corpus n est declenche par une\r\n     *   saisie. Le deduire serait la cinquieme hypothese non verifiee de la\r\n     *   journee ; on applique la methode qui a fonctionne pour pb1607 :\r\n     *   intercepter l ecriture et lui faire dire d ou elle vient.\r\n     *\r\n     *   Trois voies possibles sont piegees : window.scrollTo, scrollIntoView\r\n     *   et le setter scrollTop. Chacune journalise la valeur demandee ET LA\r\n     *   PILE D APPEL.\r\n     *\r\n     *   FENETRE D ECOUTE : uniquement dans les 4s qui suivent un focus sur un\r\n     *   champ de saisie, et seulement pour les scrolls qui REMONTENT vers le\r\n     *   haut (moins de 60px). Sans ces deux filtres, le piege journaliserait\r\n     *   chaque defilement du doigt et le log serait illisible.\r\n     *   Il se desarme apres 8 captures : un piege permanent sur le scroll\r\n     *   ralentit toute la page.\r\n     *   Revert : window._viaPb1895Off = true\r\n     * ==================================================================== *\/\r\n    (function () {\r\n        if (window._viaPb1895Off === true) { return; }\r\n        if (window._viaPiege1895Arme) { return; }\r\n        window._viaPiege1895Arme = true;\r\n        var _n1895 = 0;\r\n        var _jusqua1895 = 0;\r\n        function _fenetre1895() { return Date.now() < _jusqua1895; }\r\n        function _pile1895() {\r\n            try { throw new Error('x'); } catch (_e) {\r\n                var _l = String(_e.stack || '').split('\\n');\r\n                return _l.slice(2, 6).join(' << ').replace(\/\\s+\/g, ' ');\r\n            }\r\n        }\r\n        function _dire1895(_quoi, _val) {\r\n            if (!_fenetre1895()) { return; }\r\n            if (_n1895 >= 8) { return; }\r\n            _n1895++;\r\n            console.log('[pb1895] ' + _quoi + ' vers ' + _val\r\n                + ' | scrollY avant=' + Math.round(window.scrollY)\r\n                + ' | ' + _pile1895());\r\n        }\r\n        document.addEventListener('focusin', function (_ev) {\r\n            var _t = _ev.target;\r\n            if (!_t) { return; }\r\n            var _tag = String(_t.tagName || '').toLowerCase();\r\n            if (_tag !== 'input') { if (_tag !== 'textarea') { return; } }\r\n            _jusqua1895 = Date.now() + 4000;\r\n            console.log('[pb1895] focus sur ' + _tag + '#' + (_t.id || '?')\r\n                + ' | scrollY=' + Math.round(window.scrollY) + ' \u2014 ecoute 4s');\r\n        }, true);\r\n        try {\r\n            var _sto = window.scrollTo;\r\n            window.scrollTo = function () {\r\n                var _v = arguments[0];\r\n                var _top = (_v ? (typeof _v === 'object' ? _v.top : arguments[1]) : arguments[1]);\r\n                if (typeof _top === 'number' ? _top < 60 : false) { _dire1895('window.scrollTo', _top); }\r\n                return _sto.apply(window, arguments);\r\n            };\r\n        } catch (_e1) { console.log('[pb1895] scrollTo non piegeable : ' + _e1.message); }\r\n        try {\r\n            var _siv = Element.prototype.scrollIntoView;\r\n            Element.prototype.scrollIntoView = function () {\r\n                _dire1895('scrollIntoView sur #' + (this.id || this.className || '?'), '-');\r\n                return _siv.apply(this, arguments);\r\n            };\r\n        } catch (_e2) { console.log('[pb1895] scrollIntoView non piegeable : ' + _e2.message); }\r\n        try {\r\n            var _d = Object.getOwnPropertyDescriptor(Element.prototype, 'scrollTop');\r\n            if (_d ? _d.set : false) {\r\n                Object.defineProperty(Element.prototype, 'scrollTop', {\r\n                    configurable: true,\r\n                    get: _d.get,\r\n                    set: function (_v) {\r\n                        if (typeof _v === 'number' ? _v < 60 : false) {\r\n                            _dire1895('scrollTop sur #' + (this.id || this.tagName || '?'), _v);\r\n                        }\r\n                        return _d.set.call(this, _v);\r\n                    }\r\n                });\r\n            }\r\n        } catch (_e3) { console.log('[pb1895] scrollTop non piegeable : ' + _e3.message); }\r\n        console.log('[pb1895] piege scroll arme \u2014 saisis un champ et copie les logs');\r\n    })();\r\n\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-252d099b elementor-widget elementor-widget-html\" data-id=\"252d099b\" data-element_type=\"widget\" data-e-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\nwindow._viaRefVer = 'REF-pb2346';\r\ntry { console.log('[REFERENCES ECHO] ' + window._viaRefVer + ' SERVI'); } catch (_eRV) {}\r\n\/**\r\n * VIA Agency - R\u00c9F\u00c9RENCES CLIENT\r\n * @version 2.2 - REF-pb1706 : garde mode=popup lue AUSSI dans le hash\r\n * CORRECTIONS :\r\n * - Ne pas \u00e9craser le pays de l'\u00e9tape 1 lors de la s\u00e9lection d'un annonceur\r\n * - Appliquer la logique TVA sur le pays de l'\u00e9tape 1 uniquement\r\n * - Sauvegarde automatique en BDD \u00e0 la validation du formulaire\r\n * - Bouton #EffacerReferences pour r\u00e9initialiser les formulaires\r\n * - \u2705 v1.5 : D\u00e9tection des modifications \u2192 r\u00e9initialisation des validations ou blocage\r\n * - \u2705 v1.6 : Gestion correcte du flag references_validees_session\r\n * - \u2705 v1.7 : FIX mobile - #ProcessCommande reste visible apr\u00e8s clic FinaliserBouton\r\n * - \u2705 v1.8 : Suppression NonRedevableTVA et MsgEntiteRedevableTVA\r\n * - \u2705 v1.8 : Synchronisation pays R\u00e9f\u00e9rences \u2192 \u00c9tape 1 avec recalcul tarif\r\n * - \u2705 v1.8 : Autocomplete pays avec fond vert temporaire et auto-remplissage si unique\r\n * - \u2705 v1.9 : signalerModificationReferences ne bloque plus la visualisation\r\n * - \u2705 v1.9 : Correction TVA zone EU - n\u00b0 TVA optionnel (si saisi \u2192 HT, sinon \u2192 TTC)\r\n * - \u2705 v1.9 : Protection contre touche Enter sur formulaires Elementor\r\n * - \u2705 v1.9 : Gestion champ readonly RegimeTVA (liste d\u00e9roulante ChoixTVA masqu\u00e9e)\r\n * - \u2705 v1.9 : Texte d'aide positionn\u00e9 en absolu pour ne pas d\u00e9caler les champs\r\n * - \u2705 v1.9 : Fonction mettreAJourLogiqueTVA expos\u00e9e publiquement\r\n * - \u2705 v1.9 : Couleur verte flash autocomplete #E8F0FE (au lieu de #d4edda)\r\n * - \u2705 v1.9 : Fond #E8F0FE pour les champs renseign\u00e9s (sauf readonly)\r\n * - \u2705 v2.0 : FIX #DataFacturationForm \u2014 ciblage direct au lieu de .closest()\r\n *\/\r\n\r\n(function() {\r\n    'use strict';\r\n    \r\n    \/\/ \u2705 Fonction helper pour \u00e9viter l'encodage WordPress de &&\r\n    const AND = (a, b) => !(!a || !b);\r\n    \r\n    console.log('\ud83d\udccb Chargement module R\u00e9f\u00e9rences Client v2.0...');\r\n\r\n    \/\/ pb469 : #ChampsObligatoires 25px trop bas quand la case facturation n'est PAS cochee\r\n    \/\/   (#DataFacturationForm masque -> body.via-df-hidden). La 1re tentative (margin-top) etait\r\n    \/\/   ecrasee par yearbook-media.js (body.via-popup-achat #ChampsObligatoires : margin + transform,\r\n    \/\/   meme contexte iframe, spec >=). SOLUTION deterministe : une regle TRANSFORM plus specifique\r\n    \/\/   (1,2,1) qui passe le translateY de yearbook (-30) a -55 (= -25px de plus), uniquement dans\r\n    \/\/   l'etat decoche. Le transform etant une propriete distincte du margin, le decalage net est de\r\n    \/\/   25px vers le haut quel que soit le margin gagnant (init ET apres-clic). Le margin ci-dessous\r\n    \/\/   reste a sa valeur d'origine (inerte car ecrase, conserve pour ne rien casser).\r\n    (function _viaChampsObligPos() {\r\n        if (!document.getElementById('via-champs-oblig-pos-css')) {\r\n            var _addCss = function() {\r\n                if (!document.head) { setTimeout(_addCss, 100); return; }\r\n                if (document.getElementById('via-champs-oblig-pos-css')) { return; }\r\n                var _style = document.createElement('style');\r\n                _style.id = 'via-champs-oblig-pos-css';\r\n                _style.textContent =\r\n                    \/* pb469 : etat decoche. transform translateY ne remontait QUE ChampsObligatoires\r\n                       (sans toucher au flux -> trou en dessous). On passe en margin-top negatif : il\r\n                       remonte l'element ET reduit la place occupee -> tout ce qui suit remonte aussi.\r\n                       transform neutralise. Spec (1,2,1) > yearbook (1,1,1). Valeurs a affiner au px. *\/\r\n                    \/* ============================================================\r\n                     * pb1707 : LA REGLE GAGNANTE EST CELLE-CI, ET C EST UNE FEUILLE.\r\n                     *   Probe user, sur le telephone :\r\n                     *     inline = -            (aucun style inline)\r\n                     *     calcule marginTop = -75px\r\n                     *     transform = none\r\n                     *   Les deux ecrivains JS de pb1706 ne tournent que sur CHANGEMENT\r\n                     *   de la case facturation. A l affichage initial, personne ne pose\r\n                     *   d inline : c est cette feuille qui decide, et elle seule.\r\n                     *   Sa specificite (1,2,1) bat tout ce que j ai modifie depuis\r\n                     *   quatre tours, y compris ma regle .ReferencesConteneurScale \u2014\r\n                     *   d ou transform = none alors que l element porte la classe.\r\n                     *   Le decalage demande passe donc ici, en variable CSS, pour rester\r\n                     *   reglable sans redeploiement :\r\n                     *     document.documentElement.style.setProperty('--via-oblig-1707','60px')\r\n                     *   Les valeurs d origine restent lisibles : base + decalage.\r\n                     * ============================================================ *\/\r\n                    \/* ============================================================\r\n                     * pb1788 REVERTE : CETTE FEUILLE NE GAGNE PAS. (voir pb1789)\r\n                     *   J'avais pose ici les -70px demandes par JF. Sans effet : le\r\n                     *   HTML montre sur #ChampsObligatoires un margin-top:105px\r\n                     *   !important EN INLINE, pose par pb1617 dans yearbook-media.js.\r\n                     *   Un inline !important bat toute feuille (regle pb1343). Le\r\n                     *   commentaire pb1707 ci-dessous disait \u00ab la regle gagnante est\r\n                     *   celle-ci \u00bb : c'etait vrai a l'affichage initial d'alors, ce\r\n                     *   ne l'est plus depuis que pb1617 ecrit a chaque passage.\r\n                     *   Valeur d'origine retablie. La correction vit en pb1789.\r\n                     *   VARIABLE PROPRE, ET C'EST LE POINT : --via-oblig-1707 est\r\n                     *   partagee avec la regle mobile ci-dessous (max-width:1000px).\r\n                     *   La regler ici aurait deplace le mobile de 70px aussi \u2014\r\n                     *   exactement la regle 5.3, quatre regressions desktop en une\r\n                     *   soiree pour n'avoir pas borne au contexte. Les deux\r\n                     *   Le decouplage desktop\/mobile envisage ici n'a plus d'objet :\r\n                     *   cette regle ne decide plus rien en desktop popup.\r\n                     *   La regle ne vise que l'etat DECOCHE (.via-df-hidden) :\r\n                     *   confirme par JF, les 70px ne valent PAS case cochee, ou\r\n                     *   c'est pb1617 dans yearbook-media.js qui ecrit.\r\n                     *   Ne rien regler ici : l'inline de pb1617 passe devant.\r\n                     * ============================================================ *\/\r\n                    'body.via-popup-achat.via-df-hidden #ChampsObligatoires { transform: none !important; margin-top: calc(35px + var(--via-oblig-1707, 60px)) !important; margin-bottom: 0 !important; }' +\r\n                    '@media (max-width: 1000px) {' +\r\n                        'body.via-popup-achat.via-df-hidden #ChampsObligatoires { margin-top: calc(-75px + var(--via-oblig-1707, 60px)) !important; }' +\r\n                        \/* pb506 : SITE REGIE (mode!=popup -> pas de via-popup-achat) sur mobile.\r\n                           Decoche (via-df-hidden), #ChampsObligatoires restait sur sa base -55px\r\n                           (yearbook L571) -> 5px trop haut car le form facturation masque ne\r\n                           pousse plus rien. On descend : -10px (pb506 : -55 base -> -50 -> -20\r\n                           -> -10, demandes JF successives). :not(.via-popup-achat)\r\n                           => n'affecte PAS les sites pays (qui ont leur propre regle -75\/-35). *\/\r\n                        'body.via-df-hidden:not(.via-popup-achat) #ChampsObligatoires { margin-top: -10px !important; }' +\r\n                    '}';\r\n                document.head.appendChild(_style);\r\n            };\r\n            _addCss();\r\n        }\r\n        function _updateBodyClass() {\r\n            if (!document.body) { setTimeout(_updateBodyClass, 200); return; }\r\n            var _df = document.getElementById('DataFacturationForm');\r\n            var _hidden = false;\r\n            if (!_df) { _hidden = true; }\r\n            else if (_df.style.display === 'none') { _hidden = true; }\r\n            else if (window.getComputedStyle(_df).display === 'none') { _hidden = true; }\r\n            if (_hidden) { document.body.classList.add('via-df-hidden'); }\r\n            else { document.body.classList.remove('via-df-hidden'); }\r\n        }\r\n        _updateBodyClass();\r\n        setInterval(_updateBodyClass, 500);\r\n    })();\r\n\r\n    \/\/ Variable pour stocker la liste des clients\r\n    let ClientNames = [];\r\n\r\n    \/**\r\n     * Initialisation apr\u00e8s chargement de jQuery et VIA_Elementor\r\n     *\/\r\n    function initReferencesModule() {\r\n        if (typeof jQuery === 'undefined') {\r\n            console.error('\u274c jQuery non disponible');\r\n            setTimeout(initReferencesModule, 500);\r\n            return;\r\n        }\r\n        \r\n        if (typeof window.VIA_Elementor === 'undefined') {\r\n            setTimeout(initReferencesModule, 500);\r\n            return;\r\n        }\r\n        \r\n        \/\/ Attendre que jQuery UI autocomplete soit disponible\r\n        if (typeof jQuery.fn.autocomplete !== 'function') {\r\n            setTimeout(initReferencesModule, 500);\r\n            return;\r\n        }\r\n        \r\n        const $ = jQuery;\r\n        const STATE = window.VIA_Elementor.state;\r\n        const COUNTRIES_DATA = window.VIA_Elementor.COUNTRIES_DATA;\r\n        \r\n        console.log('\u2705 D\u00e9pendances charg\u00e9es, initialisation...');\r\n\r\n        \/\/ ============================================\r\n        \/\/ \u2705 v1.5 : D\u00c9TECTION DES MODIFICATIONS\r\n        \/\/ ============================================\r\n        \r\n        \/**\r\n         * \u2705 v1.6 : Signale une modification des r\u00e9f\u00e9rences\r\n         * - Supprime le flag references_validees_session\r\n         * - Appelle VIA_Panier.gererModificationCommande() pour :\r\n         *   - R\u00e9initialiser les validations si bon de commande pas cr\u00e9\u00e9\r\n         *   - Afficher message si bon de commande d\u00e9j\u00e0 cr\u00e9\u00e9 ET modification r\u00e9elle\r\n         * \u2705 v1.10 : Ne bloque que si c'est une vraie modification (pas une visualisation)\r\n         *\/\r\n        function signalerModificationReferences() {\r\n            \/\/ \u2705 v1.10 : Ne pas bloquer si bon de commande cr\u00e9\u00e9 (on veut permettre la visualisation)\r\n            \/\/ Le blocage r\u00e9el se fait lors de la tentative de validation\r\n            const bonCommandeCree = sessionStorage.getItem('BonCommandeCree') === 'Yes';\r\n            \r\n            if (bonCommandeCree) {\r\n                console.log('\ud83d\udd12 Modification d\u00e9tect\u00e9e mais bon de commande cr\u00e9\u00e9 - affichage message');\r\n                if (window.VIA_Panier && typeof window.VIA_Panier.afficherMessageNouvelleCommande === 'function') {\r\n                    window.VIA_Panier.afficherMessageNouvelleCommande();\r\n                }\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v1.6 : Supprimer le flag car les r\u00e9f\u00e9rences ont \u00e9t\u00e9 modifi\u00e9es\r\n            sessionStorage.removeItem('references_validees_session');\r\n            console.log('\ud83d\udd04 Flag references_validees_session supprim\u00e9 (modification d\u00e9tect\u00e9e)');\r\n            \r\n            if (window.VIA_Panier && typeof window.VIA_Panier.gererModificationCommande === 'function') {\r\n                window.VIA_Panier.gererModificationCommande('references');\r\n            }\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 v1.5 : Initialise les listeners de d\u00e9tection de modification\r\n         *\/\r\n        function initDetectionModifications() {\r\n            \/\/ Liste des champs \u00e0 surveiller\r\n            const champsASurveiller = [\r\n                'annonceur_nom_societe',\r\n                'annonceur_nom_contact',\r\n                'annonceur_direction_service',\r\n                'annonceur_numero_immatriculation',\r\n                'annonceur_numero_tva',\r\n                'annonceur_adresse_ligne1',\r\n                'annonceur_code_postal',\r\n                'annonceur_ville',\r\n                'annonceur_pays',\r\n                'annonceur_email_contact',\r\n                'annonceur_telephone_contact',\r\n                'facturation_contact',\r\n                'facturation_adresse',\r\n                'facturation_code_postal',\r\n                'facturation_ville',\r\n                'facturation_pays',\r\n                'facturation_email',\r\n                'facturation_telephone'\r\n            ];\r\n            \r\n            \/\/ Ajouter un listener sur chaque champ\r\n            champsASurveiller.forEach(champ => {\r\n                const $input = $(`input[name=\"form_fields[${champ}]\"]`);\r\n                if ($input.length > 0) {\r\n                    $input.on('change', function() {\r\n                        console.log('\ud83d\udcdd Modification d\u00e9tect\u00e9e dans les r\u00e9f\u00e9rences:', champ);\r\n                        signalerModificationReferences();\r\n                    });\r\n                }\r\n            });\r\n            \r\n            \/\/ Surveiller aussi les checkboxes\r\n            $('input[name=\"form_fields[DataFacturation]\"]').on('change', function() {\r\n                console.log('\ud83d\udcdd Modification d\u00e9tect\u00e9e: checkbox facturation diff\u00e9rente');\r\n                signalerModificationReferences();\r\n            });\r\n            \r\n            \/\/ \u2705 v1.8 : Supprim\u00e9 - handler NonRedevableTVA\r\n            \r\n            console.log('\u2705 D\u00e9tection des modifications initialis\u00e9e');\r\n        }\r\n\r\n        \/\/ ============================================\r\n        \/\/ SECTION : RECHERCHE CLIENT\r\n        \/\/ ============================================\r\n\r\n        \/**\r\n         * Charge la liste des clients depuis la DB\r\n         *\/\r\n        function fetchClientNames() {\r\n            return new Promise((resolve, reject) => {\r\n                const commercialUserId = sessionStorage.getItem('Commercial_UserId');\r\n                \r\n                \/\/ Si pas de commercial connect\u00e9, on ne charge pas les clients\r\n                if (!commercialUserId) {\r\n                    console.log('\u2139\ufe0f Pas de commercial connect\u00e9, recherche client d\u00e9sactiv\u00e9e');\r\n                    resolve([]);\r\n                    return;\r\n                }\r\n                \r\n                $.ajax({\r\n                    type: \"POST\",\r\n                    url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                    data: {\r\n                        action: 'get_client_names',\r\n                        Commercial_UserId: commercialUserId\r\n                    },\r\n                    success: function(response) {\r\n                        if (Array.isArray(response)) {\r\n                            ClientNames = response;\r\n                            console.log('\u2705 Liste clients charg\u00e9e:', ClientNames.length, 'clients');\r\n                        } else if (AND(response, response.success === false)) {\r\n                            console.warn('\u26a0\ufe0f Erreur serveur:', response.data);\r\n                            ClientNames = [];\r\n                        }\r\n                        resolve(ClientNames);\r\n                    },\r\n                    error: function(xhr, status, error) {\r\n                        console.error('\u274c Erreur chargement clients:', error);\r\n                        reject(error);\r\n                    }\r\n                });\r\n            });\r\n        }\r\n\r\n        \/**\r\n         * Initialise l'autocomplete pour la recherche de clients\r\n         *\/\r\n        function initRechercheClient() {\r\n            const $searchInput = $('input[name=\"form_fields[RechercherFicheClient]\"]');\r\n            \r\n            if ($searchInput.length === 0) {\r\n                console.log('\u2139\ufe0f Champ recherche client introuvable (normal si pas commercial)');\r\n                return;\r\n            }\r\n            \r\n            \/\/ Charger les clients puis configurer l'autocomplete\r\n            fetchClientNames().then(() => {\r\n                if (ClientNames.length === 0) {\r\n                    console.log('\u2139\ufe0f Aucun client \u00e0 afficher');\r\n                    return;\r\n                }\r\n                \r\n                $searchInput.autocomplete({\r\n                    source: function(request, response) {\r\n                        const results = $.ui.autocomplete.filter(ClientNames, request.term);\r\n                        response(results.slice(0, 10));\r\n                    },\r\n                    minLength: 2,\r\n                    delay: 200,\r\n                    \r\n                    select: function(event, ui) {\r\n                        const clientId = ui.item.id;\r\n                        const clientLabel = ui.item.label;\r\n                        const clientSource = ui.item.source || 'annonceur';\r\n                        \r\n                        console.log('\ud83d\udc64 Client s\u00e9lectionn\u00e9:', clientLabel, '(ID:', clientId, ', Source:', clientSource + ')');\r\n                        \r\n                        \/\/ \u2705 v1.5 : Signaler la modification\r\n                        signalerModificationReferences();\r\n                        \r\n                        \/\/ Charger les donn\u00e9es compl\u00e8tes du client avec la source\r\n                        loadClientDataAndFillForm(clientId, clientSource);\r\n                        \r\n                        return true;\r\n                    }\r\n                });\r\n                \r\n                console.log('\u2705 Autocomplete recherche client initialis\u00e9');\r\n                \r\n            }).catch(error => {\r\n                console.error('\u274c Erreur initialisation recherche client:', error);\r\n            });\r\n        }\r\n        \r\n        \/**\r\n         * Pr\u00e9-remplit le formulaire si un annonceur est connect\u00e9 (depuis sessionStorage)\r\n         *\/\r\n        function initPreRemplissageAnnonceurConnecte() {\r\n            const annonceurConnected =\r\n                sessionStorage.getItem('AnnonceurConnected') ||\r\n                sessionStorage.getItem('InstitutionnelConnected');\r\n            \r\n            if (annonceurConnected !== 'Yes') {\r\n                console.log('\u2139\ufe0f Pas d\\'annonceur connect\u00e9');\r\n                return;\r\n            }\r\n            \r\n            console.log('\ud83d\udc64 Annonceur connect\u00e9, pr\u00e9-remplissage depuis sessionStorage...');\r\n            \r\n            \/\/ Mapping : champ formulaire -> cl\u00e9 sessionStorage\r\n            \/\/ \u2705 CORRECTION : Exclure le pays (d\u00e9j\u00e0 renseign\u00e9 en \u00e9tape 1)\r\n            const fieldMap = {\r\n                'annonceur_nom_societe': 'AnnonceurRaisonSociale',\r\n                'annonceur_nom_contact': 'AnnonceurContact',\r\n                'annonceur_direction_service': 'AnnonceurFonction',\r\n                'annonceur_numero_immatriculation': 'AnnonceurNoImmatriculation',\r\n                'annonceur_numero_tva': 'AnnonceurNoTVA',\r\n                'annonceur_adresse_ligne1': 'AnnonceurAdresse',\r\n                'annonceur_code_postal': 'AnnonceurCP',\r\n                'annonceur_ville': 'AnnonceurVille',\r\n                \/\/ \u274c SUPPRIM\u00c9 : 'annonceur_pays': 'AnnonceurPays' - Ne pas \u00e9craser le pays de l'\u00e9tape 1\r\n                'annonceur_email_contact': 'AnnonceurEmail',\r\n                'annonceur_telephone_contact': 'AnnonceurTel',\r\n                'facturation_contact': 'AnnonceurFacturationContact',\r\n                'facturation_adresse': 'AnnonceurFacturationAdresse',\r\n                'facturation_code_postal': 'AnnonceurFacturationCP',\r\n                'facturation_ville': 'AnnonceurFacturationVille',\r\n                'facturation_pays': 'AnnonceurFacturationPays',\r\n                'facturation_email': 'AnnonceurFacturationEmail',\r\n                'facturation_telephone': 'AnnonceurFacturationTel'\r\n            };\r\n            \r\n            \/\/ Remplir chaque champ\r\n            Object.keys(fieldMap).forEach(formField => {\r\n                const sessionKey = fieldMap[formField];\r\n                const value = sessionStorage.getItem(sessionKey) || '';\r\n                $(`input[name=\"form_fields[${formField}]\"]`).val(value);\r\n            });\r\n            \r\n            \/\/ \u2705 La logique TVA est appliqu\u00e9e sur le pays de l'\u00e9tape 1 dans initBoutonFinaliser()\r\n            \/\/ Ne pas r\u00e9appliquer ici\r\n            \r\n            console.log('\u2705 Formulaire pr\u00e9-rempli depuis sessionStorage (pays conserv\u00e9)');\r\n        }\r\n        \r\n        \/**\r\n         * Charge les donn\u00e9es d'un client et remplit le formulaire\r\n         *\/\r\n        function loadClientDataAndFillForm(clientId, source) {\r\n            $.ajax({\r\n                type: \"POST\",\r\n                url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                data: {\r\n                    action: 'get_client_data_by_id',\r\n                    client_id: clientId,\r\n                    source: source || 'annonceur'\r\n                },\r\n                success: function(clientData) {\r\n                    console.log('\ud83d\udccb Donn\u00e9es client re\u00e7ues:', clientData);\r\n                    fillFormWithClientData(clientData);\r\n                },\r\n                error: function(xhr, status, error) {\r\n                    console.error('\u274c Erreur chargement donn\u00e9es client:', error);\r\n                }\r\n            });\r\n        }\r\n\r\n        \/**\r\n         * Remplit le formulaire avec les donn\u00e9es du client\r\n         * \u2705 CORRECTION v1.3 : Ne pas \u00e9craser le pays de l'\u00e9tape 1\r\n         *\/\r\n        function fillFormWithClientData(clientData) {\r\n            const $ = jQuery;\r\n            \r\n            \/\/ Mapping des champs DB vers les champs du formulaire\r\n            \/\/ \u2705 CORRECTION : Exclure 'annonceur_pays' pour conserver le pays de l'\u00e9tape 1\r\n            const fieldMap = {\r\n                'annonceur_nom_societe': 'nom_societe',\r\n                'annonceur_nom_contact': 'nom_contact',\r\n                'annonceur_direction_service': 'direction_service',\r\n                'annonceur_numero_immatriculation': 'numero_immatriculation',\r\n                'annonceur_numero_tva': 'numero_tva',\r\n                'annonceur_adresse_ligne1': 'adresse_ligne1',\r\n                'annonceur_code_postal': 'code_postal',\r\n                'annonceur_ville': 'ville',\r\n                \/\/ \u274c SUPPRIM\u00c9 : 'annonceur_pays': 'pays' - Ne pas \u00e9craser le pays de l'\u00e9tape 1\r\n                'annonceur_email_contact': 'email_contact',\r\n                'annonceur_telephone_contact': 'telephone_contact',\r\n                'facturation_contact': 'facturation_contact',\r\n                'facturation_adresse': 'facturation_adresse',\r\n                'facturation_code_postal': 'facturation_code_postal',\r\n                'facturation_ville': 'facturation_ville',\r\n                'facturation_pays': 'facturation_pays',\r\n                'facturation_email': 'facturation_email',\r\n                'facturation_telephone': 'facturation_telephone'\r\n            };\r\n            \r\n            \/\/ Remplir chaque champ\r\n            Object.keys(fieldMap).forEach(formField => {\r\n                const dbField = fieldMap[formField];\r\n                const value = clientData[dbField] || clientData[formField] || '';\r\n                \r\n                $(`input[name=\"form_fields[${formField}]\"]`).val(value);\r\n            });\r\n            \r\n            \/\/ \u2705 Stocker l'ID et la SOURCE du client s\u00e9lectionn\u00e9\r\n            sessionStorage.setItem('selected_annonceur_id', clientData.annonceur_id || clientData.id);\r\n            sessionStorage.setItem('selected_annonceur_source', clientData.source || 'annonceur');\r\n            \r\n            console.log('\ud83d\udccc Client s\u00e9lectionn\u00e9 - ID:', clientData.annonceur_id || clientData.id, 'Source:', clientData.source);\r\n            \r\n            \/\/ \u2705 NE PAS appliquer la logique TVA ici\r\n            \/\/ La logique TVA reste bas\u00e9e sur le pays de l'\u00e9tape 1 (d\u00e9j\u00e0 appliqu\u00e9e)\r\n            \r\n            console.log('\u2705 Formulaire pr\u00e9-rempli avec les donn\u00e9es du client (pays de l\\'\u00e9tape 1 conserv\u00e9)');\r\n        }\r\n\r\n        \/**\r\n         * Affiche un feedback temporaire\r\n         *\/\r\n        function showFeedback(message) {\r\n            const $feedback = $('<div>')\r\n                .text(message)\r\n                .css({\r\n                    'position': 'fixed',\r\n                    'top': '20px',\r\n                    'right': '20px',\r\n                    'background': '#4CAF50',\r\n                    'color': 'white',\r\n                    'padding': '10px 20px',\r\n                    'border-radius': '5px',\r\n                    'z-index': '9999',\r\n                    'box-shadow': '0 2px 10px rgba(0,0,0,0.2)'\r\n                })\r\n                .appendTo('body');\r\n            \r\n            setTimeout(() => {\r\n                $feedback.fadeOut(300, function() {\r\n                    $(this).remove();\r\n                });\r\n            }, 2000);\r\n        }\r\n        \r\n        \/**\r\n         * Initialise le bouton \"Finaliser\" pour passer \u00e0 l'\u00e9tape 2\r\n         *\/\r\n        function initBoutonFinaliser() {\r\n            $('.FinaliserBouton').on('click', function(e) {\r\n                e.preventDefault();\r\n                \r\n                \/\/ Mettre \u00e0 jour le flag\r\n                sessionStorage.setItem(\"FinaliserStep\", 'Yes');\r\n                \r\n                \/\/ \u2705 Activer le mode finalisation dans le panier\r\n                if (window.VIA_Panier) {\r\n                    window.VIA_Panier.gererModeFinalisationCommandes();\r\n                    window.VIA_Panier.updateRecapitulatif();\r\n                }\r\n                \r\n                \/\/ Fermer l'\u00e9tape 1\r\n                const isMobile = window.innerWidth <= 767;\r\n                \r\n                if (isMobile) {\r\n                    $('.VosCampagnesConteneurClass').hide();\r\n                    $('#RecapitulatifVosCommandesIconeUp').hide();\r\n                    $('#RecapitulatifVosCommandesIconeDown').show();  \r\n                    $('#SyntheseConteneur').hide();\r\n                    \/\/ \u2705 v1.8 : Masquer #PayableText sur mobile\r\n                    $('#PayableText').hide();\r\n                    \r\n                    \/\/ \u2705 v1.7 : Garder #ProcessCommande visible avec titre et message\r\n                    $('#ProcessEtapes').show();\r\n                    $('#ProcessCommande').show();\r\n                    $('#Etape1Container').show();  \/\/ Garder visible pour le titre\r\n                    $('#ProcessAchatInside').hide();  \/\/ Masquer seulement le formulaire\r\n                    $('#Etape1MessageContainer').show();  \/\/ Afficher le message \"Dates, dur\u00e9e et tarif choisis\"\r\n                    console.log('\ud83d\udcf1 Mobile: #ProcessCommande avec titre\/message visible apr\u00e8s Finaliser');\r\n                \r\n                    \/\/ Ouvrir l'\u00e9tape 2\r\n                    console.log('\ud83d\udccb Ouverture \u00e9tape 2 - R\u00e9f\u00e9rences client');\r\n                    \/\/ \u2705 v1.8 : Supprim\u00e9 - ne plus fermer PageWebColonne\r\n                    \/\/ window.PageWebColonneClose();\r\n                }\r\n                $('#EtapeReferences').addClass('via-etape-visible').show();\r\n                $('.ReferencesConteneur').show();\r\n                $('#ReferencesTitreIconeUp').show();\r\n                $('#ReferencesTitreIconeDown').hide();\r\n                \r\n                \/\/ \u2705 Activer le titre de l'\u00e9tape R\u00e9f\u00e9rences\r\n                if (window.VIA_Panier && typeof window.VIA_Panier.activerTitreEtape === 'function') {\r\n                    window.VIA_Panier.activerTitreEtape('references');\r\n                }\r\n                \r\n                \/\/ \u2705 NOUVEAU : Pr\u00e9-remplir si annonceur connect\u00e9\r\n                initPreRemplissageAnnonceurConnecte();\r\n                \r\n                \/\/ \u2705 Pr\u00e9-remplir le pays ET appliquer la logique TVA (pays \u00e9tape 1)\r\n                if (STATE.selectedCountry) {\r\n                    const $paysInputReferences = $('input[name=\"form_fields[annonceur_pays]\"]');\r\n                    $paysInputReferences.val(STATE.selectedCountry.label);\r\n                    \r\n                    \/\/ \u2705 Appliquer la logique TVA sur le pays de l'\u00c9TAPE 1\r\n                    appliquerLogiqueTVA(STATE.selectedCountry.label, STATE.selectedCountry.ZoneTVA);\r\n                    \r\n                    console.log('\u2705 Pays pr\u00e9-rempli:', STATE.selectedCountry.label, 'Zone TVA:', STATE.selectedCountry.ZoneTVA);\r\n                }\r\n            });\r\n            \r\n            console.log('\u2705 Bouton Finaliser initialis\u00e9');\r\n        }\r\n\r\n        \/**\r\n         * Valide que l'\u00e9tape 1 est compl\u00e8te\r\n         *\/\r\n        function validerEtape1() {\r\n            const erreurs = [];\r\n            \r\n            if (!STATE.espacePubSelected) {\r\n                erreurs.push('Veuillez s\u00e9lectionner un espace publicitaire');\r\n            }\r\n            \r\n            if (!STATE.startDate || !STATE.endDate) {\r\n                erreurs.push('Veuillez s\u00e9lectionner les dates de campagne');\r\n            }\r\n            \r\n            if (!STATE.selectedCountry) {\r\n                erreurs.push('Veuillez s\u00e9lectionner un pays');\r\n            }\r\n            \r\n            if (erreurs.length > 0) {\r\n                alert('Veuillez compl\u00e9ter les informations suivantes :\\n\\n' + erreurs.join('\\n'));\r\n                return false;\r\n            }\r\n            \r\n            return true;\r\n        }\r\n        \r\n        \/**\r\n         * Initialise la gestion du formulaire de r\u00e9f\u00e9rences (\u00c9tape 2)\r\n         *\/\r\n        function initFormulaireReferences() {\r\n            const $form = $('#Formulaire_Annonceur_donnees_notconnected2');\r\n            const $boutonValider = $('#ValiderReferencesBouton');\r\n            \r\n            if ($form.length === 0) {\r\n                console.warn('\u26a0\ufe0f Formulaire r\u00e9f\u00e9rences introuvable');\r\n                return;\r\n            }\r\n            \r\n            \/\/ Initialiser la gestion de la TVA au changement de pays\r\n            initGestionTVAPays();\r\n            \r\n            \/\/ G\u00e9rer le clic sur le bouton de validation\r\n            $boutonValider.on('click', function(e) {\r\n                e.preventDefault();\r\n                validerFormulaireReferences();\r\n            });\r\n            \r\n            \/\/ G\u00e9rer aussi la soumission du formulaire Elementor\r\n            $form.on('submit', function(e) {\r\n                e.preventDefault();\r\n                validerFormulaireReferences();\r\n            });\r\n            \r\n            console.log('\u2705 Formulaire r\u00e9f\u00e9rences initialis\u00e9');\r\n        }\r\n\r\n        \/**\r\n         * Gestion de la TVA selon le pays s\u00e9lectionn\u00e9\r\n         * \u2705 v1.8 : Autocomplete am\u00e9lior\u00e9 avec fond vert temporaire et auto-remplissage\r\n         *\/\r\n        function initGestionTVAPays() {\r\n            const $paysInput = $('input[name=\"form_fields[annonceur_pays]\"]');\r\n            \r\n            if ($paysInput.length === 0) {\r\n                console.warn('\u26a0\ufe0f Champ pays r\u00e9f\u00e9rences introuvable');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v1.8 : Style CSS pour le fond vert temporaire\r\n            const styleId = 'via-pays-autocomplete-style';\r\n            if (!document.getElementById(styleId)) {\r\n                const style = document.createElement('style');\r\n                style.id = styleId;\r\n                style.textContent = `\r\n                    .via-autocomplete-valid {\r\n                        background-color: #E8F0FE !important;\r\n                        border-color: #28a745 !important;\r\n                        transition: background-color 0.5s ease, border-color 0.5s ease;\r\n                    }\r\n                    .via-autocomplete-invalid {\r\n                        background-color: #fff3cd !important;\r\n                        border-color: #ffc107 !important;\r\n                    }\r\n                `;\r\n                document.head.appendChild(style);\r\n            }\r\n            \r\n            \/**\r\n             * \u2705 v1.8 : Applique le fond vert temporaire puis revient \u00e0 blanc\r\n             *\/\r\n            function flashVertTemporaire($input) {\r\n                $input.addClass('via-autocomplete-valid');\r\n                setTimeout(function() {\r\n                    $input.removeClass('via-autocomplete-valid');\r\n                }, 1500); \/\/ Fond vert pendant 1.5 secondes\r\n            }\r\n            \r\n            \/\/ \u2705 v1.8 : Cr\u00e9er l'autocomplete avec recherche am\u00e9lior\u00e9e et auto-remplissage\r\n            $paysInput.autocomplete({\r\n                source: function(request, response) {\r\n                    \/\/ Fallback si searchCountries n'existe pas\r\n                    let results;\r\n                    if (typeof window.VIA_Countries.searchCountries === 'function') {\r\n                        results = window.VIA_Countries.searchCountries(request.term);\r\n                    } else {\r\n                        const termLower = request.term.toLowerCase();\r\n                        results = window.VIA_Countries.COUNTRIES_DATA.filter(c => \r\n                            c.label.toLowerCase().includes(termLower)\r\n                        );\r\n                    }\r\n                    \/\/ Retourner les labels fran\u00e7ais pour l'affichage\r\n                    response(results.slice(0, 10).map(c => c.label));\r\n                },\r\n                minLength: 2,\r\n                \r\n                \/\/ \u2705 v1.8 : Auto-remplissage si un seul r\u00e9sultat\r\n                response: function(event, ui) {\r\n                    if (ui.content.length === 1) {\r\n                        \/\/ Un seul r\u00e9sultat \u2192 auto-remplir avec fond vert temporaire\r\n                        const paysUnique = ui.content[0].value;\r\n                        const country = window.VIA_Countries.getCountryByLabel(paysUnique);\r\n                        \r\n                        if (country) {\r\n                            $paysInput.val(country.label);\r\n                            flashVertTemporaire($paysInput);\r\n                            \r\n                            \/\/ Appliquer la logique TVA\r\n                            appliquerLogiqueTVA(country.label, country.ZoneTVA);\r\n                            \r\n                            \/\/ Synchroniser vers l'\u00e9tape 1\r\n                            synchroniserPaysVersEtape1(country);\r\n                            \r\n                            console.log('\u2705 Pays auto-compl\u00e9t\u00e9 (unique):', country.label);\r\n                            \r\n                            \/\/ Fermer le menu autocomplete\r\n                            $paysInput.autocomplete('close');\r\n                        }\r\n                    } else if (ui.content.length === 0) {\r\n                        \/\/ Aucun r\u00e9sultat \u2192 fond jaune (invalide)\r\n                        $paysInput.removeClass('via-autocomplete-valid').addClass('via-autocomplete-invalid');\r\n                    } else {\r\n                        \/\/ Plusieurs r\u00e9sultats \u2192 retirer les styles\r\n                        $paysInput.removeClass('via-autocomplete-valid via-autocomplete-invalid');\r\n                    }\r\n                },\r\n                \r\n                select: function(event, ui) {\r\n                    const paysSelectionne = ui.item.value;\r\n                    const country = window.VIA_Countries.getCountryByLabel(paysSelectionne);\r\n                    \r\n                    if (country) {\r\n                        \/\/ Appliquer le fond vert temporaire\r\n                        flashVertTemporaire($paysInput);\r\n                        \r\n                        appliquerLogiqueTVA(country.label, country.ZoneTVA);\r\n                        \/\/ \u2705 v1.8 : Synchroniser vers l'\u00e9tape 1\r\n                        synchroniserPaysVersEtape1(country);\r\n                        \r\n                        console.log('\u2705 Pays s\u00e9lectionn\u00e9:', country.label);\r\n                    }\r\n                    \r\n                    return true;\r\n                }\r\n            });\r\n            \r\n            \/\/ \u2705 v1.8 : Valider \u00e0 la saisie - retirer les styles pendant la saisie\r\n            $paysInput.on('input', function() {\r\n                $(this).removeClass('via-autocomplete-valid via-autocomplete-invalid');\r\n            });\r\n            \r\n            \/\/ \u2705 v2.0 : G\u00e9rer les changements manuels avec getCountryByLabel (supporte aliases)\r\n            $paysInput.on('blur', function() {\r\n                const paysValue = $(this).val().trim();\r\n                const country = window.VIA_Countries.getCountryByLabel(paysValue);\r\n                \r\n                if (country) {\r\n                    \/\/ Remplacer par le label officiel (ex: \"USA\" -> \"\u00c9tats-Unis\")\r\n                    $(this).val(country.label);\r\n                    flashVertTemporaire($(this));\r\n                    \r\n                    appliquerLogiqueTVA(country.label, country.ZoneTVA);\r\n                    \/\/ \u2705 v1.8 : Synchroniser vers l'\u00e9tape 1\r\n                    synchroniserPaysVersEtape1(country);\r\n                } else if (paysValue.length > 0) {\r\n                    \/\/ Pays invalide \u2192 fond jaune\r\n                    $(this).removeClass('via-autocomplete-valid').addClass('via-autocomplete-invalid');\r\n                } else {\r\n                    \/\/ Champ vide \u2192 retirer les styles\r\n                    $(this).removeClass('via-autocomplete-valid via-autocomplete-invalid');\r\n                }\r\n            });\r\n            \r\n            console.log('\u2705 Gestion TVA pays initialis\u00e9e (v1.8 avec auto-remplissage et fond vert temporaire)');\r\n        }\r\n\r\n        \/**\r\n         * \u2705 v1.8 : Synchronise le pays des R\u00e9f\u00e9rences vers l'\u00e9tape 1 (Dates, dur\u00e9e, tarif)\r\n         * - Met \u00e0 jour STATE.selectedCountry\r\n         * - Met \u00e0 jour le champ visuel #form-field-Nationalite_Societe\r\n         * - Met \u00e0 jour le pays de TOUS les items du panier\r\n         * - Recalcule les tarifs si n\u00e9cessaire\r\n         *\/\r\n        function synchroniserPaysVersEtape1(country) {\r\n            if (!country) {\r\n                console.log('\u26a0\ufe0f synchroniserPaysVersEtape1: country manquant');\r\n                return;\r\n            }\r\n            \r\n            console.log('\ud83d\udd04 Synchronisation pays R\u00e9f\u00e9rences \u2192 \u00c9tape 1:', country.label, '(code:', country.code + ')');\r\n            \r\n            \/\/ 1. Mettre \u00e0 jour le champ visuel dans l'\u00e9tape 1\r\n            const $champPaysEtape1 = $('#form-field-Nationalite_Societe');\r\n            if ($champPaysEtape1.length) {\r\n                const ancienneValeur = $champPaysEtape1.val();\r\n                $champPaysEtape1.val(country.label);\r\n                console.log('\u2705 Champ #form-field-Nationalite_Societe mis \u00e0 jour:', ancienneValeur, '\u2192', country.label);\r\n            } else {\r\n                console.warn('\u26a0\ufe0f Champ #form-field-Nationalite_Societe introuvable');\r\n            }\r\n            \r\n            \/\/ 2. Mettre \u00e0 jour STATE.selectedCountry\r\n            const ancienPays = STATE?.selectedCountry?.label;\r\n            \r\n            if (STATE) {\r\n                STATE.selectedCountry = country;\r\n                console.log('\u2705 STATE.selectedCountry mis \u00e0 jour:', ancienPays, '\u2192', country.label);\r\n            }\r\n            \r\n            \/\/ 3. Mettre \u00e0 jour aussi via VIA_Elementor si disponible\r\n            if (window.VIA_Elementor && window.VIA_Elementor.state) {\r\n                window.VIA_Elementor.state.selectedCountry = country;\r\n                console.log('\u2705 VIA_Elementor.state.selectedCountry mis \u00e0 jour');\r\n            }\r\n            \r\n            \/\/ 4. Si le pays a chang\u00e9, mettre \u00e0 jour TOUS les items du panier et recalculer les tarifs\r\n            if (ancienPays !== country.label) {\r\n                console.log('\ud83d\udcca Pays chang\u00e9:', ancienPays, '\u2192', country.label, '- mise \u00e0 jour du panier...');\r\n                \r\n                if (window.VIA_Panier && window.VIA_Panier.state.items.length > 0) {\r\n                    console.log('\ud83d\udcca VIA_Panier disponible, nombre d\\'items:', window.VIA_Panier.state.items.length);\r\n                    \r\n                    \/\/ Mettre \u00e0 jour le pays de tous les items\r\n                    window.VIA_Panier.state.items.forEach(function(item) {\r\n                        if (item.pays !== country.label) {\r\n                            console.log('\ud83d\udcca Mise \u00e0 jour pays item', item.id, ':', item.pays, '\u2192', country.label);\r\n                            item.pays = country.label;\r\n                        }\r\n                    });\r\n                    \r\n                    \/\/ Recalculer tous les tarifs\r\n                    if (typeof window.VIA_Panier.recalculerTousTarifs === 'function') {\r\n                        console.log('\ud83d\udd04 Appel VIA_Panier.recalculerTousTarifs()...');\r\n                        window.VIA_Panier.recalculerTousTarifs().then(function() {\r\n                            \/\/ \u2705 Mettre \u00e0 jour #Tariftobedisplayed avec le tarif du premier item\r\n                            mettreAJourTarifAffiche();\r\n                        });\r\n                    } else {\r\n                        \/\/ Fallback : recalculer manuellement chaque item\r\n                        console.log('\ud83d\udd04 Recalcul manuel des tarifs...');\r\n                        window.VIA_Panier.state.items.forEach(function(item) {\r\n                            recalculerTarifItemActif(item, country);\r\n                        });\r\n                    }\r\n                } else if (window.VIA_Panier) {\r\n                    console.log('\u2139\ufe0f Panier vide, pas de recalcul n\u00e9cessaire');\r\n                } else {\r\n                    console.warn('\u26a0\ufe0f window.VIA_Panier non disponible');\r\n                }\r\n            } else {\r\n                console.log('\u2139\ufe0f Pays inchang\u00e9, pas de recalcul n\u00e9cessaire');\r\n            }\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 v1.8 : Met \u00e0 jour #Tariftobedisplayed avec le tarif de l'item actif ou du premier item\r\n         *\/\r\n        function mettreAJourTarifAffiche() {\r\n            if (!window.VIA_Panier || !window.VIA_Panier.state.items.length) {\r\n                console.log('\u2139\ufe0f Pas d\\'items pour mettre \u00e0 jour #Tariftobedisplayed');\r\n                return;\r\n            }\r\n            \r\n            \/\/ Prendre l'item actif ou le premier item\r\n            const item = window.VIA_Panier.state.itemActif \r\n                ? window.VIA_Panier.state.items.find(i => i.id === window.VIA_Panier.state.itemActif)\r\n                : window.VIA_Panier.state.items[0];\r\n            \r\n            if (!item || !item.tarifHT) {\r\n                console.log('\u2139\ufe0f Pas de tarif disponible pour #Tariftobedisplayed');\r\n                return;\r\n            }\r\n            \r\n            const devise = sessionStorage.getItem('selected_currency') || 'EUR';\r\n            let montant = item.tarifHT;\r\n            \r\n            if (window.VIA_App && window.VIA_App.convertirDevise && devise !== 'EUR') {\r\n                montant = window.VIA_App.convertirDevise(montant, 'EUR', devise);\r\n            }\r\n            \r\n            const tarifFormate = window.VIA_App && window.VIA_App.formaterMontant \r\n                ? window.VIA_App.formaterMontant(montant, devise, 2)\r\n                : montant.toFixed(2) + ' ' + devise;\r\n            \r\n            $('#Tariftobedisplayed').html(tarifFormate).css('color', '#4B689B');\r\n            console.log('\u2705 #Tariftobedisplayed mis \u00e0 jour:', tarifFormate);\r\n        }\r\n\r\n        \/**\r\n         * \u2705 v1.8 : Recalcule le tarif de l'item actif apr\u00e8s changement de pays\r\n         *\/\r\n        async function recalculerTarifItemActif(item, country) {\r\n            if (!item || !country) {\r\n                console.log('\u26a0\ufe0f recalculerTarifItemActif: item ou country manquant');\r\n                return;\r\n            }\r\n            \r\n            console.log('\ud83d\udd04 recalculerTarifItemActif - Donn\u00e9es item:', {\r\n                id: item.id,\r\n                format: item.format,\r\n                position: item.position,\r\n                duree: item.duree,\r\n                pays: item.pays,\r\n                dateDebut: item.dateDebut,\r\n                dateFin: item.dateFin\r\n            });\r\n            \r\n            \/\/ V\u00e9rifier que les donn\u00e9es n\u00e9cessaires sont pr\u00e9sentes\r\n            if (!item.format || !item.position || !item.duree) {\r\n                console.log('\u2139\ufe0f Donn\u00e9es incompl\u00e8tes pour recalcul tarif - format:', item.format, 'position:', item.position, 'duree:', item.duree);\r\n                return;\r\n            }\r\n            \r\n            if (!window.VIA_App) {\r\n                console.warn('\u26a0\ufe0f window.VIA_App non disponible');\r\n                return;\r\n            }\r\n            \r\n            if (typeof window.VIA_App.calculerTarifAPI !== 'function') {\r\n                console.warn('\u26a0\ufe0f VIA_App.calculerTarifAPI non disponible');\r\n                return;\r\n            }\r\n            \r\n            try {\r\n                console.log('\ud83d\udd04 Appel calculerTarifAPI avec:', {\r\n                    format: item.format,\r\n                    position: item.position,\r\n                    duree: item.duree,\r\n                    paysCode: country.code,\r\n                    paysLabel: country.label\r\n                });\r\n                \r\n                const resultat = await window.VIA_App.calculerTarifAPI(\r\n                    item.format,\r\n                    item.position,\r\n                    item.duree,\r\n                    country.code  \/\/ Utiliser le code ISO du pays\r\n                );\r\n                \r\n                console.log('\ud83d\udcca R\u00e9sultat calculerTarifAPI:', resultat);\r\n                \r\n                if (resultat && resultat.success) {\r\n                    item.tarifHT = resultat.tarif_ht;\r\n                    item.tarifTTC = resultat.tarif_ttc;\r\n                    \r\n                    \/\/ Mettre \u00e0 jour le tarif initial si pas commercial\r\n                    if (sessionStorage.getItem('CommercialConnected') !== 'Yes') {\r\n                        item.tarifHT_initial = resultat.tarif_ht;\r\n                    }\r\n                    \r\n                    console.log('\u2705 Tarif recalcul\u00e9:', item.reference || item.id, '-', resultat.tarif_ht, 'EUR');\r\n                    \r\n                    \/\/ Rafra\u00eechir l'affichage de l'item dans le panier\r\n                    if (window.VIA_Panier && typeof window.VIA_Panier.rafraichirItemHTML === 'function') {\r\n                        window.VIA_Panier.rafraichirItemHTML(item.id);\r\n                    }\r\n                    \r\n                    \/\/ Rafra\u00eechir le tarif affich\u00e9 dans l'\u00e9tape 1 (#Tariftobedisplayed)\r\n                    const devise = sessionStorage.getItem('selected_currency') || 'EUR';\r\n                    let montant = resultat.tarif_ht;\r\n                    \r\n                    if (window.VIA_App.convertirDevise && devise !== 'EUR') {\r\n                        montant = window.VIA_App.convertirDevise(montant, 'EUR', devise);\r\n                    }\r\n                    \r\n                    const tarifFormate = window.VIA_App.formaterMontant \r\n                        ? window.VIA_App.formaterMontant(montant, devise, 2)\r\n                        : montant.toFixed(2) + ' ' + devise;\r\n                    \r\n                    $('#Tariftobedisplayed').html(tarifFormate).css('color', '#4B689B');\r\n                    console.log('\u2705 #Tariftobedisplayed mis \u00e0 jour:', tarifFormate);\r\n                    \r\n                    \/\/ Recalculer le total du panier\r\n                    if (window.VIA_Panier && typeof window.VIA_Panier.calculerTotalPanier === 'function') {\r\n                        window.VIA_Panier.calculerTotalPanier();\r\n                    }\r\n                    \r\n                    \/\/ Rafra\u00eechir les montants de l'\u00e9tape paiement\r\n                    if (window.VIA_Paiement && typeof window.VIA_Paiement.rafraichirMontants === 'function') {\r\n                        window.VIA_Paiement.rafraichirMontants();\r\n                    }\r\n                } else {\r\n                    console.warn('\u26a0\ufe0f calculerTarifAPI a \u00e9chou\u00e9:', resultat);\r\n                }\r\n            } catch (error) {\r\n                console.error('\u274c Erreur recalcul tarif:', error);\r\n            }\r\n        }\r\n\r\n        \/**\r\n         * Applique la logique TVA selon la zone\r\n         * \u2705 v1.8 : Suppression show\/hide NonRedevableTVA et MsgEntiteRedevableTVA (\u00e0 r\u00e9activer si besoin)\r\n         * \u2705 v1.9 : EU hors France - TVA optionnelle (si n\u00b0 TVA \u2192 pas de TVA, sinon \u2192 TVA appliqu\u00e9e)\r\n         * \u2705 v1.9 : Gestion du champ readonly field_RegimeTVA (plus de liste d\u00e9roulante)\r\n         *\/\r\n        function appliquerLogiqueTVA(pays, zoneTVA) {\r\n            console.log('\ud83d\udcb6 Application logique TVA:', { pays, zoneTVA });\r\n            \/* ================================================================\r\n             * pb2176 : SONDE \u2014 QUI REPOSE \u00ab France \u00bb A L ETAPE REFERENCES ?\r\n             *   Constat JF : la resa reprend bien la devise, puis a l etape\r\n             *   References le log enchaine\r\n             *     Application logique TVA: {pays: 'Fidji', zoneTVA: 'HorsEU'}\r\n             *     \u2705 Pays pre-rempli: Fidji\r\n             *     Application logique TVA: {pays: 'France', zoneTVA: 'FR'}\r\n             *   -> regime FR, TVA 20 %, devise forcee en EUR.\r\n             *   CINQ appelants peuvent produire cette seconde ligne (auto-\r\n             *   remplissage a resultat unique, select, blur, reinit depuis\r\n             *   l etape 1, API publique). Les designer par lecture serait la\r\n             *   meme erreur qu en pb2160 : la pile a toujours eu raison.\r\n             *   On journalise donc l APPELANT et l etat du champ au moment de\r\n             *   l appel. Sonde neutre, a retirer apres verdict.\r\n             * ================================================================ *\/\r\n            try {\r\n                var _pile2176 = '';\r\n                try { throw new Error('x'); } catch (_e) {\r\n                    _pile2176 = String(_e.stack || '').split('\\n').slice(2, 6)\r\n                        .join(' << ').replace(\/\\s+\/g, ' ');\r\n                }\r\n                var _ch2176 = document.querySelector('input[name=\"form_fields[annonceur_pays]\"]');\r\n                console.log('[pb2176] appliquerLogiqueTVA(' + pays + ', ' + zoneTVA + ')'\r\n                    + ' | champ References=\"' + (_ch2176 ? _ch2176.value : '(absent)') + '\"'\r\n                    + ' | STATE.selectedCountry='\r\n                    + ((typeof STATE !== 'undefined' ? (STATE ? STATE.selectedCountry : null) : null)\r\n                        ? STATE.selectedCountry.label : '(aucun)')\r\n                    + ' | session ZoneTVA=' + (sessionStorage.getItem('ZoneTVA') || '(vide)')\r\n                    + ' | pays etape1=' + (sessionStorage.getItem('NationaliteDataVosCampagnes') || '(vide)')\r\n                    + '\\n    appelant : ' + _pile2176);\r\n            } catch (_e2176) { console.warn('[pb2176] ' + _e2176.message); }\r\n            \r\n            const $champTVA = $('#form-field-annonceur_numero_tva');\r\n            const $champTVAConteneur = $('.elementor-field-group-annonceur_numero_tva');\r\n            const $conteneurId2 = $('#ReferencesConteneurId2');\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            \/\/ \u2705 v1.9 : Masquer la liste d\u00e9roulante ChoixTVA (plus utilis\u00e9e)\r\n            const $choixTVAConteneur = $('.elementor-field-group-field_ChoixTVA');\r\n            $choixTVAConteneur.hide();\r\n            \r\n            \/\/ \u2705 v1.9 : Champ RegimeTVA (readonly)\r\n            const $champRegimeTVA = $('#form-field-field_RegimeTVA');\r\n            const $champRegimeTVAConteneur = $('.elementor-field-group-field_RegimeTVA');\r\n            \r\n            \/\/ Mettre le champ RegimeTVA en readonly\r\n            $champRegimeTVA.attr('readonly', true).css({\r\n                'background-color': '#f5f5f5',\r\n                'cursor': 'not-allowed'\r\n            });\r\n            \r\n            \/\/ Sauvegarder la zone TVA\r\n            sessionStorage.setItem('ZoneTVA', zoneTVA);\r\n            \r\n            \/\/ \u2705 v1.9 : Cr\u00e9er ou r\u00e9cup\u00e9rer le texte d'aide sous le champ TVA\r\n            let $hintTVA = $('#hint-tva-eu');\r\n            if ($hintTVA.length === 0) {\r\n                const isMobile = window.innerWidth <= 767;\r\n                const fontSize = isMobile ? '13px' : '9px';\r\n                $hintTVA = $('<div id=\"hint-tva-eu\"><\/div>').css({\r\n                    'font-size': fontSize,\r\n                    'color': '#666',\r\n                    'font-style': 'italic',\r\n                    'text-align': 'center',\r\n                    'position': 'absolute',\r\n                    'bottom': '-14px',\r\n                    'left': '0',\r\n                    'right': '0',\r\n                    'white-space': 'nowrap'\r\n                });\r\n                \/\/ \u2705 v1.9 : Le conteneur parent doit \u00eatre en position relative\r\n                $champTVAConteneur.css({\r\n                    'position': 'relative',\r\n                    'overflow': 'visible'\r\n                });\r\n                \/\/ Ajouter le hint \u00e0 la fin du conteneur\r\n                $champTVAConteneur.append($hintTVA);\r\n            }\r\n            \r\n            \/\/ Textes selon la langue\r\n            const texteAssujetti = lang === 'EN' ? 'Subject to French VAT' : 'Assujetti \u00e0 la TVA';\r\n            const texteNonAssujetti = lang === 'EN' ? 'Not subject to French VAT' : 'Non assujetti \u00e0 la TVA';\r\n            \r\n            if (zoneTVA === 'FR') {\r\n                \/\/ France : TVA obligatoire\r\n                $champTVA.attr('placeholder', 'Num\u00e9ro de TVA *').attr('required', true);\r\n                $champTVA.css('font-size', '');\r\n                $conteneurId2.hide();\r\n                $hintTVA.hide();\r\n                \r\n                \/\/ \u2705 R\u00e9gime : Assujetti\r\n                $champRegimeTVA.val(texteAssujetti);\r\n                $champRegimeTVAConteneur.show();\r\n                sessionStorage.setItem('ClientAssujettiTVA', 'Yes');\r\n                \r\n                console.log('\ud83c\uddeb\ud83c\uddf7 France : TVA obligatoire - Assujetti');\r\n                \r\n            } else if (zoneTVA === 'EU') {\r\n                \/\/ Union Europ\u00e9enne (hors France) : TVA optionnelle\r\n                \/\/ \u2705 v1.9 : Placeholder avec * mais champ pas obligatoire\r\n                $champTVA.attr('placeholder', 'N\u00b0 de TVA *').attr('required', false);\r\n                $champTVA.css('font-size', '');\r\n                \r\n                \/\/ Afficher le texte d'aide\r\n                const isMobile = window.innerWidth <= 767;\r\n                const fontSize = isMobile ? '15px' : '9px';\r\n                const hintText = lang === 'EN' \r\n                    ? '(without VAT number, French VAT is applied)'\r\n                    : '(sans n\u00b0 TVA, la TVA fran\u00e7aise est appliqu\u00e9e)';\r\n                $hintTVA.text(hintText).css('font-size', fontSize).show();\r\n                \r\n                $conteneurId2.hide();\r\n                \r\n                \/\/ \u2705 v1.9 : Par d\u00e9faut Assujetti (TVA appliqu\u00e9e si pas de n\u00b0 TVA)\r\n                \/\/ Si n\u00b0 TVA d\u00e9j\u00e0 saisi, passer \u00e0 Non assujetti\r\n                const numeroTVAExistant = $champTVA.val()?.trim();\r\n                if (numeroTVAExistant && numeroTVAExistant !== '') {\r\n                    $champRegimeTVA.val(texteNonAssujetti);\r\n                    sessionStorage.setItem('ClientAssujettiTVA', 'No');\r\n                    console.log('\ud83c\uddea\ud83c\uddfa UE (hors France) : N\u00b0 TVA existant \u2192 Non assujetti');\r\n                } else {\r\n                    $champRegimeTVA.val(texteAssujetti);\r\n                    sessionStorage.setItem('ClientAssujettiTVA', 'Yes');\r\n                    console.log('\ud83c\uddea\ud83c\uddfa UE (hors France) : Pas de N\u00b0 TVA \u2192 Assujetti par d\u00e9faut');\r\n                }\r\n                $champRegimeTVAConteneur.show();\r\n                \r\n            } else {\r\n                \/\/ Hors UE : pas de TVA\r\n                $champTVA.attr('placeholder', 'Num\u00e9ro de TVA').attr('required', false);\r\n                $champTVA.css('font-size', '');\r\n                $conteneurId2.hide();\r\n                $hintTVA.hide();\r\n                \r\n                \/\/ \u2705 R\u00e9gime : Non assujetti\r\n                $champRegimeTVA.val(texteNonAssujetti);\r\n                $champRegimeTVAConteneur.show();\r\n                sessionStorage.setItem('ClientAssujettiTVA', 'No');\r\n                \r\n                console.log('\ud83c\udf0d Hors UE : Non assujetti');\r\n            }\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 v1.9 : Met \u00e0 jour le r\u00e9gime TVA quand le n\u00b0 TVA change (zone EU uniquement)\r\n         *\/\r\n        function initRegimeTVAListener() {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const texteAssujetti = lang === 'EN' ? 'Subject to French VAT' : 'Assujetti \u00e0 la TVA';\r\n            const texteNonAssujetti = lang === 'EN' ? 'Not subject to French VAT' : 'Non assujetti \u00e0 la TVA';\r\n            \r\n            \/\/ \u2705 v1.9 : Ajout 'input' pour d\u00e9tecter la saisie en temps r\u00e9el\r\n            $(document).on('input change blur', '#form-field-annonceur_numero_tva', function() {\r\n                const zoneTVA = sessionStorage.getItem('ZoneTVA');\r\n                \r\n                if (zoneTVA === 'EU') {\r\n                    const numeroTVA = $(this).val()?.trim();\r\n                    const $champRegimeTVA = $('#form-field-field_RegimeTVA');\r\n                    \r\n                    if (numeroTVA && numeroTVA !== '') {\r\n                        \/\/ N\u00b0 TVA saisi \u2192 Non assujetti (pas de TVA)\r\n                        $champRegimeTVA.val(texteNonAssujetti);\r\n                        sessionStorage.setItem('ClientAssujettiTVA', 'No');\r\n                        console.log('\ud83c\uddea\ud83c\uddfa UE avec n\u00b0 TVA : Non assujetti');\r\n                    } else {\r\n                        \/\/ Pas de n\u00b0 TVA \u2192 Assujetti (TVA appliqu\u00e9e)\r\n                        $champRegimeTVA.val(texteAssujetti);\r\n                        sessionStorage.setItem('ClientAssujettiTVA', 'Yes');\r\n                        console.log('\ud83c\uddea\ud83c\uddfa UE sans n\u00b0 TVA : Assujetti');\r\n                    }\r\n                }\r\n            });\r\n            \r\n            console.log('\u2705 Listener RegimeTVA initialis\u00e9');\r\n        }\r\n\r\n        \/**\r\n         * \u2705 v1.9 : Initialise les listeners pour appliquer le fond #E8F0FE aux champs renseign\u00e9s\r\n         *\/\r\n        function initChampsRenseignes() {\r\n            \/\/ S\u00e9lectionner tous les champs input du formulaire de r\u00e9f\u00e9rences\r\n            const $inputs = $('#Formulaire_Annonceur_donnees_notconnected2 input');\r\n            \r\n            \/\/ Appliquer le fond #E8F0FE aux champs d\u00e9j\u00e0 renseign\u00e9s\r\n            $inputs.each(function() {\r\n                const $input = $(this);\r\n                if ($input.prop('readonly')) return;\r\n                \r\n                if ($input.val() && $input.val().trim() !== '') {\r\n                    $input.css('background-color', '#E8F0FE');\r\n                }\r\n            });\r\n            \r\n            \/\/ \u00c9couter les changements sur tous les champs\r\n            $inputs.on('input change blur', function() {\r\n                const $input = $(this);\r\n                if ($input.prop('readonly')) return;\r\n                \r\n                if ($input.val() && $input.val().trim() !== '') {\r\n                    $input.css('background-color', '#E8F0FE');\r\n                } else {\r\n                    $input.css('background-color', '');\r\n                }\r\n            });\r\n            \r\n            console.log('\u2705 Listeners champs renseign\u00e9s initialis\u00e9s');\r\n        }\r\n\r\n        \/**\r\n         * Valide le formulaire de r\u00e9f\u00e9rences\r\n         * \u2705 CORRECTION v1.3 : Sauvegarde automatique en BDD\r\n         *\/\r\n        function validerFormulaireReferences() {\r\n            console.log('\ud83d\udd0d Validation formulaire r\u00e9f\u00e9rences...');\r\n            \r\n            const $msgErreur = $('#MsgCompleterFormulaireCoordonnees');\r\n            const $conteneurErreur = $('#MsgCompleterFormulaireCoordonneesConteneur');\r\n            const $msgOK = $('#MsgCompleterFormulaireOKConteneur');\r\n            \r\n            \/\/ Cacher les messages\r\n            $conteneurErreur.hide();\r\n            $msgOK.hide();\r\n            \r\n            \/\/ \u2705 Retirer toutes les surbrillances pr\u00e9c\u00e9dentes\r\n            retirerSurbrillances();\r\n            \r\n            \/\/ R\u00e9cup\u00e9rer TOUTES les valeurs du formulaire\r\n            const $nomSociete = $('input[name=\"form_fields[annonceur_nom_societe]\"]');\r\n            const $nomContact = $('input[name=\"form_fields[annonceur_nom_contact]\"]');\r\n            const $directionService = $('input[name=\"form_fields[annonceur_direction_service]\"]');\r\n            const $numeroImmatriculation = $('input[name=\"form_fields[annonceur_numero_immatriculation]\"]');\r\n            const $numeroTVA = $('input[name=\"form_fields[annonceur_numero_tva]\"]');\r\n            const $adresseLigne1 = $('input[name=\"form_fields[annonceur_adresse_ligne1]\"]');\r\n            const $codePostal = $('input[name=\"form_fields[annonceur_code_postal]\"]');\r\n            const $ville = $('input[name=\"form_fields[annonceur_ville]\"]');\r\n            const $pays = $('input[name=\"form_fields[annonceur_pays]\"]');\r\n            const $emailContact = $('input[name=\"form_fields[annonceur_email_contact]\"]');\r\n            const $telephoneContact = $('input[name=\"form_fields[annonceur_telephone_contact]\"]');\r\n            const $facturationContact = $('input[name=\"form_fields[facturation_contact]\"]');\r\n            const $facturationAdresse = $('input[name=\"form_fields[facturation_adresse]\"]');\r\n            const $facturationCodePostal = $('input[name=\"form_fields[facturation_code_postal]\"]');\r\n            const $facturationVille = $('input[name=\"form_fields[facturation_ville]\"]');\r\n            const $facturationPays = $('input[name=\"form_fields[facturation_pays]\"]');\r\n            const $facturationEmail = $('input[name=\"form_fields[facturation_email]\"]');\r\n            const $facturationTelephone = $('input[name=\"form_fields[facturation_telephone]\"]');\r\n            \/\/ \u2705 v1.8 : Supprim\u00e9 - $nonRedevableTVA\r\n            \r\n            const donnees = {\r\n                nomSociete: $nomSociete.val()?.trim(),\r\n                nomContact: $nomContact.val()?.trim(),\r\n                directionService: $directionService.val()?.trim(),\r\n                numeroImmatriculation: $numeroImmatriculation.val()?.trim(),\r\n                numeroTVA: $numeroTVA.val()?.trim(),\r\n                adresseLigne1: $adresseLigne1.val()?.trim(),\r\n                codePostal: $codePostal.val()?.trim(),\r\n                ville: $ville.val()?.trim(),\r\n                pays: $pays.val()?.trim(),\r\n                emailContact: $emailContact.val()?.trim(),\r\n                telephoneContact: $telephoneContact.val()?.trim(),\r\n                facturationContact: $facturationContact.val()?.trim(),\r\n                facturationAdresse: $facturationAdresse.val()?.trim(),\r\n                facturationCodePostal: $facturationCodePostal.val()?.trim(),\r\n                facturationVille: $facturationVille.val()?.trim(),\r\n                facturationPays: $facturationPays.val()?.trim(),\r\n                facturationEmail: $facturationEmail.val()?.trim(),\r\n                facturationTelephone: $facturationTelephone.val()?.trim()\r\n                \/\/ \u2705 v1.8 : Supprim\u00e9 - nonRedevableTVA\r\n            };\r\n            \r\n            const zoneTVA = sessionStorage.getItem('ZoneTVA');\r\n            const langue = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            \/\/ \u2705 Collecter TOUTES les erreurs avant d'afficher\r\n            const erreurs = [];\r\n            let premierChampInvalide = null;\r\n            \r\n            \/\/ Validation 1 : Nom soci\u00e9t\u00e9 obligatoire\r\n            if (!donnees.nomSociete) {\r\n                marquerChampInvalide($nomSociete);\r\n                erreurs.push(\r\n                    langue === 'FR' \r\n                        ? \"Merci de renseigner le nom de l'institution ou de la soci\u00e9t\u00e9\"\r\n                        : \"Please provide the institution or company name\"\r\n                );\r\n                if (!premierChampInvalide) premierChampInvalide = $nomSociete;\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds : Validation 1b : Nom contact obligatoire\r\n            if (!donnees.nomContact) {\r\n                marquerChampInvalide($nomContact);\r\n                erreurs.push(\r\n                    langue === 'FR'\r\n                        ? \"Merci de renseigner le nom du responsable\"\r\n                        : \"Please provide the responsable name\"\r\n                );\r\n                if (!premierChampInvalide) premierChampInvalide = $nomContact;\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds : Validation 1c : Adresse (ligne 1) obligatoire\r\n            if (!donnees.adresseLigne1) {\r\n                marquerChampInvalide($adresseLigne1);\r\n                erreurs.push(\r\n                    langue === 'FR'\r\n                        ? \"Merci de renseigner l'adresse\"\r\n                        : \"Please provide the address\"\r\n                );\r\n                if (!premierChampInvalide) premierChampInvalide = $adresseLigne1;\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds : Validation 1d : Code postal obligatoire\r\n            if (!donnees.codePostal) {\r\n                marquerChampInvalide($codePostal);\r\n                erreurs.push(\r\n                    langue === 'FR'\r\n                        ? \"Merci de renseigner le code postal\"\r\n                        : \"Please provide the postal code\"\r\n                );\r\n                if (!premierChampInvalide) premierChampInvalide = $codePostal;\r\n            }\r\n            \r\n            \/\/ \u2705 v4.9ds : Validation 1e : Ville obligatoire\r\n            if (!donnees.ville) {\r\n                marquerChampInvalide($ville);\r\n                erreurs.push(\r\n                    langue === 'FR'\r\n                        ? \"Merci de renseigner la ville\"\r\n                        : \"Please provide the city\"\r\n                );\r\n                if (!premierChampInvalide) premierChampInvalide = $ville;\r\n            }\r\n            \r\n            \/\/ Validation 2 : Pays obligatoire\r\n            if (!donnees.pays) {\r\n                marquerChampInvalide($pays);\r\n                erreurs.push(\r\n                    langue === 'FR' \r\n                        ? \"Merci de renseigner le pays\"\r\n                        : \"Please enter the country\"\r\n                );\r\n                if (!premierChampInvalide) premierChampInvalide = $pays;\r\n            }\r\n            \r\n            \/\/ Validation 3 : Num\u00e9ro de TVA selon la zone\r\n            const champTVARequired = $('#form-field-annonceur_numero_tva').attr('required') === 'required';\r\n            \r\n            if (AND(champTVARequired, !donnees.numeroTVA)) {\r\n                marquerChampInvalide($numeroTVA);\r\n                \r\n                if (AND(zoneTVA === 'FR', donnees.pays === 'France')) {\r\n                    erreurs.push(\r\n                        langue === 'FR'\r\n                            ? \"Merci de renseigner le num\u00e9ro de TVA\"\r\n                            : \"Please enter the VAT number\"\r\n                    );\r\n                } else {\r\n                    erreurs.push(\r\n                        langue === 'FR'\r\n                            ? \"Merci de renseigner le num\u00e9ro de TVA\"\r\n                            : \"Please provide the VAT number\"\r\n                    );\r\n                }\r\n                if (!premierChampInvalide) premierChampInvalide = $numeroTVA;\r\n            }\r\n            \r\n            \/\/ Validation 4 : Email contact obligatoire et format\r\n            if (!donnees.emailContact) {\r\n                marquerChampInvalide($emailContact);\r\n                erreurs.push(\r\n                    langue === 'FR'\r\n                        ? \"Merci de renseigner l'email du responsable\"\r\n                        : \"Please provide the manager's email\"\r\n                );\r\n                if (!premierChampInvalide) premierChampInvalide = $emailContact;\r\n            } else if (!validerEmail(donnees.emailContact)) {\r\n                marquerChampInvalide($emailContact);\r\n                erreurs.push(\r\n                    langue === 'FR'\r\n                        ? \"L'email du responsable n'est pas au bon format\"\r\n                        : \"Manager's email format is invalid\"\r\n                );\r\n                if (!premierChampInvalide) premierChampInvalide = $emailContact;\r\n            }\r\n            \r\n            \/\/ Validation 5 : Email facturation (si fourni)\r\n            if (AND(donnees.facturationEmail, !validerEmail(donnees.facturationEmail))) {\r\n                marquerChampInvalide($facturationEmail);\r\n                erreurs.push(\r\n                    langue === 'FR'\r\n                        ? \"L'email de facturation n'est pas au bon format\"\r\n                        : \"Billing email format is invalid\"\r\n                );\r\n                if (!premierChampInvalide) premierChampInvalide = $facturationEmail;\r\n            }\r\n            \r\n            \/\/ Validation 6 : Pays = Nationalit\u00e9 (si applicable)\r\n            const nationaliteAnnonceur = sessionStorage.getItem('nationalite_annonceur');\r\n            if (AND(nationaliteAnnonceur, donnees.pays !== nationaliteAnnonceur)) {\r\n                marquerChampInvalide($pays);\r\n                erreurs.push(\r\n                    langue === 'FR'\r\n                        ? \"Le pays doit \u00eatre identique \u00e0 la nationalit\u00e9 de la soci\u00e9t\u00e9\"\r\n                        : \"Country must match company nationality\"\r\n                );\r\n                if (!premierChampInvalide) premierChampInvalide = $pays;\r\n            }\r\n            \r\n            \/\/ \u274c Si des erreurs existent, afficher le message et arr\u00eater\r\n            if (erreurs.length > 0) {\r\n                \/\/ Afficher uniquement le PREMIER message d'erreur\r\n                afficherErreurReferences(erreurs[0]);\r\n                \r\n                \/\/ Scroll vers le premier champ invalide\r\n                if (premierChampInvalide) {\r\n                    $('html, body').animate({\r\n                        scrollTop: premierChampInvalide.offset().top - 150\r\n                    }, 300);\r\n                }\r\n                \r\n                console.error('\u274c Formulaire invalide - ' + erreurs.length + ' erreur(s)');\r\n                return false;\r\n            }\r\n            \r\n            \/\/ \u2705 Validation r\u00e9ussie\r\n            console.log('\u2705 Formulaire r\u00e9f\u00e9rences valide');\r\n            \r\n            \/\/ Sauvegarder les donn\u00e9es dans sessionStorage\r\n            sessionStorage.setItem('via_annonceur_data', JSON.stringify(donnees));\r\n            \r\n            \/\/ \u2705 v1.6 : Flag pour indiquer que les r\u00e9f\u00e9rences ont \u00e9t\u00e9 valid\u00e9es dans cette session\r\n            sessionStorage.setItem('references_validees_session', 'Yes');\r\n            \/\/ \u2705 v2.7.3 : Flag pour _updateMessagesEtapes\r\n            sessionStorage.setItem('ReferencesValidees', 'Yes');\r\n            console.log('\u2705 Flag references_validees_session = Yes');\r\n\r\n            \/\/ pb327 : si l'utilisateur valide les references SANS avoir clique FinaliserBouton\r\n            \/\/   (.PasserCommandeBouton), window._viaFinaliserClique reste false -> _updateMessagesEtapes\r\n            \/\/   re-cache le message vert MsgCompleterFormulaireOK ~1s apres le $msgOK.show().\r\n            \/\/   Valider les references EST une action explicite de cette session : on pose le flag ici\r\n            \/\/   pour que le message s'affiche (comme apres FinaliserBouton). Flag window (ephemere,\r\n            \/\/   reset au reload) -> pas de reapparition prematuree par flag residuel (Pb 7 preserve).\r\n            window._viaFinaliserClique = true;\r\n            \r\n            \/\/ \u2705 NOUVEAU v1.3 : Sauvegarder en BDD si un annonceur existant est s\u00e9lectionn\u00e9\r\n            sauvegarderAnnonceurEnBDD(donnees);\r\n            \r\n            \/\/ Afficher message de succ\u00e8s\r\n            \/* ====================================================================\r\n             * pb2346 : UNE SEULE DEFINITION POUR LES QUATRE ECRIVAINS.\r\n             *   pb2345 avait ferme la porte de Panier_manage en affirmant qu il n y\r\n             *   en avait qu une. C etait faux : la verification ne portait que sur le\r\n             *   corpus alors fourni. Les JS d etape en ont trois autres \u2014\r\n             *     References.txt   l.1409  $msgOK.show()\r\n             *     Mode_de_paiement l.1327  DeviseModedePaiementMsgConteneur\r\n             *     Validations.txt  l.214   MsgCommandeValidee\r\n             *   Recopier la regle a quatre endroits serait refaire l erreur d origine :\r\n             *   quatre copies divergent. La porte est donc definie UNE fois, par le\r\n             *   premier fichier charge, et les autres la reutilisent. Aucun ordre de\r\n             *   chargement a respecter.\r\n             *   Regle (identique a pb2345) : masquer si ordinateur ET site pays.\r\n             *     largeur   _viaLargeur1263() sinon outerWidth (regle 5.4)\r\n             *     site pays la regie est yearbook-media.com EN TOP ; dans l iframe\r\n             *               popup d un site pays window.top diff\u00e8re -> pays.\r\n             *   Revert : window._viaPb2345Off = true (meme knob que pb2345).\r\n             * ==================================================================== *\/\r\n            if (typeof window._viaMasquerMsg2346 !== 'function') {\r\n                window._viaMasquerMsg2346 = function () {\r\n                    if (window._viaPb2345Off === true) { return false; }\r\n                    try {\r\n                        var _lg = (typeof window._viaLargeur1263 === 'function')\r\n                            ? window._viaLargeur1263() : window.outerWidth;\r\n                        var _rg = (window === window.top)\r\n                            ? \/^(?:www\\.)?yearbook-media\\.com$\/.test(window.location.hostname || '') : false;\r\n                        var _m = (_lg >= 1000) ? !_rg : false;\r\n                        if (window._viaPb2346Dit !== true) {\r\n                            window._viaPb2346Dit = true;\r\n                            console.log('[pb2346] phrases vertes des 4 dernieres etapes : ' + (_m ? 'MASQUEES' : 'conservees')\r\n                                + ' | largeur=' + _lg + ' | regie=' + _rg + ' (top=' + (window === window.top) + ')');\r\n                        }\r\n                        return _m;\r\n                    } catch (_e2346) { return false; }\r\n                };\r\n            }\r\n\r\n            if (window._viaMasquerMsg2346()) { console.log('[pb2346] MsgCompleterFormulaireOKConteneur non affiche (pays + ordinateur)'); }\r\n            else { $msgOK.show(); }\r\n            \r\n            \/\/ \u2705 FERMER L'\u00c9TAPE 2\r\n            setTimeout(() => {\r\n                $('.ReferencesConteneur, #DataFacturationForm').hide();\r\n                $('#ReferencesTitreIconeUp').hide();\r\n                $('#ReferencesTitreIconeDown').show();\r\n                \/\/ \u2705 v2.7.3 : Mettre \u00e0 jour les messages d'\u00e9tapes\r\n                if (window.VIA_Panier && typeof window.VIA_Panier._updateMessagesEtapes === 'function') {\r\n                    window.VIA_Panier._updateMessagesEtapes();\r\n                }\r\n                console.log('\u27a1\ufe0f Passage \u00e0 l\\'\u00e9tape 3 - Paiement');\r\n                \r\n                \/\/ D\u00e9clencher l'ouverture de l'\u00e9tape paiement\r\n                $(document).trigger('ouvrir-etape-paiement');\r\n            }, 1000);\r\n            \r\n            return true;\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 FONCTION CORRIG\u00c9E : Utilise l'action existante update_client_field\r\n         *\/\r\n        function sauvegarderAnnonceurEnBDD(donnees) {\r\n            const annonceurId = sessionStorage.getItem('selected_annonceur_id');\r\n            const annonceurSource = sessionStorage.getItem('selected_annonceur_source');\r\n            \r\n            \/\/ Si aucun annonceur s\u00e9lectionn\u00e9, on ne sauvegarde pas (sera cr\u00e9\u00e9 \u00e0 la commande)\r\n            if (!annonceurId) {\r\n                console.log('\u2139\ufe0f Pas d\\'annonceur existant s\u00e9lectionn\u00e9, pas de mise \u00e0 jour BDD');\r\n                return;\r\n            }\r\n            \r\n            console.log('\ud83d\udcbe Sauvegarde annonceur en BDD - ID:', annonceurId, 'Source:', annonceurSource);\r\n            \r\n            \/\/ S\u00e9parer nom et pr\u00e9nom du contact\r\n            const nomContactParts = (donnees.nomContact || '').split(' ');\r\n            const prenom = nomContactParts.slice(0, -1).join(' ') || '';\r\n            const nom = nomContactParts.slice(-1)[0] || '';\r\n            \r\n            \/\/ \u2705 Utiliser l'action existante update_client_field\r\n            $.ajax({\r\n                url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                type: 'POST',\r\n                dataType: 'json',\r\n                data: {\r\n                    action: 'update_client_field',\r\n                    client_id: annonceurId,\r\n                    source: annonceurSource,\r\n                    annonceur_nom_societe: donnees.nomSociete,\r\n                    annonceur_nom: donnees.nomContact,\r\n                    annonceur_direction_service: donnees.directionService,\r\n                    annonceur_numero_immatriculation: donnees.numeroImmatriculation,\r\n                    annonceur_numero_tva: donnees.numeroTVA,\r\n                    annonceur_adresse_ligne1: donnees.adresseLigne1,\r\n                    annonceur_code_postal: donnees.codePostal,\r\n                    annonceur_ville: donnees.ville,\r\n                    annonceur_pays: donnees.pays,\r\n                    annonceur_email_contact: donnees.emailContact,\r\n                    annonceur_telephone_contact: donnees.telephoneContact,\r\n                    facturation_contact: donnees.facturationContact,\r\n                    facturation_adresse: donnees.facturationAdresse,\r\n                    facturation_code_postal: donnees.facturationCodePostal,\r\n                    facturation_ville: donnees.facturationVille,\r\n                    facturation_pays: donnees.facturationPays,\r\n                    facturation_email: donnees.facturationEmail,\r\n                    facturation_telephone: donnees.facturationTelephone\r\n                },\r\n                success: function(response) {\r\n                    if (AND(response, response.success)) {\r\n                        console.log('\u2705 Annonceur mis \u00e0 jour en BDD:', response.data);\r\n                    } else {\r\n                        console.warn('\u26a0\ufe0f R\u00e9ponse inattendue:', response);\r\n                    }\r\n                },\r\n                error: function(xhr, status, error) {\r\n                    console.error('\u274c Erreur mise \u00e0 jour annonceur:', error);\r\n                }\r\n            });\r\n        }\r\n\r\n        \/**\r\n         * Valide le format d'un email\r\n         *\/\r\n        function validerEmail(email) {\r\n            const regex = \/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/;\r\n            return regex.test(email);\r\n        }\r\n\r\n        \/**\r\n         * Marque un champ comme invalide (fond rose)\r\n         *\/\r\n        function marquerChampInvalide($champ) {\r\n            if ($champ.length === 0) return;\r\n            \r\n            $champ.css('background-color', '#ffe6e6');\r\n            \r\n            \/\/ Retirer la surbrillance quand l'utilisateur commence \u00e0 interagir\r\n            $champ.one('input focus click', function() {\r\n                \/\/ \u2705 v1.9 : Remettre le fond bleu si le champ a une valeur, sinon vide\r\n                const $this = $(this);\r\n                if ($this.val() && $this.val().trim() !== '' && !$this.prop('readonly')) {\r\n                    $this.css('background-color', '#E8F0FE');\r\n                } else {\r\n                    $this.css('background-color', '');\r\n                }\r\n            });\r\n            \r\n            console.log('\ud83d\udd34 Champ marqu\u00e9 invalide:', $champ.attr('name'));\r\n        }\r\n\r\n        \/**\r\n         * \u2705 v1.9 : Marque un champ comme renseign\u00e9 (fond bleu #E8F0FE)\r\n         *\/\r\n        function marquerChampRenseigne($champ) {\r\n            if ($champ.length === 0 || $champ.prop('readonly')) return;\r\n            \r\n            if ($champ.val() && $champ.val().trim() !== '') {\r\n                $champ.css('background-color', '#E8F0FE');\r\n            } else {\r\n                $champ.css('background-color', '');\r\n            }\r\n        }\r\n\r\n        \/**\r\n         * Retire toutes les surbrillances des champs\r\n         *\/\r\n        function retirerSurbrillances() {\r\n            \/\/ \u2705 v1.9 : Remettre le fond bleu pour les champs renseign\u00e9s, vide pour les autres\r\n            $('#Formulaire_Annonceur_donnees_notconnected2 input').each(function() {\r\n                const $input = $(this);\r\n                if ($input.prop('readonly')) return;\r\n                \r\n                if ($input.val() && $input.val().trim() !== '') {\r\n                    $input.css('background-color', '#E8F0FE');\r\n                } else {\r\n                    $input.css('background-color', '');\r\n                }\r\n            });\r\n        }\r\n\r\n        \/**\r\n         * Affiche un message d'erreur pour le formulaire r\u00e9f\u00e9rences\r\n         *\/\r\n        function afficherErreurReferences(message) {\r\n            const $msgErreur = $('#MsgCompleterFormulaireCoordonnees');\r\n            const $conteneurErreur = $('#MsgCompleterFormulaireCoordonneesConteneur');\r\n            \r\n            $msgErreur.html(message);\r\n            $conteneurErreur.show();\r\n            \r\n            \/\/ Scroll vers le message d'erreur\r\n            $('html, body').animate({\r\n                scrollTop: $conteneurErreur.offset().top - 100\r\n            }, 300);\r\n            \r\n            console.error('\u274c Erreur validation:', message);\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 v2.7.3 : Validation en temps r\u00e9el \u2014 met \u00e0 jour le message d'erreur d\u00e8s qu'un champ\r\n         * en erreur est renseign\u00e9, sans attendre le clic sur Valider\r\n         *\/\r\n        function initValidationEnTempsReel() {\r\n            const $ = jQuery;\r\n            const $form = $('#Formulaire_Annonceur_donnees_notconnected2');\r\n            if (!$form.length) return;\r\n\r\n            \/\/ Debounce : \u00e9vite de recalculer \u00e0 chaque frappe\r\n            let _liveTimer;\r\n\r\n            $form.on('input change', 'input, select, textarea', function() {\r\n                \/\/ N'agir que si le message d'erreur est actuellement visible\r\n                if (!$('#MsgCompleterFormulaireCoordonneesConteneur').is(':visible')) return;\r\n\r\n                clearTimeout(_liveTimer);\r\n                _liveTimer = setTimeout(function() {\r\n                    const langue = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                    const zoneTVA = sessionStorage.getItem('ZoneTVA');\r\n\r\n                    \/\/ Recollecte des valeurs\r\n                    const nomSociete   = ($('input[name=\"form_fields[annonceur_nom_societe]\"]').val() || '').trim();\r\n                    const pays         = ($('input[name=\"form_fields[annonceur_pays]\"]').val() || '').trim();\r\n                    const emailContact = ($('input[name=\"form_fields[annonceur_email_contact]\"]').val() || '').trim();\r\n                    const numeroTVA    = ($('input[name=\"form_fields[annonceur_numero_tva]\"]').val() || '').trim();\r\n                    const factEmail    = ($('input[name=\"form_fields[facturation_email]\"]').val() || '').trim();\r\n\r\n                    const erreurs = [];\r\n\r\n                    if (!nomSociete) {\r\n                        erreurs.push(langue === 'FR'\r\n                            ? \"Merci de renseigner le nom de l'institution ou de la soci\u00e9t\u00e9\"\r\n                            : \"Please provide the institution or company name\");\r\n                    }\r\n                    if (!pays) {\r\n                        erreurs.push(langue === 'FR' ? \"Merci de renseigner le pays\" : \"Please enter the country\");\r\n                    }\r\n                    const champTVARequired = $('#form-field-annonceur_numero_tva').attr('required') === 'required';\r\n                    if (champTVARequired && !numeroTVA) {\r\n                        erreurs.push(langue === 'FR' ? \"Merci de renseigner le num\u00e9ro de TVA\" : \"Please enter the VAT number\");\r\n                    }\r\n                    if (!emailContact) {\r\n                        erreurs.push(langue === 'FR'\r\n                            ? \"Merci de renseigner l'email du responsable\"\r\n                            : \"Please provide the manager's email\");\r\n                    } else if (!\/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(emailContact)) {\r\n                        erreurs.push(langue === 'FR'\r\n                            ? \"L'email du responsable n'est pas au bon format\"\r\n                            : \"Manager's email format is invalid\");\r\n                    }\r\n                    if (factEmail && !\/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(factEmail)) {\r\n                        erreurs.push(langue === 'FR'\r\n                            ? \"L'email de facturation n'est pas au bon format\"\r\n                            : \"Billing email format is invalid\");\r\n                    }\r\n                    const nationalite = sessionStorage.getItem('nationalite_annonceur');\r\n                    if (nationalite && pays !== nationalite) {\r\n                        erreurs.push(langue === 'FR'\r\n                            ? \"Le pays doit \u00eatre identique \u00e0 la nationalit\u00e9 de la soci\u00e9t\u00e9\"\r\n                            : \"Country must match company nationality\");\r\n                    }\r\n\r\n                    if (erreurs.length === 0) {\r\n                        \/\/ Plus d'erreurs \u2192 masquer le message\r\n                        $('#MsgCompleterFormulaireCoordonneesConteneur').hide();\r\n                        retirerSurbrillances();\r\n                        console.log('\u2705 [live] Toutes les erreurs corrig\u00e9es \u2014 message masqu\u00e9');\r\n                    } else {\r\n                        \/\/ Mettre \u00e0 jour avec la premi\u00e8re erreur restante\r\n                        $('#MsgCompleterFormulaireCoordonnees').html(erreurs[0]);\r\n                        console.log('\u26a0\ufe0f [live] Erreur restante:', erreurs[0]);\r\n                    }\r\n                }, 300);\r\n            });\r\n\r\n            console.log('\u2705 Validation temps r\u00e9el initialis\u00e9e');\r\n        }\r\n\r\n        \/**\r\n         * Gestion de la visibilit\u00e9 des formulaires de facturation\r\n         *\/\r\n        function initGestionFormulairesFacturation() {\r\n            const $ = jQuery;\r\n            \r\n            \/\/ S\u00e9lecteurs des formulaires par leur nom\r\n            const $formulaire1 = $('form[name=\"Formulaire_Annonceur_donnees2\"]');\r\n            const $formulaire2 = $('form[name=\"Formulaire_Annonceur_donnees3\"]');\r\n            const $formulaire3 = $('form[name=\"Formulaire_Annonceur_donnees4\"]');\r\n            \r\n            \/\/ S\u00e9lecteur de la checkbox \"DataFacturation\"\r\n            const $checkboxFacturation = $('input[name=\"form_fields[DataFacturation]\"]');\r\n            \r\n            \/\/ \u2705 v2.0 : Cibler directement #DataFacturationForm (le widget Elementor)\r\n            const $dataFacturationForm = $('#DataFacturationForm');\r\n            \r\n            if (window.outerWidth < 1000) {\r\n                \/\/ \u2705 v4.9ds+ Pb 4 sites pays mobile : ne pas r\u00e9duire les <form> internes\r\n                \/\/   (le widget parent est d\u00e9j\u00e0 g\u00e9r\u00e9 par PM CSS \u2014 cumul des scales = trop petit)\r\n                $formulaire2.css('transform', '');\r\n                $formulaire2.css('transform-origin', '');\r\n                $formulaire3.css('transform', '');\r\n                $formulaire3.css('transform-origin', '');\r\n            } else {\r\n                \/\/ \u2705 v1.16.0 : Desktop \u2014 zoom #ReferencesFormulaires de 10%\r\n                $('#ReferencesFormulaires').css({\r\n                    'transform': 'scale(1.1)',\r\n                    'transform-origin': 'top center'\r\n                });\r\n            }\r\n\r\n            \r\n            if ($dataFacturationForm.length === 0 && $checkboxFacturation.length === 0) {\r\n                console.warn('\u26a0\ufe0f #DataFacturationForm ou checkbox introuvables');\r\n                return;\r\n            }\r\n            \r\n            \/\/ \u2705 v2.0 : \u00c9tat initial \u2014 masquer #DataFacturationForm\r\n            $dataFacturationForm.hide();\r\n            \r\n            \/\/ \u2705 S'assurer que la checkbox est d\u00e9coch\u00e9e par d\u00e9faut\r\n            $checkboxFacturation.prop('checked', false);\r\n            \r\n            \/\/ \u2705 v2.0 : Listener sur la checkbox \u2014 cibler #DataFacturationForm directement\r\n            $('input[name=\"form_fields[DataFacturation]\"], #form-field-DataFacturation-0').on('change', function() {\r\n                if ($(this).is(':checked')) {\r\n                    $dataFacturationForm.slideDown(300, function() {\r\n                        \/\/ Scroll vers le formulaire facturation\r\n                        setTimeout(function() {\r\n                            $('html, body').animate({\r\n                                scrollTop: $dataFacturationForm.offset().top - 50\r\n                            }, 400);\r\n                        }, 50);\r\n                        \/\/ \u2705 #ChampsObligatoires margin-top quand form ouvert (mode=popup sites pays)\r\n                        \/* ============================================================\r\n                         * pb1706 : LA GARDE LISAIT L URL AU MAUVAIS ENDROIT.\r\n                         *   Constat user : #ChampsObligatoires ne bouge pas d un pixel,\r\n                         *   quelles que soient les valeurs posees ailleurs.\r\n                         *   Ces deux ecrivains-ci sont les seuls a poser un margin-top\r\n                         *   INLINE sur l element en contexte popup \u2014 donc les seuls qui\r\n                         *   gagnent. Mais leur garde teste location.SEARCH, alors que\r\n                         *   l URL de la regie plein ecran porte mode=popup dans le HASH :\r\n                         *     yearbook-media.com\/#mode=popup&layout=plein&...\r\n                         *   La condition est donc fausse et ils ne s executent jamais.\r\n                         *   J ai regle pb1617, pb1701, pb1703 et pb1705 sur des ecrivains\r\n                         *   perdants pendant quatre tours.\r\n                         *   On lit les deux endroits, et le decalage demande devient un\r\n                         *   reglage plutot qu une valeur enterree :\r\n                         *     window._viaPb1706Px = 60   (defaut 120, vers le bas)\r\n                         * ============================================================ *\/\r\n                        if ((window.location.search + window.location.hash).indexOf('mode=popup') !== -1) {\r\n                            var _co = document.getElementById('ChampsObligatoires');\r\n                            if (_co) {\r\n                                var _isDesktopCO = window.outerWidth >= 1001;\r\n                                var _dec1706 = (typeof window._viaPb1706Px === 'number')\r\n                                    ? window._viaPb1706Px : 120;\r\n                                \/* pb1707 : meme decalage que la feuille, meme variable *\/\r\n                                var _base1706 = _isDesktopCO ? -60 : -70;\r\n                                _co.style.setProperty('margin-top', (_base1706 + _dec1706) + 'px', 'important');\r\n                                console.log('[pb1706] #ChampsObligatoires (coche) margin-top = '\r\n                                    + (_base1706 + _dec1706) + 'px | base ' + _base1706 + ' + ' + _dec1706);\r\n                            }\r\n                        }\r\n                    });\r\n                } else {\r\n                    $dataFacturationForm.slideUp(300);\r\n                    \/\/ \u2705 #ChampsObligatoires margin-top quand form ferm\u00e9 (pb469 : valeur d'origine -30\/-40 ;\r\n                    \/\/   le decalage de -25px est porte par la regle transform translateY(-55) plus haut)\r\n                    \/* pb1706 : meme garde, meme reglage, etat decoche *\/\r\n                    if ((window.location.search + window.location.hash).indexOf('mode=popup') !== -1) {\r\n                        var _co = document.getElementById('ChampsObligatoires');\r\n                        if (_co) {\r\n                            var _isDesktopCO2 = window.outerWidth >= 1001;\r\n                            \/* ============================================================\r\n                             * pb1708 : DECOCHE REMONTE DE 30 px, COCHE NE BOUGE PAS.\r\n                             *   L etat decoche a DEUX ecrivains selon le moment :\r\n                             *     - a l affichage initial, la feuille (--via-oblig-1707)\r\n                             *     - apres un decochage, cet inline-ci\r\n                             *   Ils partageaient la valeur de l etat COCHE : decaler l un\r\n                             *   sans l autre aurait fait sauter l element au premier\r\n                             *   decochage. Les deux passent donc a 90, l etat coche garde\r\n                             *   ses 120 sur son propre reglage.\r\n                             *   Reglages independants :\r\n                             *     --via-oblig-1707 \/ window._viaPb1708Px  -> decoche\r\n                             *     window._viaPb1706Px                     -> coche\r\n                             * ============================================================ *\/\r\n                            \/* pb1710 : decoche redescend de 10 px (50 -> 60).\r\n                               Les deux ecrivains de l etat decoche restent alignes ;\r\n                               l etat coche garde ses 120. *\/\r\n                            var _dec1706b = (typeof window._viaPb1708Px === 'number')\r\n                                ? window._viaPb1708Px : 60;\r\n                            var _base1706b = _isDesktopCO2 ? -30 : -35;   \/* pb506 *\/\r\n                            _co.style.setProperty('margin-top', (_base1706b + _dec1706b) + 'px', 'important');\r\n                            console.log('[pb1706] #ChampsObligatoires (decoche) margin-top = '\r\n                                + (_base1706b + _dec1706b) + 'px');\r\n                        }\r\n                    }\r\n                }\r\n            });\r\n            \r\n            console.log('\u2705 Gestion formulaires facturation initialis\u00e9e');\r\n        }\r\n        \r\n        \/**\r\n         * Vide les champs du formulaire de facturation (formulaire 3)\r\n         *\/\r\n        function viderChampsFacturation() {\r\n            const $ = jQuery;\r\n            \r\n            const champsFacturation = [\r\n                'facturation_contact',\r\n                'facturation_adresse',\r\n                'facturation_code_postal',\r\n                'facturation_ville',\r\n                'facturation_pays',\r\n                'facturation_email',\r\n                'facturation_telephone'\r\n            ];\r\n            \r\n            champsFacturation.forEach(champ => {\r\n                $(`input[name=\"form_fields[${champ}]\"]`).val('');\r\n            });\r\n            \r\n            console.log('\ud83e\uddf9 Champs facturation vid\u00e9s');\r\n        }\r\n        \r\n        \/\/ ============================================\r\n        \/\/ \u2705 NOUVEAU v1.4 : BOUTON EFFACER R\u00c9F\u00c9RENCES\r\n        \/\/ ============================================\r\n        \r\n        \/**\r\n         * Initialise le bouton #EffacerReferences\r\n         *\/\r\n        function initBoutonEffacerReferences() {\r\n            const $boutonEffacer = $('#EffacerReferences');\r\n            \r\n            if ($boutonEffacer.length === 0) {\r\n                console.log('\u2139\ufe0f Bouton #EffacerReferences introuvable');\r\n                return;\r\n            }\r\n            \r\n            $boutonEffacer.on('click', function(e) {\r\n                e.preventDefault();\r\n                \r\n                \/\/ \u2705 v1.5 : V\u00e9rifier si modification autoris\u00e9e\r\n                if (window.VIA_Panier && typeof window.VIA_Panier.gererModificationCommande === 'function') {\r\n                    if (!window.VIA_Panier.gererModificationCommande('references')) {\r\n                        return; \/\/ Bloqu\u00e9 car bon de commande cr\u00e9\u00e9\r\n                    }\r\n                }\r\n                \r\n                effacerReferences();\r\n            });\r\n            \r\n            console.log('\u2705 Bouton Effacer R\u00e9f\u00e9rences initialis\u00e9');\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 v1.9 : Emp\u00eache la touche Enter de soumettre le formulaire Elementor\r\n         * Le bouton submit par d\u00e9faut est masqu\u00e9 mais reste actif avec Enter\r\n         *\/\r\n        function initProtectionToucheEnter() {\r\n            \/\/ Emp\u00eacher Enter de soumettre les formulaires dans les zones de r\u00e9f\u00e9rences\r\n            $(document).on('keydown', '.ReferencesConteneur input, .ReferencesConteneur select', function(e) {\r\n                if (e.key === 'Enter' || e.keyCode === 13) {\r\n                    e.preventDefault();\r\n                    e.stopPropagation();\r\n                    console.log('\u2328\ufe0f Touche Enter bloqu\u00e9e dans R\u00e9f\u00e9rences');\r\n                    \r\n                    \/\/ Optionnel : passer au champ suivant\r\n                    const $inputs = $('.ReferencesConteneur input:visible, .ReferencesConteneur select:visible');\r\n                    const currentIndex = $inputs.index(this);\r\n                    if (currentIndex < $inputs.length - 1) {\r\n                        $inputs.eq(currentIndex + 1).focus();\r\n                    }\r\n                    \r\n                    return false;\r\n                }\r\n            });\r\n            \r\n            \/\/ Emp\u00eacher aussi le submit du formulaire Elementor\r\n            $(document).on('submit', '.ReferencesConteneur form, #EtapeReferences form', function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                console.log('\ud83d\udeab Submit formulaire Elementor bloqu\u00e9');\r\n                return false;\r\n            });\r\n            \r\n            console.log('\u2705 Protection touche Enter initialis\u00e9e');\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 v1.6 : Efface toutes les donn\u00e9es des formulaires r\u00e9f\u00e9rences\r\n         * Inclut maintenant la suppression du flag references_validees_session\r\n         *\/\r\n        function effacerReferences() {\r\n            console.log('\ud83e\uddf9 Effacement des r\u00e9f\u00e9rences en cours...');\r\n            \r\n            const $ = jQuery;\r\n            \r\n            \/\/ ============================================\r\n            \/\/ 1. VIDER LES FORMULAIRES\r\n            \/\/ ============================================\r\n            \r\n            \/\/ Liste de tous les champs \u00e0 vider\r\n            const champsAVider = [\r\n                \/\/ Formulaire 2 - Donn\u00e9es annonceur\r\n                'annonceur_nom_societe',\r\n                'annonceur_nom_contact',\r\n                'annonceur_direction_service',\r\n                'annonceur_numero_immatriculation',\r\n                'annonceur_numero_tva',\r\n                'annonceur_adresse_ligne1',\r\n                'annonceur_code_postal',\r\n                'annonceur_ville',\r\n                'annonceur_pays',\r\n                'annonceur_email_contact',\r\n                'annonceur_telephone_contact',\r\n                \/\/ Formulaire 3 - Donn\u00e9es facturation\r\n                'facturation_contact',\r\n                'facturation_adresse',\r\n                'facturation_code_postal',\r\n                'facturation_ville',\r\n                'facturation_pays',\r\n                'facturation_email',\r\n                'facturation_telephone',\r\n                \/\/ Champ recherche client\r\n                'RechercherFicheClient'\r\n            ];\r\n            \r\n            \/\/ Vider chaque champ\r\n            champsAVider.forEach(champ => {\r\n                $(`input[name=\"form_fields[${champ}]\"]`).val('');\r\n            });\r\n            \r\n            \/\/ Vider aussi par s\u00e9lecteur de formulaire (au cas o\u00f9)\r\n            $('form[name=\"Formulaire_Annonceur_donnees2\"] input[type=\"text\"], form[name=\"Formulaire_Annonceur_donnees2\"] input[type=\"email\"]').val('');\r\n            $('form[name=\"Formulaire_Annonceur_donnees3\"] input[type=\"text\"], form[name=\"Formulaire_Annonceur_donnees3\"] input[type=\"email\"]').val('');\r\n            $('form[name=\"Formulaire_Annonceur_donnees4\"] input[type=\"text\"], form[name=\"Formulaire_Annonceur_donnees4\"] input[type=\"email\"]').val('');\r\n            \r\n            console.log('\u2705 Formulaires vid\u00e9s');\r\n            \r\n            \/\/ ============================================\r\n            \/\/ 2. R\u00c9INITIALISER LES CHECKBOXES\r\n            \/\/ ============================================\r\n            \r\n            \/\/ D\u00e9cocher la checkbox \"Adresse facturation diff\u00e9rente\"\r\n            const $checkboxFacturation = $('input[name=\"form_fields[DataFacturation]\"]');\r\n            $checkboxFacturation.prop('checked', false);\r\n            \r\n            \/\/ \u2705 v1.8 : Supprim\u00e9 - r\u00e9initialisation NonRedevableTVA\r\n            \r\n            console.log('\u2705 Checkboxes r\u00e9initialis\u00e9es');\r\n            \r\n            \/\/ ============================================\r\n            \/\/ 3. FERMER #DataFacturationForm SI OUVERT\r\n            \/\/ ============================================\r\n            \r\n            const $dataFacturationForm = $('#DataFacturationForm');\r\n            if ($dataFacturationForm.is(':visible')) {\r\n                $dataFacturationForm.slideUp(300);\r\n                console.log('\u2705 DataFacturationForm ferm\u00e9');\r\n            }\r\n            \r\n            \/\/ Fermer aussi le widget du formulaire 3\r\n            const $formulaire3 = $('form[name=\"Formulaire_Annonceur_donnees4\"]');\r\n            const $widgetFormulaire3 = $formulaire3.closest('.elementor-widget');\r\n            if ($widgetFormulaire3.is(':visible')) {\r\n                $widgetFormulaire3.slideUp(300);\r\n                console.log('\u2705 Formulaire facturation diff\u00e9rente ferm\u00e9');\r\n            }\r\n            \r\n            \/\/ ============================================\r\n            \/\/ 4. SUPPRIMER LES DONN\u00c9ES DU STORAGE\r\n            \/\/ ============================================\r\n            \r\n            \/\/ \u2705 v1.6 : Ajout de 'references_validees_session' \u00e0 la liste\r\n            const clesSesssionASupprimer = [\r\n                'via_annonceur_data',\r\n                'selected_annonceur_id',\r\n                'selected_annonceur_source',\r\n                'ZoneTVA',\r\n                'nationalite_annonceur',\r\n                'references_validees_session'  \/\/ \u2705 v1.6 : AJOUT\u00c9\r\n            ];\r\n            \r\n            clesSesssionASupprimer.forEach(cle => {\r\n                sessionStorage.removeItem(cle);\r\n            });\r\n            \r\n            console.log('\u2705 Donn\u00e9es sessionStorage supprim\u00e9es (incluant references_validees_session)');\r\n            \r\n            \/\/ ============================================\r\n            \/\/ 5. R\u00c9INITIALISER L'INTERFACE\r\n            \/\/ ============================================\r\n            \r\n            \/\/ Retirer les surbrillances d'erreur\r\n            retirerSurbrillances();\r\n            \r\n            \/\/ Masquer les messages d'erreur\/succ\u00e8s\r\n            $('#MsgCompleterFormulaireCoordonneesConteneur').hide();\r\n            $('#MsgCompleterFormulaireOKConteneur').hide();\r\n            \r\n            \/\/ \u2705 R\u00e9-appliquer le pays de l'\u00e9tape 1 si disponible\r\n            if (AND(STATE, STATE.selectedCountry)) {\r\n                const $paysInput = $('input[name=\"form_fields[annonceur_pays]\"]');\r\n                $paysInput.val(STATE.selectedCountry.label);\r\n                \r\n                \/\/ R\u00e9appliquer la logique TVA\r\n                appliquerLogiqueTVA(STATE.selectedCountry.label, STATE.selectedCountry.ZoneTVA);\r\n                \r\n                console.log('\u2705 Pays r\u00e9initialis\u00e9 depuis \u00e9tape 1:', STATE.selectedCountry.label);\r\n            }\r\n            \r\n            console.log('\u2705 Effacement des r\u00e9f\u00e9rences termin\u00e9');\r\n        }\r\n        \r\n        \/\/ ============================================\r\n        \/\/ INITIALISATION - APPEL DES FONCTIONS\r\n        \/\/ ============================================\r\n        try {\r\n            initBoutonFinaliser();\r\n            initFormulaireReferences();\r\n            initRechercheClient(); \r\n            initGestionFormulairesFacturation();\r\n            initBoutonEffacerReferences();\r\n            initDetectionModifications(); \/\/ \u2705 v1.5 : D\u00e9tection des modifications\r\n            initProtectionToucheEnter(); \/\/ \u2705 v1.9 : Emp\u00eacher Enter de soumettre le formulaire\r\n            initRegimeTVAListener(); \/\/ \u2705 v1.9 : Listener sur le champ n\u00b0 TVA pour zone EU\r\n            initChampsRenseignes(); \/\/ \u2705 v1.9 : Fond #E8F0FE pour les champs renseign\u00e9s\r\n            initValidationEnTempsReel(); \/\/ \u2705 v2.7.3 : Mise \u00e0 jour message erreur en temps r\u00e9el\r\n            \r\n            console.log('\u2705 Module R\u00e9f\u00e9rences Client v2.0 initialis\u00e9');\r\n            \r\n            \/\/ Exposer publiquement\r\n            window.VIA_References = {\r\n                validerEtape1: validerEtape1,\r\n                validerFormulaireReferences: validerFormulaireReferences,\r\n                loadClientDataAndFillForm: loadClientDataAndFillForm,\r\n                sauvegarderAnnonceurEnBDD: sauvegarderAnnonceurEnBDD,\r\n                effacerReferences: effacerReferences,\r\n                signalerModification: signalerModificationReferences, \/\/ \u2705 v1.5\r\n                \/\/ \u2705 v1.9 : Fonction pour mettre \u00e0 jour la logique TVA depuis l'ext\u00e9rieur\r\n                mettreAJourLogiqueTVA: function(pays) {\r\n                    if (!pays) return;\r\n                    const country = window.VIA_Countries?.getCountryByLabel(pays);\r\n                    if (country) {\r\n                        appliquerLogiqueTVA(country.label, country.ZoneTVA);\r\n                        console.log('\u2705 Logique TVA mise \u00e0 jour pour:', pays, '- Zone:', country.ZoneTVA);\r\n                    } else {\r\n                        console.warn('\u26a0\ufe0f Pays non trouv\u00e9 pour mise \u00e0 jour TVA:', pays);\r\n                    }\r\n                }\r\n            };\r\n        } catch (error) {\r\n            console.error('\u274c Erreur initialisation r\u00e9f\u00e9rences:', error);\r\n        }\r\n    }\r\n    \r\n    \/\/ Lancer l'initialisation\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', initReferencesModule);\r\n    } else {\r\n        initReferencesModule();\r\n    }\r\n\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-44413afa elementor-widget elementor-widget-html\" data-id=\"44413afa\" data-element_type=\"widget\" data-e-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\/**\r\n * VIA Agency - CHOIX MODE DE PAIEMENT\r\n * @version 1.7 - F\u00e9vrier 2026\r\n * - Virement : J, J+7, J+14 (max 3 \u00e9ch\u00e9ances) avec plages de dates\r\n * - CB : J, J+7, J+14... (max 8 \u00e9ch\u00e9ances)\r\n * v1.3 : Enrichissement textes \u00e9ch\u00e9ances (N \u00e9ch\u00e9ances de xxx \u20ac TTC)\r\n * v1.4 : Plages de dates pour virement (1 semaine pour payer chaque \u00e9ch\u00e9ance)\r\n * \u2705 v1.5 : D\u00e9tection des modifications \u2192 r\u00e9initialisation des validations ou blocage\r\n * \u2705 v1.6 : Correction TVA zone EU - si n\u00b0 TVA saisi \u2192 HT, sinon \u2192 TTC\r\n * \u2705 v1.6 : Gestion du champ radio ChoixTVA (ClientAssujettiTVA en sessionStorage)\r\n * \u2705 v1.6 : Changement devise met \u00e0 jour #DeviseModedePaiementMsg, #PaiementMsg, #Tariftobedisplayed\r\n * \u2705 v1.6 : Griser l'\u00e9tape pr\u00e9c\u00e9dente quand on passe \u00e0 l'\u00e9tape suivante\r\n * \u2705 v1.7 : CSS hauteur auto pour #DeviseModedePaiementMsgConteneur (dans styles-process-achat.css)\r\n *\/\r\n\r\n(function() {\r\n    'use strict';\r\n    \r\n    console.log('\ud83d\udcb3 Chargement module Choix Mode de Paiement v1.7...');\r\n\r\n    \/**\r\n     * Initialisation apr\u00e8s chargement des d\u00e9pendances\r\n     *\/\r\n    function initPaiementModule() {\r\n        if (typeof jQuery === 'undefined') {\r\n            console.error('\u274c jQuery non disponible');\r\n            return;\r\n        }\r\n        \r\n        if (typeof window.VIA_Elementor === 'undefined' || typeof window.VIA_App === 'undefined') {\r\n            console.warn('\u23f3 D\u00e9pendances non charg\u00e9es, retry...');\r\n            setTimeout(initPaiementModule, 500);\r\n            return;\r\n        }\r\n        \r\n        const $ = jQuery;\r\n        const STATE = window.VIA_Elementor.state;\r\n        \r\n        console.log('\u2705 D\u00e9pendances charg\u00e9es, initialisation paiement...');\r\n        \r\n        \/\/ \u00c9tat du module\r\n        const PAIEMENT_STATE = {\r\n            montantTotal: 0,\r\n            devise: 'EUR',\r\n            estHT: false,\r\n            \/\/ CB\r\n            nbEcheancesMaxCB: 1,\r\n            nbEcheancesSelectionneesCB: 1,\r\n            \/\/ Virement\r\n            nbEcheancesMaxVir: 1,\r\n            nbEcheancesSelectionneesVir: 1,\r\n            selectionManuelleVir: false, \/\/ \u2705 v1.4 : Flag pour savoir si s\u00e9lection volontaire\r\n            \/\/ Commun\r\n            dateFin: null,\r\n            modePaiement: null\r\n        };\r\n        \r\n        \/\/ ============================================\r\n        \/\/ \u2705 v1.5 : D\u00c9TECTION DES MODIFICATIONS\r\n        \/\/ ============================================\r\n        \r\n        \/**\r\n         * \u2705 v1.5 : Signale une modification du mode de paiement\r\n         * Appelle VIA_Panier.gererModificationCommande() pour :\r\n         * - R\u00e9initialiser les validations si bon de commande pas cr\u00e9\u00e9\r\n         * - Afficher message si bon de commande d\u00e9j\u00e0 cr\u00e9\u00e9\r\n         * @returns {boolean} - true si modification autoris\u00e9e, false sinon\r\n         *\/\r\n        function signalerModificationPaiement() {\r\n            if (window.VIA_Panier && typeof window.VIA_Panier.gererModificationCommande === 'function') {\r\n                return window.VIA_Panier.gererModificationCommande('paiement');\r\n            }\r\n            return true;\r\n        }\r\n        \r\n        \/**\r\n         * Ouvre l'\u00e9tape 3 apr\u00e8s validation des r\u00e9f\u00e9rences\r\n         *\/\r\n        \/* pb1636c : banniere de version, absente jusqu'ici \u2014 sans elle, impossible de\r\n           verifier en console quelle version est servie. *\/\r\n        window._viaModePaiementVer = 'MDP-pb2346';\r\n        try { console.log('[PAIEMENT ECHO] ' + window._viaModePaiementVer + ' SERVI'); } catch (_eMDP) {}\r\n\r\n        function ouvrirEtapePaiement() {\r\n            console.log('\ud83d\udcb3 Ouverture \u00e9tape 3 - Choix mode de paiement');\r\n            \r\n            \/\/ \u2705 v1.6 : Griser l'\u00e9tape R\u00e9f\u00e9rences (mais PAS recapitulatif ni dates)\r\n            console.log('\ud83d\udd0d VIA_Panier disponible:', !!window.VIA_Panier);\r\n            console.log('\ud83d\udd0d griserEtape disponible:', window.VIA_Panier && typeof window.VIA_Panier.griserEtape === 'function');\r\n            \r\n            if (window.VIA_Panier && typeof window.VIA_Panier.griserEtape === 'function') {\r\n                console.log('\ud83d\udd18 Appel griserEtape(\"references\")');\r\n                window.VIA_Panier.griserEtape('references');\r\n            } else {\r\n                console.warn('\u26a0\ufe0f griserEtape non disponible');\r\n            }\r\n            \r\n            \/\/ Afficher l'\u00e9tape\r\n            $('#EtapeModedePaiement').addClass('via-etape-visible').show();\r\n            $('.ChoisirPaiementClass').show();\r\n            $('#ChoisirPaiementTitreIconeUp').show();\r\n            $('#ChoisirPaiementTitreIconeDown').hide();\r\n            \r\n            \/\/ \u2705 Activer le titre de l'\u00e9tape Paiement\r\n            if (window.VIA_Panier && typeof window.VIA_Panier.activerTitreEtape === 'function') {\r\n                window.VIA_Panier.activerTitreEtape('paiement');\r\n            }\r\n            \r\n            \/\/ Initialiser les donn\u00e9es\r\n            initialiserDonneesPaiement();\r\n            \r\n            \/\/ Calculer et afficher\r\n            calculerEcheancesCB();\r\n            calculerEcheancesVirement();\r\n            afficherMontants();\r\n            mettreAJourMontantHebdomadaireCB();\r\n            mettreAJourMontantEcheanceVir();\r\n            genererListeEcheancesCB();\r\n            genererListeEcheancesVir();\r\n            \r\n            \/\/ Mettre \u00e0 jour le message PayablePar\r\n            mettreAJourMessagePayablePar();\r\n            \r\n            \/\/ \u2705 v1.9 : Scroll vers ChoisirPaiementTitre\r\n            \/* ============================================================\r\n             * pb1636 : UNE SELECTION VIDE FAIT LEVER LA LECTURE DE LA POSITION.\r\n             *   Log user : \u00ab Uncaught TypeError: Cannot read properties of undefined\r\n             *   (reading 'top') at ouvrirEtapePaiement \u00bb. jQuery rend undefined quand la\r\n             *   selection ne trouve rien, et la lecture qui suit leve.\r\n             *   Deux corrections, appliquees aux DEUX defilements de ce fichier :\r\n             *     - verifier que l'element existe avant de lire sa position ;\r\n             *     - en mode popup, ne pas faire defiler html\/body \u2014 ce sont ceux de\r\n             *       l'iframe, pas du popup : le defilement visait le mauvais conteneur.\r\n             *       On amene l'element dans sa propre vue.\r\n             *   Revert : window._viaPb1636Off = true.\r\n             * ============================================================ *\/\r\n            (function () {\r\n                var _e1636 = document.querySelector('#ChoisirPaiementTitre');\r\n                if (!_e1636) {\r\n                    console.warn('[pb1636] #ChoisirPaiementTitre absent \u2014 defilement ignore');\r\n                    return;\r\n                }\r\n                var _pop1636 = false;\r\n                try {\r\n                    _pop1636 = (window._viaPb1636Off !== true)\r\n                        ? (new URLSearchParams(window.location.hash.substring(1)\r\n                            || window.location.search).get('mode') === 'popup')\r\n                        : false;\r\n                } catch (_eP) { _pop1636 = false; }\r\n                if (_pop1636) {\r\n                    try { _e1636.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); }\r\n                    catch (_eS) { _e1636.scrollIntoView(); }\r\n                    return;\r\n                }\r\n                var _o1636 = $('#ChoisirPaiementTitre').offset();\r\n                if (!_o1636) { return; }\r\n                $('html, body').animate({ scrollTop: _o1636.top - 100 }, 500);\r\n            })();\r\n        }\r\n        \r\n        \/**\r\n         * Initialise les donn\u00e9es de paiement\r\n         * \u2705 CORRECTION : Paiement obligatoire en EUR si soumis \u00e0 TVA\r\n         *\/\r\n        function initialiserDonneesPaiement() {\r\n            \/\/ \u2705 CALCULER LE MONTANT TOTAL DE TOUTES LES COMMANDES\r\n            if (!window.VIA_Panier || !window.VIA_Panier.state.items) {\r\n                console.error('\u274c Panier non disponible');\r\n                return;\r\n            }\r\n            \r\n            \/\/ Filtrer les commandes avec tarif\r\n            const itemsAvecTarif = window.VIA_Panier.state.items.filter(item => \r\n                item.tarifHT && item.tarifHT > 0\r\n            );\r\n            \r\n            if (itemsAvecTarif.length === 0) {\r\n                console.error('\u274c Aucune commande avec tarif');\r\n                return;\r\n            }\r\n            \r\n            \/\/ Calculer le total HT de toutes les commandes\r\n            let totalHT = 0;\r\n            itemsAvecTarif.forEach(item => {\r\n                totalHT += item.tarifHT;\r\n            });\r\n            \r\n            console.log('\ud83d\udcb0 Total HT de toutes les commandes:', totalHT);\r\n            \r\n            \/\/ R\u00e9cup\u00e9rer la zone TVA et les donn\u00e9es annonceur\r\n            const zoneTVA = sessionStorage.getItem('ZoneTVA');\r\n            const donnees = JSON.parse(sessionStorage.getItem('via_annonceur_data') || '{}');\r\n            const clientAssujettiTVA = sessionStorage.getItem('ClientAssujettiTVA'); \/\/ \u2705 v1.6 : Champ radio ChoixTVA\r\n            \r\n            \/\/ D\u00e9terminer si on est en HT ou TTC\r\n            let estHT = false;\r\n            let tauxTVA = 0;\r\n            \r\n            console.log('\ud83d\udcb6 Donn\u00e9es TVA:', { zoneTVA, clientAssujettiTVA, numeroTVA: donnees.numeroTVA });\r\n            \r\n            if (zoneTVA === 'HorsEU') {\r\n                \/\/ Hors UE : pas de TVA\r\n                estHT = true;\r\n                tauxTVA = 0;\r\n                console.log('\ud83c\udf0d Hors UE : pas de TVA');\r\n            } else if (zoneTVA === 'EU') {\r\n                \/\/ \u2705 v1.6 : EU (hors France) - bas\u00e9 sur ClientAssujettiTVA (d\u00e9fini par pr\u00e9sence N\u00b0 TVA)\r\n                \/\/ Pas de N\u00b0 TVA \u2192 ClientAssujettiTVA = 'Yes' \u2192 TVA appliqu\u00e9e\r\n                \/\/ N\u00b0 TVA saisi \u2192 ClientAssujettiTVA = 'No' \u2192 pas de TVA\r\n                if (clientAssujettiTVA === 'Yes') {\r\n                    \/\/ Pas de N\u00b0 TVA \u2192 TVA appliqu\u00e9e\r\n                    estHT = false;\r\n                    tauxTVA = 20;\r\n                    console.log('\ud83c\uddea\ud83c\uddfa UE sans n\u00b0 TVA : TVA appliqu\u00e9e (TTC)');\r\n                } else {\r\n                    \/\/ N\u00b0 TVA saisi \u2192 pas de TVA\r\n                    estHT = true;\r\n                    tauxTVA = 0;\r\n                    console.log('\ud83c\uddea\ud83c\uddfa UE avec n\u00b0 TVA : pas de TVA (HT)');\r\n                }\r\n            } else if (zoneTVA === 'FR' && donnees.numeroTVA === 'Non assujetti \u00e0 la TVA') {\r\n                \/\/ France non assujetti : pas de TVA\r\n                estHT = true;\r\n                tauxTVA = 0;\r\n                console.log('\ud83c\uddeb\ud83c\uddf7 France non assujetti : pas de TVA');\r\n            } else if (window._viaPb2166Off === true ? false : !zoneTVA) {\r\n                \/* ============================================================\r\n                 * pb2166 : ZONE TVA INCONNUE N EST PAS \u00ab FRANCE \u00bb.\r\n                 *   Releve JF : annonceur FIDJI, et pourtant\r\n                 *   \u00ab Donnees TVA: {zoneTVA: null, clientAssujettiTVA: null} \u00bb\r\n                 *   puis \u00ab France : TVA appliquee \u00bb -> 20 % et devise forcee en\r\n                 *   EUR, ecrasant le GBP choisi jusque dans la carte de\r\n                 *   reservation.\r\n                 *   Le \u00ab else \u00bb final traitait DEUX cas distincts comme un seul :\r\n                 *   \u00ab la France \u00bb et \u00ab on ne sait pas encore \u00bb. Tant que la zone\r\n                 *   n est pas resolue, rien ne justifie d imposer le regime\r\n                 *   francais NI de forcer la devise \u2014 l annonceur peut etre hors\r\n                 *   UE, comme ici.\r\n                 *   On neutralise donc l etape tant que la zone est inconnue :\r\n                 *   HT, pas de taux, pas de forcage de devise (le forcage est\r\n                 *   conditionne a !estHT plus bas). Des que ZoneTVA est posee, le\r\n                 *   regime normal s applique, France comprise.\r\n                 *   Revert : window._viaPb2166Off = true (ancien comportement).\r\n                 * ============================================================ *\/\r\n                estHT = true;\r\n                tauxTVA = 0;\r\n                console.warn('[pb2166] ZoneTVA absente -> regime SUSPENDU (ni TVA, ni forcage EUR)'\r\n                    + ' | clientAssujettiTVA=' + (clientAssujettiTVA || '(absent)')\r\n                    + ' | numeroTVA=' + (donnees.numeroTVA || '(absent)')\r\n                    + ' | pays annonceur=' + (donnees.pays || sessionStorage.getItem('NationaliteDataVosCampagnes') || '(inconnu)'));\r\n            } else {\r\n                \/\/ France ou autre cas : TVA fran\u00e7aise obligatoire\r\n                estHT = false;\r\n                tauxTVA = 20;\r\n                console.log('\ud83c\uddeb\ud83c\uddf7 France : TVA appliqu\u00e9e');\r\n            }\r\n            \r\n            PAIEMENT_STATE.estHT = estHT;\r\n            \r\n            \/\/ Calculer le montant TTC si n\u00e9cessaire\r\n            let montantTotal = totalHT;\r\n            if (!estHT) {\r\n                montantTotal = totalHT * (1 + tauxTVA \/ 100);\r\n            }\r\n            \r\n            console.log('\ud83d\udcb6 Calcul:', {\r\n                totalHT: totalHT,\r\n                tauxTVA: tauxTVA,\r\n                montantTotal: montantTotal,\r\n                estHT: estHT\r\n            });\r\n            \r\n            \/\/ \u2705 R\u00c8GLE : Si soumis \u00e0 TVA, paiement OBLIGATOIRE en EUR\r\n            if (tauxTVA !== 0) {\r\n                console.log('\ud83d\udd12 Client soumis \u00e0 TVA : paiement obligatoire en EUR');\r\n                \r\n                \/\/ Forcer la devise \u00e0 EUR\r\n                PAIEMENT_STATE.devise = 'EUR';\r\n                PAIEMENT_STATE.montantTotal = montantTotal;\r\n                \r\n                \/\/ Masquer le s\u00e9lecteur de devise\r\n                $('.ChoisirDeviseConteneur').hide();\r\n                \r\n                \/\/ \u2705 Mettre \u00e0 jour la devise globale et dans le formulaire\r\n                if (window.VIA_App?.state?.deviseActuelle !== 'EUR') {\r\n                    const ancienneDevise = window.VIA_App.state.deviseActuelle;\r\n                    window.VIA_App.state.deviseActuelle = 'EUR';\r\n                    \r\n                    \/\/ Mettre \u00e0 jour le s\u00e9lecteur de devise principal\r\n                    $('#form-field-selected_currency_visuels').val('EUR');\r\n                    \r\n                    console.log(`\ud83d\udcb1 Devise globale forc\u00e9e: ${ancienneDevise} \u2192 EUR`);\r\n                    \r\n                    \/\/ \u2705 Reconvertir TOUS les montants du panier en EUR\r\n                    if (window.VIA_Panier) {\r\n                        window.VIA_Panier.state.deviseAffichage = 'EUR';\r\n                        \r\n                        \/\/ Rafra\u00eechir l'affichage de tous les items\r\n                        window.VIA_Panier.state.items.forEach(item => {\r\n                            if (item.tarifHT) {\r\n                                window.VIA_Panier.rafraichirItemHTML(item.id);\r\n                                \r\n                                \/\/ \u2705 Mettre \u00e0 jour aussi .TarifClosedClass (mode r\u00e9duit)\r\n                                const $item = $(`#${item.id}`);\r\n                                const tarifComplet = $item.find('.CampagneTarifClass').text();\r\n                                const tarifResume = window.VIA_Panier.extraireTarifResume(tarifComplet);\r\n                                $item.find('.TarifClosedClass').html(tarifResume);\r\n                            }\r\n                        });\r\n                        \r\n                        \/\/ Mettre \u00e0 jour le total\r\n                        window.VIA_Panier.afficherTotal('EUR');\r\n                        \r\n                        console.log('\u2705 Tous les montants reconvertis en EUR (y compris TarifClosedClass)');\r\n                    }\r\n                }\r\n            } else {\r\n                \/\/ Client HT : devise libre\r\n                PAIEMENT_STATE.devise = window.VIA_App?.state?.deviseActuelle || 'EUR';\r\n                \r\n                \/\/ Convertir dans la devise si n\u00e9cessaire\r\n                if (PAIEMENT_STATE.devise !== 'EUR' && window.VIA_App) {\r\n                    PAIEMENT_STATE.montantTotal = window.VIA_App.convertirDevise(\r\n                        montantTotal,\r\n                        'EUR',\r\n                        PAIEMENT_STATE.devise\r\n                    );\r\n                } else {\r\n                    PAIEMENT_STATE.montantTotal = montantTotal;\r\n                }\r\n                \r\n                \/\/ G\u00e9rer l'affichage du s\u00e9lecteur de devise\r\n                if (PAIEMENT_STATE.estHT) {\r\n                    $('.ChoisirDeviseConteneur').show();\r\n                    $('#form-field-selected_currency_2').val(PAIEMENT_STATE.devise);\r\n                } else {\r\n                    $('.ChoisirDeviseConteneur').hide();\r\n                }\r\n            }\r\n            \r\n            \/\/ R\u00e9cup\u00e9rer la date de fin\r\n            PAIEMENT_STATE.dateFin = window.VIA_Elementor?.state?.endDate;\r\n            \r\n            console.log('\ud83d\udcb3 Donn\u00e9es paiement initialis\u00e9es:', {\r\n                montantTotal: PAIEMENT_STATE.montantTotal,\r\n                devise: PAIEMENT_STATE.devise,\r\n                estHT: PAIEMENT_STATE.estHT,\r\n                nbCommandes: itemsAvecTarif.length,\r\n                tauxTVA: tauxTVA\r\n            });\r\n        }\r\n        \r\n        \/**\r\n         * Calcule le nombre d'\u00e9ch\u00e9ances maximum pour CB\r\n         * R\u00e8gle : hebdomadaire (J, J+7, J+14...), max 8, derni\u00e8re \u00e9ch\u00e9ance 1 semaine avant fin\r\n         *\/\r\n        function calculerEcheancesCB() {\r\n            if (!PAIEMENT_STATE.dateFin) {\r\n                PAIEMENT_STATE.nbEcheancesMaxCB = 1;\r\n                return;\r\n            }\r\n            \r\n            const aujourd_hui = new Date();\r\n            aujourd_hui.setHours(0, 0, 0, 0);\r\n            \r\n            const dateFin = new Date(PAIEMENT_STATE.dateFin);\r\n            const uneSemanneAvantFin = new Date(dateFin);\r\n            uneSemanneAvantFin.setDate(uneSemanneAvantFin.getDate() - 7);\r\n            \r\n            \/\/ Calculer le nombre de semaines disponibles\r\n            const diffTime = uneSemanneAvantFin - aujourd_hui;\r\n            const nbSemaines = Math.floor(diffTime \/ (7 * 24 * 60 * 60 * 1000));\r\n            \r\n            \/\/ Maximum 8 \u00e9ch\u00e9ances\r\n            PAIEMENT_STATE.nbEcheancesMaxCB = Math.min(Math.max(1, nbSemaines), 8);\r\n            \r\n            console.log('\ud83d\udcc5 Nombre d\\'\u00e9ch\u00e9ances max CB:', PAIEMENT_STATE.nbEcheancesMaxCB);\r\n            \r\n            \/\/ G\u00e9n\u00e9rer les options du select CB\r\n            const $selectCB = $('#form-field-nb_echeancesCB');\r\n            $selectCB.empty();\r\n            \r\n            for (let i = 1; i <= PAIEMENT_STATE.nbEcheancesMaxCB; i++) {\r\n                $selectCB.append(`<option value=\"${i}\">${i}<\/option>`);\r\n            }\r\n            \r\n            PAIEMENT_STATE.nbEcheancesSelectionneesCB = 1;\r\n        }\r\n        \r\n        \/**\r\n         * Calcule le nombre d'\u00e9ch\u00e9ances maximum pour Virement\r\n         * R\u00e8gle : J, J+7, J+14 (max 3), derni\u00e8re \u00e9ch\u00e9ance 1 semaine avant fin\r\n         *\/\r\n        function calculerEcheancesVirement() {\r\n            if (!PAIEMENT_STATE.dateFin) {\r\n                PAIEMENT_STATE.nbEcheancesMaxVir = 1;\r\n                genererSelectEcheancesVir();\r\n                return;\r\n            }\r\n            \r\n            const aujourd_hui = new Date();\r\n            aujourd_hui.setHours(0, 0, 0, 0);\r\n            \r\n            const dateFin = new Date(PAIEMENT_STATE.dateFin);\r\n            const uneSemanneAvantFin = new Date(dateFin);\r\n            uneSemanneAvantFin.setDate(uneSemanneAvantFin.getDate() - 7);\r\n            \r\n            \/\/ Dates des \u00e9ch\u00e9ances virement : J, J+7, J+14\r\n            const joursEcheancesVir = [0, 7, 14];\r\n            \r\n            let nbEcheancesPossibles = 0;\r\n            \r\n            for (let i = 0; i < joursEcheancesVir.length; i++) {\r\n                const dateEcheance = new Date(aujourd_hui);\r\n                dateEcheance.setDate(dateEcheance.getDate() + joursEcheancesVir[i]);\r\n                \r\n                \/\/ V\u00e9rifier si cette \u00e9ch\u00e9ance est au moins 1 semaine avant la fin\r\n                if (dateEcheance <= uneSemanneAvantFin) {\r\n                    nbEcheancesPossibles++;\r\n                } else {\r\n                    break; \/\/ Les \u00e9ch\u00e9ances suivantes seront aussi invalides\r\n                }\r\n            }\r\n            \r\n            \/\/ Minimum 1, maximum 3 \u00e9ch\u00e9ances\r\n            PAIEMENT_STATE.nbEcheancesMaxVir = Math.max(1, nbEcheancesPossibles);\r\n            \r\n            console.log('\ud83d\udcc5 Nombre d\\'\u00e9ch\u00e9ances max Virement:', PAIEMENT_STATE.nbEcheancesMaxVir);\r\n            \r\n            \/\/ G\u00e9n\u00e9rer les options du select Virement\r\n            genererSelectEcheancesVir();\r\n            \r\n            PAIEMENT_STATE.nbEcheancesSelectionneesVir = 1;\r\n            PAIEMENT_STATE.selectionManuelleVir = false; \/\/ \u2705 Reset du flag \u00e0 chaque ouverture\r\n        }\r\n        \r\n        \/**\r\n         * G\u00e9n\u00e8re le select des \u00e9ch\u00e9ances virement\r\n         *\/\r\n        function genererSelectEcheancesVir() {\r\n            const $selectVir = $('#form-field-nb_echeancesVir');\r\n            $selectVir.empty();\r\n            \r\n            for (let i = 1; i <= PAIEMENT_STATE.nbEcheancesMaxVir; i++) {\r\n                $selectVir.append(`<option value=\"${i}\">${i}<\/option>`);\r\n            }\r\n            \r\n            \/\/ Afficher le bloc \u00e9ch\u00e9ancier\r\n            $('.EcheancierVir').show();\r\n            $('#EcheanceActiveWithInputVir').show();\r\n        }\r\n        \r\n        \/**\r\n         * Affiche les montants\r\n         *\/\r\n        function afficherMontants() {\r\n            \/\/ \u2705 R\u00e9cup\u00e9rer la langue\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            const montantFormate = window.VIA_App.formaterMontant(\r\n                PAIEMENT_STATE.montantTotal,\r\n                PAIEMENT_STATE.devise\r\n            );\r\n            \r\n            \/\/ \u2705 Traduction H.T. \/ T.T.C.\r\n            const suffixe = PAIEMENT_STATE.estHT \r\n                ? (lang === 'EN' ? 'excl. VAT' : 'H.T.')\r\n                : (lang === 'EN' ? 'incl. VAT' : 'T.T.C.');\r\n            \r\n            \/\/ Montant total\r\n            $('#MontantARegler').html(`${montantFormate} ${suffixe}`);\r\n            \r\n            console.log('\ud83d\udcb0 Montants affich\u00e9s');\r\n        }\r\n        \r\n        \/**\r\n         * Met \u00e0 jour le message PayablePar dynamiquement\r\n         * Format : \"Payable soit par virement en Y \u00e9ch\u00e9ance(s) de XXX \u20ac, soit par CB en X \u00e9ch\u00e9ance(s) de WWW \u20ac\"\r\n         *\/\r\n        function mettreAJourMessagePayablePar() {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            \/\/ Calculer les montants par \u00e9ch\u00e9ance pour chaque mode\r\n            const montantEcheanceCB = PAIEMENT_STATE.montantTotal \/ PAIEMENT_STATE.nbEcheancesMaxCB;\r\n            const montantEcheanceVir = PAIEMENT_STATE.montantTotal \/ PAIEMENT_STATE.nbEcheancesMaxVir;\r\n            \r\n            const montantCBFormate = window.VIA_App.formaterMontant(montantEcheanceCB, PAIEMENT_STATE.devise);\r\n            const montantVirFormate = window.VIA_App.formaterMontant(montantEcheanceVir, PAIEMENT_STATE.devise);\r\n            \r\n            let messagePayable;\r\n            \r\n            \/\/ Cas o\u00f9 les deux modes n'ont qu'une seule \u00e9ch\u00e9ance\r\n            if (PAIEMENT_STATE.nbEcheancesMaxVir === 1 && PAIEMENT_STATE.nbEcheancesMaxCB === 1) {\r\n                messagePayable = lang === 'EN'\r\n                    ? `Payable by bank transfer or credit card in 1 installment`\r\n                    : `Payable par virement ou par CB en 1 \u00e9ch\u00e9ance`;\r\n            }\r\n            \/\/ Virement 1 \u00e9ch\u00e9ance, CB plusieurs\r\n            else if (PAIEMENT_STATE.nbEcheancesMaxVir === 1) {\r\n                const labelCB = lang === 'EN' ? 'installments' : '\u00e9ch\u00e9ances';\r\n                messagePayable = lang === 'EN'\r\n                    ? `Payable by bank transfer in 1 installment,<br>or by credit card up to ${PAIEMENT_STATE.nbEcheancesMaxCB} ${labelCB} of ${montantCBFormate}`\r\n                    : `Payable par virement en 1 \u00e9ch\u00e9ance,<br>ou par CB jusqu'\u00e0 ${PAIEMENT_STATE.nbEcheancesMaxCB} ${labelCB} de ${montantCBFormate}`;\r\n            }\r\n            \/\/ Les deux modes avec plusieurs \u00e9ch\u00e9ances\r\n            else {\r\n                const labelVir = lang === 'EN' \r\n                    ? (PAIEMENT_STATE.nbEcheancesMaxVir > 1 ? 'installments' : 'installment')\r\n                    : (PAIEMENT_STATE.nbEcheancesMaxVir > 1 ? '\u00e9ch\u00e9ances' : '\u00e9ch\u00e9ance');\r\n                const labelCB = lang === 'EN' \r\n                    ? (PAIEMENT_STATE.nbEcheancesMaxCB > 1 ? 'installments' : 'installment')\r\n                    : (PAIEMENT_STATE.nbEcheancesMaxCB > 1 ? '\u00e9ch\u00e9ances' : '\u00e9ch\u00e9ance');\r\n                \r\n                messagePayable = lang === 'EN'\r\n                    ? `Payable by bank transfer up to ${PAIEMENT_STATE.nbEcheancesMaxVir} ${labelVir} of ${montantVirFormate},<br>or by credit card up to ${PAIEMENT_STATE.nbEcheancesMaxCB} ${labelCB} of ${montantCBFormate}`\r\n                    : `Payable par virement jusqu'\u00e0 ${PAIEMENT_STATE.nbEcheancesMaxVir} ${labelVir} de ${montantVirFormate},<br>ou par CB jusqu'\u00e0 ${PAIEMENT_STATE.nbEcheancesMaxCB} ${labelCB} de ${montantCBFormate}`;\r\n            }\r\n            \r\n            $('#PayableParMsg').html(messagePayable);\r\n            \r\n            console.log('\ud83d\udcdd Message PayablePar mis \u00e0 jour');\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 v1.6 : Met \u00e0 jour le message #PaiementMsg avec la nouvelle devise\r\n         * Appel\u00e9 lors du changement de devise\r\n         *\/\r\n        function mettreAJourPaiementMsg() {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const refCommande = sessionStorage.getItem('commande_ref') || 'N\/A';\r\n            const montantFormate = window.VIA_App.formaterMontant(PAIEMENT_STATE.montantTotal, PAIEMENT_STATE.devise);\r\n            \r\n            \/\/ D\u00e9terminer le mode de paiement actuel\r\n            const modePaiement = sessionStorage.getItem('ModePaiement') || 'virement';\r\n            \r\n            let msgPaiement;\r\n            \r\n            if (modePaiement === 'virement') {\r\n                const nbEcheances = parseInt(sessionStorage.getItem('NbEcheancesVirement') || '1');\r\n                const montantEcheance = PAIEMENT_STATE.montantTotal \/ nbEcheances;\r\n                const montantEcheanceFormate = window.VIA_App.formaterMontant(montantEcheance, PAIEMENT_STATE.devise);\r\n                \r\n                if (nbEcheances === 1) {\r\n                    msgPaiement = lang === 'EN'\r\n                        ? `Order ${refCommande} for ${montantFormate}<br>to be paid by bank transfer in 1 installment`\r\n                        : `Commande ${refCommande} d'un montant de ${montantFormate}<br>\u00e0 r\u00e9gler par virement en 1 \u00e9ch\u00e9ance`;\r\n                } else {\r\n                    msgPaiement = lang === 'EN'\r\n                        ? `Order ${refCommande} for ${montantFormate}<br>to be paid by bank transfer in ${nbEcheances} installments of ${montantEcheanceFormate}`\r\n                        : `Commande ${refCommande} d'un montant de ${montantFormate}<br>\u00e0 r\u00e9gler par virement en ${nbEcheances} \u00e9ch\u00e9ances de ${montantEcheanceFormate}`;\r\n                }\r\n            } else {\r\n                \/\/ Mode CB\r\n                const nbEcheances = parseInt(sessionStorage.getItem('NbEcheancesCB') || '1');\r\n                const montantEcheance = PAIEMENT_STATE.montantTotal \/ nbEcheances;\r\n                const montantEcheanceFormate = window.VIA_App.formaterMontant(montantEcheance, PAIEMENT_STATE.devise);\r\n                \r\n                if (nbEcheances === 1) {\r\n                    msgPaiement = lang === 'EN'\r\n                        ? `Order ${refCommande} for ${montantFormate}<br>to be paid by credit card in 1 installment`\r\n                        : `Commande ${refCommande} d'un montant de ${montantFormate}<br>\u00e0 r\u00e9gler par CB en 1 \u00e9ch\u00e9ance`;\r\n                } else {\r\n                    msgPaiement = lang === 'EN'\r\n                        ? `Order ${refCommande} for ${montantFormate}<br>to be paid by credit card in ${nbEcheances} installments of ${montantEcheanceFormate}`\r\n                        : `Commande ${refCommande} d'un montant de ${montantFormate}<br>\u00e0 r\u00e9gler par CB en ${nbEcheances} \u00e9ch\u00e9ances de ${montantEcheanceFormate}`;\r\n                }\r\n            }\r\n            \r\n            $('#PaiementMsg').html(msgPaiement);\r\n            console.log('\ud83d\udcdd Message PaiementMsg mis \u00e0 jour:', msgPaiement);\r\n        }\r\n        \r\n        \/**\r\n         * Met \u00e0 jour le montant hebdomadaire CB\r\n         * \u2705 v1.3 : Format enrichi \"N \u00e9ch\u00e9ances de xxx \u20ac TTC\"\r\n         *\/\r\n        function mettreAJourMontantHebdomadaireCB() {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const nbEcheances = PAIEMENT_STATE.nbEcheancesSelectionneesCB;\r\n            \r\n            const montantEcheance = PAIEMENT_STATE.montantTotal \/ nbEcheances;\r\n            const montantFormate = window.VIA_App.formaterMontant(montantEcheance, PAIEMENT_STATE.devise);\r\n            \r\n            const suffixe = PAIEMENT_STATE.estHT \r\n                ? (lang === 'EN' ? 'excl. VAT' : 'H.T.')\r\n                : (lang === 'EN' ? 'incl. VAT' : 'T.T.C.');\r\n            \r\n            \/\/ \u2705 v1.3 : Format enrichi \"N \u00e9ch\u00e9ance(s) de xxx \u20ac TTC\"\r\n            const labelEcheance = lang === 'EN'\r\n                ? (nbEcheances > 1 ? 'installments' : 'installment')\r\n                : (nbEcheances > 1 ? '\u00e9ch\u00e9ances' : '\u00e9ch\u00e9ance');\r\n            \r\n            let texteHebdo = lang === 'EN'\r\n                ? `${nbEcheances} ${labelEcheance} of ${montantFormate} ${suffixe}`\r\n                : `${nbEcheances} ${labelEcheance} de ${montantFormate} ${suffixe}`;\r\n            \r\n            \/\/ \u2705 Ajouter \"Dates des \u00e9ch\u00e9ances\" si plus d'une \u00e9ch\u00e9ance\r\n            if (nbEcheances > 1) {\r\n                const titreDates = lang === 'EN' ? 'Installment dates' : 'Dates des \u00e9ch\u00e9ances';\r\n                texteHebdo += `<br><strong>${titreDates}<\/strong>`;\r\n            }\r\n            \r\n            $('#MontantHebdomadaireSansFraisText .elementor-widget-container').html(`<p style=\"text-align: center;\">${texteHebdo}<\/p>`);\r\n            $('#MontantHebdomadaireSansFraisText').show();            \r\n            console.log('\ud83d\udcca Montant hebdomadaire CB mis \u00e0 jour:', texteHebdo);\r\n        }\r\n        \r\n        \/**\r\n         * Met \u00e0 jour le montant par \u00e9ch\u00e9ance Virement\r\n         * \u2705 v1.4 : Format enrichi avec plage de dates (sauf 1 \u00e9ch\u00e9ance par d\u00e9faut)\r\n         *\/\r\n        function mettreAJourMontantEcheanceVir() {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const nbEcheances = PAIEMENT_STATE.nbEcheancesSelectionneesVir;\r\n            \r\n            const montantEcheance = PAIEMENT_STATE.montantTotal \/ nbEcheances;\r\n            const montantFormate = window.VIA_App.formaterMontant(montantEcheance, PAIEMENT_STATE.devise);\r\n            \r\n            const suffixe = PAIEMENT_STATE.estHT \r\n                ? (lang === 'EN' ? 'excl. VAT' : 'H.T.')\r\n                : (lang === 'EN' ? 'incl. VAT' : 'T.T.C.');\r\n            \r\n            \/\/ \u2705 v1.3 : Format enrichi \"N \u00e9ch\u00e9ance(s) de xxx \u20ac TTC\"\r\n            const labelEcheance = lang === 'EN'\r\n                ? (nbEcheances > 1 ? 'installments' : 'installment')\r\n                : (nbEcheances > 1 ? '\u00e9ch\u00e9ances' : '\u00e9ch\u00e9ance');\r\n            \r\n            let texteEcheance = lang === 'EN'\r\n                ? `${nbEcheances} ${labelEcheance} of ${montantFormate} ${suffixe}`\r\n                : `${nbEcheances} ${labelEcheance} de ${montantFormate} ${suffixe}`;\r\n            \r\n            \/\/ \u2705 v1.4 : Ajouter \"Date(s) de l'\u00e9ch\u00e9ance\" sauf si 1 \u00e9ch\u00e9ance par d\u00e9faut\r\n            if (nbEcheances > 1 || PAIEMENT_STATE.selectionManuelleVir) {\r\n                const titreDates = lang === 'EN' \r\n                    ? (nbEcheances > 1 ? 'Installment dates' : 'Installment date')\r\n                    : (nbEcheances > 1 ? 'Dates des \u00e9ch\u00e9ances' : 'Date de l\\'\u00e9ch\u00e9ance');\r\n                texteEcheance += `<br><strong>${titreDates}<\/strong>`;\r\n            }\r\n            \r\n            $('#MontantHebdomadaireSansFraisTextVir .elementor-widget-container').html(`<p style=\"text-align: center;\">${texteEcheance}<\/p>`);\r\n            $('#MontantHebdomadaireSansFraisTextVir').show();\r\n            \r\n            console.log('\ud83d\udcca Montant \u00e9ch\u00e9ance Virement mis \u00e0 jour:', texteEcheance);\r\n        }\r\n        \r\n        \/**\r\n         * G\u00e9n\u00e8re la liste des dates d'\u00e9ch\u00e9ances CB (hebdomadaires)\r\n         * \u2705 v1.3 : Ajout titre \"Dates des \u00e9ch\u00e9ances\"\r\n         *\/\r\n        function genererListeEcheancesCB() {\r\n            const nbEcheances = PAIEMENT_STATE.nbEcheancesSelectionneesCB;\r\n            \r\n            if (nbEcheances === 1) {\r\n                $('.Echeanciertexte').html('');\r\n                $('.EcheancierContener').hide();\r\n                return;\r\n            }\r\n            \r\n            const aujourd_hui = new Date();\r\n            const dates = [];\r\n            \r\n            \/\/ CB : \u00e9ch\u00e9ances hebdomadaires (J, J+7, J+14, ...)\r\n            for (let i = 0; i < nbEcheances; i++) {\r\n                const dateEcheance = new Date(aujourd_hui);\r\n                dateEcheance.setDate(dateEcheance.getDate() + (i * 7));\r\n                \r\n                const jour = String(dateEcheance.getDate()).padStart(2, '0');\r\n                const mois = String(dateEcheance.getMonth() + 1).padStart(2, '0');\r\n                const annee = String(dateEcheance.getFullYear()).slice(-2);\r\n                \r\n                dates.push(`${jour}\/${mois}\/${annee}`);\r\n            }\r\n            \r\n            $('.Echeanciertexte').html(dates.join('<br>'));\r\n            $('.EcheancierContener').show();\r\n            \r\n            console.log('\ud83d\udcc5 Dates \u00e9ch\u00e9ances CB g\u00e9n\u00e9r\u00e9es:', dates);\r\n        }\r\n        \r\n        \/**\r\n         * G\u00e9n\u00e8re la liste des dates d'\u00e9ch\u00e9ances Virement (J, J+7, J+14)\r\n         * \u2705 v1.4 : Affichage en plage de dates (sauf 1 \u00e9ch\u00e9ance par d\u00e9faut)\r\n         *\/\r\n        function genererListeEcheancesVir() {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const nbEcheances = PAIEMENT_STATE.nbEcheancesSelectionneesVir;\r\n            \r\n            \/\/ \u2705 v1.4 : Masquer si 1 \u00e9ch\u00e9ance par d\u00e9faut (non s\u00e9lectionn\u00e9 manuellement)\r\n            if (nbEcheances === 1 && !PAIEMENT_STATE.selectionManuelleVir) {\r\n                $('.EcheanciertexteVir').html('');\r\n                $('.EcheancierContenerVir').hide();\r\n                return;\r\n            }\r\n            \r\n            const aujourd_hui = new Date();\r\n            const plages = [];\r\n            \r\n            \/\/ Virement : \u00e9ch\u00e9ances \u00e0 J, J+7, J+14, avec 1 semaine pour payer chacune\r\n            for (let i = 0; i < nbEcheances; i++) {\r\n                const dateDebut = new Date(aujourd_hui);\r\n                dateDebut.setDate(dateDebut.getDate() + (i * 7));\r\n                \r\n                const dateFin = new Date(aujourd_hui);\r\n                dateFin.setDate(dateFin.getDate() + ((i + 1) * 7));\r\n                \r\n                const jourDebut = String(dateDebut.getDate()).padStart(2, '0');\r\n                const moisDebut = String(dateDebut.getMonth() + 1).padStart(2, '0');\r\n                \r\n                const jourFin = String(dateFin.getDate()).padStart(2, '0');\r\n                const moisFin = String(dateFin.getMonth() + 1).padStart(2, '0');\r\n                const anneeFin = String(dateFin.getFullYear()).slice(-2);\r\n                \r\n                \/\/ Format : \"du 17\/01 au 24\/01\/26\"\r\n                const plage = lang === 'EN'\r\n                    ? `from ${jourDebut}\/${moisDebut} to ${jourFin}\/${moisFin}\/${anneeFin}`\r\n                    : `du ${jourDebut}\/${moisDebut} au ${jourFin}\/${moisFin}\/${anneeFin}`;\r\n                plages.push(plage);\r\n            }\r\n            \r\n            $('.EcheanciertexteVir').html(plages.join('<br>'));\r\n            $('.EcheancierContenerVir').show();\r\n            \r\n            console.log('\ud83d\udcc5 Plages \u00e9ch\u00e9ances Virement g\u00e9n\u00e9r\u00e9es:', plages);\r\n        }   \r\n        \r\n        \/**\r\n         * G\u00e8re le changement de devise\r\n         * \u26a0\ufe0f ATTENTION : D\u00e9sactiv\u00e9 si client soumis \u00e0 TVA\r\n         *\/\r\n        function initChangementDevise() {\r\n            \/\/ \u2705 v1.6 : Handler pour selected_currency_2\r\n            $('#form-field-selected_currency_2').on('change', function() {\r\n                const nouvelleDevise = $(this).val();\r\n                \r\n                \/\/ \u2705 v1.5 : V\u00e9rifier si modification autoris\u00e9e\r\n                if (!signalerModificationPaiement()) {\r\n                    \/\/ Restaurer la valeur pr\u00e9c\u00e9dente\r\n                    $(this).val(PAIEMENT_STATE.devise);\r\n                    return;\r\n                }\r\n                \r\n                console.log('\ud83d\udcb1 Changement devise:', PAIEMENT_STATE.devise, '\u2192', nouvelleDevise);\r\n                \r\n                \/\/ Convertir le montant\r\n                if (PAIEMENT_STATE.devise !== nouvelleDevise) {\r\n                    const montantConverti = window.VIA_App.convertirDevise(\r\n                        PAIEMENT_STATE.montantTotal,\r\n                        PAIEMENT_STATE.devise,\r\n                        nouvelleDevise\r\n                    );\r\n                    \r\n                    PAIEMENT_STATE.montantTotal = montantConverti;\r\n                    PAIEMENT_STATE.devise = nouvelleDevise;\r\n                    \r\n                    \/\/ \u2705 v1.6 : Stocker la devise dans sessionStorage\r\n                    sessionStorage.setItem('selected_currency', nouvelleDevise);\r\n                    \r\n                    \/\/ Mettre \u00e0 jour tous les affichages\r\n                    afficherMontants();\r\n                    mettreAJourMessagePayablePar();\r\n                    mettreAJourMontantHebdomadaireCB();\r\n                    mettreAJourMontantEcheanceVir();\r\n                    \r\n                    \/\/ \u2705 v1.6 : Mettre \u00e0 jour #PaiementMsg\r\n                    mettreAJourPaiementMsg();\r\n                    \r\n                    \/\/ \u2705 v1.6 : Mettre \u00e0 jour #DeviseModedePaiementMsg\r\n                    mettreAJourDeviseModedePaiementMsg();\r\n                    \r\n                    \/\/ \u2705 v1.6 : Mettre \u00e0 jour #Tariftobedisplayed\r\n                    mettreAJourTariftobedisplayed(nouvelleDevise);\r\n                    \r\n                    \/\/ \u2705 Mettre \u00e0 jour les montants dans le r\u00e9capitulatif des commandes\r\n                    if (window.VIA_Panier) {\r\n                        window.VIA_Panier.state.deviseAffichage = nouvelleDevise;\r\n                        \r\n                        \/\/ Rafra\u00eechir l'affichage de tous les items\r\n                        window.VIA_Panier.state.items.forEach(item => {\r\n                            if (item.tarifHT) {\r\n                                window.VIA_Panier.rafraichirItemHTML(item.id);\r\n                                \r\n                                const $item = $(`#${item.id}`);\r\n                                const tarifComplet = $item.find('.CampagneTarifClass').text();\r\n                                const tarifResume = window.VIA_Panier.extraireTarifResume(tarifComplet);\r\n                                $item.find('.TarifClosedClass').html(tarifResume);\r\n                            }\r\n                        });\r\n                        \r\n                        window.VIA_Panier.afficherTotal(nouvelleDevise);\r\n                        \r\n                        console.log('\u2705 Montants du r\u00e9capitulatif mis \u00e0 jour en', nouvelleDevise);\r\n                    }\r\n                    \r\n                    \/\/ \u2705 v1.6 : Synchroniser selected_currency_visuels\r\n                    $('#form-field-selected_currency_visuels').val(nouvelleDevise);\r\n                }\r\n            });\r\n            \r\n            \/\/ \u2705 v1.6 : Handler pour selected_currency_visuels\r\n            $('#form-field-selected_currency_visuels').on('change', function() {\r\n                const nouvelleDevise = $(this).val();\r\n                \r\n                \/\/ Synchroniser avec selected_currency_2 et d\u00e9clencher le changement\r\n                $('#form-field-selected_currency_2').val(nouvelleDevise).trigger('change');\r\n            });\r\n            \r\n            console.log('\u2705 Changement devise initialis\u00e9');\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 v1.6 : Met \u00e0 jour #DeviseModedePaiementMsg avec la nouvelle devise\r\n         *\/\r\n        function mettreAJourDeviseModedePaiementMsg() {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const montantFormate = window.VIA_App.formaterMontant(PAIEMENT_STATE.montantTotal, PAIEMENT_STATE.devise);\r\n            \r\n            const suffixe = PAIEMENT_STATE.estHT \r\n                ? (lang === 'EN' ? 'excl. VAT' : 'H.T.')\r\n                : (lang === 'EN' ? 'incl. VAT' : 'T.T.C.');\r\n            \r\n            let messagePaiement;\r\n            \r\n            if (PAIEMENT_STATE.modePaiement === 'CB') {\r\n                const nbEcheances = PAIEMENT_STATE.nbEcheancesSelectionneesCB || 1;\r\n                \r\n                if (nbEcheances === 1) {\r\n                    messagePaiement = lang === 'EN'\r\n                        ? `Payment ${montantFormate} ${suffixe} by credit card in 1 installment`\r\n                        : `Paiement ${montantFormate} ${suffixe} par carte bancaire en 1 \u00e9ch\u00e9ance`;\r\n                } else {\r\n                    const montantEcheance = PAIEMENT_STATE.montantTotal \/ nbEcheances;\r\n                    const montantEcheanceFormate = window.VIA_App.formaterMontant(montantEcheance, PAIEMENT_STATE.devise);\r\n                    const labelEcheances = lang === 'EN' ? 'installments' : '\u00e9ch\u00e9ances';\r\n                    \r\n                    messagePaiement = lang === 'EN'\r\n                        ? `Payment ${montantFormate} ${suffixe} by credit card in ${nbEcheances} weekly ${labelEcheances}<br>of ${montantEcheanceFormate}`\r\n                        : `Paiement ${montantFormate} ${suffixe} par carte bancaire<br>en ${nbEcheances} ${labelEcheances} hebdomadaires de ${montantEcheanceFormate}`;\r\n                }\r\n            } else {\r\n                \/\/ Virement\r\n                const nbEcheances = PAIEMENT_STATE.nbEcheancesSelectionneesVir || 1;\r\n                \r\n                if (nbEcheances === 1) {\r\n                    messagePaiement = lang === 'EN'\r\n                        ? `Payment ${montantFormate} ${suffixe} by bank transfer in 1 installment`\r\n                        : `Paiement ${montantFormate} ${suffixe} par virement en 1 \u00e9ch\u00e9ance`;\r\n                } else {\r\n                    const montantEcheance = PAIEMENT_STATE.montantTotal \/ nbEcheances;\r\n                    const montantEcheanceFormate = window.VIA_App.formaterMontant(montantEcheance, PAIEMENT_STATE.devise);\r\n                    const labelEcheances = lang === 'EN' ? '\u00e9ch\u00e9ances' : '\u00e9ch\u00e9ances';\r\n                    \r\n                    messagePaiement = lang === 'EN'\r\n                        ? `Payment ${montantFormate} ${suffixe} by bank transfer<br>in ${nbEcheances} installments of ${montantEcheanceFormate}`\r\n                        : `Paiement ${montantFormate} ${suffixe} par virement<br>en ${nbEcheances} ${labelEcheances} de ${montantEcheanceFormate}`;\r\n                }\r\n            }\r\n            \r\n            $('#DeviseModedePaiementMsg').html(messagePaiement);\r\n            console.log('\ud83d\udcdd #DeviseModedePaiementMsg mis \u00e0 jour:', messagePaiement);\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 v1.6 : Met \u00e0 jour #Tariftobedisplayed avec la nouvelle devise\r\n         *\/\r\n        function mettreAJourTariftobedisplayed(devise) {\r\n            if (!window.VIA_Panier || !window.VIA_Panier.state.items.length) {\r\n                return;\r\n            }\r\n            \r\n            \/\/ Prendre l'item actif ou le premier item\r\n            const item = window.VIA_Panier.state.itemActif \r\n                ? window.VIA_Panier.state.items.find(i => i.id === window.VIA_Panier.state.itemActif)\r\n                : window.VIA_Panier.state.items[0];\r\n            \r\n            if (!item || !item.tarifHT) {\r\n                return;\r\n            }\r\n            \r\n            let montant = item.tarifHT;\r\n            \r\n            if (window.VIA_App && window.VIA_App.convertirDevise && devise !== 'EUR') {\r\n                montant = window.VIA_App.convertirDevise(montant, 'EUR', devise);\r\n            }\r\n            \r\n            const tarifFormate = window.VIA_App && window.VIA_App.formaterMontant \r\n                ? window.VIA_App.formaterMontant(montant, devise, 2)\r\n                : montant.toFixed(2) + ' ' + devise;\r\n            \r\n            $('#Tariftobedisplayed').html(tarifFormate).css('color', '#225DA9');\r\n            console.log('\ud83d\udcdd #Tariftobedisplayed mis \u00e0 jour:', tarifFormate);\r\n        }\r\n        \r\n        \/**\r\n         * G\u00e8re le changement du nombre d'\u00e9ch\u00e9ances CB\r\n         *\/\r\n        function initChangementEcheancesCB() {\r\n            $('#form-field-nb_echeancesCB').on('change', function() {\r\n                \/\/ \u2705 v1.5 : V\u00e9rifier si modification autoris\u00e9e\r\n                if (!signalerModificationPaiement()) {\r\n                    \/\/ Restaurer la valeur pr\u00e9c\u00e9dente\r\n                    $(this).val(PAIEMENT_STATE.nbEcheancesSelectionneesCB);\r\n                    return;\r\n                }\r\n                \r\n                PAIEMENT_STATE.nbEcheancesSelectionneesCB = parseInt($(this).val());\r\n                \r\n                console.log('\ud83d\udcca Nombre \u00e9ch\u00e9ances CB s\u00e9lectionn\u00e9:', PAIEMENT_STATE.nbEcheancesSelectionneesCB);\r\n                \r\n                mettreAJourMontantHebdomadaireCB();\r\n                genererListeEcheancesCB();\r\n            });\r\n            \r\n            console.log('\u2705 Changement \u00e9ch\u00e9ances CB initialis\u00e9');\r\n        }\r\n        \r\n        \/**\r\n         * G\u00e8re le changement du nombre d'\u00e9ch\u00e9ances Virement\r\n         *\/\r\n        function initChangementEcheancesVir() {\r\n            $('#form-field-nb_echeancesVir').on('change', function() {\r\n                \/\/ \u2705 v1.5 : V\u00e9rifier si modification autoris\u00e9e\r\n                if (!signalerModificationPaiement()) {\r\n                    \/\/ Restaurer la valeur pr\u00e9c\u00e9dente\r\n                    $(this).val(PAIEMENT_STATE.nbEcheancesSelectionneesVir);\r\n                    return;\r\n                }\r\n                \r\n                PAIEMENT_STATE.nbEcheancesSelectionneesVir = parseInt($(this).val());\r\n                PAIEMENT_STATE.selectionManuelleVir = true; \/\/ \u2705 L'utilisateur a chang\u00e9 manuellement\r\n                \r\n                console.log('\ud83d\udcca Nombre \u00e9ch\u00e9ances Virement s\u00e9lectionn\u00e9:', PAIEMENT_STATE.nbEcheancesSelectionneesVir);\r\n                \r\n                mettreAJourMontantEcheanceVir();\r\n                genererListeEcheancesVir();\r\n            });\r\n            \r\n            console.log('\u2705 Changement \u00e9ch\u00e9ances Virement initialis\u00e9');\r\n        }\r\n        \r\n        \/**\r\n         * G\u00e8re les boutons de paiement\r\n         *\/\r\n        function initBoutonsPaiement() {\r\n            $('#MsgAlerteModedePaiementTexte').hide();\r\n            \r\n            \/\/ Paiement par CB\r\n            $('#PaiementparCBBouton').on('click', async function(e) {\r\n                e.preventDefault();\r\n                \r\n                PAIEMENT_STATE.modePaiement = 'CB';\r\n                \r\n                sessionStorage.setItem('mode_paiement', 'CB');\r\n                sessionStorage.setItem('nb_echeances', PAIEMENT_STATE.nbEcheancesSelectionneesCB);\r\n                sessionStorage.setItem('montant_total', PAIEMENT_STATE.montantTotal);\r\n                sessionStorage.setItem('devise_paiement', PAIEMENT_STATE.devise);\r\n                \r\n                console.log('\ud83d\udcb3 Paiement par CB s\u00e9lectionn\u00e9');\r\n                console.log('\ud83d\udcca \u00c9ch\u00e9ances CB:', PAIEMENT_STATE.nbEcheancesSelectionneesCB);\r\n                \r\n                \/\/ \u2705 V\u00c9RIFIER SI UN COMMERCIAL EST CONNECT\u00c9\r\n                if (sessionStorage.getItem('CommercialConnected') === 'Yes') {\r\n                    console.log('\ud83d\udc54 Mode commercial : cr\u00e9ation commande puis envoi email au client');\r\n                    \r\n                    setTimeout(() => {\r\n                        $('#MsgAlerteModedePaiementConteneur').show();\r\n                        $(\".CampagneTarifContainer\").hide();\r\n                    }, 500);\r\n                    \r\n                    await envoyerEmailBonDeCommandeClient('CB');\r\n                } else {\r\n                    passerEtapeSuivante();\r\n                }\r\n            });\r\n            \r\n            \/\/ Paiement par Virement\r\n            $('#PaiementparVirBouton').on('click', async function(e) {\r\n                e.preventDefault();\r\n                \r\n                PAIEMENT_STATE.modePaiement = 'Virement';\r\n                \r\n                sessionStorage.setItem('mode_paiement', 'Virement');\r\n                sessionStorage.setItem('nb_echeances', PAIEMENT_STATE.nbEcheancesSelectionneesVir);\r\n                sessionStorage.setItem('montant_total', PAIEMENT_STATE.montantTotal);\r\n                sessionStorage.setItem('devise_paiement', PAIEMENT_STATE.devise);\r\n                \r\n                console.log('\ud83c\udfe6 Paiement par Virement s\u00e9lectionn\u00e9');\r\n                console.log('\ud83d\udcca \u00c9ch\u00e9ances Virement:', PAIEMENT_STATE.nbEcheancesSelectionneesVir);\r\n                \r\n                \/\/ \u2705 V\u00c9RIFIER SI UN COMMERCIAL EST CONNECT\u00c9\r\n                if (sessionStorage.getItem('CommercialConnected') === 'Yes') {\r\n                    console.log('\ud83d\udc54 Mode commercial : cr\u00e9ation commande puis envoi email au client');\r\n                    \r\n                    setTimeout(() => {\r\n                        $('#MsgAlerteModedePaiementConteneur').show();\r\n                        $(\".CampagneTarifContainer\").hide();\r\n                    }, 500);\r\n                    \r\n                    await envoyerEmailBonDeCommandeClient('Virement');\r\n                } else {\r\n                    passerEtapeSuivante();\r\n                }\r\n            });\r\n            \r\n            console.log('\u2705 Boutons paiement initialis\u00e9s');\r\n        }\r\n        \r\n        \/**\r\n         * Envoie l'email du bon de commande au client (mode commercial)\r\n         * \u2705 CR\u00c9\u00c9 D'ABORD LA COMMANDE EN BASE avant d'envoyer l'email\r\n         *\/\r\n        async function envoyerEmailBonDeCommandeClient(modePaiement) {\r\n            console.log('\ud83d\udce7 Pr\u00e9paration envoi email bon de commande au client...');\r\n\r\n            if (!window.VIA_Panier || !window.VIA_Panier.state.items) {\r\n                console.error('\u274c Panier non disponible');\r\n                return;\r\n            }\r\n            \r\n            const commandesValides = window.VIA_Panier.state.items.filter(item => \r\n                item.reference && item.tarifHT && item.tarifHT > 0 && \r\n                item.dateDebut && item.dateFin && item.duree\r\n            );\r\n            \r\n            if (commandesValides.length === 0) {\r\n                console.error('\u274c Aucune commande valide trouv\u00e9e');\r\n                return;\r\n            }\r\n            \r\n            try {\r\n                console.log('\u23f3 Attente du module VIA_RecapValidation...');\r\n                \r\n                let attempts = 0;\r\n                const maxAttempts = 20;\r\n                \r\n                while (!window.VIA_RecapValidation && attempts < maxAttempts) {\r\n                    await new Promise(resolve => setTimeout(resolve, 500));\r\n                    attempts++;\r\n                    console.log(`\u23f3 Tentative ${attempts}\/${maxAttempts}...`);\r\n                }\r\n                \r\n                if (!window.VIA_RecapValidation || typeof window.VIA_RecapValidation.creerCommandeEnBase !== 'function') {\r\n                    throw new Error('Module VIA_RecapValidation non disponible apr\u00e8s 10 secondes');\r\n                }\r\n                \r\n                console.log('\u2705 Module VIA_RecapValidation disponible');\r\n                console.log('\ud83d\udcbe Cr\u00e9ation de la commande en base de donn\u00e9es...');\r\n                \r\n                const commandeData = await window.VIA_RecapValidation.creerCommandeEnBase();\r\n                \r\n                if (!commandeData || !commandeData.success) {\r\n                    throw new Error('Erreur lors de la cr\u00e9ation de la commande en base');\r\n                }\r\n                \r\n                const commandeRef = commandeData.commande_ref;\r\n                const commandeId = commandeData.commande_id;\r\n                \r\n                \/\/ \u2705 v1.5 : Mettre le flag BonCommandeCree \u00e0 'Yes'\r\n                sessionStorage.setItem('BonCommandeCree', 'Yes');\r\n                console.log('\ud83d\udd12 Flag BonCommandeCree mis \u00e0 Yes (mode commercial)');\r\n                \r\n                \/\/ \u2705 v1.10 : Griser l'\u00e9tape Validations\r\n                if (window.VIA_Panier && typeof window.VIA_Panier.griserEtape === 'function') {\r\n                    console.log('\ud83d\udd18 Appel griserEtape(\"validations\")');\r\n                    window.VIA_Panier.griserEtape('validations');\r\n                }\r\n                \r\n                console.log('\u2705 Commande cr\u00e9\u00e9e en base:', commandeRef, '(ID:', commandeId + ')');\r\n                console.log('\ud83d\udce7 Envoi de l\\'email au client...');\r\n                \r\n                $('#MsgAlerteModedePaiementTexte').show();\r\n                \r\n                \/\/ ================================================================\r\n                \/\/ pb2132 : REFERMER l'etape Choix du mode de paiement quand le\r\n                \/\/   message \u00ab bon de commande adresse au client \u00bb s'affiche\r\n                \/\/   (demande JF). Meme trio que passerEtapeSuivante (flux client),\r\n                \/\/   + griserEtape('paiement') pour la coherence visuelle (etape\r\n                \/\/   faite, comme le flux client la grise). ouvrirEtapePaiement\r\n                \/\/   n'est declenche que par le Valider de References (evenement\r\n                \/\/   ponctuel) : pas de reouverture concurrente attendue.\r\n                \/\/   SONDE integree : rect du message journalise apres fermeture \u2014\r\n                \/\/   si le conteneur message etait un ENFANT de\r\n                \/\/   .ChoisirPaiementClass, le hide le masquerait (height=0) et le\r\n                \/\/   log le dirait immediatement.\r\n                \/\/   Revert : window._viaPb2132Off = true (etape laissee ouverte).\r\n                \/\/ ================================================================\r\n                if (window._viaPb2132Off !== true) {\r\n                    \/\/ pb2136 : drapeau pb2132b retire avec pb2134 (JF).\r\n                    \/\/ ============================================================\r\n                    \/\/ pb2136 : LE MESSAGE SORT DE L'ETAPE AVANT QU'ELLE SE FERME.\r\n                    \/\/   Constat JF : #MsgAlerteModedePaiementConteneur vit DANS\r\n                    \/\/   .ChoisirPaiementClass \u2014 le hide de pb2132 l'emporte avec\r\n                    \/\/   lui. On le REPARENTE juste apres l'etape (frere, meme\r\n                    \/\/   niveau) : il survit a la fermeture sans dependre d'un\r\n                    \/\/   display concurrent. Position d'origine memorisee en window\r\n                    \/\/   (jamais sessionStorage) pour une restauration eventuelle.\r\n                    \/\/   display pose en inline !important : la feuille regie masque\r\n                    \/\/   ces conteneurs (meme motif que MsgCommandeValidee,\r\n                    \/\/   Validations l.213).\r\n                    \/\/   Revert : window._viaPb2136Off = true (message laisse en place).\r\n                    \/\/ ============================================================\r\n                    if (window._viaPb2136Off !== true) {\r\n                        var _msgC2136 = document.getElementById('MsgAlerteModedePaiementConteneur');\r\n                        var _etp2136 = document.querySelector('.ChoisirPaiementClass');\r\n                        if (_msgC2136 ? !!_etp2136 : false) {\r\n                            var _dedans2136 = _etp2136.contains(_msgC2136);\r\n                            if (_dedans2136) {\r\n                                if (!window._viaMsgParent2136) {\r\n                                    window._viaMsgParent2136 = _msgC2136.parentElement;\r\n                                    window._viaMsgNext2136 = _msgC2136.nextElementSibling;\r\n                                }\r\n                                if (_etp2136.parentElement) {\r\n                                    _etp2136.parentElement.insertBefore(_msgC2136, _etp2136.nextSibling);\r\n                                }\r\n                            }\r\n                            _msgC2136.classList.remove('elementor-hidden-desktop',\r\n                                'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                            _msgC2136.style.setProperty('display', 'block', 'important');\r\n                            console.log('[pb2136] message bon de commande : etait dans l\\'etape='\r\n                                + _dedans2136 + ' -> sorti et affiche');\r\n                        } else {\r\n                            console.warn('[pb2136] introuvable | message='\r\n                                + (_msgC2136 ? 'ok' : 'ABSENT')\r\n                                + ' | etape=' + (_etp2136 ? 'ok' : 'ABSENTE'));\r\n                        }\r\n                    }\r\n                    \/\/ ============================================================\r\n                    \/\/ pb2139 : L'ORDRE ETAIT LE DEFAUT \u2014 griserEtape ROUVRAIT.\r\n                    \/\/   Verdict pb2138 : les 5 .ChoisirPaiementClass sortaient a\r\n                    \/\/   inline=(vide) calc=flex, h>0 \u2014 signature du removeProperty\r\n                    \/\/   de pb1716\/pb1717 (les ouvreurs n'ecrivent pas 'block', ils\r\n                    \/\/   RETIRENT l'inline), et non d'un display:none efface au\r\n                    \/\/   hasard. L'appelant etait ce bloc : griserEtape('paiement')\r\n                    \/\/   se termine par marquerEtapeEnCours() -> boucle du\r\n                    \/\/   sequenceur -> cible 'paiement' (figee par pb2130) ->\r\n                    \/\/   ouverture. Le tout SYNCHRONE, entre le hide et la sonde :\r\n                    \/\/   d'ou le \u00ab 0 modification \u00bb de pb2137, arme trop tard.\r\n                    \/\/   Remede sans nouveau garde-fou (pb2134 reste retire) : on\r\n                    \/\/   grise D'ABORD, on ferme EN DERNIER. Plus personne ne\r\n                    \/\/   repasse apres nous dans ce tick.\r\n                    \/\/   Le log final mesure la hauteur reelle : elle seule dit si\r\n                    \/\/   l'etape est effectivement fermee.\r\n                    \/\/ ============================================================\r\n                    \/\/ pb2140b : drapeau pose AVANT le grisement \u2014 c'est griserEtape\r\n                    \/\/   qui declenche marquerEtapeEnCours puis le peintre pb1169 :\r\n                    \/\/   il doit deja etre vrai quand celui-ci passe.\r\n                    window._viaCommercialTermine2140 = true;\r\n                    if (window.VIA_Panier && typeof window.VIA_Panier.griserEtape === 'function') {\r\n                        window.VIA_Panier.griserEtape('paiement');\r\n                    }\r\n                    $('#ChoisirPaiementTitreIconeUp').hide();\r\n                    $('#ChoisirPaiementTitreIconeDown').show();\r\n                    $('.ChoisirPaiementClass').hide();\r\n                    var _hMax2139 = 0;\r\n                    document.querySelectorAll('.ChoisirPaiementClass').forEach(function (_e2139) {\r\n                        var _h = Math.round(_e2139.getBoundingClientRect().height);\r\n                        if (_h > _hMax2139) { _hMax2139 = _h; }\r\n                    });\r\n                    console.log('[pb2139] fermeture apres grisement | hauteur max des conteneurs='\r\n                        + _hMax2139 + (_hMax2139 > 0 ? ' \u2014 ENCORE OUVERT' : ' \u2014 ferme'));\r\n                    var _msg2132 = document.getElementById('MsgAlerteModedePaiementConteneur');\r\n                    var _h2132 = _msg2132 ? Math.round(_msg2132.getBoundingClientRect().height) : -1;\r\n                    console.log('[pb2132] etape mode de paiement refermee | message rect.height='\r\n                        + _h2132 + (_h2132 === 0 ? ' \u2014 MASQUE : le message est enfant de ChoisirPaiementClass, a remonter' : ''));\r\n                }\r\n                \r\n                \/\/ R\u00e9cup\u00e9rer le bon nombre d'\u00e9ch\u00e9ances selon le mode\r\n                const nbEcheances = modePaiement === 'CB' \r\n                    ? PAIEMENT_STATE.nbEcheancesSelectionneesCB \r\n                    : PAIEMENT_STATE.nbEcheancesSelectionneesVir;\r\n                \r\n                const response = await $.ajax({\r\n                    url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                    type: 'POST',\r\n                    data: {\r\n                        action: 'envoyer_bon_commande_commercial',\r\n                        commande_ref: commandeRef,\r\n                        commande_id: commandeId,\r\n                        mode_paiement: modePaiement,\r\n                        nb_echeances: nbEcheances,\r\n                        montant_total: PAIEMENT_STATE.montantTotal,\r\n                        devise: PAIEMENT_STATE.devise\r\n                    }\r\n                });\r\n                \r\n                console.log('\ud83d\udce7 R\u00e9ponse brute re\u00e7ue:', response);\r\n                \r\n                let parsedResponse;\r\n                try {\r\n                    if (typeof response === 'string') {\r\n                        const jsonMatch = response.match(\/\\{[\\s\\S]*\\}\/);\r\n                        if (jsonMatch) {\r\n                            parsedResponse = JSON.parse(jsonMatch[0]);\r\n                            console.log('\u2705 JSON extrait et pars\u00e9:', parsedResponse);\r\n                        } else {\r\n                            console.error('\u274c Aucun JSON trouv\u00e9 dans la r\u00e9ponse');\r\n                            parsedResponse = { success: false };\r\n                        }\r\n                    } else {\r\n                        parsedResponse = response;\r\n                    }\r\n                } catch (parseError) {\r\n                    console.error('\u274c Erreur parsing JSON:', parseError);\r\n                    console.log('R\u00e9ponse brute:', response);\r\n                    parsedResponse = { success: false };\r\n                }\r\n                \r\n                if (parsedResponse && parsedResponse.success === true) {\r\n                    console.log('\u2705 Email bon de commande envoy\u00e9 avec succ\u00e8s');\r\n                } else {\r\n                    const errorMsg = parsedResponse?.data?.message || parsedResponse?.message || 'Erreur inconnue';\r\n                    throw new Error(errorMsg);\r\n                }\r\n                \r\n            } catch (error) {\r\n                console.error('\u274c Erreur compl\u00e8te:', error);\r\n                \r\n                let errorMessage = 'Erreur inconnue';\r\n                \r\n                if (error.responseText) {\r\n                    try {\r\n                        const jsonMatch = error.responseText.match(\/\\{[\\s\\S]*\\}\/);\r\n                        if (jsonMatch) {\r\n                            const parsedError = JSON.parse(jsonMatch[0]);\r\n                            errorMessage = parsedError.data?.message || parsedError.message || errorMessage;\r\n                        }\r\n                    } catch (e) {\r\n                        console.warn('Impossible de parser responseText');\r\n                    }\r\n                } else if (error.message) {\r\n                    errorMessage = error.message;\r\n                } else if (error.statusText) {\r\n                    errorMessage = error.statusText;\r\n                }\r\n                \r\n                const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n                const messageErreur = lang === 'EN'\r\n                    ? `Error: ${errorMessage}`\r\n                    : `Erreur : ${errorMessage}`;\r\n                \r\n                $('#MsgAlerteModedePaiementTexte').html(messageErreur).css({'color': '#ff0000'});\r\n            }\r\n        }\r\n        \r\n        \/**\r\n         * Passe \u00e0 l'\u00e9tape suivante\r\n         *\/\r\n        function passerEtapeSuivante() {\r\n            console.log('\u27a1\ufe0f Passage \u00e0 l\\'\u00e9tape 4 - R\u00e9capitulatif');\r\n            \r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            \/\/ 1. Fermer l'\u00e9tape 3\r\n            $('.ChoisirPaiementClass').hide();\r\n            $('#ChoisirPaiementTitreIconeUp').hide();\r\n            $('#ChoisirPaiementTitreIconeDown').show();\r\n            \r\n            \/\/ \u2705 v1.6 : Griser l'\u00e9tape Mode de paiement\r\n            console.log('\ud83d\udd18 Appel griserEtape(\"paiement\")');\r\n            if (window.VIA_Panier && typeof window.VIA_Panier.griserEtape === 'function') {\r\n                window.VIA_Panier.griserEtape('paiement');\r\n            } else {\r\n                console.warn('\u26a0\ufe0f griserEtape non disponible');\r\n            }\r\n            \r\n            \/\/ 2. Afficher et renseigner le message de paiement\r\n            const montantFormate = window.VIA_App.formaterMontant(\r\n                PAIEMENT_STATE.montantTotal,\r\n                PAIEMENT_STATE.devise\r\n            );\r\n            \r\n            const suffixe = PAIEMENT_STATE.estHT \r\n                ? (lang === 'EN' ? 'excl. VAT' : 'H.T.')\r\n                : (lang === 'EN' ? 'incl. VAT' : 'T.T.C.');\r\n            \r\n            let messagePaiement;\r\n            \r\n            if (PAIEMENT_STATE.modePaiement === 'CB') {\r\n                const nbEcheances = PAIEMENT_STATE.nbEcheancesSelectionneesCB;\r\n                \r\n                if (nbEcheances === 1) {\r\n                    messagePaiement = lang === 'EN'\r\n                        ? `Payment ${montantFormate} ${suffixe} by credit card in 1 installment`\r\n                        : `Paiement ${montantFormate} ${suffixe} par carte bancaire en 1 \u00e9ch\u00e9ance`;\r\n                } else {\r\n                    const montantEcheance = PAIEMENT_STATE.montantTotal \/ nbEcheances;\r\n                    const montantEcheanceFormate = window.VIA_App.formaterMontant(\r\n                        montantEcheance,\r\n                        PAIEMENT_STATE.devise\r\n                    );\r\n                    \r\n                    const labelEcheances = lang === 'EN'\r\n                        ? (nbEcheances > 1 ? 'installments' : 'installment')\r\n                        : (nbEcheances > 1 ? '\u00e9ch\u00e9ances' : '\u00e9ch\u00e9ance');\r\n                    \r\n                    messagePaiement = lang === 'EN'\r\n                        ? `Payment ${montantFormate} ${suffixe} by credit card in ${nbEcheances} weekly ${labelEcheances}<br>of ${montantEcheanceFormate}`\r\n                        : `Paiement ${montantFormate} ${suffixe} par carte bancaire<br>en ${nbEcheances} ${labelEcheances} hebdomadaires de ${montantEcheanceFormate}`;\r\n                }\r\n            } else {\r\n                \/\/ Virement\r\n                const nbEcheances = PAIEMENT_STATE.nbEcheancesSelectionneesVir;\r\n                \r\n                if (nbEcheances === 1) {\r\n                    messagePaiement = lang === 'EN'\r\n                        ? `Payment ${montantFormate} ${suffixe} by bank transfer in 1 installment`\r\n                        : `Paiement ${montantFormate} ${suffixe} par virement en 1 \u00e9ch\u00e9ance`;\r\n                } else {\r\n                    const montantEcheance = PAIEMENT_STATE.montantTotal \/ nbEcheances;\r\n                    const montantEcheanceFormate = window.VIA_App.formaterMontant(\r\n                        montantEcheance,\r\n                        PAIEMENT_STATE.devise\r\n                    );\r\n                    \r\n                    const labelEcheances = lang === 'EN'\r\n                        ? (nbEcheances > 1 ? 'installments' : 'installment')\r\n                        : (nbEcheances > 1 ? '\u00e9ch\u00e9ances' : '\u00e9ch\u00e9ance');\r\n                    \r\n                    messagePaiement = lang === 'EN'\r\n                        ? `Payment ${montantFormate} ${suffixe} by bank transfer<br>in ${nbEcheances} ${labelEcheances} of ${montantEcheanceFormate}`\r\n                        : `Paiement ${montantFormate} ${suffixe} par virement<br>en ${nbEcheances} ${labelEcheances} de ${montantEcheanceFormate}`;\r\n                }\r\n            }\r\n            \r\n            $('#DeviseModedePaiementMsg').html(messagePaiement);\r\n            \/\/ \u2705 v1.8 : setProperty pour passer display:none!important du CSS r\u00e9gie\r\n            \/* ====================================================================\r\n             * pb2346 : UNE SEULE DEFINITION POUR LES QUATRE ECRIVAINS.\r\n             *   pb2345 avait ferme la porte de Panier_manage en affirmant qu il n y\r\n             *   en avait qu une. C etait faux : la verification ne portait que sur le\r\n             *   corpus alors fourni. Les JS d etape en ont trois autres \u2014\r\n             *     References.txt   l.1409  $msgOK.show()\r\n             *     Mode_de_paiement l.1327  DeviseModedePaiementMsgConteneur\r\n             *     Validations.txt  l.214   MsgCommandeValidee\r\n             *   Recopier la regle a quatre endroits serait refaire l erreur d origine :\r\n             *   quatre copies divergent. La porte est donc definie UNE fois, par le\r\n             *   premier fichier charge, et les autres la reutilisent. Aucun ordre de\r\n             *   chargement a respecter.\r\n             *   Regle (identique a pb2345) : masquer si ordinateur ET site pays.\r\n             *     largeur   _viaLargeur1263() sinon outerWidth (regle 5.4)\r\n             *     site pays la regie est yearbook-media.com EN TOP ; dans l iframe\r\n             *               popup d un site pays window.top diff\u00e8re -> pays.\r\n             *   Revert : window._viaPb2345Off = true (meme knob que pb2345).\r\n             * ==================================================================== *\/\r\n            if (typeof window._viaMasquerMsg2346 !== 'function') {\r\n                window._viaMasquerMsg2346 = function () {\r\n                    if (window._viaPb2345Off === true) { return false; }\r\n                    try {\r\n                        var _lg = (typeof window._viaLargeur1263 === 'function')\r\n                            ? window._viaLargeur1263() : window.outerWidth;\r\n                        var _rg = (window === window.top)\r\n                            ? \/^(?:www\\.)?yearbook-media\\.com$\/.test(window.location.hostname || '') : false;\r\n                        var _m = (_lg >= 1000) ? !_rg : false;\r\n                        if (window._viaPb2346Dit !== true) {\r\n                            window._viaPb2346Dit = true;\r\n                            console.log('[pb2346] phrases vertes des 4 dernieres etapes : ' + (_m ? 'MASQUEES' : 'conservees')\r\n                                + ' | largeur=' + _lg + ' | regie=' + _rg + ' (top=' + (window === window.top) + ')');\r\n                        }\r\n                        return _m;\r\n                    } catch (_e2346) { return false; }\r\n                };\r\n            }\r\n\r\n            (function() {\r\n                if (window._viaMasquerMsg2346()) { console.log('[pb2346] DeviseModedePaiementMsgConteneur non affiche (pays + ordinateur)'); return; }\r\n                var _msgPEl = document.getElementById('DeviseModedePaiementMsgConteneur');\r\n                if (_msgPEl) {\r\n                    _msgPEl.classList.remove('elementor-hidden-desktop', 'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                    _msgPEl.style.setProperty('display', 'block', 'important');\r\n                    console.log('\u2705 DeviseModedePaiementMsgConteneur affich\u00e9');\r\n                }\r\n            })();\r\n            \/\/ \u2705 v2.7.3 : Flag + mise \u00e0 jour messages \u00e9tapes\r\n            sessionStorage.setItem('ModePaiementChoisi', 'Yes');\r\n            if (window.VIA_Panier && typeof window.VIA_Panier._updateMessagesEtapes === 'function') {\r\n                window.VIA_Panier._updateMessagesEtapes();\r\n            }\r\n            \r\n            console.log('\ud83d\udcac Message paiement:', messagePaiement);\r\n            \r\n            \/\/ 3. Ouvrir l'\u00e9tape 4 - R\u00e9capitulatif\r\n            $('#EtapeValidations').addClass('via-etape-visible').show();\r\n            $('#ValidationsConteneur').show();\r\n            $('#ValidationsTitreIconeUp').show();\r\n            $('#ValidationsTitreIconeDown').hide();\r\n            \r\n            \/\/ \u2705 Activer le titre de l'\u00e9tape Validations\r\n            if (window.VIA_Panier && typeof window.VIA_Panier.activerTitreEtape === 'function') {\r\n                window.VIA_Panier.activerTitreEtape('validations');\r\n            }\r\n            \r\n            \/\/ \u2705 NE PAS d\u00e9clencher 'ouvrir-etape-paiement-final' ici\r\n            \/\/ L'\u00e9tape Paiement s'ouvrira SEULEMENT apr\u00e8s les 3 validations (dans recap-validation.js)\r\n            \r\n            \/\/ \u2705 Activer le titre de l'\u00e9tape Paiement Final (mais ne pas ouvrir le conteneur)\r\n            if (window.VIA_Panier && typeof window.VIA_Panier.activerTitreEtape === 'function') {\r\n                window.VIA_Panier.activerTitreEtape('paiementFinal', false);\r\n            }\r\n            \r\n            \/\/ \u2705 v1.9 : Scroll vers RecapitulatifTitre\r\n            (function () {\r\n                var _e1636 = document.querySelector('.ValidationsTitre');\r\n                if (!_e1636) {\r\n                    console.warn('[pb1636b] .ValidationsTitre absent \u2014 defilement ignore');\r\n                    return;\r\n                }\r\n                var _pop1636 = false;\r\n                try {\r\n                    _pop1636 = (window._viaPb1636Off !== true)\r\n                        ? (new URLSearchParams(window.location.hash.substring(1)\r\n                            || window.location.search).get('mode') === 'popup')\r\n                        : false;\r\n                } catch (_eP) { _pop1636 = false; }\r\n                if (_pop1636) {\r\n                    try { _e1636.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); }\r\n                    catch (_eS) { _e1636.scrollIntoView(); }\r\n                    return;\r\n                }\r\n                var _o1636 = $('.ValidationsTitre').offset();\r\n                if (!_o1636) { return; }\r\n                $('html, body').animate({ scrollTop: _o1636.top - 100 }, 500);\r\n            })();\r\n        }\r\n        \r\n        \/\/ ============================================\r\n        \/\/ INITIALISATION\r\n        \/\/ ============================================\r\n        \r\n        \/\/ \u00c9couter l'\u00e9v\u00e9nement d'ouverture de l'\u00e9tape 3\r\n        $(document).on('ouvrir-etape-paiement', ouvrirEtapePaiement);\r\n        \r\n        \/\/ Initialiser les listeners\r\n        initChangementDevise();\r\n        \r\n        initChangementEcheancesCB();\r\n        initChangementEcheancesVir();\r\n        initBoutonsPaiement();\r\n        \r\n        \/**\r\n         * \u2705 Rafra\u00eechit tous les montants de l'\u00e9tape paiement\r\n         * \u00c0 appeler quand une commande est modifi\u00e9e\r\n         *\/\r\n        function rafraichirMontants() {\r\n            \/\/ \u2705 V\u00e9rifier qu'il y a des commandes avec tarif avant de continuer\r\n            if (!window.VIA_Panier || !window.VIA_Panier.state.items) {\r\n                return;\r\n            }\r\n            \r\n            const itemsAvecTarif = window.VIA_Panier.state.items.filter(item => \r\n                item.tarifHT && item.tarifHT > 0\r\n            );\r\n            \r\n            if (itemsAvecTarif.length === 0) {\r\n                return;\r\n            }\r\n            \r\n            console.log('\ud83d\udcb0 Rafra\u00eechissement des montants de l\\'\u00e9tape paiement...');\r\n            \r\n            \/\/ \u2705 Recalculer et afficher les donn\u00e9es\r\n            initialiserDonneesPaiement();\r\n            calculerEcheancesCB();\r\n            calculerEcheancesVirement();\r\n            afficherMontants();\r\n            mettreAJourMontantHebdomadaireCB();\r\n            mettreAJourMontantEcheanceVir();\r\n            genererListeEcheancesCB();\r\n            genererListeEcheancesVir();\r\n            mettreAJourMessagePayablePar();\r\n            \r\n            console.log('\u2705 Montants de l\\'\u00e9tape paiement rafra\u00eechis');\r\n        }\r\n        \r\n        console.log('\u2705 Module Choix Mode de Paiement v1.7 initialis\u00e9');\r\n        \r\n        \/\/ Exposer publiquement\r\n        window.VIA_Paiement = {\r\n            ouvrir: ouvrirEtapePaiement,\r\n            state: PAIEMENT_STATE,\r\n            signalerModification: signalerModificationPaiement, \/\/ \u2705 v1.5\r\n            rafraichirMontants: rafraichirMontants \/\/ \u2705 v1.6 - Mise \u00e0 jour imm\u00e9diate des montants\r\n        };\r\n    }\r\n    \r\n    \/\/ Lancer l'initialisation\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', initPaiementModule);\r\n    } else {\r\n        initPaiementModule();\r\n    }\r\n\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7c80b5dc elementor-widget elementor-widget-html\" data-id=\"7c80b5dc\" data-element_type=\"widget\" data-e-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\/**\r\n * VIA Agency - R\u00c9CAPITULATIF ET VALIDATION CGV\r\n * @version 1.6 - F\u00e9vrier 2026\r\n * \u2705 Ajout : Envoi taux_conversion pour rapprochement bancaire devises\r\n * \u2705 Gestion bouton .RetourModifCommande\r\n * \u2705 v1.5 : Flag BonCommandeCree pour verrouillage apr\u00e8s cr\u00e9ation\r\n * \u2705 v1.6 : Nettoyage - v\u00e9rifications s\u00e9quentielles d\u00e9plac\u00e9es dans validation-etapes-process\r\n *\/\r\n\r\n(function() {\r\n    'use strict';\r\n    \r\n    \/\/ \u2705 Fonction helper pour \u00e9viter l'encodage WordPress de &&\r\n    const AND = (a, b) => !(!a || !b);\r\n    \r\n    console.log('\u2705 Chargement module R\u00e9capitulatif et Validation v1.6...');\r\n    \r\n    \/\/ Note: .RetourModifCommande est masqu\u00e9 par d\u00e9faut via Elementor (elementor-hidden-*)\r\n    \r\n    \/\/ \u2705 FLAG ANTI-DOUBLON (simple)\r\n    let commandeEnCours = false;\r\n\r\n    function initRecapValidationModule() {\r\n        if (typeof jQuery === 'undefined') {\r\n            console.error('\u274c jQuery non disponible');\r\n            setTimeout(initRecapValidationModule, 500);\r\n            return;\r\n        }\r\n        \r\n        const $ = jQuery;\r\n        \r\n        console.log('\u2705 Initialisation module R\u00e9capitulatif...');\r\n        \r\n        function masquerMessagesErreur() {\r\n            $('#MsgElementsCommande').hide();\r\n            $('#MsgCGVText').hide();\r\n            $('#MsgAcceptationCommandeConteneur').hide();\r\n        }\r\n        \r\n        \/\/ \u2705 v1.6 : verifierProcessComplet() et afficherMessageProcessIncomplet()\r\n        \/\/ supprim\u00e9s \u2192 g\u00e9r\u00e9s par le module validation-etapes-process (phase capture)\r\n        \r\n        function verifierCheckboxes() {\r\n            let toutesValidees = true;\r\n            masquerMessagesErreur();\r\n            \r\n            if ($('input[name=\"form_fields[Validation_Commande]\"]:checked').length === 0) {\r\n                $('#MsgElementsCommandeText').css({'color': '#FB5E2A'});\r\n                $('#MsgElementsCommandeText').html(\"Valider les \u00e9l\u00e9ments de(s) commande(s)\");\r\n                $('#MsgElementsCommande').show();\r\n                toutesValidees = false;\r\n            }\r\n            \r\n            if ($('input[name=\"form_fields[Acceptation_CGV]\"]:checked').length === 0) {\r\n                $('#MsgCGVText').css({'color': '#FB5E2A'});\r\n                $('#MsgCGVText').html(\"Valider les Conditions G\u00e9n\u00e9rales de Vente\");\r\n                $('#MsgCGVText').show();\r\n                toutesValidees = false;\r\n            }\r\n            \r\n            if ($('input[name=\"form_fields[Acceptation_Commande]\"]:checked').length === 0) {\r\n                $('#MsgAcceptationCommandeText').css({'color': '#FB5E2A'});\r\n                $('#MsgAcceptationCommandeConteneur').show();\r\n                toutesValidees = false;\r\n            }\r\n            \r\n            return toutesValidees;\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 R\u00e9initialise les checkboxes de validation\r\n         *\/\r\n        function reinitialiserValidations() {\r\n            console.log('\ud83d\udd04 R\u00e9initialisation des validations...');\r\n            \r\n            \/\/ D\u00e9cocher toutes les checkboxes\r\n            $('input[name=\"form_fields[Validation_Commande]\"]').prop('checked', false);\r\n            $('input[name=\"form_fields[Acceptation_CGV]\"]').prop('checked', false);\r\n            $('input[name=\"form_fields[Acceptation_Commande]\"]').prop('checked', false);\r\n            \r\n            \/\/ Masquer les messages d'erreur\r\n            masquerMessagesErreur();\r\n            \r\n            \/\/ Supprimer les flags de validation du sessionStorage\r\n            sessionStorage.removeItem('validations_completees');\r\n            sessionStorage.removeItem('validation_commande');\r\n            sessionStorage.removeItem('acceptation_cgv');\r\n            sessionStorage.removeItem('acceptation_commande');\r\n            \r\n            console.log('\u2705 Validations r\u00e9initialis\u00e9es');\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 Affiche .RetourModifCommande quand on clique sur .PasserCommandeBouton\r\n         *\/\r\n        function initBoutonPasserCommande() {\r\n            \/\/ Utiliser un listener qui ne bloque pas la propagation\r\n            $(document).on('click', '.PasserCommandeBouton', function() {\r\n                \/\/ Afficher le bouton retour modification\r\n                \/\/ \u2705 Retirer les classes elementor-hidden-* pour que \u00e7a s'affiche sur mobile aussi\r\n                \/\/ \u2705 Ajouter z-index \u00e9lev\u00e9 et position relative pour \u00eatre cliquable sur mobile\r\n                $('.RetourModifCommande')\r\n                    .removeClass('elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile')\r\n                    .css({\r\n                        'position': 'relative',\r\n                        'z-index': '9999',\r\n                        'cursor': 'pointer'\r\n                    })\r\n                    .show();\r\n                \r\n                \/\/ \u2705 Afficher le titre R\u00e9f\u00e9rences avec le bon chevron (ferm\u00e9 par d\u00e9faut)\r\n                $('#EtapeReferences').addClass('via-etape-visible').show();\r\n                $('#ReferencesTitre').show();\r\n                $('#ReferencesTitreIconeUp').hide();\r\n                $('#ReferencesTitreIconeDown').show();\r\n                \r\n                console.log('\u2705 Clic PasserCommandeBouton - RetourModifCommande et titre R\u00e9f\u00e9rences affich\u00e9s');\r\n            });\r\n            \r\n            console.log('\u2705 Listener sur .PasserCommandeBouton initialis\u00e9');\r\n        }\r\n        \r\n        \/**\r\n         * \u2705 G\u00e8re le clic sur .RetourModifCommande\r\n         * La logique principale est dans VIA_Panier.retourModificationCommande()\r\n         *\/\r\n        function initBoutonRetourModification() {\r\n            \/\/ \u2705 Utiliser un listener d\u00e9l\u00e9gu\u00e9 qui capture aussi les clics sur les enfants (liens <a>)\r\n            $(document).on('click', '.RetourModifCommande, .RetourModifCommande a', async function(e) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                \r\n                console.log('\ud83d\udd19 Clic sur RetourModifCommande');\r\n                \r\n                \/\/ \u2705 v1.5 : V\u00e9rifier si bon de commande cr\u00e9\u00e9\r\n                const bonCommandeCree = sessionStorage.getItem('BonCommandeCree') === 'Yes';\r\n                \r\n                if (bonCommandeCree) {\r\n                    \/\/ \u2705 Bon de commande cr\u00e9\u00e9 \u2192 afficher message nouvelle commande\r\n                    console.log('\ud83d\udd12 Bon de commande cr\u00e9\u00e9 - affichage message nouvelle commande');\r\n                    if (window.VIA_Panier && typeof window.VIA_Panier.afficherMessageNouvelleCommande === 'function') {\r\n                        window.VIA_Panier.afficherMessageNouvelleCommande();\r\n                    }\r\n                    return;\r\n                }\r\n                \r\n                \/\/ Appeler la fonction du panier manager\r\n                if (window.VIA_Panier && typeof window.VIA_Panier.retourModificationCommande === 'function') {\r\n                    await window.VIA_Panier.retourModificationCommande();\r\n                } else {\r\n                    console.error('\u274c VIA_Panier.retourModificationCommande non disponible');\r\n                }\r\n            });\r\n            \r\n            \/\/ Note: .RetourModifCommande est masqu\u00e9 par d\u00e9faut via Elementor\r\n            \r\n            console.log('\u2705 Bouton RetourModifCommande initialis\u00e9');\r\n        }\r\n        \r\n        async function passerEtapePaiement() {\r\n            \/\/ \u2705 PROTECTION ANTI-DOUBLON SIMPLE\r\n            if (commandeEnCours) {\r\n                console.warn('\u26a0\ufe0f Cr\u00e9ation de commande d\u00e9j\u00e0 en cours, ignor\u00e9');\r\n                return;\r\n            }\r\n            \r\n            commandeEnCours = true;\r\n            console.log('\ud83d\udcbe Sauvegarde de la commande en base de donn\u00e9es...');\r\n            \r\n            const $bouton = $('.ValidationsCGVBouton');\r\n            $bouton.prop('disabled', true).css('opacity', '0.6');\r\n            \r\n            let commandeData;\r\n        \r\n            try {\r\n                commandeData = await creerCommandeEnBase();\r\n                \r\n                if (!commandeData || !commandeData.success) {\r\n                    throw new Error('Erreur lors de la cr\u00e9ation de la commande');\r\n                }\r\n                \r\n                console.log('\u2705 Commande cr\u00e9\u00e9e:', commandeData.commande_ref);\r\n                \r\n                \/\/ \u2705 v1.5 : Mettre le flag BonCommandeCree \u00e0 'Yes'\r\n                sessionStorage.setItem('BonCommandeCree', 'Yes');\r\n                console.log('\ud83d\udd12 Flag BonCommandeCree mis \u00e0 Yes - commande verrouill\u00e9e');\r\n                \r\n                \/\/ \u2705 Masquer le bouton RetourModifCommande\r\n                \/\/ Remettre les classes elementor-hidden-* pour le masquage propre\r\n                $('.RetourModifCommande')\r\n                    .addClass('elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile')\r\n                    .hide();\r\n                console.log('\ud83d\udd12 Bouton RetourModifCommande masqu\u00e9 (commande cr\u00e9\u00e9e)');\r\n                \r\n            } catch (error) {\r\n                console.error('\u274c Erreur cr\u00e9ation commande:', error);\r\n                alert('Erreur lors de la sauvegarde de la commande. Veuillez r\u00e9essayer.');\r\n                \r\n                \/\/ \u2705 R\u00e9activer en cas d'erreur\r\n                commandeEnCours = false;\r\n                $bouton.prop('disabled', false).css('opacity', '1');\r\n                return;\r\n            }\r\n            \r\n            console.log('\u27a1\ufe0f Passage \u00e0 l\\'\u00e9tape 5 - Proc\u00e9der au paiement');\r\n            \r\n            $(document).trigger('ouvrir-etape-paiement-final');\r\n            \r\n            $('#ValidationsConteneur').hide();\r\n            $('#ValidationsTitreIconeUp').hide();\r\n            $('#ValidationsTitreIconeDown').show();\r\n            \/\/ \u2705 v1.2 : setProperty pour passer display:none!important du CSS r\u00e9gie\r\n            \/* ====================================================================\r\n             * pb2346 : UNE SEULE DEFINITION POUR LES QUATRE ECRIVAINS.\r\n             *   pb2345 avait ferme la porte de Panier_manage en affirmant qu il n y\r\n             *   en avait qu une. C etait faux : la verification ne portait que sur le\r\n             *   corpus alors fourni. Les JS d etape en ont trois autres \u2014\r\n             *     References.txt   l.1409  $msgOK.show()\r\n             *     Mode_de_paiement l.1327  DeviseModedePaiementMsgConteneur\r\n             *     Validations.txt  l.214   MsgCommandeValidee\r\n             *   Recopier la regle a quatre endroits serait refaire l erreur d origine :\r\n             *   quatre copies divergent. La porte est donc definie UNE fois, par le\r\n             *   premier fichier charge, et les autres la reutilisent. Aucun ordre de\r\n             *   chargement a respecter.\r\n             *   Regle (identique a pb2345) : masquer si ordinateur ET site pays.\r\n             *     largeur   _viaLargeur1263() sinon outerWidth (regle 5.4)\r\n             *     site pays la regie est yearbook-media.com EN TOP ; dans l iframe\r\n             *               popup d un site pays window.top diff\u00e8re -> pays.\r\n             *   Revert : window._viaPb2345Off = true (meme knob que pb2345).\r\n             * ==================================================================== *\/\r\n            if (typeof window._viaMasquerMsg2346 !== 'function') {\r\n                window._viaMasquerMsg2346 = function () {\r\n                    if (window._viaPb2345Off === true) { return false; }\r\n                    try {\r\n                        var _lg = (typeof window._viaLargeur1263 === 'function')\r\n                            ? window._viaLargeur1263() : window.outerWidth;\r\n                        var _rg = (window === window.top)\r\n                            ? \/^(?:www\\.)?yearbook-media\\.com$\/.test(window.location.hostname || '') : false;\r\n                        var _m = (_lg >= 1000) ? !_rg : false;\r\n                        if (window._viaPb2346Dit !== true) {\r\n                            window._viaPb2346Dit = true;\r\n                            console.log('[pb2346] phrases vertes des 4 dernieres etapes : ' + (_m ? 'MASQUEES' : 'conservees')\r\n                                + ' | largeur=' + _lg + ' | regie=' + _rg + ' (top=' + (window === window.top) + ')');\r\n                        }\r\n                        return _m;\r\n                    } catch (_e2346) { return false; }\r\n                };\r\n            }\r\n\r\n            (function() {\r\n                if (window._viaMasquerMsg2346()) { console.log('[pb2346] MsgCommandeValidee non affiche (pays + ordinateur)'); return; }\r\n                var _msgVEl = document.getElementById('MsgCommandeValidee');\r\n                if (_msgVEl) {\r\n                    _msgVEl.classList.remove('elementor-hidden-desktop', 'elementor-hidden-tablet', 'elementor-hidden-mobile');\r\n                    _msgVEl.style.setProperty('display', 'block', 'important');\r\n                    console.log('\u2705 MsgCommandeValidee affich\u00e9');\r\n                }\r\n            })();\r\n            \/\/ \u2705 v2.7.3 : Mettre \u00e0 jour les messages d'\u00e9tapes\r\n            if (window.VIA_Panier && typeof window.VIA_Panier._updateMessagesEtapes === 'function') {\r\n                window.VIA_Panier._updateMessagesEtapes();\r\n            }\r\n            \r\n            $('#EtapePaiement').addClass('via-etape-visible').show();\r\n            \r\n            \/\/ \u2705 v1.9 : Retirer les classes elementor-hidden-* des conteneurs LisereBleu de l'\u00e9tape paiement\r\n            $('#EtapePaiement .LisereBleu').removeClass('elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile');\r\n            \r\n            (function(){ var _el=document.getElementById('ProcederPaiementConteneur'); if(_el){ _el.classList.remove('elementor-hidden-desktop','elementor-hidden-tablet','elementor-hidden-mobile'); _el.style.setProperty('display','block','important'); }})();\r\n            $('#ProcederPaiementTitre').show();\r\n            $('#ProcederPaiementTitreIconeUp').show();\r\n            $('#ProcederPaiementTitreIconeDown').hide();\r\n            \r\n            \/\/ \u2705 Activer le titre de l'\u00e9tape Paiement Final (avec conteneur ouvert)\r\n            if (window.VIA_Panier && typeof window.VIA_Panier.activerTitreEtape === 'function') {\r\n                window.VIA_Panier.activerTitreEtape('paiementFinal', true);\r\n            }\r\n            \r\n            \r\n            \/\/ \u2705 APR\u00c8S - Scroll adapt\u00e9 mobile\/desktop\r\n            setTimeout(function() {\r\n                const isMobile = window.innerWidth <= 767;\r\n                const isDesktop = window.innerWidth >= 1000;\r\n                \r\n                if (isMobile) {\r\n                    \/\/ Mobile : scroller la fen\u00eatre vers le bas\r\n                    const $target = $('#ProcederPaiementTitre');\r\n                    if ($target.length > 0) {\r\n                        $('html, body').animate({\r\n                            scrollTop: $target.offset().top - 50\r\n                        }, 500);\r\n                    } else {\r\n                        \/\/ Fallback : scroller tout en bas\r\n                        $('html, body').animate({\r\n                            scrollTop: $(document).height()\r\n                        }, 500);\r\n                    }\r\n                } else if (isDesktop) {\r\n                    \/* ====================================================================\r\n                     * pb2354 : UN SEUL DEFILEMENT VERS LE BAS, PARTAGE PAR LES QUATRE APPELS.\r\n                     *   pb2353 a etabli la cause sur un site : le code visait #ColonneDroite,\r\n                     *   qui ne defile pas \u2014 le piege pb1895 montrait une animation dont les\r\n                     *   pas valaient 0,016 px, donc une cible de zero. Le defileur reel est\r\n                     *   .via-col-popup-body (overflow:hidden auto).\r\n                     *   Les trois autres appels sont byte-identiques a celui qui echouait, et\r\n                     *   ils se declenchent sur des CHEMINS DIFFERENTS : ouvrir l etape en\r\n                     *   cliquant le titre passe par Formulaire, pas par Validations. Le meme\r\n                     *   geste marchait ou non selon le chemin.\r\n                     *   Les corriger en recopiant la solution serait refaire la faute que\r\n                     *   pb2346 vient de payer : quatre copies divergent, et l une se fait\r\n                     *   oublier. La fonction est donc definie UNE fois, par le premier fichier\r\n                     *   charge, et les quatre l appellent. Aucun ordre de chargement a tenir.\r\n                     *   Elle cherche le defileur au lieu de le nommer, et attend qu il y ait\r\n                     *   quelque chose a defiler \u2014 un delai fixe ne sait pas quand la mise en\r\n                     *   page est posee.\r\n                     *   Reglages : _viaPb2353Max (1500), _viaPb2353Duree (300).\r\n                     *   Revert : _viaPb2353Off = true -> ancien comportement (#ColonneDroite).\r\n                     * ==================================================================== *\/\r\n                    if (typeof window._viaScrollBas2354 !== 'function') {\r\n                        window._viaScrollBas2354 = function (_origine) {\r\n                            var _dur = (typeof window._viaPb2353Duree === 'number') ? window._viaPb2353Duree : 300;\r\n                            if (window._viaPb2353Off === true) {\r\n                                var $_cd = jQuery('#ColonneDroite');\r\n                                if ($_cd.length) { $_cd.animate({ scrollTop: $_cd[0].scrollHeight }, _dur); }\r\n                                console.log('[pb2354] ' + _origine + ' : DESARME -> ancien comportement #ColonneDroite');\r\n                                return;\r\n                            }\r\n                            var _cible = document.getElementById('ProcederPaiementTitre')\r\n                                || document.getElementById('EtapePaiement');\r\n                            var _t0 = Date.now();\r\n                            var _max = (typeof window._viaPb2353Max === 'number') ? window._viaPb2353Max : 1500;\r\n                            var _trouver = function (_el) {\r\n                                var _n = _el;\r\n                                while (_n ? (_n !== document.body) : false) {\r\n                                    var _oy = '';\r\n                                    try { _oy = window.getComputedStyle(_n).overflowY; } catch (_e) { _oy = ''; }\r\n                                    if (_oy === 'auto' ? true : _oy === 'scroll') {\r\n                                        if (_n.scrollHeight > _n.clientHeight + 4) { return _n; }\r\n                                    }\r\n                                    _n = _n.parentElement;\r\n                                }\r\n                                return null;\r\n                            };\r\n                            var _essayer = function () {\r\n                                var _ec = Date.now() - _t0;\r\n                                var _sc = _cible ? _trouver(_cible) : null;\r\n                                if (_sc) {\r\n                                    var _nom = _sc.tagName + (_sc.id ? ('#' + _sc.id) : '')\r\n                                        + (_sc.classList.length ? ('.' + Array.prototype.join.call(_sc.classList, '.').slice(0, 60)) : '');\r\n                                    console.log('[pb2354] ' + _origine + ' : defileur trouve apres ' + _ec + 'ms : ' + _nom\r\n                                        + ' | scrollHeight=' + _sc.scrollHeight + ' clientHeight=' + _sc.clientHeight\r\n                                        + ' scrollTop=' + Math.round(_sc.scrollTop));\r\n                                    jQuery(_sc).stop(true, false).animate({ scrollTop: _sc.scrollHeight }, _dur);\r\n                                    return;\r\n                                }\r\n                                if (_ec >= _max) {\r\n                                    console.log('[pb2354] ' + _origine + ' : aucun ancetre defilant apres ' + _ec + 'ms'\r\n                                        + (_cible ? '' : ' (cible absente)') + ' -> repli sur #ColonneDroite');\r\n                                    var $_r = jQuery('#ColonneDroite');\r\n                                    if ($_r.length) { $_r.animate({ scrollTop: $_r[0].scrollHeight }, _dur); }\r\n                                    return;\r\n                                }\r\n                                setTimeout(_essayer, 100);\r\n                            };\r\n                            _essayer();\r\n                        };\r\n                    }\r\n                    window._viaScrollBas2354('\u00e9tape Paiement ouverte (Validations)');\r\n                } else {\r\n                    \/\/ Tablet : scroll classique vers ProcederPaiementTitre\r\n                    const $target = $('#ProcederPaiementTitre');\r\n                    if ($target.length > 0) {\r\n                        $('html, body').animate({\r\n                            scrollTop: $target.offset().top - 100\r\n                        }, 500);\r\n                    }\r\n                }\r\n                \r\n                console.log('\ud83d\udcf1 Scroll effectu\u00e9 - Mobile:', isMobile, 'Desktop:', isDesktop);\r\n            }, 300);\r\n            \r\n            console.log('\u2705 \u00c9tape 5 ouverte');\r\n            \r\n            if (AND(commandeData, commandeData.commande_id)) {\r\n                envoyerBonCommandeAsync(commandeData.commande_id);\r\n            }\r\n            \r\n            \/\/ \u2705 R\u00e9activer apr\u00e8s succ\u00e8s (pour permettre nouvelle commande si retour arri\u00e8re)\r\n            setTimeout(function() {\r\n                commandeEnCours = false;\r\n                $bouton.prop('disabled', false).css('opacity', '1');\r\n            }, 2000);\r\n        }\r\n        \r\n        function envoyerBonCommandeAsync(commandeId) {\r\n            console.log('\ud83d\udce7 Envoi bon de commande en arri\u00e8re-plan pour commande #' + commandeId);\r\n            \r\n            $.ajax({\r\n                url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                type: 'POST',\r\n                data: {\r\n                    action: 'envoyer_bon_commande',\r\n                    commande_id: commandeId\r\n                },\r\n                success: function(response) {\r\n                    console.log('\u2705 Bon de commande envoy\u00e9');\r\n                },\r\n                error: function(error) {\r\n                    console.warn('\u26a0\ufe0f Erreur envoi bon de commande (non bloquant):', error);\r\n                }\r\n            });\r\n        }\r\n        \r\n        async function creerCommandeEnBase() {\r\n            console.log('\ud83d\udcbe Cr\u00e9ation commande en base...');\r\n            \r\n            if (!window.VIA_Panier || window.VIA_Panier.state.items.length === 0) {\r\n                throw new Error('Aucune commande dans le panier');\r\n            }\r\n            \r\n            var itemsValides = window.VIA_Panier.state.items.filter(function(item) {\r\n                \/\/ \u2705 v1.7 : V\u00e9rifier aussi que l'espace pub est s\u00e9lectionn\u00e9\r\n                return AND(item.tarifHT, AND(item.tarifHT > 0, AND(item.dateDebut, AND(item.dateFin, AND(item.duree, item.emplacementPageWeb)))));\r\n            });\r\n            \r\n            if (itemsValides.length === 0) {\r\n                throw new Error('Aucune commande valide (tarif, dates et espace pub requis)');\r\n            }\r\n            \r\n            console.log('\u2705 ' + itemsValides.length + ' commande(s) valide(s)');\r\n            \r\n            var premierItem = itemsValides[0];\r\n            \r\n            var dateDebut = '';\r\n            var dateFin = '';\r\n            var duree = 0;\r\n            \r\n            if (AND(premierItem.dateDebut, premierItem.dateFin)) {\r\n                dateDebut = convertirDateVersSql(premierItem.dateDebut);\r\n                dateFin = convertirDateVersSql(premierItem.dateFin);\r\n                duree = premierItem.duree || 0;\r\n                \r\n                if (!dateDebut || !dateFin) {\r\n                    throw new Error('Dates invalides : ' + JSON.stringify({ \r\n                        dateDebut: premierItem.dateDebut, \r\n                        dateFin: premierItem.dateFin \r\n                    }));\r\n                }\r\n            } else {\r\n                throw new Error('Dates manquantes dans le panier');\r\n            }\r\n            \r\n            console.log('\ud83d\udcc5 Dates de la commande:', { dateDebut: dateDebut, dateFin: dateFin, duree: duree });\r\n            \r\n            var donneesAnnonceur = JSON.parse(sessionStorage.getItem('via_annonceur_data') || '{}');\r\n\r\n            \/\/ \u2705 Lire la devise depuis VIA_Paiement (source de v\u00e9rit\u00e9 apr\u00e8s \u00e9tape 3)\r\n            var devise = (AND(window.VIA_Paiement, window.VIA_Paiement.state.devise)) \r\n                ? window.VIA_Paiement.state.devise\r\n                : (sessionStorage.getItem('devise_paiement') || 'EUR');\r\n            \r\n            console.log('\ud83d\udcb1 Devise pour commande:', devise);\r\n            \r\n            \/\/ \u2705 Calculer le taux de conversion SEULEMENT si devise \u2260 EUR\r\n            var tauxConversion = null;\r\n            if (AND(devise !== 'EUR', AND(window.VIA_App, typeof window.VIA_App.convertirDevise === 'function'))) {\r\n                tauxConversion = window.VIA_App.convertirDevise(1, devise, 'EUR');\r\n                console.log('\ud83d\udcb1 Taux conversion ' + devise + ' \u2192 EUR : ' + tauxConversion);\r\n            }\r\n            \r\n            var nbEcheances = parseInt(sessionStorage.getItem('nb_echeances')) || 1;\r\n            var modePaiement = sessionStorage.getItem('mode_paiement');\r\n            var zoneTVA = sessionStorage.getItem('ZoneTVA') || 'FR';\r\n            var tauxCommissionGlobal = parseFloat(sessionStorage.getItem('CommercialTauxCommission')) || 0;\r\n            \r\n            if (AND(devise !== 'EUR', AND(window.VIA_App, typeof window.VIA_App.convertirDevise === 'function'))) {\r\n                \/\/ Convertir 1 unit\u00e9 de devise en EUR pour obtenir le taux\r\n                var uniteEnEUR = window.VIA_App.convertirDevise(1, devise, 'EUR');\r\n                if (AND(uniteEnEUR, uniteEnEUR > 0)) {\r\n                    tauxConversion = uniteEnEUR;\r\n                    console.log('\ud83d\udcb1 Taux conversion ' + devise + ' \u2192 EUR : ' + tauxConversion.toFixed(4));\r\n                }\r\n            }\r\n            \r\n            var annonceurAccountId = '';\r\n            \r\n            if (sessionStorage.getItem('AnnonceurConnected') === 'Yes') {\r\n                annonceurAccountId = sessionStorage.getItem('Annonceur_UserId');\r\n            } else if (sessionStorage.getItem('CommercialConnected') === 'Yes') {\r\n                var selectedSource = sessionStorage.getItem('selected_annonceur_source');\r\n                var selectedId = sessionStorage.getItem('selected_annonceur_id');\r\n                \r\n                if (AND(selectedSource === 'wp_user', selectedId)) {\r\n                    annonceurAccountId = selectedId;\r\n                }\r\n            }\r\n            \r\n            var tauxTVA = 0;\r\n            if (zoneTVA === 'FR') {\r\n                if (donneesAnnonceur.numeroTVA === 'Non assujetti \u00e0 la TVA') {\r\n                    tauxTVA = 0;\r\n                } else {\r\n                    tauxTVA = 20;\r\n                }\r\n            } else if (zoneTVA === 'EU') {\r\n                if (donneesAnnonceur.nonRedevableTVA) {\r\n                    tauxTVA = 0;\r\n                } else {\r\n                    tauxTVA = 20;\r\n                }\r\n            }\r\n            \r\n            var codeUnique = '';\r\n            if (AND(premierItem, premierItem.reference)) {\r\n                var parts = premierItem.reference.split('-');\r\n                codeUnique = parts[0];\r\n            }\r\n            \r\n            if (!codeUnique) {\r\n                try {\r\n                    var response = await $.ajax({\r\n                        url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                        type: 'POST',\r\n                        xhrFields: { withCredentials: true },\r\n                        data: { action: 'generer_code_unique_commande' }\r\n                    });\r\n                    \r\n                    if (response.success) {\r\n                        codeUnique = response.data.code;\r\n                    }\r\n                } catch (error) {\r\n                    codeUnique = 'TMP';\r\n                }\r\n            }\r\n            \r\n            var totalHT_EUR = 0;\r\n            var totalHT_initial_EUR = 0;\r\n            var totalRemise_devise = 0;\r\n            var totalCommission_devise = 0;\r\n            \r\n            itemsValides.forEach(function(item) {\r\n                var tarifInitial_EUR = item.tarifHT_initial || item.tarifHT;\r\n                var tarifFinal_EUR = item.tarifHT;\r\n                \r\n                totalHT_EUR += tarifFinal_EUR;\r\n                totalHT_initial_EUR += tarifInitial_EUR;\r\n                \r\n                if (AND(item.montantRemise !== undefined, item.deviseRemiseCommission === devise)) {\r\n                    totalRemise_devise += item.montantRemise;\r\n                    totalCommission_devise += item.montantCommission || 0;\r\n                } else {\r\n                    var tarifInitial_devise = tarifInitial_EUR;\r\n                    var tarifFinal_devise = tarifFinal_EUR;\r\n                    \r\n                    if (AND(devise !== 'EUR', window.VIA_App)) {\r\n                        tarifInitial_devise = window.VIA_App.convertirDevise(tarifInitial_EUR, 'EUR', devise);\r\n                        tarifFinal_devise = window.VIA_App.convertirDevise(tarifFinal_EUR, 'EUR', devise);\r\n                    }\r\n                    \r\n                    var remiseItem = Math.max(0, tarifInitial_devise - tarifFinal_devise);\r\n                    var tauxCommissionItem = item.tauxCommission || tauxCommissionGlobal;\r\n                    var commissionItem = (tarifFinal_devise * tauxCommissionItem) \/ 100;\r\n                    \r\n                    totalRemise_devise += remiseItem;\r\n                    totalCommission_devise += commissionItem;\r\n                }\r\n            });\r\n            \r\n            var totalHT = totalHT_EUR;\r\n            var totalHT_initial = totalHT_initial_EUR;\r\n            \r\n            if (AND(devise !== 'EUR', window.VIA_App)) {\r\n                totalHT = window.VIA_App.convertirDevise(totalHT_EUR, 'EUR', devise);\r\n                totalHT_initial = window.VIA_App.convertirDevise(totalHT_initial_EUR, 'EUR', devise);\r\n            }\r\n            \r\n            var espacespub = itemsValides.map(function(item, index) {\r\n                var envoiUlterieur = item.donneesIframe ? item.donneesIframe.EnvoiUlterieur : null;\r\n                var envoiUlterieurValue = (AND(envoiUlterieur, ['yes', 'true', '1'].indexOf(envoiUlterieur.toLowerCase()) !== -1)) ? 'Yes' : 'No';\r\n                \r\n                var itemDateDebut = convertirDateVersSql(item.dateDebut) || dateDebut;\r\n                var itemDateFin = convertirDateVersSql(item.dateFin) || dateFin;\r\n                var itemDuree = item.duree || duree;\r\n                var lienEspacePub = item.lienEspacePub || '';\r\n                \/\/ \u2705 v2.6 : cheminFichierAnnonce peut \u00eatre mis \u00e0 jour via donneesIframe.FullPathAdFile (restauration annonce)\r\n                var cheminFichierAnnonce = item.cheminFichierAnnonce || (item.donneesIframe ? item.donneesIframe.FullPathAdFile : '') || '';\r\n                \r\n                var urlPageSource = item.donneesIframe?.LoadedPageUrl || item.linkSecteurPage || '';\r\n                \r\n                var tarifHT_initial_EUR = item.tarifHT_initial || item.tarifHT;\r\n                var tarifHT_EUR = item.tarifHT;\r\n                \r\n                var tarifHT_initial = tarifHT_initial_EUR;\r\n                var tarifHT = tarifHT_EUR;\r\n                \r\n                if (AND(devise !== 'EUR', window.VIA_App)) {\r\n                    tarifHT_initial = window.VIA_App.convertirDevise(tarifHT_initial_EUR, 'EUR', devise);\r\n                    tarifHT = window.VIA_App.convertirDevise(tarifHT_EUR, 'EUR', devise);\r\n                }\r\n                \r\n                var montantRemise, montantCommission;\r\n                var tauxCommission = item.tauxCommission || tauxCommissionGlobal;\r\n                \r\n                if (AND(item.montantRemise !== undefined, item.deviseRemiseCommission === devise)) {\r\n                    montantRemise = item.montantRemise;\r\n                    montantCommission = item.montantCommission || 0;\r\n                } else {\r\n                    montantRemise = Math.max(0, tarifHT_initial - tarifHT);\r\n                    montantCommission = (tarifHT * tauxCommission) \/ 100;\r\n                }\r\n                \r\n                var positionLibelle = window.VIA_Panier.convertirPositionEnLibelle(item.position);\r\n                console.log('\ud83d\udccd Position:', item.position, '\u2192', positionLibelle);\r\n\r\n                return {\r\n                    pays: item.pays || '',\r\n                    secteur: item.selectedPageSecteur || '',\r\n                    format: item.format || '',\r\n                    page: item.commandePage || '',\r\n                    emplacement_page_web: item.emplacementPageWeb || '',\r\n                    position: positionLibelle,\r\n                    tarif_ht_initial: tarifHT_initial,\r\n                    tarif_ht: tarifHT,\r\n                    montant_remise: montantRemise,\r\n                    commercial_taux_commission: tauxCommission,\r\n                    commercial_commission: montantCommission,\r\n                    envoi_ulterieur: envoiUlterieurValue,\r\n                    date_debut: itemDateDebut,\r\n                    date_fin: itemDateFin,\r\n                    duree: itemDuree,\r\n                    lien_espace_pub: lienEspacePub,\r\n                    chemin_fichier_annonce: cheminFichierAnnonce,\r\n                    url_page_source: urlPageSource \r\n                };\r\n            });\r\n            \r\n            var response = await $.ajax({\r\n                url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                type: 'POST',\r\n                xhrFields: { withCredentials: true },\r\n                data: {\r\n                    action: 'creer_commande',\r\n                    code_unique: codeUnique,\r\n                    email: donneesAnnonceur.emailContact,\r\n                    nom_contact: donneesAnnonceur.nomContact,\r\n                    nom_societe: donneesAnnonceur.nomSociete,\r\n                    telephone: donneesAnnonceur.telephoneContact,\r\n                    adresse: donneesAnnonceur.adresseLigne1,\r\n                    code_postal: donneesAnnonceur.codePostal,\r\n                    ville: donneesAnnonceur.ville,\r\n                    pays: donneesAnnonceur.pays,\r\n                    numero_tva: donneesAnnonceur.numeroTVA,\r\n                    facturation_contact: donneesAnnonceur.facturationContact || '',\r\n                    facturation_adresse: donneesAnnonceur.facturationAdresse || '',\r\n                    facturation_code_postal: donneesAnnonceur.facturationCodePostal || '',\r\n                    facturation_ville: donneesAnnonceur.facturationVille || '',\r\n                    facturation_pays: donneesAnnonceur.facturationPays || '',\r\n                    facturation_email: donneesAnnonceur.facturationEmail || '',\r\n                    facturation_telephone: donneesAnnonceur.facturationTelephone || '',\r\n                    tarif_ht_initial: totalHT_initial,\r\n                    tarif_ht: totalHT,\r\n                    montant_remise: totalRemise_devise,\r\n                    commercial_commission: totalCommission_devise,\r\n                    commercial_taux_commission: tauxCommissionGlobal,\r\n                    taux_tva: tauxTVA,\r\n                    zone_tva: zoneTVA,\r\n                    nb_espacepub: espacespub.length,\r\n                    date_debut: dateDebut,\r\n                    date_fin: dateFin,\r\n                    duree: duree,\r\n                    commercial_account_id: sessionStorage.getItem('CommercialConnected') === 'Yes' \r\n                        ? sessionStorage.getItem('Commercial_UserId') \r\n                        : '', \r\n                    annonceur_account_id: annonceurAccountId, \r\n                    code_devise_etrangere: devise !== 'EUR' ? devise : null,\r\n                    tarif_devise_etrangere: devise !== 'EUR' ? totalHT : null,\r\n                    taux_conversion: tauxConversion,\r\n                    nb_echeances: nbEcheances,\r\n                    mode_paiement: modePaiement,\r\n                    espacespub: JSON.stringify(espacespub)\r\n                }\r\n            });\r\n            \r\n            if (response.success) {\r\n                sessionStorage.setItem('commande_id', response.data.commande_id);\r\n                sessionStorage.setItem('commande_ref', response.data.commande_ref);\r\n                sessionStorage.setItem('commande_ref_url', response.data.commande_ref_url);\r\n                sessionStorage.setItem('paiement_id', response.data.paiement_id);\r\n                \r\n                console.log('\u2705 Commande cr\u00e9\u00e9e:', response.data.commande_ref);\r\n                return response.data;\r\n            } else {\r\n                throw new Error(response.data.message || 'Erreur cr\u00e9ation commande');\r\n            }\r\n        }\r\n        \r\n        function convertirDateVersSql(dateStr) {\r\n            if (!dateStr) return null;\r\n            \r\n            if (\/^\\d{4}-\\d{2}-\\d{2}$\/.test(dateStr)) return dateStr;\r\n            \r\n            if (\/^\\d{2}\\\/\\d{2}\\\/\\d{4}$\/.test(dateStr)) {\r\n                var parts = dateStr.split('\/');\r\n                return parts[2] + '-' + parts[1] + '-' + parts[0];\r\n            }\r\n            \r\n            if (\/^\\d{2}\\\/\\d{2}\\\/\\d{2}$\/.test(dateStr)) {\r\n                var parts = dateStr.split('\/');\r\n                var anneComplete = parseInt(parts[2]) < 50 ? '20' + parts[2] : '19' + parts[2];\r\n                return anneComplete + '-' + parts[1] + '-' + parts[0];\r\n            }\r\n            \r\n            return null;\r\n        }\r\n        \r\n        function initBoutonValidation() {\r\n            $('.ValidationsCGVBouton').on('click', function(e) {\r\n                e.preventDefault();\r\n                \r\n                if (commandeEnCours) {\r\n                    console.warn('\u26a0\ufe0f Clic ignor\u00e9 - commande en cours');\r\n                    return;\r\n                }\r\n                \r\n                \/\/ \u2705 v1.6 : V\u00e9rification s\u00e9quentielle g\u00e9r\u00e9e par validation-etapes-process (phase capture)\r\n                \r\n                if (verifierCheckboxes()) {\r\n                    sessionStorage.setItem('validations_completees', 'true');\r\n                    sessionStorage.setItem('validation_commande', 'true');\r\n                    sessionStorage.setItem('acceptation_cgv', 'true');\r\n                    sessionStorage.setItem('acceptation_commande', 'true');\r\n                    \r\n                    passerEtapePaiement();\r\n                } else {\r\n                    var $premierErreur = $('#MsgElementsCommande:visible, #MsgCGVText:visible, #MsgAcceptationCommandeConteneur:visible').first();\r\n                    if ($premierErreur.length > 0) {\r\n                        $('html, body').animate({\r\n                            scrollTop: $premierErreur.offset().top - 100\r\n                        }, 300);\r\n                    }\r\n                }\r\n            });\r\n        }\r\n        \r\n        function initAutoHideMessages() {\r\n            \/\/ \u2705 v1.6 : Blocage des checkboxes si process incomplet\r\n            \/\/ \u2192 g\u00e9r\u00e9 par validation-etapes-process (phase capture)\r\n            \r\n            $('input[name=\"form_fields[Validation_Commande]\"]').on('change', function() {\r\n                if ($(this).is(':checked')) $('#MsgElementsCommande').fadeOut(300);\r\n            });\r\n            \r\n            $('input[name=\"form_fields[Acceptation_CGV]\"]').on('change', function() {\r\n                if ($(this).is(':checked')) $('#MsgCGVText').fadeOut(300);\r\n            });\r\n            \r\n            $('input[name=\"form_fields[Acceptation_Commande]\"]').on('change', function() {\r\n                if ($(this).is(':checked')) $('#MsgAcceptationCommandeConteneur').fadeOut(300);\r\n            });\r\n        }\r\n        \r\n        \/\/ INITIALISATION\r\n        try {\r\n            masquerMessagesErreur();\r\n            initBoutonValidation();\r\n            initAutoHideMessages();\r\n            initBoutonPasserCommande();\r\n            initBoutonRetourModification();\r\n            \r\n            console.log('\u2705 Module R\u00e9capitulatif et Validation v1.6 initialis\u00e9');\r\n            \r\n            window.VIA_RecapValidation = {\r\n                verifierCheckboxes: verifierCheckboxes,\r\n                passerEtapePaiement: passerEtapePaiement,\r\n                creerCommandeEnBase: creerCommandeEnBase,\r\n                reinitialiserValidations: reinitialiserValidations,\r\n                \/\/ \u2705 v1.5 : Ces fonctions sont maintenant dans VIA_Panier\r\n                retourModificationCommande: function() {\r\n                    if (window.VIA_Panier && typeof window.VIA_Panier.retourModificationCommande === 'function') {\r\n                        return window.VIA_Panier.retourModificationCommande();\r\n                    }\r\n                },\r\n                recalculerTousTarifs: function() {\r\n                    if (window.VIA_Panier && typeof window.VIA_Panier.recalculerTousTarifs === 'function') {\r\n                        return window.VIA_Panier.recalculerTousTarifs();\r\n                    }\r\n                }\r\n            };\r\n        } catch (error) {\r\n            console.error('\u274c Erreur initialisation r\u00e9cap validation:', error);\r\n        }\r\n    }\r\n    \r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', initRecapValidationModule);\r\n    } else {\r\n        initRecapValidationModule();\r\n    }\r\n\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b9cf36f elementor-widget elementor-widget-html\" data-id=\"b9cf36f\" data-element_type=\"widget\" data-e-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\/**\r\n * VIA Agency - PAIEMENT (Virement & CB Stripe)\r\n * @version 1.4 - F\u00e9vrier 2026\r\n * \u2705 Refonte des textes #PaiementMsg et #EcheanceActiveTextNoInput\r\n * \u2705 Virement multi-\u00e9ch\u00e9ances (J, J+7, J+14) avec plages de dates\r\n * \u2705 CB multi-\u00e9ch\u00e9ances (J, J+7, J+14)\r\n * \u2705 v1.3 : Popup iframe (bon de commande \/ facture) avec URL absolue via-agency.media\r\n * \u2705 v1.4 : Largeur popup par d\u00e9faut 1050px\r\n * \u2705 PAI-pb1731 : z-index du popup au premier plan (desktop)\r\n * \u2705 PAI-pb1791 : placeholder du numero de carte -> \u00ab Card number \u00bb\r\n *\/\r\n\r\nwindow._viaPaiementVer = 'PAI-pb2355';\r\ntry { console.log('[PAIEMENT DOC ECHO] ' + window._viaPaiementVer + ' SERVI'); } catch (_ePV) {}\r\n\r\n(function() {\r\n    'use strict';\r\n    \r\n    console.log('\ud83d\udcb3 Chargement module Paiement v1.4...');\r\n    \r\n    \r\n    \/**\r\n     * \u2705 v1.3 : Ouvre le bon de commande dans un popup iframe\r\n     *\/\r\n    jQuery('.Bondecommande').on('click', function(e) {\r\n        e.preventDefault();\r\n        const ref = sessionStorage.getItem('commande_ref_url');\r\n        const commandeRef = sessionStorage.getItem('commande_ref');\r\n        if (ref) {\r\n            VIA_DocumentPopup.openBonCommande(ref, commandeRef);\r\n        } else {\r\n            alert('R\u00e9f\u00e9rence de commande introuvable');\r\n        }\r\n    });\r\n\r\n    \/**\r\n     * \u2705 v1.3 : Ouvre la facture dans un popup iframe\r\n     *\/\r\n    jQuery('#FactureDisponible').on('click', function(e) {\r\n        e.preventDefault();\r\n        const ref = sessionStorage.getItem('commande_ref_url');\r\n        const commandeRef = sessionStorage.getItem('commande_ref');\r\n        if (ref) {\r\n            VIA_DocumentPopup.openFacture(ref, 1, commandeRef);\r\n        } else {\r\n            alert('R\u00e9f\u00e9rence de commande introuvable');\r\n        }\r\n    });\r\n\r\n    \/**\r\n     * Initialisation\r\n     *\/\r\n    function initPaiementModule() {\r\n        if (typeof jQuery === 'undefined') {\r\n            console.error('\u274c jQuery non disponible');\r\n            setTimeout(initPaiementModule, 500);\r\n            return;\r\n        }\r\n        \r\n        const $ = jQuery;\r\n        \r\n        function formaterMontant(montant, devise) {\r\n            const montantArrondi = Math.round(montant * 100) \/ 100;\r\n            return new Intl.NumberFormat('fr-FR', {\r\n                style: 'currency',\r\n                currency: devise\r\n            }).format(montantArrondi);\r\n        }\r\n        \r\n        let stripe = null;\r\n        let cardNumberElement = null;\r\n        let cardExpiryElement = null;\r\n        let cardCvcElement = null;\r\n        \r\n        console.log('\u2705 Initialisation module Paiement v1.4...');\r\n        \r\n        \/**\r\n         * Initialise l'\u00e9tape 5 selon le mode de paiement\r\n         *\/\r\n        function initialiserEtapePaiement() {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            const modePaiement = sessionStorage.getItem('mode_paiement');\r\n            const montantTotal = parseFloat(sessionStorage.getItem('montant_total'));\r\n            const devise = (sessionStorage.getItem('devise_paiement') || 'EUR').toUpperCase();\r\n            const nbEcheances = parseInt(sessionStorage.getItem('nb_echeances')) || 1;\r\n            \r\n            console.log('\ud83d\udcb3 Donn\u00e9es paiement:', { montantTotal, nbEcheances, devise, modePaiement });\r\n        \r\n            \/\/ R\u00e9cup\u00e9rer les infos TVA\r\n            const zoneTVA = sessionStorage.getItem('ZoneTVA');\r\n            const donnees = JSON.parse(sessionStorage.getItem('via_annonceur_data') || '{}');\r\n            \r\n            let estHT = false;\r\n            if (zoneTVA === 'HorsEU' || (zoneTVA === 'EU' && donnees.nonRedevableTVA) || \r\n                (zoneTVA === 'FR' && donnees.numeroTVA === 'Non assujetti \u00e0 la TVA')) {\r\n                estHT = true;\r\n            }\r\n            \r\n            const suffixe = estHT \r\n                ? (lang === 'EN' ? 'excl. VAT' : 'H.T.')\r\n                : (lang === 'EN' ? 'incl. VAT' : 'T.T.C.');\r\n            \r\n            console.log('\ud83d\udcb3 Mode paiement:', modePaiement);\r\n            \r\n            \/\/ Masquer le message d'erreur par d\u00e9faut\r\n            $('#MsgErreurTitulaireCarte').hide();\r\n            \r\n            if (modePaiement === 'Virement') {\r\n                _viaPlacerProceder2146('Virement');   \/\/ pb2146\r\n                initialiserPaiementVirement(montantTotal, devise, suffixe, nbEcheances);\r\n            } else if (modePaiement === 'CB') {\r\n                _viaPlacerProceder2146('CB');         \/\/ pb2146\r\n                initialiserPaiementCB(montantTotal, devise, suffixe, nbEcheances);\r\n            } else {\r\n                console.warn('[pb2146] mode de paiement inattendu : \"'\r\n                    + (modePaiement || '(vide)') + '\" \u2014 placement inchange');\r\n            }\r\n        }\r\n\r\n        \/\/ ================================================================\r\n        \/\/ pb2146 \/ pb2147 : ORDRE DES CONTENEURS DANS L'ETAPE PAIEMENT.\r\n        \/\/   CB (demande JF) :  #ProcederPaiementConteneur\r\n        \/\/                      #MailsFactureTexte            (pb2148b : 2e rang)\r\n        \/\/                      #ValiditeBdcPaiementContainer\r\n        \/\/                      #CBPayerSommeContainer\r\n        \/\/   Virement : chacun revient a sa place d'origine.\r\n        \/\/   METHODE : on insere chaque element AVANT la cible, dans l'ordre du\r\n        \/\/   tableau \u2014 insertBefore place toujours juste avant, donc la\r\n        \/\/   sequence sort telle qu'elle est ecrite, sans calcul d'index. Pour\r\n        \/\/   ajouter un bloc, il suffit de l'inserer au bon rang du tableau.\r\n        \/\/   ATTENTION #MailsFactureTexte : le mode CB le MASQUE (l.265,\r\n        \/\/   .hide()) et le mode Virement l'affiche avec son texte. Le\r\n        \/\/   deplacement ne change pas cette regle \u2014 le bloc est place, mais\r\n        \/\/   reste masque en CB tant que ce hide subsiste. Si JF veut le voir,\r\n        \/\/   c'est ce hide qu'il faudra lever, pas le placement.\r\n        \/\/   ORIGINES GELEES au PREMIER passage, par element (parent + frere\r\n        \/\/   suivant), et jamais recalculees : un second appel memoriserait la\r\n        \/\/   position deja deplacee et le retour deviendrait impossible.\r\n        \/\/   Memorisation en window, pas en sessionStorage (une cle qui survit\r\n        \/\/   designerait un noeud d'une page morte).\r\n        \/\/   Les deux conteneurs sont recents et absents du corpus JS : toute\r\n        \/\/   absence est journalisee, jamais subie (insertBefore sur un parent\r\n        \/\/   nul echoue en silence). Un element manquant n'empeche pas le\r\n        \/\/   placement de l'autre.\r\n        \/\/   NB : les origines sont a l'interieur de #FormulaireCB, que le mode\r\n        \/\/   Virement masque (l.167) \u2014 le retour les y remet, donc masques avec\r\n        \/\/   lui. C'est le comportement attendu tant que ces blocs sont propres\r\n        \/\/   au CB ; si l'un devait rester visible en Virement, il faudrait le\r\n        \/\/   reparenter HORS de #FormulaireCB (motif pb2136).\r\n        \/\/   Revert : window._viaPb2146Off = true.\r\n        \/\/ ================================================================\r\n        function _viaPlacerProceder2146(mode) {\r\n            try {\r\n                if (window._viaPb2146Off === true) { return; }\r\n                \/\/ pb2148 : #MailsFactureTexte rejoint la sequence, en 3e position\r\n                \/\/   (demande JF) \u2014 l'ordre de ce tableau EST l'ordre affiche.\r\n                \/\/ pb2148b : erratum JF \u2014 MailsFactureTexte passe AVANT\r\n                \/\/   ValiditeBdcPaiementContainer. Seul l'ordre de ce tableau change ;\r\n                \/\/   la mecanique, les origines gelees et le retour en Virement sont\r\n                \/\/   inchanges (l'ordre du tableau EST l'ordre affiche).\r\n                var _ids2147 = ['ProcederPaiementConteneur', 'MailsFactureTexte',\r\n                    'ValiditeBdcPaiementContainer'];\r\n                if (!window._viaOrig2147) { window._viaOrig2147 = {}; }\r\n                _ids2147.forEach(function (_id) {\r\n                    var _el = document.getElementById(_id);\r\n                    if (_el ? !window._viaOrig2147[_id] : false) {\r\n                        window._viaOrig2147[_id] = {\r\n                            parent: _el.parentElement,\r\n                            suivant: _el.nextElementSibling\r\n                        };\r\n                    }\r\n                });\r\n\r\n                if (mode === 'CB') {\r\n                    var _cb2146 = document.getElementById('CBPayerSommeContainer');\r\n                    if (!_cb2146) { console.warn('[pb2147] #CBPayerSommeContainer introuvable \u2014 placement inchange'); return; }\r\n                    if (!_cb2146.parentElement) { console.warn('[pb2147] #CBPayerSommeContainer sans parent'); return; }\r\n                    var _faits2147 = [];\r\n                    _ids2147.forEach(function (_id) {\r\n                        var _el = document.getElementById(_id);\r\n                        if (!_el) { console.warn('[pb2147] #' + _id + ' introuvable \u2014 ignore'); return; }\r\n                        _cb2146.parentElement.insertBefore(_el, _cb2146);\r\n                        _faits2147.push(_id);\r\n                    });\r\n                    console.log('[pb2147] CB : ordre pose -> ' + _faits2147.join(' > ')\r\n                        + ' > CBPayerSommeContainer');\r\n                    return;\r\n                }\r\n\r\n                var _ret2147 = [];\r\n                _ids2147.forEach(function (_id) {\r\n                    var _el = document.getElementById(_id);\r\n                    var _o = window._viaOrig2147[_id];\r\n                    if (!_el) { console.warn('[pb2147] #' + _id + ' introuvable au retour'); return; }\r\n                    if (_o ? !_o.parent : true) { console.warn('[pb2147] origine inconnue pour #' + _id); return; }\r\n                    if (_el.parentElement === _o.parent\r\n                        ? (_el.nextElementSibling === _o.suivant) : false) {\r\n                        _ret2147.push(_id + '(deja)');\r\n                        return;\r\n                    }\r\n                    _o.parent.insertBefore(_el, _o.suivant);\r\n                    _ret2147.push(_id);\r\n                });\r\n                console.log('[pb2147] ' + mode + ' : retour a l\\'origine -> ' + _ret2147.join(', '));\r\n            } catch (_e2146) { console.warn('[pb2147]', _e2146.message); }\r\n        }\r\n        \r\n        \/**\r\n         * Initialise le paiement par virement\r\n         * \u2705 V1.2 : Refonte compl\u00e8te des textes avec plages de dates\r\n         *\/\r\n        function initialiserPaiementVirement(montant, devise, suffixe, nbEcheances) {\r\n            console.log('\ud83c\udfe6 Initialisation paiement par virement - \u00c9ch\u00e9ances:', nbEcheances);\r\n            \r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const montantFormate = formaterMontant(montant, devise);\r\n            const montantEcheance = montant \/ nbEcheances;\r\n            const montantEcheanceFormate = formaterMontant(montantEcheance, devise);\r\n            \r\n            \/\/ G\u00e9n\u00e9rer les plages d'\u00e9ch\u00e9ances virement (J, J+7, J+14 avec 1 semaine pour payer)\r\n            const plagesEcheances = genererDatesEcheancesVirement(nbEcheances);\r\n            const plagesFormatees = plagesEcheances.join('<br>');\r\n            \r\n            \/\/ R\u00e9cup\u00e9rer la r\u00e9f\u00e9rence commande\r\n            const refCommande = sessionStorage.getItem('commande_ref') || 'N\/A';\r\n            \r\n            \/\/ \u2705 Message r\u00e9capitulatif #PaiementMsg\r\n            let msgPaiement;\r\n            if (nbEcheances === 1) {\r\n                msgPaiement = lang === 'EN'\r\n                    ? `Order ${refCommande} for ${montantFormate}<br>to be paid by bank transfer in 1 installment`\r\n                    : `Commande ${refCommande} d'un montant de ${montantFormate}<br>\u00e0 r\u00e9gler par virement en 1 \u00e9ch\u00e9ance`;\r\n            } else {\r\n                msgPaiement = lang === 'EN'\r\n                    ? `Order ${refCommande} for ${montantFormate}<br>to be paid by bank transfer in ${nbEcheances} installments of ${montantEcheanceFormate}`\r\n                    : `Commande ${refCommande} d'un montant de ${montantFormate}<br>\u00e0 r\u00e9gler par virement en ${nbEcheances} \u00e9ch\u00e9ances de ${montantEcheanceFormate}`;\r\n            }\r\n            $('#PaiementMsg').html(msgPaiement);\r\n            \r\n            \/\/ \u2705 Texte d\u00e9taill\u00e9 #EcheanceActiveTextNoInput\r\n            let texteEcheance;\r\n            if (nbEcheances === 1) {\r\n                texteEcheance = lang === 'EN'\r\n                    ? `Bank details for the transfer are in the order form<br><br>As a reminder, the payment deadline is: ${plagesEcheances[0]}<br><br>The invoice will be sent by email after payment`\r\n                    : `Les coordonn\u00e9es bancaires pour effectuer le virement<br>sont indiqu\u00e9es dans le bon de commande<br><br>Pour m\u00e9moire, la date limite de paiement est : ${plagesEcheances[0]}`;\r\n            } else {\r\n                texteEcheance = lang === 'EN'\r\n                    ? `Bank details for the transfers are in the order form<br><br>As a reminder, the payment deadlines are:<br>${plagesFormatees}<br><br>An invoice is sent by email after each payment<br>and a summary invoice will be sent after the last payment`\r\n                    : `Les coordonn\u00e9es bancaires pour effectuer les virements<br>sont indiqu\u00e9es dans le bon de commande<br><br>Pour m\u00e9moire, les dates limites de paiements sont :<br>${plagesFormatees}<br><br>Une facture est envoy\u00e9e par mail apr\u00e8s chaque paiement<br>et une facture r\u00e9capitulative sera envoy\u00e9e apr\u00e8s le dernier paiement`;\r\n            }\r\n            $('#MailsFactureTexte').hide();\r\n            $('#EcheanceActiveTextNoInput').html(texteEcheance)\r\n                .css('color', '#666666');\r\n            \r\n            \/\/ Masquer les \u00e9l\u00e9ments CB et le d\u00e9lai\r\n            $('#FactureDisponible').hide();\r\n            $('#FactureBDCMailMsg').hide();\r\n            $('#FormulaireCB').hide();\r\n            $('#ValiditeBdcPaiement').hide();\r\n            \r\n            console.log('\u2705 Paiement virement configur\u00e9 - \u00c9ch\u00e9ances:', nbEcheances);\r\n        }\r\n        \r\n        \/**\r\n         * G\u00e9n\u00e8re les dates d'\u00e9ch\u00e9ances pour le virement (J, J+7, J+14)\r\n         * \u2705 v1.2 : Plages de dates (1 semaine pour payer chaque \u00e9ch\u00e9ance)\r\n         *\/\r\n        function genererDatesEcheancesVirement(nbEcheances) {\r\n            const aujourd_hui = new Date();\r\n            const plages = [];\r\n            \r\n            \/\/ Virement : \u00e9ch\u00e9ances \u00e0 J, J+7, J+14, avec 1 semaine pour payer chacune\r\n            for (let i = 0; i < nbEcheances; i++) {\r\n                const dateDebut = new Date(aujourd_hui);\r\n                dateDebut.setDate(dateDebut.getDate() + (i * 7));\r\n                \r\n                const dateFin = new Date(aujourd_hui);\r\n                dateFin.setDate(dateFin.getDate() + ((i + 1) * 7));\r\n                \r\n                const jourDebut = String(dateDebut.getDate()).padStart(2, '0');\r\n                const moisDebut = String(dateDebut.getMonth() + 1).padStart(2, '0');\r\n                \r\n                const jourFin = String(dateFin.getDate()).padStart(2, '0');\r\n                const moisFin = String(dateFin.getMonth() + 1).padStart(2, '0');\r\n                const anneeFin = String(dateFin.getFullYear()).slice(-2);\r\n                \r\n                \/\/ Format : \"du 17\/01 au 24\/01\/26\"\r\n                plages.push(`du ${jourDebut}\/${moisDebut} au ${jourFin}\/${moisFin}\/${anneeFin}`);\r\n            }\r\n            \r\n            return plages;\r\n        }\r\n        \r\n        \/**\r\n         * G\u00e9n\u00e8re les dates d'\u00e9ch\u00e9ances pour la CB (hebdomadaires : J+0, J+7, J+14...)\r\n         *\/\r\n        function genererDatesEcheancesCB(nbEcheances) {\r\n            const aujourd_hui = new Date();\r\n            const dates = [];\r\n            \r\n            for (let i = 0; i < nbEcheances; i++) {\r\n                const dateEcheance = new Date(aujourd_hui);\r\n                dateEcheance.setDate(dateEcheance.getDate() + (i * 7));\r\n                \r\n                const jour = String(dateEcheance.getDate()).padStart(2, '0');\r\n                const mois = String(dateEcheance.getMonth() + 1).padStart(2, '0');\r\n                const annee = String(dateEcheance.getFullYear()).slice(-2);\r\n                \r\n                dates.push(`${jour}\/${mois}\/${annee}`);\r\n            }\r\n            \r\n            return dates;\r\n        }\r\n\r\n        \/**\r\n         * Initialise le paiement par CB\r\n         * \u2705 V1.2 : Refonte compl\u00e8te des textes\r\n         *\/\r\n        function initialiserPaiementCB(montantTotal, devise, suffixe, nbEcheances) {\r\n            console.log('\ud83d\udcb3 Initialisation paiement par CB - \u00c9ch\u00e9ances:', nbEcheances);\r\n            \r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            const montantFormate = formaterMontant(montantTotal, devise);\r\n            const montantEcheance = montantTotal \/ nbEcheances;\r\n            const montantEcheanceFormate = formaterMontant(montantEcheance, devise);\r\n            \r\n            \/\/ G\u00e9n\u00e9rer les dates d'\u00e9ch\u00e9ances CB (hebdomadaires : J+0, J+7, J+14...)\r\n            const datesEcheances = genererDatesEcheancesCB(nbEcheances);\r\n            const datesFormatees = datesEcheances.join(', ');\r\n            \r\n            \/\/ Pour multi-\u00e9ch\u00e9ances, exclure la 1\u00e8re date (paiement imm\u00e9diat)\r\n            const datesSuivantes = datesEcheances.slice(1).join(', ');\r\n            \r\n            \/\/ R\u00e9cup\u00e9rer la r\u00e9f\u00e9rence commande\r\n            const refCommande = sessionStorage.getItem('commande_ref') || 'N\/A';\r\n            \r\n            \/\/ \u2705 Message r\u00e9capitulatif #PaiementMsg\r\n            let msgPaiement;\r\n            if (nbEcheances === 1) {\r\n                msgPaiement = lang === 'EN'\r\n                    ? `Order ${refCommande} for ${montantFormate}<br>to be paid by card in 1 installment`\r\n                    : `Commande ${refCommande} d'un montant de ${montantFormate}<br>\u00e0 r\u00e9gler par carte bancaire en 1 \u00e9ch\u00e9ance`;\r\n            } else {\r\n                msgPaiement = lang === 'EN'\r\n                    ? `Order ${refCommande} for ${montantFormate}<br>to be paid by card in ${nbEcheances} installments of ${montantEcheanceFormate}`\r\n                    : `Commande ${refCommande} d'un montant de ${montantFormate}<br>\u00e0 r\u00e9gler par carte bancaire en ${nbEcheances} \u00e9ch\u00e9ances de ${montantEcheanceFormate}`;\r\n            }\r\n            $('#PaiementMsg').html(msgPaiement);\r\n            \r\n            \/\/ \u2705 Texte d\u00e9taill\u00e9 #EcheanceActiveTextNoInput\r\n            let texteEcheance;\r\n            if (nbEcheances === 1) {\r\n                texteEcheance = lang === 'EN'\r\n                    ? `The invoice will be sent by email after payment`\r\n                    : `La facture est envoy\u00e9e par mail apr\u00e8s le paiement`;\r\n                $('#MailsFactureTexte').hide();\r\n            } else if (nbEcheances === 2) {\r\n                texteEcheance = lang === 'EN'\r\n                    ? `After the first card payment, the following installment will be automatically debited<br>on ${datesSuivantes}`\r\n                    : `Apr\u00e8s le 1er paiement par carte bancaire, l'\u00e9ch\u00e9ance suivante sera automatiquement d\u00e9bit\u00e9e sur la carte bancaire le ${datesSuivantes}`;\r\n                \r\n                \/\/ \u2705 Texte factures dans #MailsFactureTexte\r\n                const texteFacture = lang === 'EN'\r\n                    ? `An invoice is sent by email after each payment<br>and a summary invoice will be sent after the last payment`\r\n                    : `Une facture est envoy\u00e9e par mail apr\u00e8s chaque paiement<br>et une facture r\u00e9capitulative sera envoy\u00e9e apr\u00e8s le dernier paiement`;\r\n                $('#MailsFactureTexte').html(texteFacture).show();\r\n            } else {\r\n                texteEcheance = lang === 'EN'\r\n                    ? `After the first card payment, the following installments will be automatically debited<br>on ${datesSuivantes}`\r\n                    : `Apr\u00e8s le 1er paiement par carte bancaire, les \u00e9ch\u00e9ances suivantes seront automatiquement d\u00e9bit\u00e9es sur la carte bancaire les ${datesSuivantes}`;\r\n                \r\n                \/\/ \u2705 Texte factures dans #MailsFactureTexte\r\n                const texteFacture = lang === 'EN'\r\n                    ? `An invoice is sent by email after each payment<br>and a summary invoice will be sent after the last payment`\r\n                    : `Une facture est envoy\u00e9e par mail apr\u00e8s chaque paiement<br>et une facture r\u00e9capitulative sera envoy\u00e9e apr\u00e8s le dernier paiement`;\r\n                $('#MailsFactureTexte').html(texteFacture).show();\r\n            }\r\n            $('#EcheanceActiveTextNoInput').html(texteEcheance)\r\n                .css('color', '#666666');\r\n            \r\n            \/\/ \u2705 Texte d\u00e9lai #ValiditeBdcPaiement (2 heures)\r\n            const maintenant = new Date();\r\n            const limite = new Date(maintenant.getTime() + (2 * 60 * 60 * 1000));\r\n            const heures = String(limite.getHours()).padStart(2, '0');\r\n            const minutes = String(limite.getMinutes()).padStart(2, '0');\r\n            \r\n            const texteDelai = lang === 'EN'\r\n                ? `Please proceed with payment within 2 hours until ${heures}:${minutes} GMT+1:00`\r\n                : `Merci de proc\u00e9der au paiement dans les 2 heures jusqu'\u00e0 ${heures}H${minutes} GMT+1:00`;\r\n            $('#ValiditeBdcPaiement').html(texteDelai);\r\n            \r\n            \/\/ Afficher le montant de la premi\u00e8re \u00e9ch\u00e9ance dans le formulaire\r\n            $('#FormCBMontant').html(montantEcheanceFormate);\r\n            \r\n            \/\/ Masquer les \u00e9l\u00e9ments non n\u00e9cessaires\r\n            $('#FactureDisponible').hide();\r\n            $('#FactureBDCMailMsg').hide();\r\n            \r\n            \/\/ Afficher le formulaire CB\r\n            $('#FormulaireCB').show();\r\n            \r\n            \/\/ Initialiser Stripe\r\n            initialiserStripe(montantEcheance);\r\n            \r\n            console.log('\u2705 Paiement CB configur\u00e9 - \u00c9ch\u00e9ances:', nbEcheances);\r\n        }\r\n        \r\n        \/**\r\n         * Initialise Stripe Elements\r\n         *\/\r\n        function initialiserStripe(montantEcheance) {\r\n            \/\/ Charger Stripe.js si pas d\u00e9j\u00e0 charg\u00e9\r\n            if (typeof Stripe === 'undefined') {\r\n                const script = document.createElement('script');\r\n                script.src = 'https:\/\/js.stripe.com\/v3\/';\r\n                script.onload = () => {\r\n                    console.log('\u2705 Stripe.js charg\u00e9');\r\n                    configurerStripeElements(montantEcheance);\r\n                };\r\n                document.head.appendChild(script);\r\n            } else {\r\n                configurerStripeElements(montantEcheance);\r\n            }\r\n        }\r\n        \r\n        \/**\r\n         * Configure les \u00e9l\u00e9ments Stripe\r\n         *\/\r\n        function configurerStripeElements(montantEcheance) {\r\n            \/\/ R\u00e9cup\u00e9rer la cl\u00e9 publique Stripe via AJAX\r\n            $.ajax({\r\n                url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                type: 'POST',\r\n                data: {\r\n                    action: 'get_stripe_publishable_key'\r\n                },\r\n                success: function(response) {\r\n                    if (response.success) {\r\n                        const publishableKey = response.data.key;\r\n                        stripe = Stripe(publishableKey);\r\n                        \r\n                        creerElementsStripe();\r\n                        \r\n                        console.log('\u2705 Stripe Elements configur\u00e9s');\r\n                    }\r\n                },\r\n                error: function() {\r\n                    afficherErreur('Erreur lors du chargement de Stripe');\r\n                }\r\n            });\r\n        }\r\n        \r\n        \/**\r\n         * Cr\u00e9e les \u00e9l\u00e9ments de formulaire Stripe\r\n         *\/\r\n        function creerElementsStripe() {\r\n            const elements = stripe.elements();\r\n            \/* pb2355 : le CONTENEUR de chaque champ reste dans la page \u2014 Stripe lui pose\r\n               StripeElement--webkit-autofill precisement pour qu on puisse l habiller.\r\n               Une regle par pseudo-element \/ pseudo-classe, jamais groupees : une regle\r\n               contenant un seul selecteur invalide est integralement rejetee (lecon pb922,\r\n               deja payee sur les placeholders de espace_publicitaire).\r\n               opacity:1 parce que Firefox grise le fond du remplissage automatique.\r\n               La regle couvre aussi le champ Titulaire, qui est un input de PAGE : lui,\r\n               le fond jaune de Chrome ne cede qu a une ombre interne \u2014 background-color\r\n               y est ignore, c est la seule methode qui tienne. *\/\r\n            if (window._viaPb2355Off === true ? false : true) {\r\n                if (!document.getElementById('via-autofill-2355')) {\r\n                    var _f2355 = (typeof window._viaPb2355Fond === 'string') ? window._viaPb2355Fond : '#ffffff';\r\n                    var _s2355 = document.createElement('style');\r\n                    _s2355.id = 'via-autofill-2355';\r\n                    _s2355.textContent =\r\n                        '.StripeElement--webkit-autofill{background-color:' + _f2355 + ' !important;opacity:1 !important;} '\r\n                        + '#form-field-nom_titulaire_carte:-webkit-autofill{'\r\n                        + '-webkit-box-shadow:0 0 0 1000px ' + _f2355 + ' inset !important;'\r\n                        + 'box-shadow:0 0 0 1000px ' + _f2355 + ' inset !important;'\r\n                        + '-webkit-text-fill-color:#000 !important;} '\r\n                        + '#form-field-nom_titulaire_carte:-webkit-autofill:focus{'\r\n                        + '-webkit-box-shadow:0 0 0 1000px ' + _f2355 + ' inset !important;'\r\n                        + 'box-shadow:0 0 0 1000px ' + _f2355 + ' inset !important;'\r\n                        + '-webkit-text-fill-color:#000 !important;} '\r\n                        + '#form-field-nom_titulaire_carte:autofill{'\r\n                        + 'box-shadow:0 0 0 1000px ' + _f2355 + ' inset !important;}';\r\n                    (document.head || document.documentElement).appendChild(_s2355);\r\n                    console.log('[pb2355] feuille remplissage automatique posee | fond=' + _f2355);\r\n                }\r\n            }\r\n            \r\n            const style = {\r\n                base: {\r\n                    fontSize: '12px',\r\n                    fontWeight: '600',\r\n                    color: '#32325d',\r\n                    fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\r\n                    \/* ====================================================================\r\n                     * pb2355 : FOND JAUNE DU REMPLISSAGE AUTOMATIQUE.\r\n                     *   Constat JF : quand le navigateur preremplit la carte, les champs\r\n                     *   virent au jaune. Le HTML fourni le nomme sans ambiguite :\r\n                     *     class=\"StripeElement StripeElement--complete StripeElement--webkit-autofill\"\r\n                     *   Ces champs sont rendus par Stripe DANS UNE IFRAME (pb1791 l a deja\r\n                     *   etabli pour le placeholder) : ni le gabarit ni la feuille de la page\r\n                     *   n atteignent l input. Le jaune vient de Chrome, applique a l interieur.\r\n                     *   DEUX LEVIERS, et il faut les deux :\r\n                     *     1. l INTERIEUR de l iframe -> l objet style transmis a Stripe.\r\n                     *        Stripe accepte la pseudo-classe :-webkit-autofill, et c est la\r\n                     *        SEULE ou il accepte backgroundColor. C est donc exactement le\r\n                     *        cas prevu par son API, pas un contournement.\r\n                     *     2. le CONTENEUR reste dans la page : Stripe lui pose la classe\r\n                     *        StripeElement--webkit-autofill pour qu on puisse l habiller.\r\n                     *        Traite plus bas, avec la feuille pb2355.\r\n                     *   Reglage : window._viaPb2355Fond (defaut '#ffffff').\r\n                     *   Revert : window._viaPb2355Off = true.\r\n                     * ==================================================================== *\/\r\n                    ':-webkit-autofill': (window._viaPb2355Off === true ? {} : {\r\n                        backgroundColor: (typeof window._viaPb2355Fond === 'string') ? window._viaPb2355Fond : '#ffffff',\r\n                        color: '#32325d'\r\n                    }),\r\n                    '::placeholder': {\r\n                        color: '#aab7c4'\r\n                    }\r\n                },\r\n                invalid: {\r\n                    color: '#fa755a',\r\n                    iconColor: '#fa755a'\r\n                }\r\n            };\r\n            \r\n            \/\/ Cr\u00e9er les \u00e9l\u00e9ments\r\n            \/* ============================================================\r\n             * pb1791 : PLACEHOLDER DU NUMERO DE CARTE.\r\n             *   Demande JF : \u00ab 1234 1234 1234 1234 \u00bb -> \u00ab Card number \u00bb.\r\n             *   Ce champ est rendu par Stripe DANS UNE IFRAME : ni le HTML\r\n             *   du gabarit ni la feuille de style de la page ne l'atteignent.\r\n             *   1234 1234 1234 1234 est le defaut de l'element cardNumber.\r\n             *   Le seul levier est l'option placeholder, posee A LA CREATION.\r\n             *   Apres coup il faudrait cardNumberElement.update({placeholder}).\r\n             *   Reglage : window._viaPb1791Placeholder = 'Numero de carte'\r\n             *   \u2014 a poser AVANT creerElementsStripe, sinon sans effet.\r\n             * ============================================================ *\/\r\n            const _ph1791 = (typeof window._viaPb1791Placeholder === 'string')\r\n                ? window._viaPb1791Placeholder : 'Card number';\r\n            cardNumberElement = elements.create('cardNumber', { style, placeholder: _ph1791 });\r\n            cardExpiryElement = elements.create('cardExpiry', { style });\r\n            cardCvcElement = elements.create('cardCvc', { style });\r\n            const postalCodeElement = elements.create('postalCode', { style });\r\n            \r\n            \/\/ Monter les \u00e9l\u00e9ments\r\n            cardNumberElement.mount('#card-number-element');\r\n            cardExpiryElement.mount('#card-expiry-element');\r\n            cardCvcElement.mount('#card-cvc-element');\r\n            postalCodeElement.mount('#postal-code-element');\r\n            \r\n            \/\/ G\u00e9rer les erreurs en temps r\u00e9el\r\n            cardNumberElement.on('change', handleCardChange);\r\n            cardExpiryElement.on('change', handleCardChange);\r\n            cardCvcElement.on('change', handleCardChange);\r\n            postalCodeElement.on('change', handleCardChange);\r\n            \r\n            \/\/ G\u00e9rer le changement de marque de carte\r\n            cardNumberElement.on('change', function(event) {\r\n                if (event.brand) {\r\n                    afficherIconeMarque(event.brand);\r\n                }\r\n            });\r\n            \r\n            console.log('\u2705 \u00c9l\u00e9ments Stripe mont\u00e9s');\r\n        }\r\n        \r\n        \/**\r\n         * G\u00e8re les changements dans les champs de carte\r\n         *\/\r\n        function handleCardChange(event) {\r\n            if (event.error) {\r\n                afficherErreur(event.error.message);\r\n            } else {\r\n                $('#MsgErreurTitulaireCarte').hide();\r\n            }\r\n        }\r\n        \r\n        \/**\r\n         * Affiche l'ic\u00f4ne de la marque de carte\r\n         *\/\r\n        function afficherIconeMarque(brand) {\r\n            const icones = {\r\n                'visa': 'https:\/\/js.stripe.com\/v3\/fingerprinted\/img\/visa-729c05c240c4bdb47b03ac81d9945bfe.svg',\r\n                'mastercard': 'https:\/\/js.stripe.com\/v3\/fingerprinted\/img\/mastercard-4d8844094130711885b5e41b28c9848f.svg',\r\n                'amex': 'https:\/\/js.stripe.com\/v3\/fingerprinted\/img\/amex-a49b82f46c5cd6a96a6e418a6ca1717c.svg',\r\n                'discover': 'https:\/\/js.stripe.com\/v3\/fingerprinted\/img\/discover-ac52cd46f89fa40a29a0bfb954e33173.svg'\r\n            };\r\n            \r\n            const icone = icones[brand] || '';\r\n            $('#brand-icon').attr('src', icone);\r\n        }\r\n        \r\n        \/**\r\n         * Valide le formulaire de paiement\r\n         *\/\r\n        function validerFormulairePaiement() {\r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            \/\/ V\u00e9rifier le nom du titulaire\r\n            const nomTitulaire = $('#form-field-nom_titulaire_carte').val()?.trim();\r\n            \r\n            if (!nomTitulaire) {\r\n                const message = lang === 'EN'\r\n                    ? 'Please enter the cardholder\\'s name'\r\n                    : 'Merci de renseigner le nom du titulaire de la carte';\r\n                afficherErreur(message);\r\n                return false;\r\n            }\r\n            \r\n            if (nomTitulaire.length < 3) {\r\n                const message = lang === 'EN'\r\n                    ? 'The cardholder\\'s name must contain at least 3 characters'\r\n                    : 'Le nom du titulaire doit contenir au moins 3 caract\u00e8res';\r\n                afficherErreur(message);\r\n                return false;\r\n            }\r\n            \r\n            return true;\r\n        }\r\n        \r\n        \/**\r\n         * Traite le paiement\r\n         *\/\r\n        async function traiterPaiement() {\r\n            console.log('\ud83d\udcb3 Traitement du paiement...');\r\n            \r\n            \/\/ Valider d'abord le formulaire\r\n            if (!validerFormulairePaiement()) {\r\n                console.log('\u274c Validation formulaire \u00e9chou\u00e9e');\r\n                return;\r\n            }\r\n            \r\n            \/\/ Masquer imm\u00e9diatement le bouton pour \u00e9viter les double-clics\r\n            $('#ButtonValiderCB').hide();\r\n            \r\n            try {\r\n                const paiementId = sessionStorage.getItem('paiement_id');\r\n                const montantTotal = parseFloat(sessionStorage.getItem('montant_total'));\r\n                const nbEcheances = parseInt(sessionStorage.getItem('nb_echeances')) || 1;\r\n                const devise = sessionStorage.getItem('devise_paiement') || 'EUR';\r\n                const donneesAnnonceur = JSON.parse(sessionStorage.getItem('via_annonceur_data') || '{}');\r\n                \r\n                console.log('\ud83d\udce4 Cr\u00e9ation PaymentIntent:', {\r\n                    paiement_id: paiementId,\r\n                    montant_total: montantTotal,\r\n                    nb_echeances: nbEcheances,\r\n                    devise: devise\r\n                });\r\n                \r\n                const response = await $.ajax({\r\n                    url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                    type: 'POST',\r\n                    data: {\r\n                        action: 'creer_payment_intent',\r\n                        paiement_id: paiementId,\r\n                        montant_total: montantTotal,\r\n                        nb_echeances: nbEcheances,\r\n                        devise: devise\r\n                    }\r\n                });\r\n                \r\n                console.log('\u2705 R\u00e9ponse:', response);\r\n                \r\n                if (!response.success) {\r\n                    throw new Error(response.data?.message || 'Erreur serveur');\r\n                }\r\n                \r\n                const clientSecret = response.data.client_secret;\r\n                const nomTitulaire = $('#form-field-nom_titulaire_carte').val().trim();\r\n                \r\n                \/\/ Confirmer le paiement\r\n                const { error, paymentIntent } = await stripe.confirmCardPayment(clientSecret, {\r\n                    payment_method: {\r\n                        card: cardNumberElement,\r\n                        billing_details: {\r\n                            name: nomTitulaire,\r\n                            email: donneesAnnonceur.emailContact\r\n                        }\r\n                    }\r\n                });\r\n                \r\n                if (error) {\r\n                    throw new Error(error.message);\r\n                }\r\n                \r\n                if (paymentIntent.status === 'succeeded') {\r\n                    console.log('\u2705 Paiement r\u00e9ussi:', paymentIntent.id);\r\n                    \r\n                    \/\/ Cr\u00e9er l'abonnement si plusieurs \u00e9ch\u00e9ances\r\n                    if (nbEcheances > 1) {\r\n                        await $.ajax({\r\n                            url: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n                            type: 'POST',\r\n                            xhrFields: { withCredentials: true },\r\n                            data: {\r\n                                action: 'confirmer_et_creer_schedule',\r\n                                payment_intent_id: paymentIntent.id,\r\n                                payment_method_id: paymentIntent.payment_method\r\n                            }\r\n                        });\r\n                    }\r\n                    \r\n                    afficherConfirmationPaiement();\r\n                }\r\n                \r\n            } catch (error) {\r\n                console.error('\u274c Erreur paiement:', error);\r\n                afficherErreur(error.message);\r\n                \/\/ R\u00e9afficher le bouton en cas d'erreur\r\n                $('#ButtonValiderCB').show();\r\n            }\r\n        }\r\n        \r\n        \/**\r\n         * Convertit le nom du pays en code ISO\r\n         *\/\r\n        function getCountryCode(nomPays) {\r\n            const pays = {\r\n                'France': 'FR',\r\n                'Belgique': 'BE',\r\n                'Suisse': 'CH',\r\n                'Luxembourg': 'LU',\r\n                'Maroc': 'MA',\r\n                'Tunisie': 'TN',\r\n                'Alg\u00e9rie': 'DZ',\r\n                'S\u00e9n\u00e9gal': 'SN',\r\n                'C\u00f4te d\\'Ivoire': 'CI',\r\n                'Cameroun': 'CM',\r\n                'Togo': 'TG',\r\n                'Canada': 'CA',\r\n                '\u00c9tats-Unis': 'US'\r\n            };\r\n            \r\n            return pays[nomPays] || 'FR';\r\n        }\r\n        \r\n        \/**\r\n         * Affiche la confirmation de paiement\r\n         *\/\r\n        function afficherConfirmationPaiement() {\r\n            console.log('\u2705 Affichage confirmation paiement');\r\n            \r\n            const lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n            \r\n            \/\/ Masquer les \u00e9l\u00e9ments du paiement\r\n            $('#FormulaireCB').hide();\r\n            $('#FactureApresPaiement').hide();\r\n            $('#ValiditeBdcPaiement').hide();\r\n            $('#ButtonValiderCB').hide();\r\n            \r\n            \/\/ Afficher les \u00e9l\u00e9ments de confirmation\r\n            $('#FactureDisponible').show();\r\n            $('#FactureBDCMailMsg').show();\r\n            $('#DocsEnvoy\u00e9sparMail').hide();\r\n            \r\n            \/\/ \u2705 Masquer le 2e lis\u00e9r\u00e9 bleu sur mobile\r\n            if (window.innerWidth <= 1000) {\r\n                $('#Paiement2eLisereBleu').hide();\r\n            }\r\n            \r\n            \/\/ Modifier le texte de confirmation\r\n            const texteConfirmation = lang === 'EN'\r\n                ? 'Your advertising space purchase is confirmed'\r\n                : 'Votre achat d\\'espace publicitaire est confirm\u00e9';\r\n            \r\n            $('#EcheanceActiveTextNoInput')\r\n                .html(texteConfirmation)\r\n                .css('color', '#666666');\r\n            \r\n            console.log('\u2705 Paiement confirm\u00e9 - Affichage facture');\r\n        }\r\n        \r\n        \/**\r\n         * Affiche un message d'erreur\r\n         *\/\r\n        function afficherErreur(message) {\r\n            $('#MsgErreurTitulaireCarte').html(message)\r\n                .css('color', '#FB5E2A')\r\n                .show();\r\n            \r\n            \/\/ Masquer apr\u00e8s 4 secondes\r\n            setTimeout(() => {\r\n                $('#MsgErreurTitulaireCarte').fadeOut();\r\n            }, 4000);\r\n            \r\n            console.error('\u274c Erreur:', message);\r\n        }\r\n        \r\n        \/**\r\n         * Initialise le bouton de paiement CB\r\n         *\/\r\n        function initBoutonPaiementCB() {\r\n            $('#ButtonValiderCB').on('click', function(e) {\r\n                e.preventDefault();\r\n                traiterPaiement();\r\n            });\r\n            \r\n            console.log('\u2705 Bouton paiement CB initialis\u00e9');\r\n        }\r\n        \r\n        \/\/ ============================================\r\n        \/\/ INITIALISATION\r\n        \/\/ ============================================\r\n        \r\n        try {\r\n            \r\n            \/\/ \u2705 \u00c9COUTER L'\u00c9V\u00c9NEMENT D'OUVERTURE\r\n            $(document).on('ouvrir-etape-paiement-final', function() {\r\n                console.log('\ud83c\udfaf \u00c9v\u00e9nement re\u00e7u : ouverture \u00e9tape 5');\r\n                initialiserEtapePaiement();\r\n                \r\n                \/\/ \u2705 Scroll vers #ProcederPaiementTitre apr\u00e8s initialisation\r\n                setTimeout(function() {\r\n                    const $target = $('#ProcederPaiementTitre');\r\n                    \r\n                    if ($target.length > 0) {\r\n                        $('html, body').animate({\r\n                            scrollTop: $target.offset().top - 50\r\n                        }, 500);\r\n                    }\r\n                    console.log('\ud83d\udcf1 Scroll vers ProcederPaiementTitre');\r\n                }, 400);\r\n            });\r\n    \r\n            initBoutonPaiementCB();\r\n            \r\n            console.log('\u2705 Module Paiement v1.4 initialis\u00e9');\r\n            \r\n            \/\/ Exposer publiquement\r\n            window.VIA_PaiementFinal = {\r\n                traiterPaiement: traiterPaiement\r\n            };\r\n        } catch (error) {\r\n            console.error('\u274c Erreur initialisation paiement:', error);\r\n        }\r\n    }\r\n    \r\n    \/\/ Lancer l'initialisation\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', initPaiementModule);\r\n    } else {\r\n        initPaiementModule();\r\n    }\r\n\r\n})();\r\n<\/script>\r\n\r\n<script>\r\n\/\/ ============================================================================\r\n\/\/ MODULE VIA_DocumentPopup - Bons de Commande et Factures en popup\r\n\/\/ Version 1.1 : iframe avec URL absolue via-agency.media\r\n\/\/ \u2705 v1.1 : Largeur popup par d\u00e9faut 1050px\r\n\/\/ Design identique aux popups espace annonceur\r\n\/\/ ============================================================================\r\n(function() {\r\n    'use strict';\r\n\r\n    const CONFIG = {\r\n        minWidth: 400,\r\n        minHeight: 350,\r\n        defaultWidth: 1050,  \/\/ \u2705 v1.1 : Largeur par d\u00e9faut 1050px\r\n        baseZIndex: 10000,\r\n        urls: {\r\n            bonCommande: 'https:\/\/via-agency.media\/bon-de-commande\/?ref=',\r\n            facture: 'https:\/\/via-agency.media\/facture\/?ref='\r\n        }\r\n    };\r\n\r\n    let currentZIndex = CONFIG.baseZIndex;\r\n    \/* ============================================================\r\n     * pb1731 : LE POPUP DOIT PASSER DEVANT \u2014 DESKTOP UNIQUEMENT.\r\n     *   Constat user, HTML a l appui :\r\n     *     .via-doc-popup            z-index: 10003\r\n     *     #via-col-ColonneGauche    z-index: 10043 !important\r\n     *   Deux echelles independantes : celle-ci part de CONFIG.baseZIndex\r\n     *   (10000) ; celle des VLP et du popup de colonne est geree par _vlpZ\r\n     *   dans yearbook-media.js, sur une plage plus haute. Le bon de commande\r\n     *   naissait donc toujours derriere.\r\n     *   Relever la constante ne reglerait rien durablement : les deux plages\r\n     *   evoluent chacune de leur cote et se recroiseraient. On MESURE le plus\r\n     *   haut z-index reellement pose par les popups voisins, et on se place\r\n     *   juste au-dessus.\r\n     *   RESTREINT AU DESKTOP, comme demande : sous 768 px le comportement\r\n     *   d origine est conserve a l identique, incrementation simple.\r\n     *   Les valeurs au-dela de 2 000 000 000 sont ignorees : c est l iframe\r\n     *   plein ecran (2147483000), devant laquelle ce popup ne doit pas passer.\r\n     *   Revert : window._viaPb1731Off = true (comportement d origine partout).\r\n     * ============================================================ *\/\r\n    function _zDevant1731() {\r\n        currentZIndex++;\r\n        if (window._viaPb1731Off === true) { return currentZIndex; }\r\n        if (window.innerWidth <= 768) { return currentZIndex; }\r\n        try {\r\n            var _max = currentZIndex;\r\n            var _els = document.querySelectorAll('.via-link-popup, .via-doc-popup,'\r\n                + ' .fp-popup-container, .via-col-popup');\r\n            for (var _i = 0; _i < _els.length; _i++) {\r\n                var _z = parseInt(window.getComputedStyle(_els[_i]).zIndex, 10);\r\n                if (isNaN(_z)) { continue; }\r\n                if (_z > 2000000000) { continue; }\r\n                if (_z >= _max) { _max = _z + 1; }\r\n            }\r\n            if (_max > currentZIndex) { currentZIndex = _max; }\r\n        } catch (_e1731) {\r\n            console.warn('[pb1731] mesure des z-index impossible : ' + _e1731.message);\r\n        }\r\n        return currentZIndex;\r\n    }\r\n    const openPopups = new Map();\r\n    let eventsInit = false;\r\n\r\n    const drag = { active: false, popup: null, sx: 0, sy: 0, sl: 0, st: 0 };\r\n    const resize = { active: false, popup: null, zone: '', sx: 0, sy: 0, sw: 0, sh: 0, sl: 0, st: 0 };\r\n\r\n    \/\/ --- Styles CSS (identiques annonceur-popup) ---\r\n    function injectStyles() {\r\n        if (document.getElementById('via-doc-popup-css')) return;\r\n        const s = document.createElement('style');\r\n        s.id = 'via-doc-popup-css';\r\n        s.textContent = `\r\n.via-doc-popup{position:fixed;background:#fff;border-radius:8px;box-shadow:0 8px 32px rgba(0,0,0,.25);display:flex;flex-direction:column;overflow:hidden;opacity:0;transition:opacity .2s;border:1px solid #d0d0d0;min-width:${CONFIG.minWidth}px;min-height:${CONFIG.minHeight}px;max-width:95vw;max-height:90vh;touch-action:none}\r\n.via-doc-popup.visible{opacity:1}\r\n.via-doc-popup-header{display:flex;align-items:center;justify-content:center;position:relative;padding:8px 35px;background:#f5f5f5;border-bottom:1px solid #e0e0e0;cursor:move;user-select:none;flex-shrink:0;touch-action:none}\r\n.via-doc-popup-title{font-size:15px;font-weight:600;color:#225DA9;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\r\n.via-doc-popup-close{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:20px;height:20px;border:none;background:transparent!important;cursor:pointer;display:flex;align-items:center;justify-content:center;color:#888;font-size:16px;font-weight:300;line-height:1;padding:0;transition:color .2s}\r\n.via-doc-popup-close:hover{color:#333;background:transparent!important}\r\n.via-doc-popup-body{flex:1;position:relative;overflow:hidden;background:#fff;min-height:0}\r\n.via-doc-popup-body iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:none}\r\n.via-doc-popup-loader{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;background:#fff;color:#225DA9;font-size:14px;z-index:2}\r\n.via-doc-popup-loader::after{content:'';width:24px;height:24px;margin-left:10px;border:3px solid #e0e0e0;border-top-color:#225DA9;border-radius:50%;animation:vdps .8s linear infinite}\r\n@keyframes vdps{to{transform:rotate(360deg)}}\r\n.via-doc-popup-rz{position:absolute;z-index:10;background:transparent}\r\n.via-doc-popup-rz-r{right:0;top:10px;bottom:10px;width:6px;cursor:ew-resize}\r\n.via-doc-popup-rz-l{left:0;top:10px;bottom:10px;width:6px;cursor:ew-resize}\r\n.via-doc-popup-rz-b{bottom:0;left:10px;right:10px;height:6px;cursor:ns-resize}\r\n.via-doc-popup-rz-t{top:0;left:10px;right:10px;height:6px;cursor:ns-resize}\r\n.via-doc-popup-rz-br{bottom:0;right:0;width:12px;height:12px;cursor:nwse-resize}\r\n.via-doc-popup-rz-bl{bottom:0;left:0;width:12px;height:12px;cursor:nesw-resize}\r\n.via-doc-popup-rz-tr{top:0;right:0;width:12px;height:12px;cursor:nesw-resize}\r\n.via-doc-popup-rz-tl{top:0;left:0;width:12px;height:12px;cursor:nwse-resize}\r\n@media(max-width:768px){\r\n.via-doc-popup{width:93vw;max-width:93vw;height:70vh;max-height:80vh;touch-action:none}\r\n.via-doc-popup-rz{display:none}\r\n.via-doc-popup-header{padding:6px 28px}\r\n.via-doc-popup-title{font-size:14px}\r\n.via-doc-popup-close{right:6px;width:18px;height:18px;font-size:14px}\r\n}`;\r\n        document.head.appendChild(s);\r\n    }\r\n\r\n    \/\/ --- Cr\u00e9er un popup ---\r\n    function openPopup(type, reference, echeance, commandeRef) {\r\n        injectStyles();\r\n        initEvents();\r\n\r\n        const id = type + '-' + reference + (echeance ? '-' + echeance : '');\r\n        if (openPopups.has(id)) {\r\n            openPopups.get(id).style.zIndex = _zDevant1731();   \/* pb1731 *\/\r\n            return;\r\n        }\r\n\r\n        \/\/ \u2705 Titre avec commande_ref (ex: BDC-QDH-020226 pour BDC, FCT-QDH-020226 pour facture)\r\n        const displayRef = commandeRef || reference;\r\n        const factureRef = displayRef.replace(\/^BDC-\/, 'FCT-');\r\n        const titles = {\r\n            bonCommande: 'Bon de commande ' + displayRef,\r\n            facture: 'Facture ' + factureRef\r\n        };\r\n\r\n        let url = CONFIG.urls[type] + encodeURIComponent(reference);\r\n        if (type === 'facture' && echeance) url += '&echeance=' + echeance;\r\n\r\n        const isMobile = window.innerWidth <= 768;\r\n        \/\/ \u2705 v1.1 : Largeur par d\u00e9faut 1050px sur desktop\r\n        const w = isMobile ? window.innerWidth * 0.93 : Math.min(CONFIG.defaultWidth, window.innerWidth * 0.95);\r\n        const h = isMobile ? window.innerHeight * 0.70 : Math.min(700, window.innerHeight * 0.9);\r\n        const offset = openPopups.size * (isMobile ? 15 : 30);\r\n        const l = Math.max(10, (window.innerWidth - w) \/ 2 + offset);\r\n        const t = Math.max(10, (window.innerHeight - h) \/ 2 + offset);\r\n\r\n        var _z1731 = _zDevant1731();   \/* pb1731 *\/\r\n        const p = document.createElement('div');\r\n        p.className = 'via-doc-popup';\r\n        p.dataset.popupId = id;\r\n        p.style.cssText = 'width:' + w + 'px;height:' + h + 'px;left:' + l + 'px;top:' + t + 'px;z-index:' + _z1731;\r\n        p.innerHTML =\r\n            '<div class=\"via-doc-popup-header\">' +\r\n                '<span class=\"via-doc-popup-title\">' + (titles[type] || 'Document') + '<\/span>' +\r\n                '<button class=\"via-doc-popup-close\" title=\"Fermer\">\u00d7<\/button>' +\r\n            '<\/div>' +\r\n            '<div class=\"via-doc-popup-body\">' +\r\n                '<div class=\"via-doc-popup-loader\">Chargement...<\/div>' +\r\n                '<iframe src=\"' + url + '\"><\/iframe>' +\r\n            '<\/div>' +\r\n            '<div class=\"via-doc-popup-rz via-doc-popup-rz-r\" data-z=\"right\"><\/div>' +\r\n            '<div class=\"via-doc-popup-rz via-doc-popup-rz-l\" data-z=\"left\"><\/div>' +\r\n            '<div class=\"via-doc-popup-rz via-doc-popup-rz-b\" data-z=\"bottom\"><\/div>' +\r\n            '<div class=\"via-doc-popup-rz via-doc-popup-rz-t\" data-z=\"top\"><\/div>' +\r\n            '<div class=\"via-doc-popup-rz via-doc-popup-rz-br\" data-z=\"br\"><\/div>' +\r\n            '<div class=\"via-doc-popup-rz via-doc-popup-rz-bl\" data-z=\"bl\"><\/div>' +\r\n            '<div class=\"via-doc-popup-rz via-doc-popup-rz-tr\" data-z=\"tr\"><\/div>' +\r\n            '<div class=\"via-doc-popup-rz via-doc-popup-rz-tl\" data-z=\"tl\"><\/div>';\r\n\r\n        document.body.appendChild(p);\r\n        openPopups.set(id, p);\r\n\r\n        \/\/ Loader\r\n        var iframe = p.querySelector('iframe');\r\n        var loader = p.querySelector('.via-doc-popup-loader');\r\n        iframe.onload = function() { loader.style.display = 'none'; };\r\n        setTimeout(function() { loader.style.display = 'none'; }, 5000);\r\n\r\n        \/\/ Apparition\r\n        requestAnimationFrame(function() { p.classList.add('visible'); });\r\n\r\n        \/\/ Fermer\r\n        p.querySelector('.via-doc-popup-close').onclick = function() { closePopup(id); };\r\n\r\n        \/\/ Premier plan au clic\r\n        p.onmousedown = function() { p.style.zIndex = _zDevant1731(); };   \/* pb1731 *\/\r\n\r\n        \/\/ Drag sur header\r\n        var hdr = p.querySelector('.via-doc-popup-header');\r\n        function dragStart(e) {\r\n            if (e.target.closest('.via-doc-popup-close')) return;\r\n            var cx = e.touches ? e.touches[0].clientX : e.clientX;\r\n            var cy = e.touches ? e.touches[0].clientY : e.clientY;\r\n            var r = p.getBoundingClientRect();\r\n            drag.active = true; drag.popup = p;\r\n            drag.sx = cx; drag.sy = cy; drag.sl = r.left; drag.st = r.top;\r\n            p.querySelector('iframe').style.pointerEvents = 'none';\r\n            e.preventDefault();\r\n        }\r\n        hdr.addEventListener('mousedown', dragStart);\r\n        hdr.addEventListener('touchstart', dragStart, { passive: false });\r\n\r\n        \/\/ Resize sur poign\u00e9es\r\n        p.querySelectorAll('.via-doc-popup-rz').forEach(function(h) {\r\n            function rzStart(e) {\r\n                var cx = e.touches ? e.touches[0].clientX : e.clientX;\r\n                var cy = e.touches ? e.touches[0].clientY : e.clientY;\r\n                var r = p.getBoundingClientRect();\r\n                resize.active = true; resize.popup = p; resize.zone = h.dataset.z;\r\n                resize.sx = cx; resize.sy = cy;\r\n                resize.sw = r.width; resize.sh = r.height;\r\n                resize.sl = r.left; resize.st = r.top;\r\n                p.querySelector('iframe').style.pointerEvents = 'none';\r\n                e.preventDefault();\r\n            }\r\n            h.addEventListener('mousedown', rzStart);\r\n            h.addEventListener('touchstart', rzStart, { passive: false });\r\n        });\r\n\r\n        console.log('\ud83d\udcc4 Popup ouvert:', id, url);\r\n    }\r\n\r\n    \/\/ --- Fermer ---\r\n    function closePopup(id) {\r\n        var p = openPopups.get(id);\r\n        if (!p) return;\r\n        p.classList.remove('visible');\r\n        setTimeout(function() { if (p.parentNode) p.parentNode.removeChild(p); openPopups.delete(id); }, 200);\r\n    }\r\n\r\n    \/\/ --- Events globaux ---\r\n    function initEvents() {\r\n        if (eventsInit) return;\r\n        eventsInit = true;\r\n\r\n        function onMove(e) {\r\n            var cx = e.touches ? e.touches[0].clientX : e.clientX;\r\n            var cy = e.touches ? e.touches[0].clientY : e.clientY;\r\n\r\n            if (drag.active && drag.popup) {\r\n                var nl = drag.sl + (cx - drag.sx);\r\n                var nt = drag.st + (cy - drag.sy);\r\n                var pw = drag.popup.offsetWidth;\r\n                nl = Math.max(100 - pw, Math.min(nl, window.innerWidth - 100));\r\n                nt = Math.max(10, Math.min(nt, window.innerHeight - 45));\r\n                drag.popup.style.left = nl + 'px';\r\n                drag.popup.style.top = nt + 'px';\r\n                e.preventDefault();\r\n            }\r\n\r\n            if (resize.active && resize.popup) {\r\n                var dx = cx - resize.sx, dy = cy - resize.sy;\r\n                var z = resize.zone, rp = resize.popup;\r\n                var nw = resize.sw, nh = resize.sh, nl2 = resize.sl, nt2 = resize.st;\r\n                var minW = CONFIG.minWidth, minH = CONFIG.minHeight;\r\n                var maxW = window.innerWidth * 0.95, maxH = window.innerHeight * 0.9;\r\n\r\n                if (z === 'right' || z === 'br' || z === 'tr') nw = Math.max(minW, Math.min(maxW, resize.sw + dx));\r\n                if (z === 'left' || z === 'bl' || z === 'tl') { var dw = Math.min(dx, resize.sw - minW); nw = resize.sw - dw; nl2 = resize.sl + dw; }\r\n                if (z === 'bottom' || z === 'br' || z === 'bl') nh = Math.max(minH, Math.min(maxH, resize.sh + dy));\r\n                if (z === 'top' || z === 'tr' || z === 'tl') { var dh = Math.min(dy, resize.sh - minH); nh = resize.sh - dh; nt2 = resize.st + dh; }\r\n\r\n                rp.style.width = nw + 'px'; rp.style.height = nh + 'px';\r\n                rp.style.left = nl2 + 'px'; rp.style.top = nt2 + 'px';\r\n                e.preventDefault();\r\n            }\r\n        }\r\n\r\n        function onEnd() {\r\n            if (drag.active && drag.popup) { drag.popup.querySelector('iframe').style.pointerEvents = ''; drag.active = false; drag.popup = null; }\r\n            if (resize.active && resize.popup) { resize.popup.querySelector('iframe').style.pointerEvents = ''; resize.active = false; resize.popup = null; }\r\n        }\r\n\r\n        document.addEventListener('mousemove', onMove);\r\n        document.addEventListener('touchmove', onMove, { passive: false });\r\n        document.addEventListener('mouseup', onEnd);\r\n        document.addEventListener('touchend', onEnd);\r\n        document.addEventListener('keydown', function(e) {\r\n            if (e.key === 'Escape' && openPopups.size > 0) closePopup(Array.from(openPopups.keys()).pop());\r\n        });\r\n    }\r\n\r\n    \/\/ --- API publique ---\r\n    window.VIA_DocumentPopup = {\r\n        openBonCommande: function(ref, commandeRef) { openPopup('bonCommande', ref, null, commandeRef); },\r\n        openFacture: function(ref, ech, commandeRef) { openPopup('facture', ref, ech, commandeRef); },\r\n        closeAll: function() { openPopups.forEach(function(p, id) { closePopup(id); }); }\r\n    };\r\n\r\n    console.log('\u2705 VIA_DocumentPopup v1.1 charg\u00e9');\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-feaf64d elementor-widget elementor-widget-html\" data-id=\"feaf64d\" data-element_type=\"widget\" data-e-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\/**\r\n * VIA Agency - VALIDATION S\u00c9QUENTIELLE DES \u00c9TAPES DU PROCESS D'ACHAT\r\n * @version 1.4 - F\u00e9vrier 2026\r\n * \r\n * Pr\u00e9requis PAR BOUTON :\r\n *   #Etape1BoutonValider       \u2192 espace_pub\r\n *   .PasserCommandeBouton      \u2192 espace_pub + tarif_valide\r\n *   #PaiementparCBBouton       \u2192 espace_pub + tarif_valide\r\n *   #PaiementparVirBouton      \u2192 espace_pub + tarif_valide\r\n *   #ChoisirPaiementTitre      \u2192 espace_pub + tarif_valide + recapitulatif + references\r\n *   #ProcederPaiementTitre     \u2192 espace_pub + tarif_valide + recapitulatif + references + paiement + validations_cgv\r\n *   .ValidationsCGVBouton      \u2192 espace_pub + tarif_valide + recapitulatif + references + paiement\r\n *   Checkboxes validations     \u2192 espace_pub + tarif_valide + recapitulatif + references + paiement\r\n * \r\n * NOTE : R\u00e9f\u00e9rences = ind\u00e9pendantes pour naviguer, mais requises pour finaliser (CGV).\r\n * \r\n * FLAG : sessionStorage 'etape1_tarif_valide' = 'Yes'\r\n *   \u2192 Pos\u00e9 quand #Etape1BoutonValider passe les contr\u00f4les\r\n *   \u2192 \u00c0 nettoyer dans reinitialiserProcessComplet() :\r\n *     sessionStorage.removeItem('etape1_tarif_valide');\r\n *\/\r\n\r\n(function() {\r\n    'use strict';\r\n\r\n    console.log('\ud83d\udd12 Chargement module Validation S\u00e9quentielle v1.4...');\r\n\r\n    \/\/ =============================================\r\n    \/\/ R\u00c9INITIALISATION AU CHARGEMENT DE LA PAGE\r\n    \/\/ =============================================\r\n    sessionStorage.removeItem('etape1_tarif_valide');\r\n    console.log('\ud83d\udd04 etape1_tarif_valide r\u00e9initialis\u00e9 au chargement');\r\n\r\n    \/\/ =============================================\r\n    \/\/ D\u00c9FINITION DES \u00c9TAPES\r\n    \/\/ =============================================\r\n\r\n    var ETAPES = {\r\n        espace_pub: {\r\n            id: 'espace_pub',\r\n            estComplete: function() {\r\n                \/\/ M\u00eame condition que afficherEtape1DansItem() dans Panier_manager\r\n                if (window.VIA_Panier && window.VIA_Panier.state && window.VIA_Panier.state.items) {\r\n                    return window.VIA_Panier.state.items.some(function(item) {\r\n                        return item.lienEspacePub || \r\n                               item.cheminFichierAnnonce || \r\n                               (item.donneesIframe && (item.donneesIframe.FileReceived === 'Yes' || \r\n                                item.donneesIframe.EnvoiUlterieur === 'true'));\r\n                    });\r\n                }\r\n                return false;\r\n            },\r\n            messageFR: \"Merci de s\u00e9lectionner un espace publicitaire\",\r\n            messageEN: \"Please select an advertising space\"\r\n        },\r\n        tarif_valide: {\r\n            id: 'tarif_valide',\r\n            estComplete: function() {\r\n                return sessionStorage.getItem('etape1_tarif_valide') === 'Yes';\r\n            },\r\n            messageFR: \"Merci de valider les dates et le tarif de votre campagne\",\r\n            messageEN: \"Please validate the dates and rate for your campaign\"\r\n        },\r\n        recapitulatif: {\r\n            id: 'recapitulatif',\r\n            estComplete: function() {\r\n                return sessionStorage.getItem('FinaliserStep') === 'Yes';\r\n            },\r\n            messageFR: \"Merci de valider le r\u00e9capitulatif de votre r\u00e9servation\",\r\n            messageEN: \"Please validate your order summary\"\r\n        },\r\n        references: {\r\n            id: 'references',\r\n            estComplete: function() {\r\n                return sessionStorage.getItem('references_validees_session') === 'Yes';\r\n            },\r\n            messageFR: \"Merci d'indiquer et valider vos r\u00e9f\u00e9rences\",\r\n            messageEN: \"Please fill in and validate your details\"\r\n        },\r\n        paiement: {\r\n            id: 'paiement',\r\n            estComplete: function() {\r\n                var modeSS = sessionStorage.getItem('mode_paiement');\r\n                if (modeSS) return true;\r\n                if (window.VIA_Paiement && window.VIA_Paiement.state && window.VIA_Paiement.state.modePaiement) {\r\n                    return true;\r\n                }\r\n                return false;\r\n            },\r\n            messageFR: \"Merci de choisir un mode de paiement\",\r\n            messageEN: \"Please choose a payment method\"\r\n        },\r\n        validations_cgv: {\r\n            id: 'validations_cgv',\r\n            estComplete: function() {\r\n                var cb1 = document.querySelector('input[name=\"form_fields[Validation_Commande]\"]');\r\n                var cb2 = document.querySelector('input[name=\"form_fields[Acceptation_CGV]\"]');\r\n                var cb3 = document.querySelector('input[name=\"form_fields[Acceptation_Commande]\"]');\r\n                return (cb1 && cb1.checked) && (cb2 && cb2.checked) && (cb3 && cb3.checked);\r\n            },\r\n            messageFR: \"Merci de valider votre r\u00e9servation et les conditions g\u00e9n\u00e9rales de vente\",\r\n            messageEN: \"Please validate your order and the general terms and conditions\"\r\n        }\r\n    };\r\n\r\n    \/\/ =============================================\r\n    \/\/ PR\u00c9REQUIS PAR BOUTON\r\n    \/\/ =============================================\r\n\r\n    var PREREQUIS = {\r\n        Etape1BoutonValider:  ['espace_pub'],\r\n        PasserCommandeBouton: ['espace_pub', 'tarif_valide'],\r\n        BoutonPaiement:       ['espace_pub', 'tarif_valide'],\r\n        ValidationsCGVBouton: ['espace_pub', 'tarif_valide', 'recapitulatif', 'references', 'paiement'],\r\n        CheckboxValidation:   ['espace_pub', 'tarif_valide', 'recapitulatif', 'references', 'paiement'],\r\n        OuvrirPaiement:       ['espace_pub', 'tarif_valide', 'recapitulatif', 'references'],\r\n        ProcederPaiement:     ['espace_pub', 'tarif_valide', 'recapitulatif', 'references', 'paiement', 'validations_cgv']\r\n    };\r\n\r\n    \/\/ =============================================\r\n    \/\/ FONCTIONS DE V\u00c9RIFICATION\r\n    \/\/ =============================================\r\n\r\n    function verifierPrerequis(listeIds) {\r\n        for (var i = 0; i < listeIds.length; i++) {\r\n            var etape = ETAPES[listeIds[i]];\r\n            if (etape && !etape.estComplete()) {\r\n                return etape;\r\n            }\r\n        }\r\n        return null;\r\n    }\r\n\r\n    function alerterEtapeManquante(etapeManquante, prerequisKey) {\r\n        if (!etapeManquante) return;\r\n        var lang = sessionStorage.getItem('SiteLangue') || 'FR';\r\n        var message = (lang === 'EN') ? etapeManquante.messageEN : etapeManquante.messageFR;\r\n        console.log('\u26a0\ufe0f Alerte \u00e9tape [' + etapeManquante.id + ']:', message);\r\n        \/\/ pb330 : selon le bouton, ne plus ouvrir la popup VIA_PopupValidation ; afficher le texte\r\n        \/\/   en rouge #FB5E2A a 5px sous le conteneur de titre cible (voir CIBLE_MSG). Fallback popup\r\n        \/\/   pour les cles non mappees (Etape1BoutonValider, PasserCommandeBouton, ...).\r\n        var cibleId = CIBLE_MSG[prerequisKey];\r\n        if (cibleId) {\r\n            afficherMessageSousTitre(message, cibleId);\r\n            return;\r\n        }\r\n        afficherPopupValidation(message);\r\n    }\r\n\r\n    \/\/ pb330 : cible du message inline selon le bouton (prerequisKey).\r\n    var CIBLE_MSG = {\r\n        BoutonPaiement:       'ModePaiementTitreContainer',  \/\/ #PaiementparCBBouton \/ #PaiementparVirBouton\r\n        OuvrirPaiement:       'ModePaiementTitreContainer',  \/\/ #ChoisirPaiementTitre\r\n        ProcederPaiement:     'PaiementTitreContainer',      \/\/ #ProcederPaiementTitre\r\n        ValidationsCGVBouton: 'ValidationTitreContainer',    \/\/ .ValidationsCGVBouton\r\n        CheckboxValidation:   'ValidationTitreContainer'     \/\/ checkboxes validations\r\n    };\r\n\r\n    \/\/ pb330 : message d'alerte inline (rouge #FB5E2A) insere a 5px sous le conteneur de titre cible,\r\n    \/\/   en remplacement de la popup VIA_PopupValidation. Un seul element reutilise : insertBefore\r\n    \/\/   le deplace sous la cible courante (la cible varie selon le bouton). Fallback popup si la\r\n    \/\/   cible est absente du DOM.\r\n    function afficherMessageSousTitre(message, contId) {\r\n        var cont = document.getElementById(contId);\r\n        if (!cont) { afficherPopupValidation(message); return; }\r\n        var el = document.getElementById('VIA_MsgValidationInline');\r\n        if (!el) {\r\n            el = document.createElement('div');\r\n            el.id = 'VIA_MsgValidationInline';\r\n        }\r\n        \/\/ pb330 : taille de police reduite de 2px (calc(1em - 2px)) ; remontee (margin-top -25px\r\n        \/\/   desktop \/ -10px mobile = 30px\/15px au-dessus du +5px d'origine) ; margin-bottom ajoute\r\n        \/\/   20px desktop \/ 15px mobile. cssText re-applique a chaque appel pour suivre desktop\/mobile.\r\n        var isMobileMsg = window.innerWidth <= 767;\r\n        el.style.cssText = 'color:#FB5E2A;font-weight:600;text-align:center;line-height:1.4;font-family:inherit;font-size:calc(1em - 2px);margin:' + (isMobileMsg ? '-10px 0 15px' : '-25px 0 20px') + ';';\r\n        el.textContent = message;\r\n        el.style.setProperty('display', 'block', 'important');\r\n        \/\/ (re)positionner sous le titre cible courant (insertBefore deplace l'element existant)\r\n        if (cont.parentNode) { cont.parentNode.insertBefore(el, cont.nextSibling); }\r\n    }\r\n\r\n    function masquerMessageInline() {\r\n        var el = document.getElementById('VIA_MsgValidationInline');\r\n        if (el) { el.style.setProperty('display', 'none', 'important'); }\r\n    }\r\n\r\n    \/\/ =============================================\r\n    \/\/ POPUP STYL\u00c9E (design coh\u00e9rent avec le site)\r\n    \/\/ =============================================\r\n\r\n    var popupTimer = null;\r\n\r\n    function afficherPopupValidation(message) {\r\n        \/\/ Supprimer une \u00e9ventuelle popup existante\r\n        fermerPopupValidation();\r\n\r\n        var isMobile = window.innerWidth <= 767;\r\n        var popupWidth = isMobile ? '45%' : '420px';\r\n        var popupPadding = isMobile ? '20px 15px' : '30px 40px';\r\n        var fontSize = isMobile ? '14px' : '16px';\r\n        var btnFontSize = isMobile ? '14px' : '16px';\r\n        var btnPadding = isMobile ? '10px 25px' : '12px 40px';\r\n\r\n        var overlay = document.createElement('div');\r\n        overlay.id = 'VIA_PopupValidationOverlay';\r\n        overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.4);z-index:99998;opacity:0;transition:opacity 0.25s ease;';\r\n\r\n        var popup = document.createElement('div');\r\n        popup.id = 'VIA_PopupValidation';\r\n        popup.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%) scale(0.9);background:#FFFFFF;border:3px solid #A2C6F3;border-radius:10px;padding:' + popupPadding + ';z-index:99999;box-shadow:0 10px 30px rgba(0,0,0,0.25);width:' + popupWidth + ';max-width:420px;text-align:center;box-sizing:border-box;opacity:0;transition:opacity 0.25s ease, transform 0.25s ease;';\r\n\r\n        \/\/ Message\r\n        var textEl = document.createElement('p');\r\n        textEl.style.cssText = 'margin:0 0 20px;font-size:' + fontSize + ';color:#333;line-height:1.5;font-family:inherit;';\r\n        textEl.textContent = message;\r\n\r\n        \/\/ Bouton Valider (style identique \u00e0 la capture : fond bleu clair, texte bleu fonc\u00e9)\r\n        var btnText = (sessionStorage.getItem('SiteLangue') === 'EN') ? 'OK' : 'Valider';\r\n        var btn = document.createElement('a');\r\n        btn.href = '#';\r\n        btn.style.cssText = 'display:inline-block;background:#D4E6F9;color:#4B689B;padding:' + btnPadding + ';border-radius:5px;text-decoration:none;font-weight:500;font-size:' + btnFontSize + ';font-family:inherit;cursor:pointer;transition:background 0.2s;border:none;';\r\n        btn.textContent = btnText;\r\n        btn.onmouseover = function() { btn.style.background = '#A2C6F3'; };\r\n        btn.onmouseout = function() { btn.style.background = '#D4E6F9'; };\r\n\r\n        popup.appendChild(textEl);\r\n        popup.appendChild(btn);\r\n\r\n        document.body.appendChild(overlay);\r\n        document.body.appendChild(popup);\r\n\r\n        \/\/ Animation d'entr\u00e9e\r\n        requestAnimationFrame(function() {\r\n            overlay.style.opacity = '1';\r\n            popup.style.opacity = '1';\r\n            popup.style.transform = 'translate(-50%,-50%) scale(1)';\r\n        });\r\n\r\n        \/\/ Fermeture\r\n        btn.addEventListener('click', function(e) {\r\n            e.preventDefault();\r\n            fermerPopupValidation();\r\n        });\r\n        overlay.addEventListener('click', function() {\r\n            fermerPopupValidation();\r\n        });\r\n\r\n        \/\/ Auto-fermeture apr\u00e8s 5s\r\n        popupTimer = setTimeout(function() {\r\n            fermerPopupValidation();\r\n        }, 5000);\r\n    }\r\n\r\n    function fermerPopupValidation() {\r\n        if (popupTimer) {\r\n            clearTimeout(popupTimer);\r\n            popupTimer = null;\r\n        }\r\n        var popup = document.getElementById('VIA_PopupValidation');\r\n        var overlay = document.getElementById('VIA_PopupValidationOverlay');\r\n\r\n        if (popup) {\r\n            popup.style.opacity = '0';\r\n            popup.style.transform = 'translate(-50%,-50%) scale(0.9)';\r\n        }\r\n        if (overlay) {\r\n            overlay.style.opacity = '0';\r\n        }\r\n\r\n        setTimeout(function() {\r\n            if (popup && popup.parentNode) popup.parentNode.removeChild(popup);\r\n            if (overlay && overlay.parentNode) overlay.parentNode.removeChild(overlay);\r\n        }, 250);\r\n    }\r\n\r\n    function verifierOuBloquer(prerequisKey, contexte, event) {\r\n        var liste = PREREQUIS[prerequisKey];\r\n        if (!liste) return true;\r\n\r\n        var manquante = verifierPrerequis(liste);\r\n        if (manquante) {\r\n            event.preventDefault();\r\n            event.stopImmediatePropagation();\r\n            console.log('\u26d4 [' + contexte + '] Bloqu\u00e9 \u2192 \u00e9tape manquante:', manquante.id);\r\n            alerterEtapeManquante(manquante, prerequisKey);\r\n            return false;\r\n        }\r\n        \/\/ pb330 : prerequis OK -> retirer l'eventuel message inline (si ce bouton en utilise un)\r\n        if (CIBLE_MSG[prerequisKey]) { masquerMessageInline(); }\r\n        console.log('\u2705 [' + contexte + '] Pr\u00e9requis OK');\r\n        return true;\r\n    }\r\n\r\n    \/\/ =============================================\r\n    \/\/ HELPER : MATCHER S\u00c9LECTEUR CSS\r\n    \/\/ =============================================\r\n\r\n    function elementCorrespond(element, selecteur) {\r\n        var el = element;\r\n        while (el && el !== document) {\r\n            try {\r\n                if (el.matches && el.matches(selecteur)) return true;\r\n            } catch(e) {}\r\n            el = el.parentElement;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    \/\/ =============================================\r\n    \/\/ INTERCEPTEUR UNIQUE - PHASE CAPTURE\r\n    \/\/ =============================================\r\n\r\n    document.addEventListener('click', function(e) {\r\n        var target = e.target;\r\n\r\n        \/\/ ----------------------------------------------------------\r\n        \/\/ #Etape1BoutonValider \u2192 v\u00e9rifie : espace_pub\r\n        \/\/ Si OK et tarifHT > 0 \u2192 pose le flag etape1_tarif_valide\r\n        \/\/ ----------------------------------------------------------\r\n        if (elementCorrespond(target, '#Etape1BoutonValider')) {\r\n\r\n            if (!verifierOuBloquer('Etape1BoutonValider', 'Etape1BoutonValider', e)) return;\r\n\r\n            var aUnTarif = false;\r\n            if (window.VIA_Panier && window.VIA_Panier.state && window.VIA_Panier.state.items) {\r\n                aUnTarif = window.VIA_Panier.state.items.some(function(item) {\r\n                    var estIndisponible = item.disponibilite === false || item.statut === 'indisponible';\r\n                    return item.tarifHT && item.tarifHT > 0 && !estIndisponible;\r\n                });\r\n            }\r\n\r\n            if (aUnTarif) {\r\n                sessionStorage.setItem('etape1_tarif_valide', 'Yes');\r\n                console.log('\u2705 Flag etape1_tarif_valide = Yes');\r\n            }\r\n            \/\/ Laisser le handler jQuery continuer dans tous les cas\r\n            return;\r\n        }\r\n\r\n        \/\/ ----------------------------------------------------------\r\n        \/\/ .PasserCommandeBouton \u2192 v\u00e9rifie : espace_pub + tarif_valide\r\n        \/\/ ----------------------------------------------------------\r\n        if (elementCorrespond(target, '.PasserCommandeBouton')) {\r\n            if (!verifierOuBloquer('PasserCommandeBouton', 'PasserCommandeBouton', e)) return;\r\n        }\r\n\r\n        \/\/ ----------------------------------------------------------\r\n        \/\/ Boutons paiement \u2192 v\u00e9rifie : espace_pub + tarif_valide\r\n        \/\/ ----------------------------------------------------------\r\n        if (elementCorrespond(target, '#PaiementparCBBouton') ||\r\n            elementCorrespond(target, '#PaiementparVirBouton')) {\r\n            if (!verifierOuBloquer('BoutonPaiement', 'BoutonPaiement', e)) return;\r\n        }\r\n\r\n        \/\/ ----------------------------------------------------------\r\n        \/\/ .ValidationsCGVBouton \u2192 v\u00e9rifie tout (y compris r\u00e9f\u00e9rences)\r\n        \/\/ ----------------------------------------------------------\r\n        if (elementCorrespond(target, '.ValidationsCGVBouton')) {\r\n            if (!verifierOuBloquer('ValidationsCGVBouton', 'ValidationsCGVBouton', e)) return;\r\n        }\r\n\r\n        \/\/ ----------------------------------------------------------\r\n        \/\/ #ChoisirPaiementTitre \u2192 v\u00e9rifie : espace_pub + tarif + recap + references\r\n        \/\/ ----------------------------------------------------------\r\n        if (elementCorrespond(target, '#ChoisirPaiementTitre')) {\r\n            if (!verifierOuBloquer('OuvrirPaiement', 'ChoisirPaiementTitre', e)) return;\r\n        }\r\n\r\n        \/\/ ----------------------------------------------------------\r\n        \/\/ #ProcederPaiementTitre \u2192 v\u00e9rifie TOUT y compris paiement + validations CGV\r\n        \/\/ ----------------------------------------------------------\r\n        if (elementCorrespond(target, '#ProcederPaiementTitre')) {\r\n            if (!verifierOuBloquer('ProcederPaiement', 'ProcederPaiementTitre', e)) return;\r\n        }\r\n\r\n        \/\/ ----------------------------------------------------------\r\n        \/\/ Checkboxes validation (cochage seulement)\r\n        \/\/ ----------------------------------------------------------\r\n        if (elementCorrespond(target, 'input[name=\"form_fields[Validation_Commande]\"]') ||\r\n            elementCorrespond(target, 'input[name=\"form_fields[Acceptation_CGV]\"]') ||\r\n            elementCorrespond(target, 'input[name=\"form_fields[Acceptation_Commande]\"]')) {\r\n\r\n            var checkbox = target;\r\n            if (checkbox.tagName === 'INPUT' && checkbox.type === 'checkbox') {\r\n                if (!checkbox.checked) {\r\n                    if (!verifierOuBloquer('CheckboxValidation', 'CheckboxValidation', e)) return;\r\n                }\r\n            }\r\n        }\r\n\r\n    }, true);  \/\/ \u2190 CAPTURE\r\n\r\n    \/\/ =============================================\r\n    \/\/ EXPOSITION GLOBALE\r\n    \/\/ =============================================\r\n\r\n    window.VIA_ValidationProcess = {\r\n        ETAPES: ETAPES,\r\n        PREREQUIS: PREREQUIS,\r\n        verifierPrerequis: verifierPrerequis,\r\n        alerterEtapeManquante: alerterEtapeManquante,\r\n\r\n        estEtapeComplete: function(etapeId) {\r\n            return ETAPES[etapeId] ? ETAPES[etapeId].estComplete() : false;\r\n        },\r\n\r\n        etatComplet: function() {\r\n            var etat = {};\r\n            Object.keys(ETAPES).forEach(function(key) {\r\n                etat[key] = ETAPES[key].estComplete();\r\n            });\r\n            return etat;\r\n        },\r\n\r\n        diagnostic: function() {\r\n            console.log('\ud83d\udcca Diagnostic Validation S\u00e9quentielle v1.4:');\r\n            console.table(Object.keys(ETAPES).map(function(key) {\r\n                var e = ETAPES[key];\r\n                return { etape: e.id, complete: e.estComplete(), messageFR: e.messageFR };\r\n            }));\r\n            console.log('\ud83d\udccb Pr\u00e9requis par bouton:', PREREQUIS);\r\n            return this.etatComplet();\r\n        },\r\n\r\n        resetTarifValide: function() {\r\n            sessionStorage.removeItem('etape1_tarif_valide');\r\n            console.log('\ud83d\udd04 etape1_tarif_valide supprim\u00e9');\r\n        }\r\n    };\r\n\r\n    console.log('\u2705 Module Validation S\u00e9quentielle v1.4 initialis\u00e9');\r\n\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-380f112c elementor-widget elementor-widget-html\" data-id=\"380f112c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<head>\r\n    <meta name=\"google\" content=\"notranslate\">\r\n    <meta name=\"robots\" content=\"noindex: .do-not-index-class\">\r\n\r\n    <script src=\"https:\/\/code.jquery.com\/jquery-3.6.0.min.js\"><\/script>\r\n    <script src=\"https:\/\/code.jquery.com\/ui\/1.12.1\/jquery-ui.min.js\"><\/script>\r\n    <link rel=\"stylesheet\" href=\"https:\/\/code.jquery.com\/ui\/1.12.1\/themes\/base\/jquery-ui.css\">\r\n<\/head>\r\n\r\n<style>\r\n\/* ============================================\r\n   YEARBOOK MEDIA - STYLES PRINCIPAUX\r\n   Version 1.1.0\r\n   \u2705 v1.1.0 : Ajout hauteur auto #DeviseModedePaiementMsgConteneur\r\n   ============================================ *\/\r\n\r\n\/* ============================================\r\n   VARIABLES CSS\r\n   ============================================ *\/\r\n:root {\r\n    \/* Couleurs *\/\r\n    --color-primary: #61FC2C;\r\n    --color-secondary: #4B689B;\r\n    --color-text: #586A8B;\r\n    --color-bg-light: #F0F0F0;\r\n    --color-bg-white: #FFFFFF;\r\n    --color-error: #fff0f0;\r\n    --color-gray: #989898;\r\n    \r\n    \/* Breakpoints *\/\r\n    --breakpoint-mobile: 640px;\r\n    --breakpoint-tablet: 768px;\r\n    --breakpoint-desktop: 1000px;\r\n    --breakpoint-tablet-max: 1024px;\r\n    \r\n    \/* Z-index *\/\r\n    --z-popup: 999999;\r\n    --z-overlay: 99;\r\n    \r\n    \/* Transitions *\/\r\n    --transition-default: 0.3s ease-in-out;\r\n    --transition-slow: 1s steps(4) infinite;\r\n    \r\n    \/* Dimensions *\/\r\n    --height-element: 3rem;\r\n    --scale-mobile: 0.8;\r\n    --scale-tablet: 0.7;\r\n}\r\n\r\n\/* ============================================\r\n   RESET & BASE\r\n   ============================================ *\/\r\n.notranslate {\r\n    translate: no;\r\n}\r\n\r\nbody.iframe-mode #HeaderPageAchat,\r\nbody.iframe-mode #FooterPageAchat {\r\n    display: none !important;\r\n}\r\n\r\n#PageWebColonne,\r\n#ProcessCommande,\r\n#Etape1Container,\r\n#EtapeRecapitulatif,\r\n#EtapeReferences,\r\n#EtapeModedePaiement,\r\n#EtapeValidations,\r\n#EtapePaiement {\r\n    display: none;\r\n}\r\n\r\n\/* ============================================\r\n   DRAGGABLE POPUPS\r\n   Note: G\u00e9r\u00e9 par JS, styles de base ici\r\n   ============================================ *\/\r\n.draggable-popup {\r\n    position: fixed !important;\r\n    cursor: move !important;\r\n}\r\n\r\n.draggable-popup .dialog-close-button,\r\n.draggable-popup .dialog-lightbox-close-button {\r\n    position: absolute !important;\r\n    top: 10px !important;\r\n    right: 20px !important;\r\n    z-index: var(--z-popup) !important;\r\n}\r\n\r\n.draggable-popup.dragging {\r\n    opacity: 0.95 !important;\r\n    cursor: grabbing !important;\r\n}\r\n\r\n\/* ============================================\r\n   VISIBILITY & DISPLAY MANAGEMENT\r\n   ============================================ *\/\r\n.ToBeHidden {\r\n    opacity: 1;\r\n}\r\n\r\n.TobedisplayedLater,\r\n.MenuArticlesTobedisplayedLater,\r\n.MsgFormatIncorrectConteneur {\r\n    display: none;\r\n}\r\n\r\n\/* \u00c9l\u00e9ments cach\u00e9s par d\u00e9faut *\/\r\n#EnteteSite,\r\n#HeaderMobilehorizontal,\r\n.footer {\r\n    display: none;\r\n}\r\n\r\n\/* Boutons de formulaire cach\u00e9s *\/\r\n#NationaliteAnnonceurForm .elementor-button,\r\n#Formulaire_Copyright .elementor-button,\r\n#ReferencesConteneurId .elementor-button,\r\n#ReferencesConteneurId2 .elementor-button,\r\n#ChoixDataFacturationForm .elementor-button,\r\n#DataFacturationForm .elementor-button,\r\n#TVARadio1 .elementor-button,\r\n#TVARadio2 .elementor-button,\r\n#TVARadio3 .elementor-button,\r\n#TVARadio4 .elementor-button,\r\n#TVARadio5 .elementor-button,\r\n#TVARadio6 .elementor-button,\r\n#FormDevise2 .elementor-button,\r\n#DateDebutForm .elementor-button,\r\n#DateFinForm .elementor-button,\r\n#ValidationCommandeCheck .elementor-button,\r\n#ValidationCGVCheck .elementor-button,\r\n#AcceptationCommandeCheck .elementor-button,\r\n#SaisieEcheance .elementor-button,\r\n#FormSelectDevisesId .elementor-button,\r\n#Nationalite_Societe_Tarifs_Id .elementor-button,\r\n#CBNomTitulaireCarte .elementor-button,\r\n#TarifCommercialForm .elementor-button,\r\n#TarifCommercialForm .elementor-field-type-submit,\r\n#TarifCommercialForm .e-form__buttons,\r\n.FormHideButton .elementor-button {\r\n    display: none !important;\r\n}\r\n\r\n#form-field-nom_titulaire_carte { color: #000 !important; }\r\n#form-field-nom_titulaire_carte::placeholder { color: #AAB7C4 !important; opacity: 1 !important; }\r\n#form-field-nom_titulaire_carte::-webkit-input-placeholder { color: #AAB7C4 !important; opacity: 1 !important; }\r\n\r\n\/* ============================================\r\n   ANIMATIONS & EFFECTS\r\n   ============================================ *\/\r\n\r\n\/* Zoom Effects *\/\r\n.zoom,\r\n.zoomtarif,\r\n.zoomformat,\r\n.ActiviteSectorielle {\r\n    display: inline-block;\r\n    transition: transform var(--transition-default);\r\n}\r\n\r\n.zoom:hover,\r\n.ActiviteSectorielle:hover {\r\n    transform: scale(1.1);\r\n}\r\n\r\n.zoomtarif:hover,\r\n.zoomformat:hover {\r\n    transform: scale(1.05);\r\n}\r\n\r\n.zoomformat {\r\n    word-wrap: break-word;\r\n}\r\n\r\n\/* Blink Animation *\/\r\n.blink_me {\r\n    animation: blinker 2s linear infinite;\r\n}\r\n\r\n@keyframes blinker {\r\n    50% {\r\n        opacity: 0;\r\n    }\r\n}\r\n\r\n\/* Loading Animation *\/\r\n.loading {\r\n    font-weight: bold;\r\n    display: inline-block;\r\n    font-family: monospace;\r\n    clip-path: inset(0 2ch 0 0);\r\n    animation: loading-dots var(--transition-slow);\r\n}\r\n\r\n@keyframes loading-dots {\r\n    to {\r\n        clip-path: inset(0 -1ch 0 0);\r\n    }\r\n}\r\n\r\n\/* Dots Animation (Message d'attente) *\/\r\n.dot-container {\r\n    display: inline-block;\r\n}\r\n\r\n.dot {\r\n    opacity: 0;\r\n    transition: opacity var(--transition-default);\r\n}\r\n\r\n.dot:nth-child(1) { animation: dot-pulse-1 3s infinite; }\r\n.dot:nth-child(2) { animation: dot-pulse-2 3s infinite; }\r\n.dot:nth-child(3) { animation: dot-pulse-3 3s infinite; }\r\n\r\n@keyframes dot-pulse-1 {\r\n    0%, 100% { opacity: 0; }\r\n    10%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n@keyframes dot-pulse-2 {\r\n    0%, 20%, 100% { opacity: 0; }\r\n    30%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n@keyframes dot-pulse-3 {\r\n    0%, 40%, 100% { opacity: 0; }\r\n    50%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n\/* ============================================\r\n   CURSORS\r\n   ============================================ *\/\r\n.wait-cursor {\r\n    cursor: wait;\r\n}\r\n\r\n.HPType, \r\n.PTType, \r\n.ArtType, \r\n.SiteContinentPaysTitre {\r\n    cursor: pointer;\r\n}\r\n\r\n\/* ============================================\r\n   FORMS & INPUTS\r\n   ============================================ *\/\r\n\r\n\/* Checkboxes *\/\r\n.elementor-field-option input[type=\"checkbox\"] {\r\n    margin: 0;\r\n    vertical-align: middle;\r\n}\r\n\r\n\/* Error State *\/\r\n.error {\r\n    background-color: var(--color-error) !important;\r\n}\r\n\r\n\/* Field Heights *\/\r\n#ReferencesConteneurId .elementor-field-textual.elementor-size-xs {\r\n    height: 25px !important;\r\n    min-height: 25px !important;\r\n}\r\n\r\n\/* ============================================\r\n   DATE PICKER (PIKADAY)\r\n   ============================================ *\/\r\n.default-date,\r\n.pika-single .pika-button:hover,\r\n.pika-single .pika-button:focus,\r\n.pika-single .pika-button.is-selected {\r\n    background: var(--color-gray);\r\n}\r\n\r\n\/* ============================================\r\n   AUTOCOMPLETE (JQUERY UI)\r\n   ============================================ *\/\r\n.ui-autocomplete,\r\n.ui-autocomplete.ui-widget {\r\n    font-size: 12px !important;\r\n    line-height: 1.2 !important;\r\n}\r\n\r\n.ui-menu .ui-menu-item {\r\n    padding: 2px 5px !important;\r\n}\r\n\r\n.ui-menu .ui-menu-item-wrapper {\r\n    padding: 1px 3px !important;\r\n}\r\n\r\n\/* ============================================\r\n   LAYOUT COMPONENTS\r\n   ============================================ *\/\r\n\r\n\/* Campagnes Container *\/\r\n#VosCampagnesConteneur {\r\n    display: flex;\r\n    flex-direction: row;\r\n}\r\n\r\n.CampagneNoClass {\r\n    margin-top: -3px !important;\r\n}\r\n\r\n\/* Message d'attente *\/\r\n.MsgAttente {\r\n    font-size: 18px;\r\n    font-weight: 600;\r\n    background-color: transparent;\r\n    color: var(--color-primary);\r\n    height: 10px;\r\n    width: 100%;\r\n    position: relative;\r\n    z-index: var(--z-overlay);\r\n    top: 100px;\r\n    text-align: center;\r\n    line-height: 10px;\r\n}\r\n\r\n\/* Background *\/\r\n#FondGris {\r\n    background-color: rgba(240, 240, 240, 0.71);\r\n}\r\n\r\n\/* ============================================\r\n   MESSAGE MODE DE PAIEMENT\r\n   \u2705 v1.1.0 : Hauteur auto pour texte multi-lignes\r\n   ============================================ *\/\r\n#DeviseModedePaiementMsgConteneur {\r\n    height: auto !important;\r\n    min-height: 30px !important;\r\n    padding-bottom: 10px !important;\r\n}\r\n\r\n#DeviseModedePaiementMsg {\r\n    line-height: 1.4 !important;\r\n}\r\n\r\n\/* ============================================\r\n   HORIZONTAL SCROLL\r\n   ============================================ *\/\r\n.scroll-row {\r\n    display: flex;\r\n    flex-wrap: nowrap;\r\n    margin-bottom: 0;\r\n    width: max-content;\r\n    margin-left: auto;\r\n    justify-content: flex-end;\r\n    will-change: transform;\r\n    transform: translateX(0);\r\n    transform-style: preserve-3d;\r\n}\r\n\r\n.scroll-row > * {\r\n    flex: 0 0 auto;\r\n    margin-right: 10px;\r\n}\r\n\r\n#ListeSecteurs {\r\n    width: 100%;\r\n    overflow-x: auto;\r\n    -webkit-overflow-scrolling: touch;\r\n}\r\n\r\n\/* ============================================\r\n   SITE & SECTOR ELEMENTS\r\n   ============================================ *\/\r\n.HPContinentPays {\r\n    height: var(--height-element);\r\n    margin-top: 6px;\r\n}\r\n\r\n.HPType,\r\n.PTType,\r\n.ArtType,\r\n.FuturType {\r\n    width: 24.3%;\r\n    min-height: var(--height-element);\r\n    margin-top: 6px;\r\n}\r\n\r\n.ActiviteSectorielle {\r\n    white-space: nowrap;\r\n}\r\n\r\n.titredelapage {\r\n    font-size: 18px;\r\n}\r\n\r\n\/* ============================================\r\n   VIDEO & FORMAT CONTAINERS\r\n   ============================================ *\/\r\n#Step1VideoContainer {\r\n    max-height: 46px;\r\n}\r\n\r\n.FormatsAnnonces {\r\n    transform: scale(0.8);\r\n    transform-origin: top center;\r\n}\r\n\r\n\/* ============================================\r\n   MEDIA QUERIES\r\n   ============================================ *\/\r\n\r\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n   Desktop: 600px pour popups\r\n   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\r\n@media (min-width: 769px) {\r\n    .draggable-popup .dialog-message,\r\n    .draggable-popup .dialog-lightbox-message {\r\n        width: 600px !important;\r\n        max-width: 600px !important;\r\n        min-width: 300px !important;\r\n    }\r\n}\r\n\r\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n   Tablet: 768px - 1024px\r\n   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\r\n@media only screen and (min-width: 768px) and (max-width: 1024px) {\r\n    #EnteteSite {\r\n        display: none;\r\n    }\r\n}\r\n\r\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n   Mobile: max-width 768px\r\n   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\r\n@media (max-width: 768px) {\r\n    \/* Popups en pleine largeur *\/\r\n    .draggable-popup .dialog-message,\r\n    .draggable-popup .dialog-lightbox-message {\r\n        width: 100vw !important;\r\n        max-width: 100vw !important;\r\n        min-width: 100vw !important;\r\n    }\r\n    \r\n    .draggable-popup {\r\n        left: 0 !important;\r\n    }\r\n    \r\n    \/* Headers *\/\r\n    #HeaderMobilehorizontal {\r\n        display: none;\r\n    }\r\n}\r\n\r\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n   Mobile Small: max-width 640px\r\n   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\r\n@media only screen and (max-width: 640px) {\r\n    .ZoomTitreMobile {\r\n        display: inline-block;\r\n        transition: transform var(--transition-default);\r\n    }\r\n    \r\n    .ZoomTitreMobile:hover {\r\n        transform: scale(1.2);\r\n    }\r\n}\r\n\r\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n   Mobile\/Tablet: max-width 1000px\r\n   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\r\n@media only screen and (max-width: 1000px) {\r\n    \/* Scroll containers *\/\r\n    #ListeSitesConteneurScroll,\r\n    #ListeSecteurs {\r\n        transform-origin: 0 0;\r\n        transform: scale(var(--scale-mobile));\r\n    }\r\n    \r\n    \/* Video & Format elements *\/\r\n    #Step1VideoContainer,\r\n    .FormatClassique,\r\n    .FormatPopup,\r\n    #FooterBanniere,\r\n    #FooterVideo,\r\n    #FooterPopUp,\r\n    #FooterCommunique,\r\n    #FooterInterview,\r\n    #FooterParrainage {\r\n        max-height: 37px;\r\n        max-width: 67px;\r\n    }\r\n    \r\n    .FormatsAnnonces {\r\n        transform: scale(0.85);\r\n        transform-origin: top center;\r\n    }\r\n    \r\n    \/* Card layout *\/\r\n    .card {\r\n        background-color: transparent;\r\n        min-width: 25%;\r\n        display: flex;\r\n        flex-wrap: nowrap;\r\n        overflow-x: auto;\r\n        -webkit-overflow-scrolling: touch;\r\n    }\r\n    \r\n    .card::-webkit-scrollbar {\r\n        display: none;\r\n    }\r\n    \r\n    .card-content {\r\n        flex: 0 0 auto;\r\n        margin: 5px;\r\n    }\r\n    \r\n    \/* Background *\/\r\n    #FondGris {\r\n        background-color: var(--color-bg-white);\r\n    }\r\n    \r\n    \/* Checkboxes *\/\r\n    .ValidationBoiteACocher input[type=\"checkbox\"] {\r\n        width: 20px;\r\n        height: 20px;\r\n        margin: -6px 0 0 0;\r\n    }\r\n}\r\n\r\n\r\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n   Mobile\/Tablet: max-width 1024px\r\n   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\r\n@media only screen and (max-width: 1024px) {\r\n    \/* Forms zoom *\/\r\n    #DateDebutForm,\r\n    #DateFinForm,\r\n    #NationaliteAnnonceurForm,\r\n    #NbJoursField,\r\n    #ReferencesConteneurId,\r\n    #ChoixDataFacturationForm,\r\n    #DataFacturationForm,\r\n    #Nationalite_Societe_Tarifs_Id {\r\n        transform: scale(var(--scale-tablet));\r\n        transform-origin: top center;\r\n    }\r\n    \r\n    #Nationalite_Societe_Tarifs_Id,\r\n    #TarifsDateDebutForm,\r\n    #TarifsDateFinForm {\r\n        transform: scale(0.6);\r\n        transform-origin: top center;\r\n    }\r\n    \r\n    \/* Continent styles *\/\r\n    .FondContinent {\r\n        height: 40px !important;\r\n        background-color: var(--color-bg-light) !important;\r\n    }\r\n    \r\n    .TextContinent {\r\n        color: var(--color-text) !important;\r\n    }\r\n    \r\n    \/* Evite les d\u00e9bordements sur mobile *\/\r\n    html { overflow-x: clip; }\r\n    body { overflow-x: clip; }\r\n}\r\n\r\n\/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n   Desktop: min-width 1024px\r\n   \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\r\n@media only screen and (min-width: 1024px) {\r\n    #HeaderMobilehorizontal {\r\n        display: none;\r\n    }\r\n    #HeaderTexteGauche {\r\n        max-width: 550px !important;\r\n    }\r\n    \r\n    #TarifPub{\r\n        max-width: 650px !important;\r\n    }\r\n    \r\n    #DateDebutForm input,\r\n    #DateFinForm input,\r\n    #TarifsDateDebutForm input,\r\n    #TarifsDateFinForm input {\r\n        padding: 5px !important;\r\n        box-sizing: border-box;\r\n        text-align: center;\r\n    }\r\n}\r\n\r\n\/* ============================================\r\n   PRINT STYLES\r\n   ============================================ *\/\r\n@media print {\r\n    .draggable-popup,\r\n    #HeaderPageAchat,\r\n    #FooterPageAchat {\r\n        display: none !important;\r\n    }\r\n}\r\n\r\n\/* Aligner les r\u00e9f\u00e9rences des campagnes *\/\r\n.CampagneTemplateClass .CampagneFormatClass p,\r\n.CampagneTemplateClass .CampagneNoClass p,\r\n.CampagneTemplateClass .CampagnePageTextClass p,\r\n.CampagneTemplateClass .CampagnePaysClass p {\r\n    margin: 0 !important;\r\n    padding: 0 !important;\r\n}\r\n\r\n\/* Aligner la 2e ligne de label sous la 1ere ligne *\/\r\n.elementor-field-group-Validation_Commande .elementor-field-option,\r\n.elementor-field-group-DataFacturation .elementor-field-option {\r\n    display: flex;\r\n    align-items: flex-start;\r\n    gap: 8px;\r\n}\r\n.elementor-field-group-Validation_Commande .elementor-field-option input[type=\"checkbox\"], \r\n.elementor-field-group-DataFacturation .elementor-field-option input[type=\"checkbox\"] {\r\n    flex-shrink: 0;\r\n    margin-top: 3px;\r\n}\r\n.elementor-field-group-Validation_Commande .elementor-field-option label, .elementor-field-group-DataFacturation .elementor-field-option label {\r\n    margin: 0;\r\n}\r\n\r\n<\/style>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2662421c elementor-widget elementor-widget-html\" data-id=\"2662421c\" data-element_type=\"widget\" data-e-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(function() {\r\n    'use strict';\r\n\r\n    \/\/ Anti-doublon\r\n    if (window.ViaPopupInitialized) return;\r\n    window.ViaPopupInitialized = true;\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ CONFIGURATION\r\n    \/\/ =========================================================================\r\n    \r\n    const VIA_POPUP_CONFIG = {\r\n        \/\/ Patterns de chemins \u00e0 intercepter (fonctionne sur tous les domaines\/sous-domaines)\r\n        targetPaths: [\r\n            '\/communication-institutionnelle',\r\n            '\/communication-corporate',\r\n            '\/vous-accompagner',\r\n            '\/via-agency-direction-redaction-media',\r\n            '\/espace-commercial',\r\n            '\/espace-annonceur',\r\n            '\/espace-institutionnel',\r\n            '\/espace-via-agency',\r\n            '\/mentions-legales-disclaimers'\r\n        ],\r\n        \r\n        \/\/ Domaines autoris\u00e9s (et leurs sous-domaines)\r\n        allowedDomains: [\r\n            'via-agency.media',\r\n            'yearbook-media.com'\r\n        ],\r\n        \r\n        \/\/ Page d'accueil yearbook \u00e0 intercepter\r\n        yearbookHomepage: true,\r\n        \r\n        \/\/ Titres personnalis\u00e9s par chemin (fran\u00e7ais)\r\n        titles: {\r\n            '\/communication-institutionnelle': 'Communication institutionnelle',\r\n            '\/communication-corporate': 'Communication corporate',\r\n            '\/vous-accompagner': 'Vous accompagner',\r\n            '\/via-agency-direction-redaction-media': 'Gouvernance & R\u00e9daction',\r\n            '\/espace-commercial': 'Advisory desk',\r\n            '\/espace-annonceur': 'Espace Acteurs priv\u00e9s',\r\n            '\/espace-institutionnel': 'Espace Acteurs publics',\r\n            '\/espace-via-agency': 'Espace Via Agency',\r\n            '\/mentions-legales-disclaimers-textes-2': 'Mentions l\u00e9gales & CGV',\r\n            '\/': 'Achat d\\'espaces publicitaires'\r\n        },\r\n        \r\n        \/\/ Titres en anglais\r\n        titlesEN: {\r\n            '\/communication-institutionnelle': 'Institutional Communication',\r\n            '\/communication-corporate': 'Corporate Communication',\r\n            '\/vous-accompagner': 'Support Services',\r\n            '\/via-agency-direction-redaction-media': 'Governance & Editorial',\r\n            '\/espace-commercial': 'Advisory desk',\r\n            '\/espace-annonceur': 'Private Sector Area',\r\n            '\/espace-institutionnel': 'Public Sector Area',\r\n            '\/espace-via-agency': 'Via Agency Area',\r\n            '\/mentions-legales-disclaimers-textes-2': 'Legal Notice \u2013 T&Cs',\r\n            '\/': 'Advertising Space Purchase'\r\n        },\r\n        \r\n        \/\/ pb344 : certains liens footer pointent vers la page complete mais doivent ouvrir\r\n        \/\/   une version \"textes\" (sans header\/menu) DANS le popup. Reecriture chemin -> URL popup.\r\n        pathOverrides: {\r\n            '\/mentions-legales-disclaimers': 'https:\/\/via-agency.media\/mentions-legales-disclaimers-textes-2\/'\r\n        },\r\n        \r\n        \/\/ Chemins n\u00e9cessitant des dimensions personnalis\u00e9es\r\n        customDimensionsPaths: [\r\n            '\/',\r\n            '\/espace-commercial',\r\n            '\/espace-annonceur',\r\n            '\/espace-institutionnel',\r\n            '\/espace-via-agency'\r\n        ],\r\n        \r\n        \/\/ Chemins n\u00e9cessitant la transmission du sessionStorage\r\n        sessionPaths: [\r\n            '\/espace-commercial',\r\n            '\/espace-annonceur',\r\n            '\/espace-institutionnel',\r\n            '\/espace-via-agency'\r\n        ],\r\n        \r\n        popup: {\r\n            width: 1100,\r\n            height: 600,\r\n            customWidth: 1300,\r\n            customHeight: 630\r\n        },\r\n        baseZIndex: 10000,\r\n        cascadeOffset: 30,\r\n        cssPrefix: 'via-popup-v2'\r\n    };\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ STATE\r\n    \/\/ =========================================================================\r\n    \r\n    const state = {\r\n        popups: new Map(),\r\n        currentZIndex: VIA_POPUP_CONFIG.baseZIndex,\r\n        popupCount: 0,\r\n        stylesInjected: false,\r\n        hoveredPopup: null,\r\n        draggingPopup: null,\r\n        resizingPopup: null\r\n    };\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ STYLES CSS\r\n    \/\/ =========================================================================\r\n    \r\n    function injectStyles() {\r\n        if (state.stylesInjected) return;\r\n        \r\n        const styles = `\r\n            \/* Container du popup *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-container {\r\n                position: fixed;\r\n                background: #fff;\r\n                border-radius: 4px;\r\n                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);\r\n                display: flex;\r\n                flex-direction: column;\r\n                overflow: hidden;\r\n                opacity: 0;\r\n                transition: opacity 0.2s ease, box-shadow 0.2s ease;\r\n                border: 1px solid #d0d0d0;\r\n                min-width: 300px;\r\n                min-height: 200px;\r\n                max-width: 95vw;\r\n                max-height: 90vh;\r\n            }\r\n            \r\n            .${VIA_POPUP_CONFIG.cssPrefix}-container.visible {\r\n                opacity: 1;\r\n            }\r\n            \r\n            .${VIA_POPUP_CONFIG.cssPrefix}-container.closing {\r\n                opacity: 0;\r\n            }\r\n            \r\n            \/* Poign\u00e9es de redimensionnement - bords et coins *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-resize-handle {\r\n                position: absolute;\r\n                z-index: 10;\r\n                background: transparent;\r\n            }\r\n            \r\n            \/* Bord haut *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-resize-top {\r\n                top: 0;\r\n                left: 10px;\r\n                right: 10px;\r\n                height: 6px;\r\n                cursor: ns-resize;\r\n            }\r\n            \r\n            \/* Bord bas *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-resize-bottom {\r\n                bottom: 0;\r\n                left: 10px;\r\n                right: 10px;\r\n                height: 6px;\r\n                cursor: ns-resize;\r\n            }\r\n            \r\n            \/* Bord gauche *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-resize-left {\r\n                left: 0;\r\n                top: 10px;\r\n                bottom: 10px;\r\n                width: 6px;\r\n                cursor: ew-resize;\r\n            }\r\n            \r\n            \/* Bord droit *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-resize-right {\r\n                right: 0;\r\n                top: 10px;\r\n                bottom: 10px;\r\n                width: 6px;\r\n                cursor: ew-resize;\r\n            }\r\n            \r\n            \/* Coin haut-gauche *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-resize-tl {\r\n                top: 0;\r\n                left: 0;\r\n                width: 10px;\r\n                height: 10px;\r\n                cursor: nwse-resize;\r\n            }\r\n            \r\n            \/* Coin haut-droit *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-resize-tr {\r\n                top: 0;\r\n                right: 0;\r\n                width: 10px;\r\n                height: 10px;\r\n                cursor: nesw-resize;\r\n            }\r\n            \r\n            \/* Coin bas-gauche *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-resize-bl {\r\n                bottom: 0;\r\n                left: 0;\r\n                width: 10px;\r\n                height: 10px;\r\n                cursor: nesw-resize;\r\n            }\r\n            \r\n            \/* Coin bas-droit *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-resize-br {\r\n                bottom: 0;\r\n                right: 0;\r\n                width: 10px;\r\n                height: 10px;\r\n                cursor: nwse-resize;\r\n            }\r\n            \r\n            \/* Header - Style \u00e9pur\u00e9 gris clair - DESIGN COMPACT *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-header {\r\n                display: flex;\r\n                align-items: center;\r\n                justify-content: center;\r\n                position: relative;\r\n                padding: 8px 35px;\r\n                background: #f5f5f5;\r\n                border-bottom: 1px solid #e0e0e0;\r\n                cursor: move;\r\n                user-select: none;\r\n                flex-shrink: 0;\r\n                touch-action: none;\r\n            }\r\n            \r\n            \/* Titre du popup - DESIGN COMPACT *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-title {\r\n                font-size: 15px;\r\n                font-weight: 600;\r\n                color: #4B689B;\r\n                text-align: center;\r\n                white-space: nowrap;\r\n                overflow: hidden;\r\n                text-overflow: ellipsis;\r\n            }\r\n            \r\n            \/* Bouton fermer - Style \u00d7 simple - DESIGN COMPACT *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-btn-close {\r\n                position: absolute;\r\n                right: 8px;\r\n                top: 50%;\r\n                transform: translateY(-50%);\r\n                width: 20px;\r\n                height: 20px;\r\n                border: none;\r\n                background: transparent !important;\r\n                cursor: pointer;\r\n                display: flex;\r\n                align-items: center;\r\n                justify-content: center;\r\n                color: #4B689B;\r\n                font-size: 16px;\r\n                font-weight: 500;\r\n                line-height: 1;\r\n                padding: 0;\r\n                transition: color 0.2s ease;\r\n                touch-action: manipulation;\r\n                -webkit-tap-highlight-color: transparent;\r\n                -webkit-appearance: none;\r\n            }\r\n            \r\n            .${VIA_POPUP_CONFIG.cssPrefix}-btn-close:hover {\r\n                color: #1a4a8a;\r\n                background: transparent !important;\r\n                outline: none;\r\n                box-shadow: none;\r\n            }\r\n            \r\n            .${VIA_POPUP_CONFIG.cssPrefix}-btn-close:focus {\r\n                outline: none;\r\n                background: transparent !important;\r\n                box-shadow: none;\r\n            }\r\n            \r\n            .${VIA_POPUP_CONFIG.cssPrefix}-btn-close:active {\r\n                background: transparent !important;\r\n                box-shadow: none;\r\n            }\r\n            \r\n            \/* Contenu (iframe) *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-content {\r\n                flex: 1;\r\n                position: relative;\r\n                overflow: hidden;\r\n                background: #fff;\r\n            }\r\n            \r\n            .${VIA_POPUP_CONFIG.cssPrefix}-iframe {\r\n                width: 100%;\r\n                height: 100%;\r\n                border: none;\r\n            }\r\n            \r\n            \/* Loader - NOUVEAU STYLE *\/\r\n            .${VIA_POPUP_CONFIG.cssPrefix}-loader {\r\n                position: absolute;\r\n                top: 25%;\r\n                left: 50%;\r\n                transform: translate(-50%, -50%);\r\n                display: flex;\r\n                flex-direction: column;\r\n                align-items: center;\r\n                gap: 16px;\r\n            }\r\n            \r\n            .${VIA_POPUP_CONFIG.cssPrefix}-spinner {\r\n                width: 50px;\r\n                height: 50px;\r\n                border: 4px solid #eee;\r\n                border-top: 4px solid #00FF19;\r\n                border-radius: 50%;\r\n                animation: ${VIA_POPUP_CONFIG.cssPrefix}-spin 0.8s linear infinite;\r\n            }\r\n            \r\n            @keyframes ${VIA_POPUP_CONFIG.cssPrefix}-spin {\r\n                0% { transform: rotate(0deg); }\r\n                100% { transform: rotate(360deg); }\r\n            }\r\n            \r\n            .${VIA_POPUP_CONFIG.cssPrefix}-loader-text {\r\n                color: #00FF19;\r\n                font-size: 18px;\r\n                font-weight: 500;\r\n            }\r\n            \r\n            \/* Responsive - DESIGN COMPACT MOBILE *\/\r\n            @media (max-width: 768px) {\r\n                .${VIA_POPUP_CONFIG.cssPrefix}-container {\r\n                    width: 95vw !important;\r\n                    height: calc(80vh - 100px) !important;\r\n                    left: 2.5vw !important;\r\n                    top: 10vh !important;\r\n                }\r\n                \r\n                .${VIA_POPUP_CONFIG.cssPrefix}-resize-handle {\r\n                    display: none;\r\n                }\r\n                \r\n                .${VIA_POPUP_CONFIG.cssPrefix}-header {\r\n                    padding: 6px 28px;\r\n                }\r\n                \r\n                .${VIA_POPUP_CONFIG.cssPrefix}-title {\r\n                    font-size: 14px;\r\n                }\r\n                \r\n                .${VIA_POPUP_CONFIG.cssPrefix}-btn-close {\r\n                    right: 6px;\r\n                    width: 18px;\r\n                    height: 18px;\r\n                    font-size: 14px;\r\n                }\r\n            }\r\n        `;\r\n        \r\n        const styleEl = document.createElement('style');\r\n        styleEl.id = `${VIA_POPUP_CONFIG.cssPrefix}-styles`;\r\n        styleEl.textContent = styles;\r\n        document.head.appendChild(styleEl);\r\n        \r\n        state.stylesInjected = true;\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ UTILITAIRES\r\n    \/\/ =========================================================================\r\n    \r\n    \/**\r\n     * V\u00e9rifie si un domaine est autoris\u00e9 (domaine principal ou sous-domaine)\r\n     *\/\r\n    function isAllowedDomain(hostname) {\r\n        return VIA_POPUP_CONFIG.allowedDomains.some(domain => \r\n            hostname === domain || hostname.endsWith('.' + domain)\r\n        );\r\n    }\r\n    \r\n    \/**\r\n     * Obtient la langue du site depuis sessionStorage\r\n     * @returns {string} 'FR' ou 'EN'\r\n     *\/\r\n    function getSiteLangue() {\r\n        return sessionStorage.getItem('SiteLangue') || 'FR';\r\n    }\r\n    \r\n    \/**\r\n     * Extrait le chemin de base sans le pr\u00e9fixe de langue\r\n     * \/en\/communication-institutionnelle -> \/communication-institutionnelle\r\n     * \/communication-institutionnelle -> \/communication-institutionnelle\r\n     *\/\r\n    function getBasePathWithoutLang(path) {\r\n        const normalized = normalizePath(path);\r\n        if (normalized.startsWith('\/en\/')) {\r\n            return normalized.substring(3); \/\/ Enl\u00e8ve '\/en'\r\n        }\r\n        if (normalized === '\/en') {\r\n            return '\/';\r\n        }\r\n        return normalized;\r\n    }\r\n    \r\n    \/**\r\n     * Adapte un chemin selon la langue\r\n     * @param {string} basePath - Chemin de base (sans \/en\/)\r\n     * @returns {string} Chemin adapt\u00e9 \u00e0 la langue courante\r\n     *\/\r\n    function getLocalizedPath(basePath) {\r\n        const lang = getSiteLangue();\r\n        if (lang === 'EN') {\r\n            if (basePath === '\/') {\r\n                return '\/en';\r\n            }\r\n            return '\/en' + basePath;\r\n        }\r\n        return basePath;\r\n    }\r\n    \r\n    \/**\r\n     * Adapte une URL compl\u00e8te selon la langue\r\n     * @param {string} url - URL \u00e0 adapter\r\n     * @returns {string} URL adapt\u00e9e \u00e0 la langue courante\r\n     *\/\r\n    function getLocalizedUrl(url) {\r\n        try {\r\n            const urlObj = new URL(url, window.location.origin);\r\n            const basePath = getBasePathWithoutLang(urlObj.pathname);\r\n            const localizedPath = getLocalizedPath(basePath);\r\n            urlObj.pathname = localizedPath;\r\n            return urlObj.href;\r\n        } catch (e) {\r\n            return url;\r\n        }\r\n    }\r\n    \r\n    \/**\r\n     * Normalise un chemin (supprime le slash final)\r\n     *\/\r\n    function normalizePath(path) {\r\n        return path.replace(\/\\\/$\/, '') || '\/';\r\n    }\r\n    \r\n    \/**\r\n     * V\u00e9rifie si une URL doit \u00eatre intercept\u00e9e\r\n     *\/\r\n    function shouldIntercept(url) {\r\n        try {\r\n            const urlObj = new URL(url, window.location.origin);\r\n            const hostname = urlObj.hostname;\r\n            const path = normalizePath(urlObj.pathname);\r\n            const basePath = getBasePathWithoutLang(path);\r\n            \r\n            \/\/ V\u00e9rifier si le domaine est autoris\u00e9\r\n            if (!isAllowedDomain(hostname)) {\r\n                return false;\r\n            }\r\n            \r\n            \/\/ Cas sp\u00e9cial : page d'accueil yearbook (\/ ou \/en)\r\n            if (VIA_POPUP_CONFIG.yearbookHomepage && (basePath === '\/') && hostname.includes('yearbook-media.com')) {\r\n                return true;\r\n            }\r\n            \r\n            \/\/ V\u00e9rifier si le chemin de base est dans la liste\r\n            return VIA_POPUP_CONFIG.targetPaths.some(targetPath => \r\n                normalizePath(targetPath) === basePath\r\n            );\r\n        } catch (e) {\r\n            return false;\r\n        }\r\n    }\r\n    \r\n    \/**\r\n     * pb344 : applique une reecriture d'URL (pathOverrides) si le chemin de base du\r\n     *   lien correspond (ex. mentions-legales -> version -textes-2 pour le popup).\r\n     *\/\r\n    function applyPathOverride(url) {\r\n        try {\r\n            const urlObj = new URL(url, window.location.origin);\r\n            const basePath = getBasePathWithoutLang(normalizePath(urlObj.pathname));\r\n            const override = VIA_POPUP_CONFIG.pathOverrides ? VIA_POPUP_CONFIG.pathOverrides[basePath] : null;\r\n            return override ? override : url;\r\n        } catch (e) {\r\n            return url;\r\n        }\r\n    }\r\n    \r\n    \/**\r\n     * Obtient le titre pour une URL\r\n     *\/\r\n    function getTitleFromUrl(url) {\r\n        try {\r\n            const urlObj = new URL(url, window.location.origin);\r\n            const path = normalizePath(urlObj.pathname);\r\n            const basePath = getBasePathWithoutLang(path);\r\n            const lang = getSiteLangue();\r\n            \r\n            \/\/ Choisir le mapping de titres selon la langue\r\n            const titlesMap = lang === 'EN' ? VIA_POPUP_CONFIG.titlesEN : VIA_POPUP_CONFIG.titles;\r\n            \r\n            \/\/ Chercher dans le mapping des titres\r\n            if (titlesMap[basePath]) {\r\n                return titlesMap[basePath];\r\n            }\r\n            \r\n            \/\/ Fallback sur les titres FR si pas trouv\u00e9 en EN\r\n            if (lang === 'EN' && VIA_POPUP_CONFIG.titles[basePath]) {\r\n                return VIA_POPUP_CONFIG.titles[basePath];\r\n            }\r\n            \r\n            \/\/ Fallback : g\u00e9n\u00e9rer depuis le chemin\r\n            const lastSegment = basePath.split('\/').filter(Boolean).pop() || 'Page';\r\n            return lastSegment\r\n                .replace(\/-\/g, ' ')\r\n                .replace(\/\\b\\w\/g, c => c.toUpperCase());\r\n        } catch (e) {\r\n            return 'Page';\r\n        }\r\n    }\r\n    \r\n    \/**\r\n     * Obtient les dimensions pour une URL\r\n     *\/\r\n    function getDimensions(url) {\r\n        try {\r\n            const urlObj = new URL(url, window.location.origin);\r\n            const path = normalizePath(urlObj.pathname);\r\n            const basePath = getBasePathWithoutLang(path);\r\n            \r\n            \/\/ V\u00e9rifier si ce chemin n\u00e9cessite des dimensions personnalis\u00e9es\r\n            if (VIA_POPUP_CONFIG.customDimensionsPaths.some(p => normalizePath(p) === basePath)) {\r\n                return {\r\n                    width: VIA_POPUP_CONFIG.popup.customWidth,\r\n                    height: VIA_POPUP_CONFIG.popup.customHeight\r\n                };\r\n            }\r\n        } catch (e) {}\r\n        \r\n        return {\r\n            width: VIA_POPUP_CONFIG.popup.width,\r\n            height: VIA_POPUP_CONFIG.popup.height\r\n        };\r\n    }\r\n    \r\n    \/**\r\n     * V\u00e9rifie si une URL n\u00e9cessite la transmission du sessionStorage\r\n     *\/\r\n    function requiresSession(url) {\r\n        try {\r\n            const urlObj = new URL(url, window.location.origin);\r\n            const path = normalizePath(urlObj.pathname);\r\n            const basePath = getBasePathWithoutLang(path);\r\n            \r\n            return VIA_POPUP_CONFIG.sessionPaths.some(p => normalizePath(p) === basePath);\r\n        } catch (e) {\r\n            return false;\r\n        }\r\n    }\r\n    \r\n    \/**\r\n     * Normalise une URL compl\u00e8te (pour cl\u00e9 unique des popups)\r\n     *\/\r\n    function normalizeUrl(url) {\r\n        try {\r\n            const urlObj = new URL(url, window.location.origin);\r\n            return urlObj.href.replace(\/\\\/$\/, '');\r\n        } catch (e) {\r\n            return url.replace(\/\\\/$\/, '');\r\n        }\r\n    }\r\n    \r\n    function getInitialPosition(width, height) {\r\n        const offset = (state.popupCount % 5) * VIA_POPUP_CONFIG.cascadeOffset;\r\n        const viewportWidth = window.innerWidth;\r\n        const viewportHeight = window.innerHeight;\r\n        \r\n        \/\/ Horizontal : bas\u00e9 sur la largeur r\u00e9elle (pour voir la croix de fermeture)\r\n        const left = Math.max(50, (viewportWidth - width) \/ 2 + offset);\r\n        \r\n        \/\/ Vertical : dimensions de r\u00e9f\u00e9rence pour cascade coh\u00e9rente\r\n        const refHeight = VIA_POPUP_CONFIG.popup.height; \/\/ 600\r\n        const top = Math.max(50, (viewportHeight - refHeight) \/ 2 + offset);\r\n        \r\n        return { left, top };\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ SESSION STORAGE TRANSMISSION\r\n    \/\/ =========================================================================\r\n    \r\n    \/**\r\n     * Envoie les donn\u00e9es sessionStorage \u00e0 l'iframe via postMessage\r\n     *\/\r\n    function sendSessionStorageToIframe(iframe, targetUrl) {\r\n        try {\r\n            const targetOrigin = new URL(targetUrl).origin;\r\n            \r\n            \/\/ Collecter toutes les donn\u00e9es sessionStorage\r\n            const sessionData = {};\r\n            for (let i = 0; i < sessionStorage.length; i++) {\r\n                const key = sessionStorage.key(i);\r\n                sessionData[key] = sessionStorage.getItem(key);\r\n            }\r\n            \r\n            \/\/ Envoyer via postMessage\r\n            iframe.contentWindow.postMessage({\r\n                type: 'VIA_SESSION_DATA',\r\n                data: sessionData\r\n            }, targetOrigin);\r\n            \r\n            console.log('\u2705 SessionStorage transmis \u00e0:', targetOrigin);\r\n        } catch (e) {\r\n            console.error('Erreur transmission sessionStorage:', e);\r\n        }\r\n    }\r\n    \r\n    \/**\r\n     * Configure la transmission du sessionStorage avec retry\r\n     *\/\r\n    function setupSessionTransmission(iframe, url) {\r\n        \/\/ V\u00e9rifier si cette URL n\u00e9cessite le sessionStorage\r\n        if (!requiresSession(url)) {\r\n            return;\r\n        }\r\n        \r\n        \/\/ Envoyer d\u00e8s que l'iframe est charg\u00e9e\r\n        iframe.addEventListener('load', () => {\r\n            sendSessionStorageToIframe(iframe, url);\r\n            \r\n            \/\/ Retry apr\u00e8s 500ms au cas o\u00f9\r\n            setTimeout(() => {\r\n                sendSessionStorageToIframe(iframe, url);\r\n            }, 500);\r\n        });\r\n        \r\n        \/\/ \u00c9couter si l'iframe signale qu'elle est pr\u00eate\r\n        window.addEventListener('message', function handler(event) {\r\n            if (event.data && event.data.type === 'VIA_IFRAME_READY') {\r\n                console.log('\ud83d\udce8 Iframe pr\u00eate, envoi des donn\u00e9es session...');\r\n                sendSessionStorageToIframe(iframe, url);\r\n                \r\n                \/\/ Retirer le listener apr\u00e8s utilisation\r\n                window.removeEventListener('message', handler);\r\n            }\r\n        });\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ CR\u00c9ATION DU POPUP\r\n    \/\/ =========================================================================\r\n    \r\n    \/\/ =========================================================================\r\n    \/\/ pb2372 : LE TITRE DU POPUP REPREND LE TEXTE DU LIEN CLIQUE.\r\n    \/\/   Demande JF. Jusqu'ici le titre venait de la table VIA_POPUP_CONFIG.titles\r\n    \/\/   (cle = chemin de base), donc un libelle fige par URL. Le lien clique est\r\n    \/\/   deja entre les mains de interceptLinks : on le fait simplement descendre.\r\n    \/\/   PORTEE : seul l'appel depuis interceptLinks transmet ce texte. Les deux\r\n    \/\/   autres appelants (ViaPopup.open et openAfterLogin) n'ont pas de lien et\r\n    \/\/   n'en passent pas -> ils gardent la table, inchanges.\r\n    \/\/   REPLIS, dans l'ordre : texte du lien -> title\/aria-label -> table.\r\n    \/\/   Un lien sans texte (picto seul) ne doit pas produire un en-tete vide.\r\n    \/\/   ECHAPPEMENT : ce texte vient du DOM et entre dans un innerHTML \u2014 il est\r\n    \/\/   echappe, ce dont la table codee en dur n'avait pas besoin.\r\n    \/\/   Knob : window._viaPb2372Off = true -> retour a la table seule.\r\n    \/\/ =========================================================================\r\n    function _viaTitreLien2372(_lien) {\r\n        if (window._viaPb2372Off === true) { return ''; }\r\n        if (!_lien) { return ''; }\r\n        var _t2372 = '';\r\n        try { _t2372 = _lien.textContent ? _lien.textContent : ''; } catch (_e2372) { _t2372 = ''; }\r\n        _t2372 = _t2372.replace(\/\\s+\/g, ' ').trim();\r\n        if (_t2372 === '') {\r\n            try { _t2372 = (_lien.getAttribute('title') || _lien.getAttribute('aria-label') || ''); } catch (_e2b2372) { _t2372 = ''; }\r\n            _t2372 = _t2372.replace(\/\\s+\/g, ' ').trim();\r\n        }\r\n        return _t2372;\r\n    }\r\n    function _viaEchappe2372(_s) {\r\n        var _d2372 = document.createElement('span');\r\n        _d2372.textContent = _s;\r\n        return _d2372.innerHTML;\r\n    }\r\n    function createPopup(url, _titreLien2372) {\r\n        \/\/ Fermer le menu Elementor s'il est ouvert\r\n        const menuPopupId = findMenuPopupId();\r\n        const menuPopup = document.getElementById(menuPopupId);\r\n        if (menuPopup) {\r\n            menuPopup.style.display = 'none';\r\n        }\r\n        \r\n        \/\/ Adapter l'URL selon la langue\r\n        const localizedUrl = getLocalizedUrl(url);\r\n        \r\n        const normalizedUrl = normalizeUrl(localizedUrl);\r\n        if (state.popups.has(normalizedUrl)) {\r\n            bringToFront(state.popups.get(normalizedUrl));\r\n            return;\r\n        }\r\n        \r\n        injectStyles();\r\n        \r\n        \/\/ pb2372 : le texte du lien prime, la table sert de repli.\r\n        const _titreTable2372 = getTitleFromUrl(localizedUrl);\r\n        const _viaDuLien2372 = (_titreLien2372 ? _titreLien2372 : '') !== '';\r\n        const _titreRetenu2372 = _viaDuLien2372 ? _titreLien2372 : _titreTable2372;\r\n        const title = _viaEchappe2372(_titreRetenu2372);\r\n        console.log('[pb2372] titre popup = \"' + _titreRetenu2372 + '\" (source : '\r\n            + (_viaDuLien2372 ? 'texte du lien' : 'table titles') + ')');\r\n        \/\/ =====================================================================\r\n        \/\/ pb1228b : le z-index d'OUVERTURE suit lui aussi l'echelle partagee.\r\n        \/\/   Constat user : au clic le popup passe bien devant (2000016), mais a son\r\n        \/\/   OUVERTURE il vaut 10001 et reste derriere.\r\n        \/\/   Cause : pb1228 n'a corrige que bringToFront, appele au clic. La\r\n        \/\/   creation, elle, prend ++state.currentZIndex \u2014 la valeur locale, qui\r\n        \/\/   repart de baseZIndex 10000.\r\n        \/\/   Un popup doit s'ouvrir devant : c'est ce que l'utilisateur vient de\r\n        \/\/   demander. On applique donc le meme calcul qu'au clic.\r\n        \/\/   Revert : window._viaPb1228Off = true.\r\n        \/\/ =====================================================================\r\n        if (window._viaPb1228Off !== true) {\r\n            if (typeof window._viaMaxZPopups663 === 'function') {\r\n                try {\r\n                    var _max1228b = window._viaMaxZPopups663();\r\n                    if (_max1228b + 2 > state.currentZIndex) { state.currentZIndex = _max1228b + 2; }\r\n                } catch (_e1228b) {}\r\n            }\r\n        }\r\n        const zIndex = ++state.currentZIndex;\r\n        \r\n        \/\/ Dimensions : personnalis\u00e9es ou par d\u00e9faut\r\n        const dimensions = getDimensions(localizedUrl);\r\n        const width = dimensions.width;\r\n        const height = dimensions.height;\r\n        \r\n        const position = getInitialPosition(width, height);\r\n        \r\n        \/\/ Container\r\n        const container = document.createElement('div');\r\n        container.className = `${VIA_POPUP_CONFIG.cssPrefix}-container`;\r\n        container.style.cssText = `\r\n            left: ${position.left}px;\r\n            top: ${position.top}px;\r\n            width: ${width}px;\r\n            height: ${height}px;\r\n            z-index: ${zIndex};\r\n        `;\r\n        container.dataset.url = normalizedUrl;\r\n        \r\n        \/\/ Header \u00e9pur\u00e9\r\n        const header = document.createElement('div');\r\n        header.className = `${VIA_POPUP_CONFIG.cssPrefix}-header`;\r\n        header.innerHTML = `\r\n            <span class=\"${VIA_POPUP_CONFIG.cssPrefix}-title\">${title}<\/span>\r\n            <button class=\"${VIA_POPUP_CONFIG.cssPrefix}-btn-close\" title=\"Fermer\">\u00d7<\/button>\r\n        `;\r\n        \r\n        \/\/ Contenu\r\n        const content = document.createElement('div');\r\n        content.className = `${VIA_POPUP_CONFIG.cssPrefix}-content`;\r\n        content.innerHTML = `\r\n            <div class=\"${VIA_POPUP_CONFIG.cssPrefix}-loader\">\r\n                <div class=\"${VIA_POPUP_CONFIG.cssPrefix}-spinner\"><\/div>\r\n                <span class=\"${VIA_POPUP_CONFIG.cssPrefix}-loader-text\">Loading in progress<\/span>\r\n            <\/div>\r\n            <iframe class=\"${VIA_POPUP_CONFIG.cssPrefix}-iframe\" src=\"${localizedUrl}\"><\/iframe>\r\n        `;\r\n        \r\n        \/\/ Assemblage\r\n        container.appendChild(header);\r\n        container.appendChild(content);\r\n        \r\n        \/\/ Poign\u00e9es de redimensionnement - 4 bords + 4 coins\r\n        const zones = ['top', 'bottom', 'left', 'right', 'tl', 'tr', 'bl', 'br'];\r\n        zones.forEach(zone => {\r\n            const handle = document.createElement('div');\r\n            handle.className = `${VIA_POPUP_CONFIG.cssPrefix}-resize-handle ${VIA_POPUP_CONFIG.cssPrefix}-resize-${zone}`;\r\n            handle.dataset.zone = zone;\r\n            container.appendChild(handle);\r\n        });\r\n        \r\n        document.body.appendChild(container);\r\n        \r\n        \/\/ Enregistrement\r\n        state.popups.set(normalizedUrl, container);\r\n        state.popupCount++;\r\n        \r\n        \/\/ Animation d'entr\u00e9e\r\n        requestAnimationFrame(() => {\r\n            container.classList.add('visible');\r\n        });\r\n        \r\n        \/\/ Gestion iframe\r\n        const iframe = content.querySelector(`.${VIA_POPUP_CONFIG.cssPrefix}-iframe`);\r\n        const loader = content.querySelector(`.${VIA_POPUP_CONFIG.cssPrefix}-loader`);\r\n        \r\n        \/\/ Fonction pour masquer le loader\r\n        function hideLoader() {\r\n            if (loader) {\r\n                loader.style.display = 'none';\r\n            }\r\n        }\r\n        \r\n        \/\/ Masquer apr\u00e8s un d\u00e9lai minimum (laisser le temps de voir le loader)\r\n        setTimeout(hideLoader, 10000);\r\n        \r\n        \/\/ \u00c9couter VIA_IFRAME_READY pour le sessionStorage (mais pas pour le loader)\r\n        const readyHandler = function(event) {\r\n            if (event.data && event.data.type === 'VIA_IFRAME_READY') {\r\n                \/\/ Ne pas masquer le loader ici, juste pour le sessionStorage\r\n            }\r\n        };\r\n        window.addEventListener('message', readyHandler);\r\n        \r\n        \/\/ Masquer au load complet si plus de 2500ms (fallback)\r\n        iframe.addEventListener('load', hideLoader);\r\n        \r\n        \/\/ Configuration de la transmission du sessionStorage\r\n        setupSessionTransmission(iframe, url);\r\n        \r\n        \/\/ Events\r\n        setupDrag(container, header);\r\n        setupClose(container);\r\n        setupFocus(container);\r\n        setupResizeAllZones(container);\r\n        \r\n        return container;\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ DRAG & DROP\r\n    \/\/ =========================================================================\r\n    \r\n    \/\/ \u00c9v\u00e9nements globaux pour le drag (attach\u00e9s une seule fois)\r\n    let dragEventsInitialized = false;\r\n    \r\n    function initGlobalDragEvents() {\r\n        if (dragEventsInitialized) return;\r\n        \r\n        document.addEventListener('mousemove', drag);\r\n        document.addEventListener('mouseup', dragEnd);\r\n        document.addEventListener('touchmove', drag, { passive: false });\r\n        document.addEventListener('touchend', dragEnd);\r\n        \r\n        dragEventsInitialized = true;\r\n    }\r\n    \r\n    function setupDrag(container, header) {\r\n        initGlobalDragEvents();\r\n        \r\n        \/\/ Donn\u00e9es de drag pour ce popup\r\n        container.dragData = {\r\n            isDragging: false,\r\n            currentX: 0,\r\n            currentY: 0,\r\n            initialX: 0,\r\n            initialY: 0,\r\n            xOffset: 0,\r\n            yOffset: 0\r\n        };\r\n        \r\n        header.addEventListener('mousedown', (e) => dragStart(e, container));\r\n        header.addEventListener('touchstart', (e) => dragStart(e, container), { passive: false });\r\n    }\r\n    \r\n    function dragStart(e, container) {\r\n        \/\/ Ignorer si clic sur le bouton fermer\r\n        if (e.target.closest(`.${VIA_POPUP_CONFIG.cssPrefix}-btn-close`)) {\r\n            return;\r\n        }\r\n        \r\n        e.preventDefault();\r\n        \r\n        const data = container.dragData;\r\n        \r\n        if (e.type === \"touchstart\") {\r\n            data.initialX = e.touches[0].clientX - data.xOffset;\r\n            data.initialY = e.touches[0].clientY - data.yOffset;\r\n        } else {\r\n            data.initialX = e.clientX - data.xOffset;\r\n            data.initialY = e.clientY - data.yOffset;\r\n        }\r\n        \r\n        data.isDragging = true;\r\n        state.draggingPopup = container;\r\n        \r\n        bringToFront(container);\r\n        \r\n        \/\/ Feedback visuel\r\n        container.style.boxShadow = '0 8px 25px rgba(0,0,0,0.3)';\r\n    }\r\n    \r\n    function drag(e) {\r\n        const container = state.draggingPopup;\r\n        if (!container || !container.dragData.isDragging) return;\r\n        \r\n        e.preventDefault();\r\n        \r\n        const data = container.dragData;\r\n        \r\n        if (e.type === \"touchmove\") {\r\n            data.currentX = e.touches[0].clientX - data.initialX;\r\n            data.currentY = e.touches[0].clientY - data.initialY;\r\n        } else {\r\n            data.currentX = e.clientX - data.initialX;\r\n            data.currentY = e.clientY - data.initialY;\r\n        }\r\n        \r\n        \/\/ Limites pour garder le popup visible (au moins une partie)\r\n        const containerWidth = container.offsetWidth;\r\n        const containerHeight = container.offsetHeight;\r\n        const viewportWidth = window.innerWidth;\r\n        const viewportHeight = window.innerHeight;\r\n        \r\n        \/\/ R\u00e9cup\u00e9rer la position initiale du popup\r\n        const initialTop = parseFloat(container.style.top) || 0;\r\n        const initialLeft = parseFloat(container.style.left) || 0;\r\n        \r\n        \/\/ Horizontal : garder 50px du popup visible \u00e0 gauche et \u00e0 droite\r\n        const minX = 50 - initialLeft - containerWidth; \/\/ 50px visible quand on va \u00e0 gauche\r\n        const maxX = viewportWidth - 50 - initialLeft; \/\/ 50px visible quand on va \u00e0 droite\r\n        data.currentX = Math.max(minX, Math.min(maxX, data.currentX));\r\n        \r\n        \/\/ Vertical : peut remonter jusqu'\u00e0 20px du haut, descendre jusqu'\u00e0 20px du bas (header visible)\r\n        const minY = 20 - initialTop;\r\n        const maxY = viewportHeight - 20 - initialTop - 50; \/\/ 50 = hauteur du header environ\r\n        data.currentY = Math.max(minY, Math.min(maxY, data.currentY));\r\n        \r\n        data.xOffset = data.currentX;\r\n        data.yOffset = data.currentY;\r\n        \r\n        container.style.transform = `translate(${data.currentX}px, ${data.currentY}px)`;\r\n    }\r\n    \r\n    function dragEnd() {\r\n        const container = state.draggingPopup;\r\n        if (!container) return;\r\n        \r\n        const data = container.dragData;\r\n        \r\n        if (data.isDragging) {\r\n            data.initialX = data.currentX;\r\n            data.initialY = data.currentY;\r\n            data.isDragging = false;\r\n            \r\n            \/\/ Reset feedback visuel\r\n            container.style.boxShadow = '';\r\n        }\r\n        \r\n        state.draggingPopup = null;\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ RESIZE - 4 BORDS + 4 COINS\r\n    \/\/ =========================================================================\r\n    \r\n    let resizeEventsInitialized = false;\r\n    \r\n    function initGlobalResizeEvents() {\r\n        if (resizeEventsInitialized) return;\r\n        \r\n        document.addEventListener('mousemove', resizeMove);\r\n        document.addEventListener('mouseup', resizeEnd);\r\n        document.addEventListener('touchmove', resizeMove, { passive: false });\r\n        document.addEventListener('touchend', resizeEnd);\r\n        \r\n        resizeEventsInitialized = true;\r\n    }\r\n    \r\n    function setupResizeAllZones(container) {\r\n        initGlobalResizeEvents();\r\n        \r\n        container.resizeData = {\r\n            isResizing: false,\r\n            zone: null,\r\n            startX: 0,\r\n            startY: 0,\r\n            startWidth: 0,\r\n            startHeight: 0,\r\n            startLeft: 0,\r\n            startTop: 0\r\n        };\r\n        \r\n        \/\/ Attacher les \u00e9v\u00e9nements \u00e0 chaque poign\u00e9e\r\n        const handles = container.querySelectorAll(`.${VIA_POPUP_CONFIG.cssPrefix}-resize-handle`);\r\n        handles.forEach(handle => {\r\n            handle.addEventListener('mousedown', (e) => resizeStart(e, container, handle.dataset.zone));\r\n            handle.addEventListener('touchstart', (e) => resizeStart(e, container, handle.dataset.zone), { passive: false });\r\n        });\r\n    }\r\n    \r\n    function resizeStart(e, container, zone) {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        \r\n        const data = container.resizeData;\r\n        const rect = container.getBoundingClientRect();\r\n        \r\n        \/\/ Position initiale de la souris\r\n        if (e.type === 'touchstart') {\r\n            data.startX = e.touches[0].clientX;\r\n            data.startY = e.touches[0].clientY;\r\n        } else {\r\n            data.startX = e.clientX;\r\n            data.startY = e.clientY;\r\n        }\r\n        \r\n        \/\/ Dimensions et position initiales du popup\r\n        data.startWidth = rect.width;\r\n        data.startHeight = rect.height;\r\n        data.startLeft = rect.left;\r\n        data.startTop = rect.top;\r\n        data.zone = zone;\r\n        \r\n        data.isResizing = true;\r\n        state.resizingPopup = container;\r\n        \r\n        bringToFront(container);\r\n        \r\n        \/\/ Feedback visuel\r\n        container.style.boxShadow = '0 8px 25px rgba(0,0,0,0.3)';\r\n    }\r\n    \r\n    function resizeMove(e) {\r\n        const container = state.resizingPopup;\r\n        if (!container || !container.resizeData.isResizing) return;\r\n        \r\n        e.preventDefault();\r\n        \r\n        const data = container.resizeData;\r\n        \r\n        let currentX, currentY;\r\n        if (e.type === 'touchmove') {\r\n            currentX = e.touches[0].clientX;\r\n            currentY = e.touches[0].clientY;\r\n        } else {\r\n            currentX = e.clientX;\r\n            currentY = e.clientY;\r\n        }\r\n        \r\n        \/\/ Calcul du delta\r\n        const deltaX = currentX - data.startX;\r\n        const deltaY = currentY - data.startY;\r\n        \r\n        \/\/ Limites\r\n        const minWidth = 300;\r\n        const minHeight = 200;\r\n        const maxWidth = window.innerWidth * 0.95;\r\n        const maxHeight = window.innerHeight * 0.9;\r\n        \r\n        let newWidth = data.startWidth;\r\n        let newHeight = data.startHeight;\r\n        let newLeft = data.startLeft;\r\n        let newTop = data.startTop;\r\n        \r\n        \/\/ Comportement selon la zone\r\n        switch (data.zone) {\r\n            \/\/ Bords\r\n            case 'top':\r\n                newHeight = data.startHeight - deltaY;\r\n                newTop = data.startTop + deltaY;\r\n                break;\r\n                \r\n            case 'bottom':\r\n                newHeight = data.startHeight + deltaY;\r\n                break;\r\n                \r\n            case 'left':\r\n                newWidth = data.startWidth - deltaX;\r\n                newLeft = data.startLeft + deltaX;\r\n                break;\r\n                \r\n            case 'right':\r\n                newWidth = data.startWidth + deltaX;\r\n                break;\r\n                \r\n            \/\/ Coins\r\n            case 'tl': \/\/ Top-left\r\n                newWidth = data.startWidth - deltaX;\r\n                newHeight = data.startHeight - deltaY;\r\n                newLeft = data.startLeft + deltaX;\r\n                newTop = data.startTop + deltaY;\r\n                break;\r\n                \r\n            case 'tr': \/\/ Top-right\r\n                newWidth = data.startWidth + deltaX;\r\n                newHeight = data.startHeight - deltaY;\r\n                newTop = data.startTop + deltaY;\r\n                break;\r\n                \r\n            case 'bl': \/\/ Bottom-left\r\n                newWidth = data.startWidth - deltaX;\r\n                newHeight = data.startHeight + deltaY;\r\n                newLeft = data.startLeft + deltaX;\r\n                break;\r\n                \r\n            case 'br': \/\/ Bottom-right\r\n                newWidth = data.startWidth + deltaX;\r\n                newHeight = data.startHeight + deltaY;\r\n                break;\r\n        }\r\n        \r\n        \/\/ Appliquer les limites de taille et corriger la position si n\u00e9cessaire\r\n        if (newWidth < minWidth) {\r\n            if (data.zone === 'left' || data.zone === 'tl' || data.zone === 'bl') {\r\n                newLeft = data.startLeft + data.startWidth - minWidth;\r\n            }\r\n            newWidth = minWidth;\r\n        }\r\n        if (newWidth > maxWidth) {\r\n            newWidth = maxWidth;\r\n        }\r\n        \r\n        if (newHeight < minHeight) {\r\n            if (data.zone === 'top' || data.zone === 'tl' || data.zone === 'tr') {\r\n                newTop = data.startTop + data.startHeight - minHeight;\r\n            }\r\n            newHeight = minHeight;\r\n        }\r\n        if (newHeight > maxHeight) {\r\n            newHeight = maxHeight;\r\n        }\r\n        \r\n        \/\/ Limites de position\r\n        newLeft = Math.max(20, newLeft);\r\n        newTop = Math.max(20, newTop);\r\n        \r\n        \/\/ Appliquer\r\n        container.style.width = newWidth + 'px';\r\n        container.style.height = newHeight + 'px';\r\n        container.style.left = newLeft + 'px';\r\n        container.style.top = newTop + 'px';\r\n        \r\n        \/\/ Reset transform car on utilise left\/top directement\r\n        container.style.transform = 'none';\r\n        \r\n        \/\/ Reset les offsets du drag\r\n        if (container.dragData) {\r\n            container.dragData.xOffset = 0;\r\n            container.dragData.yOffset = 0;\r\n            container.dragData.currentX = 0;\r\n            container.dragData.currentY = 0;\r\n            container.dragData.initialX = 0;\r\n            container.dragData.initialY = 0;\r\n        }\r\n    }\r\n    \r\n    function resizeEnd() {\r\n        const container = state.resizingPopup;\r\n        if (!container) return;\r\n        \r\n        if (container.resizeData.isResizing) {\r\n            container.resizeData.isResizing = false;\r\n            container.resizeData.zone = null;\r\n            container.style.boxShadow = '';\r\n        }\r\n        \r\n        state.resizingPopup = null;\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ FERMETURE\r\n    \/\/ =========================================================================\r\n    \r\n    function setupClose(container) {\r\n        const closeBtn = container.querySelector(`.${VIA_POPUP_CONFIG.cssPrefix}-btn-close`);\r\n        \r\n        \/\/ Desktop\r\n        closeBtn.addEventListener('click', (e) => {\r\n            e.stopPropagation();\r\n            e.preventDefault();\r\n            closePopup(container);\r\n        });\r\n        \r\n        \/\/ Mobile - touchstart pour \u00e9viter le d\u00e9lai\r\n        closeBtn.addEventListener('touchstart', (e) => {\r\n            e.stopPropagation();\r\n        }, { passive: true });\r\n        \r\n        closeBtn.addEventListener('touchend', (e) => {\r\n            e.stopPropagation();\r\n            e.preventDefault();\r\n            closePopup(container);\r\n        });\r\n    }\r\n    \r\n    function closePopup(container) {\r\n        const url = container.dataset.url;\r\n        \r\n        \/\/ V\u00e9rifier si c'est un espace utilisateur \u2192 d\u00e9connexion\r\n        if (requiresSession(url)) {\r\n            performLogout();\r\n        }\r\n        \r\n        container.classList.add('closing');\r\n        container.classList.remove('visible');\r\n        \r\n        setTimeout(() => {\r\n            state.popups.delete(url);\r\n            container.remove();\r\n        }, 200);\r\n    }\r\n    \r\n    \/**\r\n     * D\u00e9connexion automatique\r\n     *\/\r\n    function performLogout() {\r\n        console.log('\ud83d\udd12 D\u00e9connexion automatique...');\r\n        \r\n        \/\/ Vider sessionStorage\r\n        sessionStorage.clear();\r\n        \r\n        \/\/ Appel AJAX pour d\u00e9connecter c\u00f4t\u00e9 serveur\r\n        fetch('\/wp-admin\/admin-ajax.php', {\r\n            method: 'POST',\r\n            headers: {\r\n                'Content-Type': 'application\/x-www-form-urlencoded',\r\n            },\r\n            body: 'action=custom_logout'\r\n        })\r\n        .then(response => {\r\n            console.log('\u2705 D\u00e9connexion effectu\u00e9e');\r\n        })\r\n        .catch(error => {\r\n            console.error('Erreur d\u00e9connexion:', error);\r\n        });\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ FOCUS (Z-INDEX)\r\n    \/\/ =========================================================================\r\n    \r\n    function setupFocus(container) {\r\n        \/\/ Clic sur le container (header, bordures)\r\n        container.addEventListener('mousedown', () => {\r\n            bringToFront(container);\r\n        });\r\n        \r\n        \/\/ D\u00e9tection du clic dans l'iframe via focus\r\n        const iframe = container.querySelector(`.${VIA_POPUP_CONFIG.cssPrefix}-iframe`);\r\n        \r\n        \/\/ Quand l'iframe re\u00e7oit le focus (clic dedans)\r\n        iframe.addEventListener('mouseenter', () => {\r\n            \/\/ Marquer ce container comme \"survol\u00e9\"\r\n            state.hoveredPopup = container;\r\n        });\r\n        \r\n        iframe.addEventListener('mouseleave', () => {\r\n            if (state.hoveredPopup === container) {\r\n                state.hoveredPopup = null;\r\n            }\r\n        });\r\n    }\r\n    \r\n    \/\/ D\u00e9tection globale : quand la fen\u00eatre principale perd le focus,\r\n    \/\/ c'est qu'on a cliqu\u00e9 dans une iframe\r\n    function setupGlobalFocusDetection() {\r\n        window.addEventListener('blur', () => {\r\n            \/\/ Si on a un popup survol\u00e9, c'est celui qui a re\u00e7u le clic\r\n            if (state.hoveredPopup) {\r\n                bringToFront(state.hoveredPopup);\r\n            }\r\n        });\r\n    }\r\n    \r\n    function bringToFront(container) {\r\n        \/\/ =====================================================================\r\n        \/\/ pb1228 : ECHELLE PARTAGEE avec les VLP et les popups de colonne.\r\n        \/\/   Constat user : ces popups restent derriere le popup Tarifs, les VLP et\r\n        \/\/   ColonneGauche\/Droite. Ils comptaient sur leur PROPRE echelle, partant de\r\n        \/\/   baseZIndex 10000 et progressant de 1 en 1 \u2014 pendant que les autres\r\n        \/\/   montent a 2000006 via une echelle qu'ils ignorent.\r\n        \/\/   yearbook-media.js expose window._viaMaxZPopups663(), qui donne le rang le\r\n        \/\/   plus haut TOUS popups confondus. C'est deja ce que fait le popup Tarifs\r\n        \/\/   depuis pb665 (\"echelle partagee\"), pour exactement la meme raison.\r\n        \/\/   On s'y raccorde : currentZIndex ne repart plus de sa valeur locale mais du\r\n        \/\/   maximum reel, et le +2 nous place devant.\r\n        \/\/   Ecriture en !important : les VLP ecrivent ainsi, un z-index simple se\r\n        \/\/   ferait battre.\r\n        \/\/   Repli sur le comportement d'origine si la fonction n'est pas disponible \u2014\r\n        \/\/   ce fichier peut etre charge sans yearbook-media.js.\r\n        \/\/   Revert : window._viaPb1228Off = true.\r\n        \/\/ =====================================================================\r\n        if (window._viaPb1228Off !== true) {\r\n            if (typeof window._viaMaxZPopups663 === 'function') {\r\n                try {\r\n                    var _max1228 = window._viaMaxZPopups663();\r\n                    if (_max1228 + 2 > state.currentZIndex) { state.currentZIndex = _max1228 + 2; }\r\n                    container.style.setProperty('z-index', String(state.currentZIndex), 'important');\r\n                    return;\r\n                } catch (_e1228) {}\r\n            }\r\n        }\r\n        state.currentZIndex++;\r\n        container.style.zIndex = state.currentZIndex;\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ INTERCEPTION DES LIENS\r\n    \/\/ =========================================================================\r\n    \r\n    function interceptLinks() {\r\n        document.addEventListener('click', (e) => {\r\n            const link = e.target.closest('a[href]');\r\n            if (!link) return;\r\n            \r\n            const href = link.getAttribute('href');\r\n            if (!href) return;\r\n            \r\n            \/\/ Ne PAS intercepter les liens Elementor action (menu, popups, etc.)\r\n            if (href.includes('elementor-action')) {\r\n                return;\r\n            }\r\n            \r\n            \/\/ Ne PAS intercepter les liens avec # seulement ou # au d\u00e9but (ancres, toggles)\r\n            if (href === '#' || href.startsWith('#')) {\r\n                return;\r\n            }\r\n            \r\n            let fullUrl;\r\n            try {\r\n                fullUrl = new URL(href, window.location.origin).href;\r\n            } catch (err) {\r\n                return;\r\n            }\r\n            \r\n            if (shouldIntercept(fullUrl)) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                createPopup(applyPathOverride(fullUrl), _viaTitreLien2372(link)); \/\/ pb2372\r\n            }\r\n        }, true);\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ GESTION POPUPS ELEMENTOR (Connexion + Menu)\r\n    \/\/ =========================================================================\r\n    \r\n    const ELEMENTOR_POPUP_IDS = {\r\n        LOGIN: 'elementor-popup-modal-14297'\r\n        \/\/ MENU est d\u00e9tect\u00e9 dynamiquement\r\n    };\r\n    \r\n    \/**\r\n     * Trouve l'ID du popup menu Elementor dynamiquement\r\n     * Fonctionne sur via-agency.media (21589) et les sites pays (diff\u00e9rents IDs)\r\n     *\/\r\n    function findMenuPopupId() {\r\n        \/\/ Chercher tous les popups Elementor\r\n        const popups = document.querySelectorAll('[id^=\"elementor-popup-modal-\"]');\r\n        for (const popup of popups) {\r\n            \/\/ Exclure le popup de connexion\r\n            if (popup.id === ELEMENTOR_POPUP_IDS.LOGIN) continue;\r\n            \/\/ Le popup menu contient g\u00e9n\u00e9ralement des liens de navigation\r\n            if (popup.querySelector('.elementor-nav-menu, .menu-item, a[href]')) {\r\n                return popup.id;\r\n            }\r\n        }\r\n        \/\/ Fallback : retourner le premier popup qui n'est pas celui de connexion\r\n        for (const popup of popups) {\r\n            if (popup.id !== ELEMENTOR_POPUP_IDS.LOGIN) {\r\n                return popup.id;\r\n            }\r\n        }\r\n        \/\/ Fallback ultime pour via-agency.media\r\n        return 'elementor-popup-modal-21589';\r\n    }\r\n    \r\n    let elementorPopupHandled = false; \/\/ Flag pour \u00e9viter les boucles\r\n        \r\n    \/**\r\n     * Met un popup Elementor au-dessus de tous les ViaPopup\r\n     *\/\r\n    function bringElementorPopupToFront(popupId) {\r\n        if (elementorPopupHandled) return; \/\/ \u00c9viter la boucle\r\n        \r\n        const popup = document.getElementById(popupId);\r\n        if (popup) {\r\n            elementorPopupHandled = true;\r\n            \r\n            state.currentZIndex++;\r\n            const newZIndex = state.currentZIndex + 1000;\r\n            popup.style.zIndex = newZIndex.toString();\r\n            \r\n            \/\/ S'assurer que l'overlay est aussi au bon z-index\r\n            const overlay = popup.querySelector('.dialog-lightbox-overlay');\r\n            if (overlay) {\r\n                overlay.style.zIndex = (newZIndex - 1).toString();\r\n            }\r\n            \r\n            \/\/ \u2705 Correction : Emp\u00eacher Elementor de masquer l'ascenseur vertical\r\n            \/\/ Avec plusieurs d\u00e9lais car Elementor peut appliquer le style \u00e0 diff\u00e9rents moments\r\n            function fixOverflow() {\r\n                document.body.style.overflow = '';\r\n                document.documentElement.style.overflow = '';\r\n            }\r\n            fixOverflow();\r\n            setTimeout(fixOverflow, 50);\r\n            setTimeout(fixOverflow, 100);\r\n            setTimeout(fixOverflow, 200);\r\n            setTimeout(fixOverflow, 300);\r\n            setTimeout(fixOverflow, 500);\r\n            \r\n            console.log('\ud83d\udd1d Popup Elementor pass\u00e9 au premier plan, z-index:', newZIndex);\r\n            \r\n            \/\/ Reset le flag apr\u00e8s un court d\u00e9lai\r\n            setTimeout(() => {\r\n                elementorPopupHandled = false;\r\n            }, 500);\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * Met le popup de connexion au premier plan\r\n     *\/\r\n    function bringLoginPopupToFront() {\r\n        bringElementorPopupToFront(ELEMENTOR_POPUP_IDS.LOGIN);\r\n    }\r\n    \r\n    \/**\r\n     * Met le menu au premier plan\r\n     *\/\r\n    function bringMenuPopupToFront() {\r\n        const menuPopupId = findMenuPopupId();\r\n        bringElementorPopupToFront(menuPopupId);\r\n    }\r\n    \r\n    \/**\r\n     * Ouvre le popup de connexion Elementor (uniquement sur via-agency.media)\r\n     * Sur yearbook-media.com, utiliser ViaLoginOverlay \u00e0 la place\r\n     *\/\r\n    function showLoginPopup() {\r\n        \/\/ Seulement sur via-agency.media\r\n        if (!window.location.hostname.includes('via-agency.media')) {\r\n            console.log('showLoginPopup ignor\u00e9 - utiliser ViaLoginOverlay sur ce site');\r\n            return;\r\n        }\r\n        \r\n        \/\/ Masquer le menu s'il est ouvert\r\n        const menuPopupId = findMenuPopupId();\r\n        const menuPopup = document.getElementById(menuPopupId);\r\n        if (menuPopup) {\r\n            menuPopup.style.display = 'none';\r\n        }\r\n        \r\n        \/\/ Ouvrir le popup Elementor\r\n        if (typeof elementorProFrontend !== 'undefined' && elementorProFrontend.modules && elementorProFrontend.modules.popup) {\r\n            elementorProFrontend.modules.popup.showPopup({ id: 14297 });\r\n        }\r\n        \r\n        elementorPopupHandled = false;\r\n        setTimeout(bringLoginPopupToFront, 150);\r\n    }\r\n    \r\n    \/**\r\n     * Passe le popup de connexion en dessous puis le masque\r\n     *\/\r\n    function hideLoginPopup() {\r\n        elementorPopupHandled = true; \/\/ Emp\u00eacher bringToFront pendant la fermeture\r\n        \r\n        const loginPopup = document.getElementById(ELEMENTOR_POPUP_IDS.LOGIN);\r\n        if (loginPopup) {\r\n            \/\/ Passer en dessous\r\n            loginPopup.style.zIndex = '1';\r\n            console.log('\ud83d\udd3d Popup connexion pass\u00e9 en dessous');\r\n            \r\n            \/\/ Masquer apr\u00e8s un court d\u00e9lai\r\n            setTimeout(() => {\r\n                loginPopup.style.display = 'none';\r\n                document.body.classList.remove('elementor-popup-is-opened');\r\n                console.log('\ud83d\ude48 Popup connexion masqu\u00e9');\r\n                \r\n                \/\/ Reset le flag\r\n                setTimeout(() => {\r\n                    elementorPopupHandled = false;\r\n                }, 100);\r\n            }, 300);\r\n        }\r\n    }\r\n    \r\n    \/**\r\n     * V\u00e9rifie si l'URL contient #login pour ouvrir automatiquement le popup\r\n     *\/\r\n    function checkHashLogin() {\r\n        if (window.location.hash === '#login') {\r\n            setTimeout(showLoginPopup, 1000);\r\n        }\r\n    }\r\n    \r\n    \/**\r\n     * Intercepter les ouvertures des popups Elementor\r\n     *\/\r\n    function setupElementorPopupInterception() {\r\n        \/\/ Intercepter les clics sur les d\u00e9clencheurs du popup de connexion\r\n        document.addEventListener('click', (e) => {\r\n            \/\/ D\u00e9clencheurs du popup de connexion (.popup-login-trigger)\r\n            const loginTrigger = e.target.closest('.popup-login-trigger');\r\n            if (loginTrigger) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                showLoginPopup();\r\n                return;\r\n            }\r\n            \r\n            \/\/ D\u00e9clencheurs du menu sandwich - tout lien avec elementor-action popup\r\n            const menuLink = e.target.closest('a[href*=\"elementor-action\"]');\r\n            if (menuLink && menuLink.href.includes('popup')) {\r\n                elementorPopupHandled = false;\r\n                setTimeout(bringMenuPopupToFront, 150);\r\n                return;\r\n            }\r\n        }, true);\r\n        \r\n        \/\/ Observer le menu popup directement pour d\u00e9tecter son ouverture\r\n        let menuWasHidden = true;\r\n        const observeMenuPopup = () => {\r\n            const menuPopupId = findMenuPopupId();\r\n            const menuPopup = document.getElementById(menuPopupId);\r\n            if (menuPopup) {\r\n                const observer = new MutationObserver(() => {\r\n                    const display = window.getComputedStyle(menuPopup).display;\r\n                    const isVisible = display !== 'none';\r\n                    \r\n                    \/\/ Seulement si le popup vient de devenir visible (transition hidden -> visible)\r\n                    if (isVisible && menuWasHidden) {\r\n                        menuWasHidden = false;\r\n                        elementorPopupHandled = false;\r\n                        setTimeout(bringMenuPopupToFront, 50);\r\n                    } else if (!isVisible) {\r\n                        menuWasHidden = true;\r\n                    }\r\n                });\r\n                observer.observe(menuPopup, { attributes: true, attributeFilter: ['style', 'class'] });\r\n                console.log('\ud83d\udc40 Observer menu popup install\u00e9:', menuPopupId);\r\n            } else {\r\n                setTimeout(observeMenuPopup, 1000);\r\n            }\r\n        };\r\n        observeMenuPopup();\r\n        \r\n        \/\/ Observer aussi le popup de connexion\r\n        let loginWasHidden = true;\r\n        const observeLoginPopup = () => {\r\n            const loginPopup = document.getElementById(ELEMENTOR_POPUP_IDS.LOGIN);\r\n            if (loginPopup) {\r\n                const observer = new MutationObserver(() => {\r\n                    const display = window.getComputedStyle(loginPopup).display;\r\n                    const isVisible = display !== 'none';\r\n                    \r\n                    if (isVisible && loginWasHidden) {\r\n                        loginWasHidden = false;\r\n                        elementorPopupHandled = false;\r\n                        setTimeout(bringLoginPopupToFront, 50);\r\n                    } else if (!isVisible) {\r\n                        loginWasHidden = true;\r\n                    }\r\n                });\r\n                observer.observe(loginPopup, { attributes: true, attributeFilter: ['style', 'class'] });\r\n                console.log('\ud83d\udc40 Observer login popup install\u00e9');\r\n            } else {\r\n                setTimeout(observeLoginPopup, 1000);\r\n            }\r\n        };\r\n        observeLoginPopup();\r\n        \r\n        \/\/ V\u00e9rifier si #login dans l'URL\r\n        checkHashLogin();\r\n        \r\n        console.log('\u2705 Interception popups Elementor install\u00e9e');\r\n    }\r\n    \r\n    \/\/ Lancer l'interception\r\n    setupElementorPopupInterception();\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ API PUBLIQUE\r\n    \/\/ =========================================================================\r\n    \r\n    window.ViaPopup = {\r\n        open: function(url) {\r\n            createPopup(url);\r\n        },\r\n        closeAll: function() {\r\n            state.popups.forEach((container) => closePopup(container));\r\n        },\r\n        close: function(url) {\r\n            const container = state.popups.get(normalizeUrl(url));\r\n            if (container) closePopup(container);\r\n        },\r\n        addPath: function(path) {\r\n            VIA_POPUP_CONFIG.targetPaths.push(normalizePath(path));\r\n        },\r\n        \/**\r\n         * Ouvre un popup apr\u00e8s connexion (utilis\u00e9 par le module de login)\r\n         * @param {string} url - URL de l'espace utilisateur\r\n         *\/\r\n        openAfterLogin: function(url) {\r\n            \/\/ Fermer le popup de connexion si ouvert\r\n            \/\/ puis ouvrir le nouvel espace\r\n            createPopup(url);\r\n        },\r\n        \/**\r\n         * V\u00e9rifie si une URL est configur\u00e9e pour les popups\r\n         * @param {string} url - URL \u00e0 v\u00e9rifier\r\n         * @returns {boolean}\r\n         *\/\r\n        isPopupUrl: function(url) {\r\n            return shouldIntercept(url);\r\n        },\r\n        \/**\r\n         * D\u00e9connexion manuelle\r\n         *\/\r\n        logout: function() {\r\n            performLogout();\r\n        },\r\n        \/**\r\n         * Masque le popup de connexion (passe en dessous puis dispara\u00eet)\r\n         *\/\r\n        hideLoginPopup: hideLoginPopup,\r\n        \/**\r\n         * Met le popup de connexion au premier plan\r\n         *\/\r\n        bringLoginPopupToFront: bringLoginPopupToFront,\r\n        \/**\r\n         * Met le menu sandwich au premier plan\r\n         *\/\r\n        bringMenuPopupToFront: bringMenuPopupToFront,\r\n        \/**\r\n         * Ouvre le popup de connexion\r\n         *\/\r\n        showLoginPopup: showLoginPopup\r\n    };\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ INIT\r\n    \/\/ =========================================================================\r\n    \r\n    function init() {\r\n        interceptLinks();\r\n        setupGlobalFocusDetection();\r\n        console.log('\u2705 ViaPopup System initialis\u00e9');\r\n    }\r\n    \r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', init);\r\n    } else {\r\n        init();\r\n    }\r\n\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-765cbf97 elementor-widget elementor-widget-html\" data-id=\"765cbf97\" data-element_type=\"widget\" data-e-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\/**\r\n * VIA Agency - Login Overlay System\r\n * Container fixe transparent avec iframe pour la page de connexion\r\n * Fonctionne sur yearbook-media.com et tous ses sous-domaines\r\n *\/\r\n\r\n(function() {\r\n    'use strict';\r\n\r\n    \/\/ Anti-doublon\r\n    if (window.ViaLoginOverlayInitialized) return;\r\n    window.ViaLoginOverlayInitialized = true;\r\n\r\n    const VIA_LOGIN_CONFIG = {\r\n        loginUrl: 'https:\/\/via-agency.media\/connexion\/',\r\n        overlayId: 'via-login-overlay',\r\n        iframeId: 'via-login-iframe',\r\n        \/\/ Domaines autoris\u00e9s pour les messages postMessage\r\n        allowedDomains: [\r\n            'via-agency.media',\r\n            'yearbook-media.com'\r\n        ]\r\n    };\r\n\r\n    let overlayElement = null;\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ UTILITAIRES\r\n    \/\/ =========================================================================\r\n    \r\n    \/**\r\n     * V\u00e9rifie si une origine est autoris\u00e9e (domaine principal ou sous-domaine)\r\n     *\/\r\n    function isAllowedOrigin(origin) {\r\n        try {\r\n            const url = new URL(origin);\r\n            const hostname = url.hostname;\r\n            return VIA_LOGIN_CONFIG.allowedDomains.some(domain => \r\n                hostname === domain || hostname.endsWith('.' + domain)\r\n            );\r\n        } catch (e) {\r\n            return false;\r\n        }\r\n    }\r\n    \r\n    \/**\r\n     * Trouve l'ID du popup menu Elementor dynamiquement\r\n     *\/\r\n    function findMenuPopupId() {\r\n        \/\/ Chercher le popup menu par ses caract\u00e9ristiques\r\n        const popups = document.querySelectorAll('[id^=\"elementor-popup-modal-\"]');\r\n        for (const popup of popups) {\r\n            \/\/ Exclure le popup de connexion (14297)\r\n            if (popup.id === 'elementor-popup-modal-14297') continue;\r\n            \/\/ Le popup menu contient g\u00e9n\u00e9ralement un menu ou des liens de navigation\r\n            if (popup.querySelector('.elementor-nav-menu, .menu-item, .BoutonMenu') || \r\n                popup.classList.contains('menu-popup')) {\r\n                return popup.id;\r\n            }\r\n        }\r\n        \/\/ Fallback : retourner le premier popup qui n'est pas celui de connexion\r\n        for (const popup of popups) {\r\n            if (popup.id !== 'elementor-popup-modal-14297') {\r\n                return popup.id;\r\n            }\r\n        }\r\n        return null;\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ STYLES\r\n    \/\/ =========================================================================\r\n    \r\n    function injectStyles() {\r\n        if (document.getElementById('via-login-overlay-styles')) return;\r\n        \r\n        const styles = `\r\n            \/* Overlay fond semi-transparent *\/\r\n            #${VIA_LOGIN_CONFIG.overlayId} {\r\n                position: fixed;\r\n                top: 0;\r\n                left: 0;\r\n                width: 100%;\r\n                height: 100%;\r\n                background: rgba(0, 0, 0, 0.5);\r\n                z-index: 99999;\r\n                display: flex;\r\n                justify-content: center;\r\n                align-items: center;\r\n                opacity: 0;\r\n                visibility: hidden;\r\n                transition: opacity 0.3s ease, visibility 0.3s ease;\r\n            }\r\n            \r\n            #${VIA_LOGIN_CONFIG.overlayId}.visible {\r\n                opacity: 1;\r\n                visibility: visible;\r\n            }\r\n            \r\n            \/* Container - DIMENSIONS G\u00c9N\u00c9REUSES *\/\r\n            #${VIA_LOGIN_CONFIG.overlayId} .login-container {\r\n                position: relative;\r\n                width: 1150px;\r\n                max-width: 95vw;\r\n                height: 500px;\r\n                max-height: 90vh;\r\n                background: transparent !important;\r\n                border: none !important;\r\n                box-shadow: none !important;\r\n                overflow: visible;\r\n                margin-top: -150px;\r\n            }\r\n            \r\n            \/* Iframe TRANSPARENTE *\/\r\n            #${VIA_LOGIN_CONFIG.iframeId} {\r\n                width: 100%;\r\n                height: 100%;\r\n                border: none !important;\r\n                background: transparent !important;\r\n            }\r\n            \r\n            \/* Loader *\/\r\n            #${VIA_LOGIN_CONFIG.overlayId} .login-loader {\r\n                position: absolute;\r\n                top: 50%;\r\n                left: 50%;\r\n                transform: translate(-50%, -50%);\r\n                display: flex;\r\n                flex-direction: column;\r\n                align-items: center;\r\n                gap: 12px;\r\n                z-index: 5;\r\n            }\r\n            \r\n            #${VIA_LOGIN_CONFIG.overlayId} .login-spinner {\r\n                width: 40px;\r\n                height: 40px;\r\n                border: 3px solid rgba(255,255,255,0.3);\r\n                border-top: 3px solid #fff;\r\n                border-radius: 50%;\r\n                animation: via-login-spin 0.8s linear infinite;\r\n            }\r\n            \r\n            @keyframes via-login-spin {\r\n                0% { transform: rotate(0deg); }\r\n                100% { transform: rotate(360deg); }\r\n            }\r\n            \r\n            #${VIA_LOGIN_CONFIG.overlayId} .login-loader-text {\r\n                color: #fff;\r\n                font-size: 14px;\r\n                text-shadow: 0 1px 3px rgba(0,0,0,0.3);\r\n            }\r\n            \r\n            \/* Mobile *\/\r\n            @media (max-width: 480px) {\r\n                #${VIA_LOGIN_CONFIG.overlayId} .login-container {\r\n                    width: 95vw;\r\n                    height: 85vh;\r\n                }\r\n            }\r\n        `;\r\n        \r\n        const styleEl = document.createElement('style');\r\n        styleEl.id = 'via-login-overlay-styles';\r\n        styleEl.textContent = styles;\r\n        document.head.appendChild(styleEl);\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ OVERLAY CREATION\r\n    \/\/ =========================================================================\r\n    \r\n    function createOverlay() {\r\n        if (overlayElement) return overlayElement;\r\n        \r\n        injectStyles();\r\n        \r\n        const overlay = document.createElement('div');\r\n        overlay.id = VIA_LOGIN_CONFIG.overlayId;\r\n        overlay.innerHTML = `\r\n            <div class=\"login-container\">\r\n                <div class=\"login-loader\">\r\n                    <div class=\"login-spinner\"><\/div>\r\n                    <span class=\"login-loader-text\">Chargement...<\/span>\r\n                <\/div>\r\n                <iframe id=\"${VIA_LOGIN_CONFIG.iframeId}\" src=\"about:blank\" allowtransparency=\"true\"><\/iframe>\r\n            <\/div>\r\n        `;\r\n        \r\n        document.body.appendChild(overlay);\r\n        overlayElement = overlay;\r\n        \r\n        \/\/ Events\r\n        setupOverlayEvents(overlay);\r\n        \r\n        return overlay;\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ EVENTS\r\n    \/\/ =========================================================================\r\n    \r\n    function setupOverlayEvents(overlay) {\r\n        \/\/ Fermer au clic sur le fond (overlay)\r\n        overlay.addEventListener('click', (e) => {\r\n            if (e.target === overlay) {\r\n                hideLoginOverlay();\r\n            }\r\n        });\r\n        \r\n        \/\/ Fermer avec Escape\r\n        document.addEventListener('keydown', (e) => {\r\n            if (e.key === 'Escape' && overlay.classList.contains('visible')) {\r\n                hideLoginOverlay();\r\n            }\r\n        });\r\n    }\r\n    \r\n    \/\/ =========================================================================\r\n    \/\/ MESSAGE LISTENER (s\u00e9par\u00e9 pour \u00eatre initialis\u00e9 une seule fois)\r\n    \/\/ =========================================================================\r\n    \r\n    function setupMessageListener() {\r\n        window.addEventListener('message', (event) => {\r\n            \/\/ Debug\r\n            \/\/console.log('\ud83d\udce8 Message re\u00e7u de:', event.origin, event.data);\r\n            \r\n            \/\/ V\u00e9rifier l'origine avec la nouvelle fonction\r\n            if (!isAllowedOrigin(event.origin)) {\r\n                console.log('\u274c Origine non autoris\u00e9e:', event.origin);\r\n                return;\r\n            }\r\n            \r\n            const data = event.data;\r\n            if (!data || !data.type) return;\r\n            \r\n            \/\/console.log('\u2705 Message valide:', data.type);\r\n            \r\n            \/\/ Fermeture du popup (croix cliqu\u00e9e dans l'iframe)\r\n            if (data.type === 'VIA_LOGIN_CLOSE') {\r\n                console.log('\ud83d\udd12 Fermeture demand\u00e9e par iframe');\r\n                hideLoginOverlay();\r\n                return;\r\n            }\r\n            \r\n            \/\/ Connexion r\u00e9ussie\r\n            if (data.type === 'VIA_LOGIN_SUCCESS') {\r\n                console.log('\u2705 Connexion r\u00e9ussie!');\r\n                console.log('  - Profil:', data.profilUser);\r\n                console.log('  - Espace:', data.espaceUrl);\r\n                console.log('  - SessionData keys:', data.sessionData ? Object.keys(data.sessionData) : 'none');\r\n                \r\n                \/\/ Fermer l'overlay de connexion\r\n                hideLoginOverlay();\r\n                \r\n                \/\/ Stocker les donn\u00e9es de session\r\n                if (data.sessionData) {\r\n                    Object.keys(data.sessionData).forEach(key => {\r\n                        sessionStorage.setItem(key, data.sessionData[key]);\r\n                    });\r\n                    console.log('\ud83d\udcbe SessionStorage mis \u00e0 jour:', Object.keys(data.sessionData).length, 'cl\u00e9s');\r\n                }\r\n                \r\n                \/\/ Ouvrir l'espace utilisateur\r\n                if (data.espaceUrl) {\r\n                    console.log('\ud83d\ude80 Ouverture espace dans 500ms:', data.espaceUrl);\r\n                    setTimeout(() => {\r\n                        if (typeof ViaPopup !== 'undefined' && ViaPopup.open) {\r\n                            console.log('\ud83c\udfaf ViaPopup.open()');\r\n                            ViaPopup.open(data.espaceUrl);\r\n                        } else {\r\n                            console.log('\ud83c\udfaf Redirection classique');\r\n                            window.location.href = data.espaceUrl;\r\n                        }\r\n                    }, 500);\r\n                }\r\n            }\r\n        });\r\n        \r\n        console.log('\ud83d\udc42 ViaLoginOverlay: Message listener install\u00e9');\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ SHOW \/ HIDE\r\n    \/\/ =========================================================================\r\n    \r\n    function showLoginOverlay() {\r\n        \/\/ Fermer le menu Elementor s'il est ouvert (d\u00e9tection dynamique)\r\n        const menuPopupId = findMenuPopupId();\r\n        if (menuPopupId) {\r\n            const menuPopup = document.getElementById(menuPopupId);\r\n            if (menuPopup) {\r\n                menuPopup.style.display = 'none';\r\n            }\r\n        }\r\n        \r\n        const overlay = createOverlay();\r\n        const iframe = overlay.querySelector(`#${VIA_LOGIN_CONFIG.iframeId}`);\r\n        const loader = overlay.querySelector('.login-loader');\r\n        \r\n        \/\/ Afficher le loader\r\n        loader.style.display = 'flex';\r\n        iframe.style.opacity = '0';\r\n        \r\n        \/\/ Charger la page de connexion\r\n        iframe.src = VIA_LOGIN_CONFIG.loginUrl;\r\n        \r\n        \/\/ Masquer le loader quand l'iframe est charg\u00e9e\r\n        iframe.onload = () => {\r\n            console.log('\ud83d\udcc4 Iframe charg\u00e9e');\r\n            loader.style.display = 'none';\r\n            iframe.style.opacity = '1';\r\n        };\r\n        \r\n        \/\/ Afficher l'overlay\r\n        requestAnimationFrame(() => {\r\n            overlay.classList.add('visible');\r\n        });\r\n        \r\n        \/\/ Bloquer le scroll du body\r\n        document.body.style.overflow = 'hidden';\r\n        \r\n        console.log('\ud83d\udd10 Overlay connexion ouvert');\r\n    }\r\n    \r\n    function hideLoginOverlay() {\r\n        if (!overlayElement) return;\r\n        \r\n        overlayElement.classList.remove('visible');\r\n        \r\n        \/\/ R\u00e9activer le scroll\r\n        document.body.style.overflow = '';\r\n        \r\n        \/\/ Reset l'iframe apr\u00e8s la fermeture\r\n        setTimeout(() => {\r\n            const iframe = overlayElement.querySelector(`#${VIA_LOGIN_CONFIG.iframeId}`);\r\n            if (iframe) {\r\n                iframe.src = 'about:blank';\r\n            }\r\n        }, 300);\r\n        \r\n        console.log('\ud83d\udd12 Overlay connexion ferm\u00e9');\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ INTERCEPTION DES CLICS .popup-login-trigger\r\n    \/\/ =========================================================================\r\n    \r\n    function interceptLoginTriggers() {\r\n        document.addEventListener('click', (e) => {\r\n            const trigger = e.target.closest('.popup-login-trigger');\r\n            if (trigger) {\r\n                e.preventDefault();\r\n                e.stopPropagation();\r\n                showLoginOverlay();\r\n            }\r\n        }, true);\r\n        \r\n        console.log('\u2705 Interception .popup-login-trigger install\u00e9e');\r\n    }\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ API PUBLIQUE\r\n    \/\/ =========================================================================\r\n    \r\n    window.ViaLoginOverlay = {\r\n        show: showLoginOverlay,\r\n        hide: hideLoginOverlay\r\n    };\r\n\r\n    \/\/ =========================================================================\r\n    \/\/ INIT\r\n    \/\/ =========================================================================\r\n    \r\n    function init() {\r\n        \/\/ Seulement sur yearbook-media.com et ses sous-domaines (pas sur via-agency.media)\r\n        if (window.location.hostname.includes('via-agency.media')) {\r\n            console.log('ViaLoginOverlay: ignor\u00e9 sur via-agency.media');\r\n            return;\r\n        }\r\n        \r\n        \/\/ Installer le message listener IMM\u00c9DIATEMENT\r\n        setupMessageListener();\r\n        \r\n        \/\/ Intercepter les clics\r\n        interceptLoginTriggers();\r\n        \r\n        console.log('\u2705 ViaLoginOverlay initialis\u00e9 sur', window.location.hostname);\r\n    }\r\n    \r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', init);\r\n    } else {\r\n        init();\r\n    }\r\n\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-8ba8dda e-con-full TobedisplayedLater  e-flex e-con e-child\" data-id=\"8ba8dda\" data-element_type=\"container\" data-e-type=\"container\" id=\"FormatRedactFooter\">\n\t\t<div class=\"elementor-element elementor-element-1bccba90 e-con-full elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"1bccba90\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-361394d9 e-con-full MobileFondBlanc e-flex e-con e-child\" data-id=\"361394d9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5c3b718a e-con-full MobileFondBlanc elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"5c3b718a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-691d4b04 e-con-full MobileFondBlanc e-flex e-con e-child\" data-id=\"691d4b04\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-66933056 e-con-full e-flex e-con e-child\" data-id=\"66933056\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1395b93 e-con-full  FormatsAnnonces e-flex e-con e-child\" data-id=\"1395b93\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-e8576e6 e-con-full popup-Creation e-flex e-con e-child\" data-id=\"e8576e6\" data-element_type=\"container\" data-e-type=\"container\" id=\"FooterCreation\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4647eb5 elementor-widget elementor-widget-text-editor\" data-id=\"4647eb5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCr\u00e9ation<br>\nd&rsquo;annonce\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3ca74d2 e-con-full  FormatsAnnonces e-flex e-con e-child\" data-id=\"3ca74d2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-0457910 e-con-full popup-Banniere  e-flex e-con e-child\" data-id=\"0457910\" data-element_type=\"container\" data-e-type=\"container\" id=\"FooterBanniere\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-08f76f8 elementor-widget elementor-widget-text-editor\" data-id=\"08f76f8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tBanni\u00e8re\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-22df9da8 e-con-full DeferedImageContainer FormatsAnnonces elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"22df9da8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-1cf72738 e-con-full e-flex e-con e-child\" data-id=\"1cf72738\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-2617ad96 e-con-full popup-Video e-flex e-con e-child\" data-id=\"2617ad96\" data-element_type=\"container\" data-e-type=\"container\" id=\"FooterVideo\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5a09e555 elementor-widget elementor-widget-html\" data-id=\"5a09e555\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"video-container\"><\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-21e99b8a elementor-widget elementor-widget-text-editor\" data-id=\"21e99b8a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tVid\u00e9o\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-343af9ef e-con-full  FormatsAnnonces e-flex e-con e-child\" data-id=\"343af9ef\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-2c2c984a e-con-full popup-PopUp e-flex e-con e-child\" data-id=\"2c2c984a\" data-element_type=\"container\" data-e-type=\"container\" id=\"FooterPopUp\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-562aa1ea elementor-widget elementor-widget-text-editor\" data-id=\"562aa1ea\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPop-up\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2107827a e-con-full  FormatsAnnonces e-flex e-con e-child\" data-id=\"2107827a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-22731690 e-con-full popup-Communique e-flex e-con e-child\" data-id=\"22731690\" data-element_type=\"container\" data-e-type=\"container\" id=\"FooterCommunique\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-32d8c301 elementor-widget elementor-widget-text-editor\" data-id=\"32d8c301\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tCommuniqu\u00e9\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7e14c86 e-con-full  FormatsAnnonces e-flex e-con e-child\" data-id=\"7e14c86\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-3e4b2c83 e-con-full popup-Interview e-flex e-con e-child\" data-id=\"3e4b2c83\" data-element_type=\"container\" data-e-type=\"container\" id=\"FooterInterview\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-480f8db6 elementor-widget elementor-widget-text-editor\" data-id=\"480f8db6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tInterview\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-bd2afd9 e-con-full  FormatsAnnonces e-flex e-con e-child\" data-id=\"bd2afd9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-28919aea e-con-full popup-Parrainage e-flex e-con e-child\" data-id=\"28919aea\" data-element_type=\"container\" data-e-type=\"container\" id=\"FooterParrainage\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-54be13db elementor-widget elementor-widget-text-editor\" data-id=\"54be13db\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tParrainage\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-41247a9 e-con-full MobileFondBlanc e-flex e-con e-child\" data-id=\"41247a9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-66f3e8c1 e-con-full MobileFondBlanc e-flex e-con e-child\" data-id=\"66f3e8c1\" data-element_type=\"container\" data-e-type=\"container\" id=\"RedactionnelTitresMobile\">\n\t\t<div class=\"elementor-element elementor-element-1098392d e-con-full e-flex e-con e-child\" data-id=\"1098392d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-6f24e09 e-con-full e-flex e-con e-child\" data-id=\"6f24e09\" data-element_type=\"container\" data-e-type=\"container\" id=\"TitrePopUpDoc1\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b176db1 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"4b176db1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Audience et accompagnement<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6dd04825 e-con-full e-flex e-con e-child\" data-id=\"6dd04825\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-1d2ad38d e-con-full e-flex e-con e-child\" data-id=\"1d2ad38d\" data-element_type=\"container\" data-e-type=\"container\" id=\"TitrePopUpDoc2\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-55357e36 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"55357e36\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Formats des annonces &amp; Kit Media<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-63eba67 e-con-full e-flex e-con e-child\" data-id=\"63eba67\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-796de1a2 e-con-full e-flex e-con e-child\" data-id=\"796de1a2\" data-element_type=\"container\" data-e-type=\"container\" id=\"TitrePopUpDoc3\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6fc1f1fe elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"6fc1f1fe\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Tarifs et achat express<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2c804c49 e-con-full e-flex e-con e-child\" data-id=\"2c804c49\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-2145da7b e-con-full e-flex e-con e-child\" data-id=\"2145da7b\" data-element_type=\"container\" data-e-type=\"container\" id=\"TitrePopUpDoc4\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-556830f2 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"556830f2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Conditions G\u00e9n\u00e9rales de Vente<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1732abb7 e-con-full e-flex e-con e-child\" data-id=\"1732abb7\" data-element_type=\"container\" data-e-type=\"container\" id=\"FooterPageAchat\">\n\t\t<div class=\"elementor-element elementor-element-b137a68 e-con-full e-flex e-con e-child\" data-id=\"b137a68\" data-element_type=\"container\" data-e-type=\"container\" id=\"FooterPageAchatBackground\">\n\t\t<div class=\"elementor-element elementor-element-7199354 e-con-full elementor-hidden-desktop e-flex e-con e-child\" data-id=\"7199354\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a64e889 elementor-widget-mobile__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"a64e889\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #4b689b;\"><a style=\"color: #4b689b;\" href=\"https:\/\/via-agency.media\/vous-accompagner\/\">Accompagnement\n&amp; Kit Media<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-24a47701 e-con-full elementor-hidden-desktop e-flex e-con e-child\" data-id=\"24a47701\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-60388482 notranslate UrlAchatEspaces elementor-widget__width-inherit elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"60388482\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #4b689b;\"><a style=\"color: #4b689b;\" href=\"#\"><span style=\"font-size: 8,5px;\">YEARBOOK <\/span> Media<br>R\u00e9gie de Via Agency<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-32b97bbf e-con-full elementor-hidden-desktop e-flex e-con e-child\" data-id=\"32b97bbf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4bb632b1 UrlMentionsLegales elementor-widget elementor-widget-text-editor\" data-id=\"4bb632b1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #4b689b;\"><a style=\"color: #4b689b;\" href=\"https:\/\/via-agency.media\/mentions-legales-disclaimers\/\">Mentions l\u00e9gales<br>&amp; CGV<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-0f15353 e-con-full elementor-hidden-mobile elementor-hidden-tablet e-flex e-con e-child\" data-id=\"0f15353\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3e8970e elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"3e8970e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #4b689b;\"><a style=\"color: #4b689b;\" href=\"https:\/\/via-agency.media\/vous-accompagner\/\">Accompagnement &amp; Kit Media<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<a class=\"elementor-element elementor-element-a1e51fe e-con-full elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"a1e51fe\" data-element_type=\"container\" data-e-type=\"container\" href=\"https:\/\/via-agency.media\/\">\n\t\t\t\t<div class=\"elementor-element elementor-element-af1670c elementor-widget-mobile__width-inherit notranslate elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"af1670c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tYEARBOOK Media r\u00e9gie de Via Agency Media et LDMD\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/a>\n\t\t<div class=\"elementor-element elementor-element-3a794081 e-con-full elementor-hidden-mobile elementor-hidden-tablet e-flex e-con e-child\" data-id=\"3a794081\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d6aadb5 UrlMentionsLegales elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"d6aadb5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<span style=\"color: #4b689b;\"><a style=\"color: #4b689b;\" href=\"https:\/\/via-agency.media\/mentions-legales-disclaimers\/\">Mentions l\u00e9gales &#038; CGV<\/a><\/span>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":316017,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-218790","page","type-page","status-publish","has-post-thumbnail"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Yearbook Media Advertising Agency<\/title>\n<meta name=\"description\" content=\"Communicate and distribute your announcements on YEARBOOK Media sites, a site for buying advertising space for your digital communication.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/yearbook-media.com\/en\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Yearbook Media R\u00e9gie Publicitaire\" \/>\n<meta property=\"og:description\" content=\"Communicate and distribute your announcements on YEARBOOK Media sites, a site for buying advertising space for your digital communication.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/yearbook-media.com\/en\/\" \/>\n<meta property=\"og:site_name\" content=\"YEARBOOK MEDIA\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-12T18:26:42+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/yearbook-media.com\/wp-content\/uploads\/2026\/05\/cropped-Favicon-Yearbook-Media-160526-V1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"512\" \/>\n\t<meta property=\"og:image:height\" content=\"512\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/\",\"url\":\"https:\\\/\\\/yearbook-media.com\\\/\",\"name\":\"Yearbook Media R\u00e9gie Publicitaire\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/yearbook-media.com\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/cropped-Favicon-Yearbook-Media-160526-V1.png\",\"datePublished\":\"2025-10-06T11:12:23+00:00\",\"dateModified\":\"2026-09-12T18:26:42+00:00\",\"description\":\"Communiquez et diffusez vos annonces sur les sites YEARBOOK Media, site d'achat d'espaces publicitaires pour votre communication digitale.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/yearbook-media.com\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#primaryimage\",\"url\":\"https:\\\/\\\/yearbook-media.com\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/cropped-Favicon-Yearbook-Media-160526-V1.png\",\"contentUrl\":\"https:\\\/\\\/yearbook-media.com\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/cropped-Favicon-Yearbook-Media-160526-V1.png\",\"width\":512,\"height\":512},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/yearbook-media.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Yearbook Media R\u00e9gie Publicitaire\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#website\",\"url\":\"https:\\\/\\\/yearbook-media.com\\\/\",\"name\":\"YEARBOOK MEDIA\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/yearbook-media.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#organization\",\"name\":\"YEARBOOK MEDIA\",\"url\":\"https:\\\/\\\/yearbook-media.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/yearbook-media.com\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/cropped-Favicon-Yearbook-Media-160526-V1.png\",\"contentUrl\":\"https:\\\/\\\/yearbook-media.com\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/cropped-Favicon-Yearbook-Media-160526-V1.png\",\"width\":512,\"height\":512,\"caption\":\"YEARBOOK MEDIA\"},\"image\":{\"@id\":\"https:\\\/\\\/yearbook-media.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Yearbook Media Advertising Agency","description":"Communicate and distribute your announcements on YEARBOOK Media sites, a site for buying advertising space for your digital communication.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/yearbook-media.com\/en\/","og_locale":"en_US","og_type":"article","og_title":"Yearbook Media R\u00e9gie Publicitaire","og_description":"Communicate and distribute your announcements on YEARBOOK Media sites, a site for buying advertising space for your digital communication.","og_url":"https:\/\/yearbook-media.com\/en\/","og_site_name":"YEARBOOK MEDIA","article_modified_time":"2026-09-12T18:26:42+00:00","og_image":[{"width":512,"height":512,"url":"https:\/\/yearbook-media.com\/wp-content\/uploads\/2026\/05\/cropped-Favicon-Yearbook-Media-160526-V1.png","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/yearbook-media.com\/","url":"https:\/\/yearbook-media.com\/","name":"Yearbook Media Advertising Agency","isPartOf":{"@id":"https:\/\/yearbook-media.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/yearbook-media.com\/#primaryimage"},"image":{"@id":"https:\/\/yearbook-media.com\/#primaryimage"},"thumbnailUrl":"https:\/\/yearbook-media.com\/wp-content\/uploads\/2026\/05\/cropped-Favicon-Yearbook-Media-160526-V1.png","datePublished":"2025-10-06T11:12:23+00:00","dateModified":"2026-09-12T18:26:42+00:00","description":"Communicate and distribute your announcements on YEARBOOK Media sites, a site for buying advertising space for your digital communication.","breadcrumb":{"@id":"https:\/\/yearbook-media.com\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/yearbook-media.com\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/yearbook-media.com\/#primaryimage","url":"https:\/\/yearbook-media.com\/wp-content\/uploads\/2026\/05\/cropped-Favicon-Yearbook-Media-160526-V1.png","contentUrl":"https:\/\/yearbook-media.com\/wp-content\/uploads\/2026\/05\/cropped-Favicon-Yearbook-Media-160526-V1.png","width":512,"height":512},{"@type":"BreadcrumbList","@id":"https:\/\/yearbook-media.com\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/yearbook-media.com\/"},{"@type":"ListItem","position":2,"name":"Yearbook Media R\u00e9gie Publicitaire"}]},{"@type":"WebSite","@id":"https:\/\/yearbook-media.com\/#website","url":"https:\/\/yearbook-media.com\/","name":"YEARBOOK MEDIA","description":"","publisher":{"@id":"https:\/\/yearbook-media.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/yearbook-media.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/yearbook-media.com\/#organization","name":"YEARBOOK MEDIA","url":"https:\/\/yearbook-media.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/yearbook-media.com\/#\/schema\/logo\/image\/","url":"https:\/\/yearbook-media.com\/wp-content\/uploads\/2026\/05\/cropped-Favicon-Yearbook-Media-160526-V1.png","contentUrl":"https:\/\/yearbook-media.com\/wp-content\/uploads\/2026\/05\/cropped-Favicon-Yearbook-Media-160526-V1.png","width":512,"height":512,"caption":"YEARBOOK MEDIA"},"image":{"@id":"https:\/\/yearbook-media.com\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/yearbook-media.com\/en\/wp-json\/wp\/v2\/pages\/218790","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yearbook-media.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/yearbook-media.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/yearbook-media.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yearbook-media.com\/en\/wp-json\/wp\/v2\/comments?post=218790"}],"version-history":[{"count":140,"href":"https:\/\/yearbook-media.com\/en\/wp-json\/wp\/v2\/pages\/218790\/revisions"}],"predecessor-version":[{"id":340054,"href":"https:\/\/yearbook-media.com\/en\/wp-json\/wp\/v2\/pages\/218790\/revisions\/340054"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/yearbook-media.com\/en\/wp-json\/wp\/v2\/media\/316017"}],"wp:attachment":[{"href":"https:\/\/yearbook-media.com\/en\/wp-json\/wp\/v2\/media?parent=218790"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}