{
    "id": 38623,
    "date": "2025-06-02T10:14:18",
    "date_gmt": "2025-06-02T08:14:18",
    "guid": {
        "rendered": "https:\/\/yearbooktest1.com\/?p=38623"
    },
    "modified": "2025-06-04T13:08:35",
    "modified_gmt": "2025-06-04T11:08:35",
    "slug": "togo-btp-de-grands-chantiers",
    "status": "publish",
    "type": "post",
    "link": "https:\/\/togo-en.yearbook-media.com\/fr\/togo-btp-de-grands-chantiers\/",
    "title": {
        "rendered": "Togo &#8211; BTP <br>&#8211; De grands chantiers"
    },
    "content": {
        "rendered": "<div data-elementor-type=\"wp-post\" data-elementor-id=\"38623\" class=\"elementor elementor-38623\" data-elementor-post-type=\"post\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7a5322e ToBeHidden e-flex e-con-boxed e-con e-child\" data-id=\"7a5322e\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-1e902ed e-con-full droppable e-flex e-con e-child\" data-id=\"1e902ed\" data-element_type=\"container\" id=\"Ele1A\">\n\t\t\t\t<div class=\"elementor-element elementor-element-bb2709b elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"bb2709b\" data-element_type=\"widget\" data-widget_type=\"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=\"page\" data-elementor-id=\"83347\" class=\"elementor elementor-83347\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6442de91 e-con-full OrdiMobileConteneurClass e-flex e-con e-child\" data-id=\"6442de91\" data-element_type=\"container\" id=\"testIdTest\">\n\t\t\t\t<div class=\"elementor-element elementor-element-57de103 elementor-widget elementor-widget-text-editor\" data-id=\"57de103\" data-element_type=\"widget\" data-widget_type=\"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-249870 .elementor-element.elementor-element-6da64a60{--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;--justify-content:space-around;--align-items:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:50px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-6da64a60.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-45f807e0{--display:flex;--min-height:0px;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-100px;--margin-bottom:62px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:3;}.elementor-249870 .elementor-element.elementor-element-45f807e0.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-61dcced4{--display:flex;--margin-top:0px;--margin-bottom:-11px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-6c65b106{--display:flex;--margin-top:0px;--margin-bottom:-30px;--margin-left:-25px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-eb74aa8{--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-249870 .elementor-element.elementor-element-eb74aa8:not(.elementor-motion-effects-element-type-background), .elementor-249870 .elementor-element.elementor-element-eb74aa8 > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-1c762c45{--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;--flex-wrap:nowrap;--margin-top:-3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-5be6a53a{--display:flex;--align-items:flex-start;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249870 .elementor-element.elementor-element-5be6a53a.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-75917e71{--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-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-249870 .elementor-element.elementor-element-6be76773 > .elementor-widget-container{margin:38px 5px -38px -40px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-6be76773.elementor-element{--align-self:flex-start;}.elementor-249870 .elementor-element.elementor-element-6be76773{text-align:right;}.elementor-249870 .elementor-element.elementor-element-6be76773 img{width:17px;}.elementor-249870 .elementor-element.elementor-element-5ad25a69{--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-249870 .elementor-element.elementor-element-5ad25a69.e-con{--align-self:flex-end;}.elementor-249870 .elementor-element.elementor-element-52dec736 > .elementor-widget-container{margin:45px -18px -55px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-52dec736{z-index:101;text-align:right;}.elementor-249870 .elementor-element.elementor-element-469b1a7c{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-25px;--margin-bottom:90px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-469b1a7c:not(.elementor-motion-effects-element-type-background), .elementor-249870 .elementor-element.elementor-element-469b1a7c > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#9FC5F3;}.elementor-249870 .elementor-element.elementor-element-3f5f9124{--display:flex;--min-height:30px;--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;--justify-content:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:1px;--margin-bottom:-6px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:99;}.elementor-249870 .elementor-element.elementor-element-3f5f9124.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-48a37689{--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;--justify-content:flex-start;--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--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-249870 .elementor-element.elementor-element-4b68287 > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249870 .elementor-element.elementor-element-4b68287.elementor-element{--align-self:flex-start;}.elementor-249870 .elementor-element.elementor-element-4b68287{text-align:start;font-family:\"Roboto\", Sans-serif;font-size:12px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-79a46db6{--display:flex;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249870 .elementor-element.elementor-element-47d25f98 > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-47d25f98{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:18px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-3aa42503{--display:flex;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:flex-end;--align-items:flex-end;--margin-top:4px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-12d5dc39 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-12d5dc39.elementor-element{--align-self:flex-start;}.elementor-249870 .elementor-element.elementor-element-12d5dc39{text-align:end;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-21535e15{--display:flex;--justify-content:flex-start;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--flex-wrap:wrap;--margin-top:-2px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-21535e15.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-de420c1{--display:flex;--min-height:30px;--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-249870 .elementor-element.elementor-element-2f60f3f > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-2f60f3f.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-2f60f3f{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:500;line-height:1.1em;color:#FB5E2A;}.elementor-249870 .elementor-element.elementor-element-6b485447 > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-6b485447.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-6b485447{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-78e1d9f5{--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;--justify-content:center;--gap:010px 9px;--row-gap:010px;--column-gap:9px;--flex-wrap:wrap;--margin-top:-14px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:100;}.elementor-249870 .elementor-element.elementor-element-78e1d9f5.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-cf3602e{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-7a1bb33 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-7a1bb33.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-7a1bb33{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-6bf72a5{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-1a57dd9 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-1a57dd9.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-1a57dd9{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-34d8bbba{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-32bd35c6 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-32bd35c6.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-32bd35c6{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-5a9252c3{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-8722042 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-8722042.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-8722042{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-19ecc2b3{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-6071d405 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-6071d405.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-6071d405{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-3617569c{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-4b013e71 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-4b013e71.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-4b013e71{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-7450a6f8{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-30970f89 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-30970f89.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-30970f89{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-6aac67a6{--display:flex;--margin-top:-46px;--margin-bottom:-20px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:2;}.elementor-249870 .elementor-element.elementor-element-40d299c{width:100%;max-width:100%;}.elementor-249870 .elementor-element.elementor-element-40d299c.elementor-element{--align-self:flex-end;}.elementor-249870 .elementor-element.elementor-element-1fd15d20{width:100%;max-width:100%;}.elementor-249870 .elementor-element.elementor-element-1fd15d20.elementor-element{--align-self:flex-end;}.elementor-249870 .elementor-element.elementor-element-54e4e530{--display:flex;--justify-content:center;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249870 .elementor-element.elementor-element-531f3cb1{width:100%;max-width:100%;font-family:\"Roboto\", Sans-serif;font-size:10px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249870 .elementor-element.elementor-element-531f3cb1 > .elementor-widget-container{margin:-37px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-531f3cb1.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-3a352c3f > .elementor-widget-container{margin:7px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-3a352c3f.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-3a352c3f{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249870 .elementor-element.elementor-element-7abb0aba > .elementor-widget-container{margin:7px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-7abb0aba.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-7abb0aba{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249870 .elementor-element.elementor-element-68e2b2ca > .elementor-widget-container{margin:-110px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-68e2b2ca.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-68e2b2ca{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:18px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249870 .elementor-element.elementor-element-8d50d33{--display:flex;--margin-top:-85px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-8d50d33.e-con{--align-self:center;}.elementor-widget-form .elementor-field-group > label, .elementor-widget-form .elementor-field-subgroup label{color:var( --e-global-color-text );}.elementor-widget-form .elementor-field-group > label{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .elementor-field-type-html{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-widget-form .elementor-field-group .elementor-field{color:var( --e-global-color-text );}.elementor-widget-form .elementor-field-group .elementor-field, .elementor-widget-form .elementor-field-subgroup label{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .elementor-button{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-widget-form .e-form__buttons__wrapper__button-next{background-color:var( --e-global-color-accent );}.elementor-widget-form .elementor-button[type=\"submit\"]{background-color:var( --e-global-color-accent );}.elementor-widget-form .e-form__buttons__wrapper__button-previous{background-color:var( --e-global-color-accent );}.elementor-widget-form .elementor-message{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .e-form__indicators__indicator, .elementor-widget-form .e-form__indicators__indicator__label{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-widget-form{--e-form-steps-indicator-inactive-primary-color:var( --e-global-color-text );--e-form-steps-indicator-active-primary-color:var( --e-global-color-accent );--e-form-steps-indicator-completed-primary-color:var( --e-global-color-accent );--e-form-steps-indicator-progress-color:var( --e-global-color-accent );--e-form-steps-indicator-progress-background-color:var( --e-global-color-text );--e-form-steps-indicator-progress-meter-color:var( --e-global-color-text );}.elementor-widget-form .e-form__indicators__indicator__progress__meter{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-249870 .elementor-element.elementor-element-6ae6ef83{width:var( --container-widget-width, 75% );max-width:75%;--container-widget-width:75%;--container-widget-flex-grow:0;z-index:120;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group{padding-right:calc( 10px\/2 );padding-left:calc( 10px\/2 );margin-bottom:6px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-form-fields-wrapper{margin-left:calc( -10px\/2 );margin-right:calc( -10px\/2 );margin-bottom:-6px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label, .elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{color:#7B88A3;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-type-html{padding-bottom:0px;color:#7A7A7A;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field{color:#484848;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:01px 01px 01px 01px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:01px 01px 01px 01px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249870 .elementor-element.elementor-element-66fd4d36{--display:flex;--min-height:58px;--gap:0px 0px;--row-gap:0px;--column-gap:0px;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:8px 8px 8px 8px;--margin-top:12px;--margin-bottom:10px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249870 .elementor-element.elementor-element-66fd4d36.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4{width:auto;max-width:auto;z-index:120;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 > .elementor-widget-container{margin:2px 0px 2px 1px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label, .elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field{color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:600;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249870 .elementor-element.elementor-element-4a59cf88 > .elementor-widget-container{margin:-3px 0px -24px 0px;}.elementor-249870 .elementor-element.elementor-element-4a59cf88.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-4a59cf88{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-17d3ad0c{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;border-style:none;--border-style:none;--border-radius:8px 8px 8px 8px;--margin-top:-4px;--margin-bottom:05px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249870 .elementor-element.elementor-element-17d3ad0c.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-177c9b71{width:auto;max-width:auto;z-index:5;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 > .elementor-widget-container{margin:2px 0px 2px 1px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-177c9b71.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label, .elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{color:#000000;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field{color:#000000;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:16px;font-weight:600;line-height:1.1em;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249870 .elementor-element.elementor-element-5bafe1f3{--display:flex;--min-height:0px;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--gap:0px 0px;--row-gap:0px;--column-gap:0px;--overlay-opacity:1;--margin-top:230px;--margin-bottom:-220px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:10;}.elementor-249870 .elementor-element.elementor-element-5bafe1f3::before, .elementor-249870 .elementor-element.elementor-element-5bafe1f3 > .elementor-background-video-container::before, .elementor-249870 .elementor-element.elementor-element-5bafe1f3 > .e-con-inner > .elementor-background-video-container::before, .elementor-249870 .elementor-element.elementor-element-5bafe1f3 > .elementor-background-slideshow::before, .elementor-249870 .elementor-element.elementor-element-5bafe1f3 > .e-con-inner > .elementor-background-slideshow::before, .elementor-249870 .elementor-element.elementor-element-5bafe1f3 > .elementor-motion-effects-container > .elementor-motion-effects-layer::before{--background-overlay:'';background-size:cover;}.elementor-249870 .elementor-element.elementor-element-5bafe1f3.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-432cc2a1{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--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-249870 .elementor-element.elementor-element-446e8565 > .elementor-widget-container{margin:0px 3px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-446e8565.elementor-element{--align-self:flex-end;}.elementor-249870 .elementor-element.elementor-element-446e8565{z-index:5;text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249870 .elementor-element.elementor-element-60df49d0 > .elementor-widget-container{margin:35px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-60df49d0.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-60df49d0{z-index:5;text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:500;line-height:1.1em;color:#6185C0;}.elementor-249870 .elementor-element.elementor-element-62ef38f0{--display:flex;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:space-between;--align-items:flex-start;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-287px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-f4f51cb > .elementor-widget-container{margin:0px 3px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-f4f51cb.elementor-element{--align-self:flex-end;}.elementor-249870 .elementor-element.elementor-element-f4f51cb{z-index:5;text-align:left;font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249870 .elementor-element.elementor-element-f214306 > .elementor-widget-container{margin:0px 0px 0px 3px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-f214306.elementor-element{--align-self:flex-end;}.elementor-249870 .elementor-element.elementor-element-f214306{z-index:5;text-align:start;font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249870 .elementor-element.elementor-element-1c5a5ed5{--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;--justify-content:flex-start;--align-items:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--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-249870 .elementor-element.elementor-element-1c5a5ed5.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-4740d3e8{--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;--justify-content:space-between;--margin-top:5px;--margin-bottom:5px;--margin-left:010px;--margin-right:10px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-e964c6b > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-e964c6b.elementor-element{--align-self:flex-end;}.elementor-249870 .elementor-element.elementor-element-e964c6b{z-index:5;text-align:left;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249870 .elementor-element.elementor-element-30eb836c > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-30eb836c{z-index:101;text-align:right;}.elementor-249870 .elementor-element.elementor-element-342c88b1{--display:flex;--min-height:180px;--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;--justify-content:center;--align-items:center;--overflow:hidden;border-style:solid;--border-style:solid;border-width:4px 4px 4px 4px;--border-top-width:4px;--border-right-width:4px;--border-bottom-width:4px;--border-left-width:4px;border-color:#00FF19;--border-color:#00FF19;--border-radius:0px 0px 0px 0px;--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-249870 .elementor-element.elementor-element-342c88b1:not(.elementor-motion-effects-element-type-background), .elementor-249870 .elementor-element.elementor-element-342c88b1 > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-3c7e790f > .elementor-widget-container{padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-3c7e790f{font-family:\"Roboto\", Sans-serif;font-weight:500;color:#6185C0;}.elementor-249870 .elementor-element.elementor-element-51f00578{width:auto;max-width:auto;z-index:5;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249870 .elementor-element.elementor-element-51f00578 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-51f00578.elementor-element{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group > label, .elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{color:#000000;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field{color:#213864;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:15.5px;font-weight:600;line-height:1.1em;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249870 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249870 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249870 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249870 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-message.elementor-message-success{color:#00FF2700;}@media(max-width:1001px){.elementor-249870 .elementor-element.elementor-element-6ae6ef83{z-index:11;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-size:10px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4{z-index:11;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-size:10px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-177c9b71{z-index:11;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-size:10px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-button{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-51f00578{z-index:11;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-size:10px;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-button{font-size:12px;}}@media(min-width:1001px){.elementor-249870 .elementor-element.elementor-element-6da64a60{--width:500px;}.elementor-249870 .elementor-element.elementor-element-45f807e0{--width:100%;}.elementor-249870 .elementor-element.elementor-element-6c65b106{--width:500px;}.elementor-249870 .elementor-element.elementor-element-75917e71{--width:10px;}.elementor-249870 .elementor-element.elementor-element-5ad25a69{--width:100%;}.elementor-249870 .elementor-element.elementor-element-469b1a7c{--width:500px;}.elementor-249870 .elementor-element.elementor-element-48a37689{--width:22%;}.elementor-249870 .elementor-element.elementor-element-79a46db6{--width:50%;}.elementor-249870 .elementor-element.elementor-element-3aa42503{--width:22%;}.elementor-249870 .elementor-element.elementor-element-78e1d9f5{--width:100%;}.elementor-249870 .elementor-element.elementor-element-cf3602e{--width:103px;}.elementor-249870 .elementor-element.elementor-element-6bf72a5{--width:103px;}.elementor-249870 .elementor-element.elementor-element-34d8bbba{--width:103px;}.elementor-249870 .elementor-element.elementor-element-5a9252c3{--width:103px;}.elementor-249870 .elementor-element.elementor-element-19ecc2b3{--width:103px;}.elementor-249870 .elementor-element.elementor-element-3617569c{--width:103px;}.elementor-249870 .elementor-element.elementor-element-7450a6f8{--width:103px;}.elementor-249870 .elementor-element.elementor-element-8d50d33{--width:100%;}.elementor-249870 .elementor-element.elementor-element-66fd4d36{--width:390px;}.elementor-249870 .elementor-element.elementor-element-17d3ad0c{--width:100%;}.elementor-249870 .elementor-element.elementor-element-5bafe1f3{--width:150%;}.elementor-249870 .elementor-element.elementor-element-62ef38f0{--width:95%;}.elementor-249870 .elementor-element.elementor-element-1c5a5ed5{--width:100%;}.elementor-249870 .elementor-element.elementor-element-4740d3e8{--width:100%;}}@media(max-width:1000px){.elementor-249870 .elementor-element.elementor-element-6da64a60{--width:390px;--margin-top:105px;--margin-bottom:-75px;--margin-left:0px;--margin-right:0px;}.elementor-249870 .elementor-element.elementor-element-45f807e0{--min-height:150px;--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;--margin-top:-47px;--margin-bottom:-32px;--margin-left:0px;--margin-right:0px;--z-index:3;}.elementor-249870 .elementor-element.elementor-element-61dcced4{--width:25%;}.elementor-249870 .elementor-element.elementor-element-6c65b106{--width:100%;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:center;--align-items:center;--flex-wrap:nowrap;--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249870 .elementor-element.elementor-element-6c65b106.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-eb74aa8{--width:75%;--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:center;}.elementor-249870 .elementor-element.elementor-element-eb74aa8.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-1c762c45{--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249870 .elementor-element.elementor-element-6be76773 > .elementor-widget-container{margin:-3px 40px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-5ad25a69{--width:100%;--justify-content:flex-end;--align-items:flex-end;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249870 .elementor-element.elementor-element-52dec736 > .elementor-widget-container{margin:40px 55px -30px 0px;}.elementor-249870 .elementor-element.elementor-element-52dec736{z-index:100;}.elementor-249870 .elementor-element.elementor-element-469b1a7c{--width:78%;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--flex-wrap:nowrap;--margin-top:-103px;--margin-bottom:-7px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-469b1a7c.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-3f5f9124{--justify-content:center;--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249870 .elementor-element.elementor-element-48a37689{--width:25%;--margin-top:2px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-4b68287 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-4b68287{font-size:8px;}.elementor-249870 .elementor-element.elementor-element-79a46db6{--width:46%;--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-249870 .elementor-element.elementor-element-47d25f98 > .elementor-widget-container{margin:0px -20px 0px -20px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-47d25f98{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-3aa42503{--width:25%;--margin-top:4px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-12d5dc39 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-12d5dc39{font-size:7px;}.elementor-249870 .elementor-element.elementor-element-21535e15{--margin-top:-15px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249870 .elementor-element.elementor-element-de420c1{--min-height:15px;--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-249870 .elementor-element.elementor-element-2f60f3f{width:100%;max-width:100%;font-size:10px;}.elementor-249870 .elementor-element.elementor-element-2f60f3f > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-6b485447{width:100%;max-width:100%;font-size:10px;}.elementor-249870 .elementor-element.elementor-element-6b485447 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-78e1d9f5{--width:100%;--gap:6px 4px;--row-gap:6px;--column-gap:4px;--flex-wrap:wrap;--margin-top:-12px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249870 .elementor-element.elementor-element-cf3602e{--width:61px;--min-height:15px;}.elementor-249870 .elementor-element.elementor-element-7a1bb33{font-size:9px;}.elementor-249870 .elementor-element.elementor-element-6bf72a5{--width:61px;--min-height:15px;}.elementor-249870 .elementor-element.elementor-element-1a57dd9{font-size:9px;}.elementor-249870 .elementor-element.elementor-element-34d8bbba{--width:61px;--min-height:15px;}.elementor-249870 .elementor-element.elementor-element-32bd35c6{font-size:9px;}.elementor-249870 .elementor-element.elementor-element-5a9252c3{--width:61px;--min-height:15px;}.elementor-249870 .elementor-element.elementor-element-8722042{font-size:9px;}.elementor-249870 .elementor-element.elementor-element-19ecc2b3{--width:61px;--min-height:15px;}.elementor-249870 .elementor-element.elementor-element-6071d405{font-size:9px;}.elementor-249870 .elementor-element.elementor-element-3617569c{--width:61px;--min-height:15px;}.elementor-249870 .elementor-element.elementor-element-4b013e71{font-size:9px;}.elementor-249870 .elementor-element.elementor-element-7450a6f8{--width:61px;--min-height:15px;}.elementor-249870 .elementor-element.elementor-element-30970f89{font-size:9px;}.elementor-249870 .elementor-element.elementor-element-6aac67a6{--width:96%;--min-height:250px;--margin-top:-56px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-40d299c > .elementor-widget-container{margin:5px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-1fd15d20 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-54e4e530{--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249870 .elementor-element.elementor-element-54e4e530.e-con{--order:-99999 \/* order start hack *\/;}.elementor-249870 .elementor-element.elementor-element-531f3cb1 > .elementor-widget-container{margin:-30px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-3a352c3f > .elementor-widget-container{margin:-181px 0px 1px 0px;}.elementor-249870 .elementor-element.elementor-element-3a352c3f{text-align:center;font-size:10px;line-height:1.2em;}.elementor-249870 .elementor-element.elementor-element-7abb0aba > .elementor-widget-container{margin:-180px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-7abb0aba{text-align:center;font-size:14px;line-height:1.2em;}.elementor-249870 .elementor-element.elementor-element-68e2b2ca > .elementor-widget-container{margin:-110px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-68e2b2ca{font-size:10px;}.elementor-249870 .elementor-element.elementor-element-8d50d33{--width:184px;--margin-top:-156px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249870 .elementor-element.elementor-element-8d50d33.e-con{--align-self:center;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83{width:var( --container-widget-width, 100% );max-width:100%;--container-widget-width:100%;--container-widget-flex-grow:0;z-index:120;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-size:8px;}.elementor-249870 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-size:10.5px;}.elementor-249870 .elementor-element.elementor-element-66fd4d36{--width:85%;--min-height:42px;--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:center;--margin-top:10px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 > .elementor-widget-container{margin:2px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4{z-index:120;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-type-html{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-size:10px;}.elementor-249870 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-size:10.5px;}.elementor-249870 .elementor-element.elementor-element-4a59cf88 > .elementor-widget-container{margin:2px 0px -10px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-4a59cf88{font-size:7.5px;}.elementor-249870 .elementor-element.elementor-element-17d3ad0c{--width:85%;--min-height:42px;--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:center;--margin-top:2px;--margin-bottom:-20px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:251;}.elementor-249870 .elementor-element.elementor-element-177c9b71 > .elementor-widget-container{margin:2px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-177c9b71{z-index:120;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-type-html{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-177c9b71 .elementor-button{font-size:10.5px;}.elementor-249870 .elementor-element.elementor-element-5bafe1f3{--min-height:150px;--margin-top:-149px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249870 .elementor-element.elementor-element-446e8565 > .elementor-widget-container{margin:-133px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-446e8565.elementor-element{--align-self:flex-start;}.elementor-249870 .elementor-element.elementor-element-446e8565{text-align:left;font-size:10px;}.elementor-249870 .elementor-element.elementor-element-f4f51cb > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249870 .elementor-element.elementor-element-f4f51cb.elementor-element{--align-self:flex-start;}.elementor-249870 .elementor-element.elementor-element-f4f51cb{text-align:center;font-size:10px;}.elementor-249870 .elementor-element.elementor-element-f214306 > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249870 .elementor-element.elementor-element-f214306.elementor-element{--align-self:flex-start;}.elementor-249870 .elementor-element.elementor-element-f214306{text-align:center;font-size:10px;}.elementor-249870 .elementor-element.elementor-element-1c5a5ed5{--width:390px;--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-249870 .elementor-element.elementor-element-e964c6b > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249870 .elementor-element.elementor-element-e964c6b.elementor-element{--align-self:flex-start;}.elementor-249870 .elementor-element.elementor-element-e964c6b{text-align:center;font-size:10px;}.elementor-249870 .elementor-element.elementor-element-30eb836c > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-30eb836c{z-index:100;}.elementor-249870 .elementor-element.elementor-element-342c88b1{--min-height:112px;--margin-top:5px;--margin-bottom:5px;--margin-left:5px;--margin-right:5px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249870 .elementor-element.elementor-element-3c7e790f{text-align:center;font-size:15px;}.elementor-249870 .elementor-element.elementor-element-51f00578 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249870 .elementor-element.elementor-element-51f00578{z-index:120;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group > label{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-type-html{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-size:12px;}.elementor-249870 .elementor-element.elementor-element-51f00578 .elementor-button{font-size:10.5px;}}<\/style>\t\t<div data-elementor-type=\"loop-item\" data-elementor-id=\"249870\" class=\"elementor elementor-249870 elementor-bc-flex-widget e-loop-item e-loop-item-38623 post-38623 post type-post status-publish format-standard has-post-thumbnail hentry category-btp category-page-pays-only category-togo category-togo-btp generate-columns tablet-grid-50 mobile-grid-100 grid-parent grid-20\" data-elementor-post-type=\"elementor_library\" data-custom-edit-handle=\"1\">\n\t\t\t<div class=\"elementor-element elementor-element-6da64a60 e-con-full OrdiMobileConteneurClass e-flex e-con e-child\" data-id=\"6da64a60\" data-element_type=\"container\" id=\"testIdTest\">\n\t\t<div class=\"elementor-element elementor-element-45f807e0 e-con-full UploadFileConteneur AdUploadedTitle elementor-hidden-tablet elementor-hidden-mobile elementor-hidden-desktop e-flex e-con e-child\" data-id=\"45f807e0\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-61dcced4 e-con-full e-flex e-con e-child\" data-id=\"61dcced4\" data-element_type=\"container\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6c65b106 e-con-full e-flex e-con e-child\" data-id=\"6c65b106\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-eb74aa8 e-con-full e-flex e-con e-child\" data-id=\"eb74aa8\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1c762c45 e-con-full e-flex e-con e-child\" data-id=\"1c762c45\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5be6a53a e-con-full e-flex e-con e-child\" data-id=\"5be6a53a\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-75917e71 e-con-full e-flex e-con e-child\" data-id=\"75917e71\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6be76773 AnnonceDragIcone elementor-widget elementor-widget-image\" data-id=\"6be76773\" data-element_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\/2025\/05\/arrow-drag-64-bleu.png\" 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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5ad25a69 e-con-full CroixResetAnnonceContainer e-flex e-con e-child\" data-id=\"5ad25a69\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-52dec736 elementor-widget elementor-widget-image\" data-id=\"52dec736\" data-element_type=\"widget\" id=\"CroixResetAnnonce\" 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:\/\/via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-transparent.png\" 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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-469b1a7c e-con-full UploadFileConteneur e-flex e-con e-child\" data-id=\"469b1a7c\" data-element_type=\"container\" id=\"UploadFileConteneur\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-3f5f9124 e-con-full ChoisirEspacePublicitaireDisponibiliteConteneur e-flex e-con e-child\" data-id=\"3f5f9124\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-48a37689 e-con-full e-flex e-con e-child\" data-id=\"48a37689\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b68287 PositionEspacePublicitaire elementor-widget elementor-widget-text-editor\" data-id=\"4b68287\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPosition\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-79a46db6 e-con-full e-flex e-con e-child\" data-id=\"79a46db6\" data-element_type=\"container\" id=\"ChoixEspacePublicitaireTitre\">\n\t\t\t\t<div class=\"elementor-element elementor-element-47d25f98 elementor-widget elementor-widget-text-editor\" data-id=\"47d25f98\" data-element_type=\"widget\" id=\"ChoixEspacePublicitaireTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tChoix d&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-3aa42503 e-con-full e-flex e-con e-child\" data-id=\"3aa42503\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-12d5dc39 ReferenceEspacePublicitaire elementor-widget elementor-widget-text-editor\" data-id=\"12d5dc39\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-21535e15 e-con-full EspPubFormatMainContainer e-flex e-con e-child\" data-id=\"21535e15\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-de420c1 e-con-full e-flex e-con e-child\" data-id=\"de420c1\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2f60f3f elementor-widget-mobile__width-inherit SelectionFormatTitre elementor-widget elementor-widget-text-editor\" data-id=\"2f60f3f\" data-element_type=\"widget\" data-widget_type=\"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 s\u00e9lectionner un format d&rsquo;annonce<\/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-6b485447 elementor-widget-mobile__width-inherit elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile SelectionFormatTitreBlancOLD elementor-widget elementor-widget-text-editor\" data-id=\"6b485447\" data-element_type=\"widget\" data-widget_type=\"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 changer de format d&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-78e1d9f5 e-con-full EspPubFormatListe e-flex e-con e-child\" data-id=\"78e1d9f5\" data-element_type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-cf3602e e-con-full EspPubFormatContainer FormatIdCreation e-flex e-con e-child\" data-id=\"cf3602e\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7a1bb33 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"7a1bb33\" data-element_type=\"widget\" data-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\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-6bf72a5 e-con-full EspPubFormatContainer FormatIdPopUp e-flex e-con e-child\" data-id=\"6bf72a5\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1a57dd9 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"1a57dd9\" data-element_type=\"widget\" data-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-34d8bbba e-con-full EspPubFormatContainer FormatIdBanniere e-flex e-con e-child\" data-id=\"34d8bbba\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-32bd35c6 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"32bd35c6\" data-element_type=\"widget\" data-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-5a9252c3 e-con-full EspPubFormatContainer FormatIdVideo e-flex e-con e-child\" data-id=\"5a9252c3\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8722042 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"8722042\" data-element_type=\"widget\" data-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<a class=\"elementor-element elementor-element-19ecc2b3 e-con-full EspPubFormatContainer FormatIdCommunique e-flex e-con e-child\" data-id=\"19ecc2b3\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6071d405 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"6071d405\" data-element_type=\"widget\" data-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<a class=\"elementor-element elementor-element-3617569c e-con-full EspPubFormatContainer FormatIdInterview e-flex e-con e-child\" data-id=\"3617569c\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b013e71 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"4b013e71\" data-element_type=\"widget\" data-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-7450a6f8 e-con-full EspPubFormatContainer FormatIdParrainage e-flex e-con e-child\" data-id=\"7450a6f8\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-30970f89 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"30970f89\" data-element_type=\"widget\" data-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<div class=\"elementor-element elementor-element-6aac67a6 e-con-full HTMLUploadfileConteneur e-flex e-con e-child\" data-id=\"6aac67a6\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-40d299c elementor-widget__width-inherit HTMLUploadfileClass elementor-widget elementor-widget-html\" data-id=\"40d299c\" data-element_type=\"widget\" id=\"HTMLUploadfile\" 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=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <meta name=\"google\" content=\"notranslate\">\r\n    \r\n    <script data-jetpack-boost=\"ignore\" src=\"https:\/\/code.jquery.com\/jquery-3.6.0.min.js\"><\/script>\r\n    <script data-jetpack-boost=\"ignore\" src=\"https:\/\/code.jquery.com\/ui\/1.12.1\/jquery-ui.min.js\"><\/script>\r\n\r\n<script data-jetpack-boost=\"ignore\">\r\n\/\/ Lazy loading des biblioth\u00e8ques - charg\u00e9es uniquement au besoin\r\nwindow.VIALibraries = {\r\n    mammothLoaded: false,\r\n    pdfLoaded: false,\r\n    \r\n    loadMammoth: function(callback) {\r\n        if (this.mammothLoaded) { callback(); return; }\r\n        var script = document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/mammoth\/1.4.0\/mammoth.browser.min.js';\r\n        script.onload = function() { \r\n            window.VIALibraries.mammothLoaded = true; \r\n            callback(); \r\n        };\r\n        document.head.appendChild(script);\r\n    },\r\n    \r\n    loadPdfJs: function(callback) {\r\n        if (this.pdfLoaded) { callback(); return; }\r\n        var script = document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.11.174\/pdf.min.js';\r\n        script.onload = function() {\r\n            window.VIALibraries.pdfLoaded = true;\r\n            pdfjsLib.GlobalWorkerOptions.workerSrc = '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n            callback();\r\n        };\r\n        document.head.appendChild(script);\r\n    }\r\n};\r\n<\/script>\r\n\r\n<\/head>\r\n<body>\r\n    <div id=\"PopUpMessageAchattest\" class=\"draggable\" draggable=\"true\" style=\"justify-content: center; align-items: flex-start;\">\r\n        <div id=\"drop_file_zone_achat\" class=\"drop_file_zone_achat_class\" ondrop=\"uploadFile_achat(event)\" ondragover=\"return false\">\r\n        <div id=\"drag_upload_file_achat\">\r\n            <p><input class=\"button-2_achat\" type=\"button\" value=\"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\" onclick=\"fileExplorer_achat(event);\" \/><\/p>\r\n                <input type=\"file\" id=\"selectfile_achat\" \/>\r\n        <\/div>\r\n        <\/div>\r\n        <div class=\"img-content\"><\/div>\r\n    <\/div>\r\n<\/body>\r\n<\/html>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1fd15d20 elementor-widget__width-inherit HTMLUploadfileClass elementor-widget elementor-widget-html\" data-id=\"1fd15d20\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script data-jetpack-boost=\"ignore\">\r\nif (!window._espPubScriptLoaded) {\r\nwindow._espPubScriptLoaded = true;\r\n\/**\r\n * Configuration centralis\u00e9e\r\n *\/\r\nconst CONFIG = {\r\n    iframeId: 'yearbook-iframe',\r\n    ajaxUrl: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n    apercuUrl: 'https:\/\/rdc.yearbook-media.com\/apercu',\r\n    \r\n    allowedExtensions: {\r\n        video: ['mp4', 'mov', 'wmv', 'avi', 'flv', 'f4v', 'swf', 'mkv', 'webm', 'mpeg'],\r\n        image: ['jpg', 'jpeg', 'png', 'gif', 'tif', 'svg', 'webp'],\r\n        document: ['doc', 'docx', 'ppt', 'pptx', 'pdf']\r\n    },\r\n    \r\n    mimeTypes: {\r\n        docx: 'application\/vnd.openxmlformats-officedocument.wordprocessingml.document',\r\n        pdf: 'application\/pdf'\r\n    },\r\n    \r\n    dragScroll: {\r\n        threshold: 150,\r\n        maxSpeed: 65,\r\n        throttleDelay: 50\r\n    },\r\n    \r\n    breakpoints: {\r\n        mobile: 1000\r\n    },\r\n    \r\n    keywords: [\r\n        { normal: \"parrainage\", display: \"Parrainage\" },\r\n        { normal: \"communique\", display: \"Communiqu\u00e9\" },\r\n        { normal: \"interview\", display: \"Interview\" }\r\n    ]\r\n};\r\n\r\n\/**\r\n * \u2705 v1.19.1 : Module de positionnement dans l'iframe\r\n * \r\n * PROBL\u00c8ME : L'iframe ne scrolle pas en desktop \u2014 c'est le parent (#PageWebTitrePage) qui scrolle.\r\n * L'iframe est scal\u00e9e \u00e0 0.85 \u2192 les coordonn\u00e9es iframe \u2260 coordonn\u00e9es parent.\r\n * position:fixed dans l'iframe = relatif au CONTENU TOTAL, pas au viewport visible.\r\n * \r\n * SOLUTION : Le parent calcule visibleTopIframe (la position iframe du haut du viewport)\r\n * et l'envoie dans le message 'PageWebTitrePage-scroll'. L'iframe n'a qu'\u00e0 l'utiliser.\r\n * \r\n * Pour scroller, l'iframe envoie 'scrollToIframeY' au parent qui fait la conversion.\r\n *\/\r\nconst ScrollHelper = {\r\n    _visibleTopIframe: 0,\r\n    _iframeScale: 0.85,\r\n\r\n    init() {\r\n        \/\/ \u00c9couter les donn\u00e9es de scroll envoy\u00e9es par le parent\r\n        window.addEventListener('message', (event) => {\r\n            var msg = event.data;\r\n            if (msg && msg.action === 'PageWebTitrePage-scroll') {\r\n                if (typeof msg.visibleTopIframe === 'number') {\r\n                    this._visibleTopIframe = msg.visibleTopIframe;\r\n                }\r\n                if (typeof msg.iframeScale === 'number') {\r\n                    this._iframeScale = msg.iframeScale;\r\n                }\r\n            }\r\n        });\r\n        console.log('\u2705 ScrollHelper initialis\u00e9');\r\n    },\r\n\r\n    \/**\r\n     * Position Y dans le document iframe correspondant au haut du viewport visible\r\n     *\/\r\n    getVisibleTop() {\r\n        if (window === window.top) {\r\n            return window.scrollY || 0;\r\n        }\r\n        return this._visibleTopIframe;\r\n    },\r\n\r\n    \/**\r\n     * Demande au parent de scroller pour positionner `element` \u00e0 `offsetFromTop` px du viewport\r\n     *\/\r\n    scrollElementTo(element, offsetFromTop) {\r\n        if (!element) return;\r\n\r\n        \/\/ getBoundingClientRect().top dans une iframe sans scroll = position absolue Y\r\n        var elementAbsY = element.getBoundingClientRect().top;\r\n\r\n        if (window === window.top) {\r\n            window.scrollTo({ top: elementAbsY - offsetFromTop + (window.scrollY || 0), behavior: 'smooth' });\r\n            return;\r\n        }\r\n\r\n        \/\/ Envoyer au parent \u2014 le parent fait la conversion scale\r\n        window.parent.postMessage({\r\n            type: 'scrollToIframeY',\r\n            iframeId: CONFIG.iframeId,\r\n            iframeY: elementAbsY,\r\n            offsetFromTop: offsetFromTop\r\n        }, '*');\r\n        console.log('\ud83d\udcdc scrollToIframeY:', { iframeY: Math.round(elementAbsY), offsetFromTop });\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'\u00e9tat (SessionStorage)\r\n *\/\r\nconst StateManager = {\r\n    init() {\r\n        if (sessionStorage.getItem(\"AchatEspaceCall\") === 'No') {\r\n            sessionStorage.clear();\r\n        }\r\n        \r\n        this.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        this.set('dragstart_Rank_Emplacement_Page_Web', 'No');\r\n        this.set('dragstart_Commande_Emplacement_Page_Web', 'No');\r\n        \r\n        \/\/ \u2705 v2.1.1 : Popup \u2192 ne jamais pr\u00e9remplir le format\r\n        if (this.get('PopUpChoice') === 'Yes') {\r\n            this.set('Formatchoisi', 'No');\r\n            this.set('FormatSelect', '');\r\n            this.set('Commande_Format_Transmis', '');\r\n        }\r\n    },\r\n    \r\n    get(key) {\r\n        return sessionStorage.getItem(key);\r\n    },\r\n    \r\n    set(key, value) {\r\n        sessionStorage.setItem(key, value);\r\n    },\r\n    \r\n    getMultiple(keys) {\r\n        return keys.reduce((acc, key) => {\r\n            acc[key] = this.get(key);\r\n            return acc;\r\n        }, {});\r\n    },\r\n    \r\n    setMultiple(obj) {\r\n        Object.entries(obj).forEach(([key, value]) => {\r\n            this.set(key, value);\r\n        });\r\n    },\r\n    \r\n    buildEmplacementReference(rank) {\r\n        const codeSite = this.get('codeSite');\r\n        const codePage = this.get('codePage');\r\n        return `${codeSite}${codePage}L${rank.substring(3)}`;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des fichiers\r\n *\/\r\nconst FileManager = {\r\n    getExtension(filename) {\r\n        console.log('filename:', filename);\r\n        const parts = filename.split('.');\r\n        return parts.length > 1 ? parts.pop().toLowerCase() : '';\r\n    },\r\n    \r\n    isAllowedExtension(extension) {\r\n        return Object.values(CONFIG.allowedExtensions)\r\n            .flat()\r\n            .includes(extension);\r\n    },\r\n    \r\n    getFileType(extension) {\r\n        for (const [type, extensions] of Object.entries(CONFIG.allowedExtensions)) {\r\n            if (extensions.includes(extension)) {\r\n                return type;\r\n            }\r\n        }\r\n        return null;\r\n    },\r\n    \r\n    async urlToFile(url, filename) {\r\n        console.log(\"Fetching from URL:\", url);\r\n        \r\n        const mimeType = filename.includes('.docx') \r\n            ? CONFIG.mimeTypes.docx \r\n            : filename.includes('.pdf') \r\n            ? CONFIG.mimeTypes.pdf \r\n            : null;\r\n        \r\n        try {\r\n            const response = await fetch(url);\r\n            \r\n            if (!response.ok) {\r\n                throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`);\r\n            }\r\n            \r\n            const blob = await response.blob();\r\n            return new File([blob], filename, { type: mimeType });\r\n        } catch (error) {\r\n            console.error(\"Error in urlToFile:\", error);\r\n            alert(\"Erreur lors du chargement du fichier. Veuillez r\u00e9essayer.\");\r\n            throw error;\r\n        }\r\n    },\r\n    \r\n    createObjectUrl(file) {\r\n        \/\/ R\u00e9voquer l'ancien URL si existant\r\n        const oldUrl = StateManager.get('objectUrl');\r\n        if (oldUrl && oldUrl.startsWith('blob:')) {\r\n            URL.revokeObjectURL(oldUrl);\r\n            console.log('\ud83d\uddd1\ufe0f Old Object URL revoked');\r\n        }\r\n        \r\n        const url = URL.createObjectURL(file);\r\n        StateManager.set('objectUrl', url);\r\n        return url;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion du Drag & Drop\r\n *\/\r\nconst DragDropManager = {\r\n    state: {\r\n        isFileBeingDragged: false,\r\n        draggedFile: null,\r\n        dragInProgress: false,\r\n        throttleTimeout: null\r\n    },\r\n    \r\n    init() {\r\n        this.attachEventListeners();\r\n    },\r\n    \r\n    attachEventListeners() {\r\n        window.addEventListener('dragstart', (e) => this.handleDragStart(e), true);\r\n        jQuery(document).on('dragover', (e) => this.handleDragOver(e));\r\n        jQuery(document).on('dragleave drop', (e) => this.handleDragEnd(e));\r\n        jQuery(\"#drop_file_zone_achat\").on(\"dragover\", (e) => this.handleDropZoneDragOver(e));\r\n        jQuery(\".draggable\").on(\"dragend\", (e) => this.handleDraggableEnd(e));\r\n    },\r\n    \r\n    handleDragStart(e) {\r\n        console.log('Window-level dragstart', e);\r\n        this.state.dragInProgress = true;\r\n    \r\n        const $target = $(e.target);\r\n        const droppableParent = $target.closest('.droppable');\r\n        const parentId = droppableParent.length ? droppableParent.attr('id') : null;\r\n        \r\n        StateManager.set('dragstart_Rank_Emplacement_Page_Web', parentId);\r\n        console.log('dragstart_Rank_Emplacement_Page_Web', parentId);\r\n        \r\n        \/\/ \u2705 CALCULER IMM\u00c9DIATEMENT dragstart_Commande_Emplacement_Page_Web\r\n        if (parentId) {\r\n            const dragstartRef = StateManager.buildEmplacementReference(parentId);\r\n            StateManager.set('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n            console.log('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n            \/\/ \u2705 v2.4.5 : Capturer l'\u00e9tat checkbox R\u00e9server au moment du dragstart\r\n            \/\/ Si l'utilisateur a explicitement d\u00e9coch\u00e9, forcer \u00e0 No m\u00eame si DOM est coch\u00e9\r\n            var $_dragCb = $('#' + parentId).find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n            var _dragCbChecked = $_dragCb.prop('checked') === true;\r\n            var _expliciteDecocheDrag = StateManager.get('_reserverDecoche_' + parentId) === 'Yes';\r\n            var _reserverDrag = _dragCbChecked && !_expliciteDecocheDrag;\r\n            StateManager.set('dragstart_ReserverChecked', _reserverDrag ? 'Yes' : 'No');\r\n            \/\/ R\u00e9initialiser le flag apr\u00e8s lecture\r\n            StateManager.set('_reserverDecoche_' + parentId, 'No');\r\n            console.log('[dragstart] ReserverChecked dom:', _dragCbChecked, '| d\u00e9coch\u00e9 explicitement:', _expliciteDecocheDrag, '| final:', _reserverDrag);\r\n        }\r\n    \r\n        const dataTransfer = e.dataTransfer || e.originalEvent?.dataTransfer;\r\n        const files = dataTransfer?.files || null;\r\n        \r\n        const imgSrc = $target.closest('.draggable').find('img').attr('src');\r\n        const videoSrc = $target.closest('.draggable').find('video').attr('src') || \r\n                        $target.closest('.draggable').find('video source').attr('src');\r\n        const mediaSrc = imgSrc || videoSrc;\r\n    \r\n        console.log('dragstart target:', e.target);\r\n        console.log('files:', files);\r\n        console.log('mediaSrc:', mediaSrc);\r\n    \r\n        if (!mediaSrc && (!files || files.length === 0)) {\r\n            console.log('No media source or files found, preventing drag');\r\n            e.preventDefault();\r\n            this.state.dragInProgress = false;\r\n            return false;\r\n        }\r\n    \r\n        if (mediaSrc) {\r\n            StateManager.set('objectUrl', mediaSrc);\r\n        }\r\n    \r\n        StateManager.set('Commande_Format_Transmis', '');\r\n        \r\n        if ($target.closest('.droppable').find('.doc-preview-container:visible').length > 0) {\r\n            StateManager.set('Commande_Format_Transmis', 'R\u00e9dactionnel');\r\n            StateManager.set('FullPathAdFile', \r\n                $target.closest('.droppable').find('.doc-preview-FullPathAdFile').text());\r\n        }\r\n    \r\n        if (files && files.length > 0) {\r\n            this.state.isFileBeingDragged = true;\r\n            this.state.draggedFile = files[0];\r\n        }\r\n        \r\n        \/\/ \u2705 TOUJOURS marquer comme \"Moved\" quand on drag depuis un espace existant\r\n        if (parentId && mediaSrc) {\r\n            StateManager.set('FirstUploadFileorMoved', 'Moved');\r\n            console.log('\u2705 Drag depuis espace existant - Moved');\r\n        }\r\n    \r\n        console.log('Drag Started', {\r\n            file: this.state.draggedFile,\r\n            mediaSrc: mediaSrc,\r\n            dragstartRef: StateManager.get('dragstart_Commande_Emplacement_Page_Web')\r\n        });\r\n    },\r\n    \r\n    handleDragOver(e) {\r\n        e.preventDefault();\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            this.handleIframeDragScroll(e);\r\n        } else {\r\n            this.handleDirectPageScroll(e);\r\n        }\r\n    },\r\n    \r\n    handleIframeDragScroll(e) {\r\n        if (!this.state.throttleTimeout) {\r\n            this.state.throttleTimeout = setTimeout(() => {\r\n                MessageManager.sendToParent('dragScroll', { clientY: e.clientY });\r\n                this.state.throttleTimeout = null;\r\n            }, CONFIG.dragScroll.throttleDelay);\r\n        }\r\n    },\r\n    \r\n    handleDirectPageScroll(e) {\r\n        const { threshold, maxSpeed } = CONFIG.dragScroll;\r\n        const windowHeight = window.innerHeight;\r\n        \r\n        if (e.clientY < threshold) {\r\n            const speed = Math.max(1, maxSpeed * (1 - e.clientY \/ threshold));\r\n            window.scrollBy(0, -speed);\r\n        } else if (e.clientY > windowHeight - threshold) {\r\n            const speed = Math.max(1, maxSpeed * (1 - (windowHeight - e.clientY) \/ threshold));\r\n            window.scrollBy(0, speed);\r\n        }\r\n    },\r\n    \r\n    handleDragEnd(e) {\r\n        e.preventDefault();\r\n        MessageManager.sendToParent('dragEnd', {});\r\n        console.log('dragleave drop');\r\n    },\r\n    \r\n    handleDropZoneDragOver(e) {\r\n        e.preventDefault();\r\n        console.log(\"FirstUploadFileorMoved:\", StateManager.get('FirstUploadFileorMoved'));\r\n    },\r\n    \r\n    handleDraggableEnd(e) {\r\n        e.preventDefault();\r\n        this.resetState();\r\n        console.log('dragend');\r\n    },\r\n    \r\n    resetState() {\r\n        this.state.isFileBeingDragged = false;\r\n        this.state.draggedFile = null;\r\n        this.state.dragInProgress = false;\r\n    },\r\n    \r\n    clearDataTransferFiles(e) {\r\n        e.dataTransfer = new DataTransfer();\r\n        console.log('DataTransfer files cleared');\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'interface utilisateur\r\n *\/\r\nconst UIManager = {\r\n    isMobile() {\r\n        return window.outerWidth < CONFIG.breakpoints.mobile;\r\n    },\r\n    \r\n    isDesktop() {\r\n        const userAgent = navigator.userAgent;\r\n        const isWindows = userAgent.indexOf('Windows') > -1;\r\n        const isMac = userAgent.indexOf('Macintosh') > -1;\r\n        const isLinux = userAgent.indexOf('Linux') > -1 && userAgent.indexOf('Android') === -1;\r\n        return isWindows || isMac || isLinux;\r\n    },\r\n    \r\n    initMobileUI() {\r\n        $(document).ready(() => {\r\n            $('label[for=\"form-field-LienAnnonce\"]').each(function() {\r\n                $(this).text('Renseigner le lien hypertexte de l\\'annonce');\r\n            });\r\n            \r\n            $('input[name=\"form_fields[LienAnnonce]\"]').each(function() {\r\n                $(this).attr('placeholder', 'Renseigner le lien hypertexte de l\\'annonce');\r\n            });\r\n        });\r\n        \r\n        jQuery('.MsgDatesText').hide();\r\n        this.attachMobileEventListeners();\r\n    },\r\n    \r\n    attachMobileEventListeners() {\r\n        jQuery('.TransmettreFichierAnnonceContainer').on('click', (e) => {\r\n            this.handleMobileSpaceSelection(e);\r\n        });\r\n        \r\n        jQuery('[id=\"form-field-selected_currency_Mobile\"]').off('change').on('change', (e) => {\r\n            this.handleMobileCurrencyChange(e);\r\n        });\r\n    },\r\n    \r\n    handleMobileSpaceSelection(e) {\r\n        e.preventDefault();\r\n        jQuery('#IndisponibilitesMsg').hide();\r\n        \r\n        jQuery('input[name=\"form_fields[SelectEspacePublicitaireMobile]\"]').prop('checked', false);\r\n        jQuery(e.currentTarget).find('input[name=\"form_fields[SelectEspacePublicitaireMobile]\"]').prop('checked', true);\r\n        \r\n        StateManager.set(\"PageWebDisplayed\", 'Yes');\r\n        \r\n        jQuery('.FormSelectDevisesMobile').hide();\r\n        jQuery(e.target).closest('.EspacePublicitaireMobile').find('.FormSelectDevisesMobile').show();\r\n        \r\n        const $droppable = jQuery(e.currentTarget).closest('.droppable');\r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', rankId);\r\n        StateManager.set('Commande_Emplacement_Page_Web', \r\n            StateManager.buildEmplacementReference(rankId));\r\n        \r\n        this.updateEmplacementDisplay();\r\n        this.handleAvailabilityDisplay(e);\r\n        this.displayUploadedAdIfExists(e);\r\n        this.updateTariffDisplay(e);\r\n    },\r\n    \r\n    updateEmplacementDisplay() {\r\n        const emplacement = StateManager.get('Commande_Emplacement_Page_Web');\r\n        jQuery('#EmplacementAnnonceDataStep3').html(emplacement).css({'color': '#56BE50'});\r\n        console.log(\"Emplacement:\", emplacement);\r\n    },\r\n    \r\n    handleAvailabilityDisplay(e) {\r\n        const $espace = jQuery(e.target).closest('.EspacePublicitaireMobile');\r\n        const dispoText = $espace.find('.ChoisirEspacePublicitaireDisponibilite').text();\r\n        \r\n        if (dispoText.length > 46) {\r\n            const espacePublicitaireDispoFrom = dispoText.slice(-10);\r\n            console.log(\"espacePublicitaireDispoFrom:\", espacePublicitaireDispoFrom);\r\n            console.log(\"Date de debut:\", StateManager.get(\"Debut_de_campagne\"));\r\n        } else {\r\n            jQuery('#form-field-DebutCampagne').val(StateManager.get(\"Debut_de_campagne\"));\r\n        }\r\n    },\r\n    \r\n    displayUploadedAdIfExists(e) {\r\n        if (StateManager.get(\"FileReceived\") === 'Yes') {\r\n            jQuery('.VisualisationAnnonceMobile').hide();\r\n            \r\n            const espaceId = StateManager.get('espaceChoisi');\r\n            const $espace = document.querySelector(`[id=\"${espaceId}\"]`);\r\n            \r\n            jQuery($espace).find('.MessageAnnonceMobileTexte')\r\n                .html('Merci de choisir des dates de campagne<br>afin d\\'obtenir le tarif de cet espace publicitaire');\r\n            jQuery($espace).find('.VisualisationAnnonceMobile').show();\r\n        \r\n            const img = document.createElement('img');\r\n            img.src = StateManager.get('objectUrl');\r\n            img.style.width = 'auto';\r\n            img.style.height = 'auto';\r\n            img.style.maxWidth = '100%';\r\n            img.style.maxHeight = '200px';\r\n            \r\n            jQuery('.VisualisationAnnonceMobile').empty();\r\n            jQuery($espace).find('.VisualisationAnnonceMobile').append(img);\r\n        }\r\n    },\r\n    \r\n    updateTariffDisplay(e) {\r\n        jQuery('.TariftobedisplayedMobile').html('-');\r\n        const newTarif = StateManager.get('NewTarifformatted');\r\n        \r\n        if (newTarif && newTarif !== '-') {\r\n            jQuery(e.target).closest('.EspacePublicitaireMobile')\r\n                .find('.TariftobedisplayedMobile')\r\n                .html(newTarif);\r\n        }\r\n    },\r\n    \r\n    handleMobileCurrencyChange(e) {\r\n        event.preventDefault();\r\n        StateManager.setMultiple({\r\n            \"SelectionCatalogueOuAchat\": 'Catalogue',\r\n            \"selected_currency\": jQuery(e.currentTarget).val()\r\n        });\r\n        \r\n        jQuery('#form-field-selected_currency_2').val(StateManager.get(\"selected_currency\"));\r\n        console.log(\"selected currency:\", StateManager.get(\"selected_currency\"));\r\n        \r\n        setTimeout(() => {\r\n            jQuery(e.target).closest('.EspacePublicitaireMobile')\r\n                .find('.TariftobedisplayedMobile')\r\n                .html(StateManager.get(\"NewTarifformatted\"));\r\n        }, 500);\r\n    },\r\n    \r\n    initDesktopUI() {\r\n        StateManager.setMultiple({\r\n            \"FileReceived\": \"No\",\r\n            \"AdDisplayed\": \"No\"\r\n        });\r\n        jQuery('.MsgAdNotDisplayed').hide();\r\n    },\r\n    \r\n    showUploadProgress($dropZone) {\r\n        \/\/ Cacher les \u00e9l\u00e9ments\r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .TexteMobileAnnonce')\r\n            .hide();\r\n        \r\n        \/\/ Afficher et styler le message de progression\r\n        var _uplMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed')\r\n            .show()\r\n            .html(_uplMsg)\r\n            .css({\r\n                'color': '#00ff19',\r\n                'background-color': 'white',\r\n                'padding': '12px 20px',\r\n                'border-radius': '6px',\r\n                'font-weight': '700',\r\n                'font-size': '18px',\r\n                'line-height': '1.4',\r\n                'display': 'inline-block',\r\n                'margin': '10px auto',\r\n                'text-align': 'center'\r\n            });\r\n        \r\n        \/\/ Cacher les autres \u00e9l\u00e9ments\r\n        $dropZone.closest('.droppable')\r\n            .find('.UploadIci, .EnvoiUlterieurTexte, .EnvoiUlterieurContainer')\r\n            .hide();\r\n            \r\n        $dropZone.closest('.droppable')\r\n            .find('.UploadFileConteneur')\r\n            .css({\r\n                'background-color': 'transparent'\r\n            });\r\n    },\r\n    \r\n    showFormatError($dropZone, message = 'Format de fichier incompatible') {\r\n        \/\/ \u2705 v2.4.6 : M\u00eame rendu overlay que le bloc jpeg \u2014 position absolute sur $dropZone\r\n        var _errId = 'fmt-error-msg-' + Date.now();\r\n        $dropZone.css('position', 'relative');\r\n        var _errHtml = '<div id=\"' + _errId + '\" style=\"'\r\n            + 'position:absolute;top:50px;left:50%;transform:translateX(-50%);width:auto;white-space:nowrap;'\r\n            + 'background:#fff;color:#FB5E2A;font-weight:700;font-size:13px;'\r\n            + 'text-align:center;padding:8px 10px;border-radius:6px;'\r\n            + 'border:2px solid #FB5E2A;box-sizing:border-box;'\r\n            + 'z-index:99999;line-height:1.4;'\r\n            + '\">' + message + '<\/div>';\r\n        $dropZone.append(_errHtml);\r\n        setTimeout(function() { jQuery('#' + _errId).remove(); }, 4000);\r\n    },\r\n    \r\n    updateAfterSuccessfulUpload($dropZone) {\r\n        jQuery('#errorMessageMobileText').hide();\r\n        \r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 Pas de margin-top:150px si d\u00e9p\u00f4t depuis miniature kit (d\u00e9j\u00e0 positionn\u00e9)\r\n        if (!window._dropFromMiniature) {\r\n            $dropZone.closest('.OrdiMobileConteneurClass')\r\n                .css({'margin-top': '150px', 'margin-bottom': '0px'});\r\n        }\r\n    },\r\n    \r\n    finalizeAdDisplay($dropZone) {\r\n        StateManager.setMultiple({\r\n            \"FileReceived\": \"Yes\",\r\n            \"PageWebDisplayed\": \"Yes\"\r\n        });\r\n        \r\n        jQuery('#MsgChoixPageWeb, #MsgInsererAnnonceConteneur').hide();\r\n        jQuery('#ChoixEspacePublicitaire')\r\n            .html('L\\'annonce est plac\u00e9e dans un espace publicitaire')\r\n            .show()\r\n            .css({'color': '#56BE50'});\r\n        \r\n        jQuery('#MsgPlacerAnnoncePosition').hide();\r\n        jQuery('#FonctionMenu4').show();\r\n        jQuery('.AnnonceData').html(\"Transmis\").css({'color': '#56BE50'});\r\n        \r\n        jQuery('#ProcederPaiementConteneur').hide();\r\n        jQuery('#ProcederPaiementTitreIconeUp').hide();\r\n        jQuery('#ProcederPaiementTitreIconeDown').show();\r\n        \r\n        jQuery('#message').remove();\r\n        \r\n        this.styleUploadedAd($dropZone);\r\n        this.adjustLayoutAfterUpload($dropZone);\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox \"R\u00e9server\" apr\u00e8s upload\r\n        FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n    },\r\n    \r\n    styleUploadedAd($dropZone) {\r\n        const $container = $dropZone.closest('.OrdiMobileConteneurClass');\r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \r\n        \/\/ \u2705 v1.19.5 : V\u00e9rifier si c'est une restauration via flag d\u00e9di\u00e9\r\n        const isRestoration = StateManager.get('_isAdRestoration') === 'Yes';\r\n        \r\n        $container\r\n            .find('.PositionReference, .TexteMobile, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        $container\r\n            .find('.AdUploadedTitle, .DimensionsMaximales')\r\n            .show();\r\n        \r\n        \/\/ \u2705 Bug 2 fix : montrer le conteneur parent + la croix (CroixResetAnnonceContainer cach\u00e9 par reset)\r\n        $droppable.find('.CroixResetAnnonceContainer').show();\r\n        $droppable.find('#CroixResetAnnonce').show();\r\n        \r\n        \/\/ \u2705 v2.2 : Marquer le droppable comme occup\u00e9 pour qu'Entete le skip\r\n        $droppable.attr('data-via-ad-loaded', 'true');\r\n        \r\n        \/\/ \u2705 v2.0.11 : AdUploadedTitle ne doit pas bloquer le touch sur doc-preview-readmore (mobile)\r\n        $container.find('.AdUploadedTitle').css('pointer-events', 'none');\r\n        \r\n        \/\/ \u2705 #CroixResetAnnonce au-dessus de tous les conteneurs superpos\u00e9s\r\n        $container.find('#CroixResetAnnonce').css({\r\n            'position': 'relative',\r\n            'z-index': '9999'\r\n        });\r\n        \r\n        \/\/ \u2705 Desktop : les conteneurs superpos\u00e9s bloquent la croix \u2014 les rendre transparents aux clics\r\n        if (!UIManager.isMobile()) {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css('pointer-events', 'none');\r\n            \/\/ R\u00e9activer les \u00e9l\u00e9ments interactifs\r\n            $container.find('#CroixResetAnnonce').css('pointer-events', 'auto');\r\n            $dropZone.closest('#PopUpMessageAchattest').css('pointer-events', 'auto'); \/\/ drag annonce\r\n        }\r\n        \r\n        \/\/ \u2705 v2.4.3 : Sur mobile, masquer titre et logo drag quand annonce d\u00e9pos\u00e9e dans Ele0A\r\n        if (UIManager.isMobile()) {\r\n            if ($droppable.attr('id') === 'Ele0A') {\r\n                $droppable.find('#ChoixEspacePublicitaireTexte').hide();\r\n                $droppable.find('#Ele0ADragHandle').hide();\r\n                \/\/ \u2705 v2.4.12 : UploadFileConteneur a pointer-events:none \u2192 forcer auto sur la croix\r\n                $droppable.find('.CroixResetAnnonceContainer')[0] && $droppable.find('.CroixResetAnnonceContainer')[0].style.setProperty('pointer-events', 'auto', 'important');\r\n                $droppable.find('#CroixResetAnnonce')[0] && $droppable.find('#CroixResetAnnonce')[0].style.setProperty('pointer-events', 'auto', 'important');\r\n            }\r\n        }\r\n        \r\n        jQuery(\".HTMLUploadfileConteneur\").css({\r\n            'border': 'none',\r\n            'background-color': 'transparent'\r\n        });\r\n        \r\n        \/\/ \u2705 v2.4.12 : Retirer le liser\u00e9 envoi diff\u00e9r\u00e9 (#UploadFileConteneur) si pr\u00e9sent\r\n        \/\/ (le d\u00e9p\u00f4t d'une annonce cr\u00e9e son propre liser\u00e9 sur .HTMLUploadfileConteneur)\r\n        var $_ufcEd = $dropZone.closest('.droppable').find('#UploadFileConteneur');\r\n        if ($_ufcEd[0]) {\r\n            $_ufcEd[0].style.removeProperty('box-shadow');\r\n            $_ufcEd[0].style.removeProperty('box-sizing');\r\n            if (UIManager.isMobile()) {\r\n                $_ufcEd[0].style.removeProperty('transform');\r\n                $_ufcEd[0].style.removeProperty('transform-origin');\r\n            }\r\n        }\r\n        \r\n        $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n            'box-shadow': 'inset 0 0 0 2px #00FF19',  \/\/ \u2705 v2.4.5 : inset \u2192 jamais clipp\u00e9 par overflow:hidden\r\n            'background-color': 'white',\r\n            'box-sizing': 'border-box',\r\n            'overflow': 'hidden'\r\n        });\r\n        \r\n        \/\/ \u2705 v2.0.9 : Fix mobile \u2014 r\u00e9duire le scale pour que le liser\u00e9 vert soit visible\r\n        \/\/ \u2705 Pas de scale si annonce d\u00e9pos\u00e9e depuis la miniature kit (d\u00e9j\u00e0 aux bonnes dimensions)\r\n        \/\/ \u2705 v2.4.9 : Pas de scale si AchatEspaceCall=Yes (drop depuis miniature dans iframe)\r\n        \/\/ \u2705 data-kit-drop : marqueur DOM pos\u00e9 par kitAdCreated, r\u00e9siste \u00e0 l'async\r\n        var _fromKitDrop = $droppable[0] ? $droppable[0].getAttribute('data-kit-drop') === 'true' : false;\r\n        if (_fromKitDrop) { window._dropFromMiniature = true; } \/\/ sync le flag window\r\n        var _fromMiniature = window._dropFromMiniature || _fromKitDrop;\r\n        var _fromAchat = StateManager.get('AchatEspaceCall') === 'Yes';\r\n        if (UIManager.isMobile() && !_fromMiniature && !_fromAchat) {\r\n            $dropZone.closest('.UploadFileConteneur').css({\r\n                'transform': 'scale(1.35)',\r\n                'transform-origin': 'top center'\r\n            });\r\n            \/\/ \u2705 v2.4.11 : Corps de page mobile \u2014 le .ToBeHidden clippe le scale(1.35) c\u00f4t\u00e9 droit\r\n            \/\/ \u2192 overflow:visible pour que le liser\u00e9 vert soit visible sur les 4 c\u00f4t\u00e9s\r\n            $dropZone.closest('.ToBeHidden').css('overflow', 'visible');\r\n        }\r\n        \r\n        \/\/ \u2705 v2.2 : Sur restauration, Entete a d\u00e9j\u00e0 positionn\u00e9 le droppable correctement\r\n        \/\/ et est emp\u00each\u00e9 de le retoucher (data-via-ad-loaded). On ne touche pas aux marges.\r\n        \/\/ Sur premier upload, on applique les marges normalement.\r\n        \/\/ \u2705 Pas de marges si d\u00e9p\u00f4t depuis miniature kit (dimensions naturelles conserv\u00e9es)\r\n        if (!isRestoration && !_fromMiniature) {\r\n            if ($container.data('orig-mb') === undefined) {\r\n                $container.data('orig-mb', parseInt($container.css('margin-bottom')) || 0);\r\n            }\r\n            if ($droppable.data('orig-mt') === undefined) {\r\n                $droppable.data('orig-mt', parseInt($droppable.css('margin-top')) || 0);\r\n            }\r\n            var _isDocPreview = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _marginAdd = _isDocPreview ? 60 : 130;\r\n            var _marginReduce = _isDocPreview ? 60 : 130;\r\n            $container.css({\r\n                'margin-bottom': ($container.data('orig-mb') + _marginAdd) + 'px'\r\n            });\r\n            $droppable.css({\r\n                'margin-top': ($droppable.data('orig-mt') - _marginReduce + 75) + 'px'\r\n            });\r\n        } else {\r\n            \/\/ \u2705 Sur restauration, ajouter 50px en dessous pour \u00e9viter que le contenu soit trop coll\u00e9\r\n            var _curMb = parseInt($container.css('margin-bottom')) || 0;\r\n            $container.css('margin-bottom', (_curMb + 50) + 'px');\r\n        }\r\n        \r\n        \/\/ \u2705 Masquer .PositionEspacePublicitaireContainer et l'ancien .ReserverContainer\r\n        $droppable.find('.PositionEspacePublicitaireContainer').hide();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        \/\/ \u2705 Supprimer tout ancien bouton dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 v2.1.2 : Cr\u00e9er le bouton R\u00e9server m\u00eame lors d'une restauration\r\n        if (isRestoration) {\r\n            console.log('\ud83d\udd04 Restauration d\u00e9tect\u00e9e - affichage bouton R\u00e9server + DeplaceAnnonce');\r\n            $droppable.find('.DeplaceAnnonce').show();\r\n            \/\/ S'assurer que FileReceived est d\u00e9fini pour la validation\r\n            StateManager.set('FileReceived', 'Yes');\r\n            \/\/ Cocher automatiquement SEULEMENT si c'est une restauration de commande r\u00e9serv\u00e9e (pas pendingAd)\r\n            var _isPendingAdRestore = sessionStorage.getItem('_pendingAdRestoration') === 'Yes';\r\n            if (!_isPendingAdRestore) {\r\n                var _isReservedRestore = sessionStorage.getItem('_isReservedRestoration') === 'Yes';\r\n                setTimeout(function() {\r\n                    var $checkbox = $droppable.find('.reserver-dynamic-checkbox');\r\n                    if ($checkbox.length && _isReservedRestore) {\r\n                        $checkbox.prop('checked', true);\r\n                        $droppable.find('.reserver-dynamic-label').text('Espace publicitaire r\u00e9serv\u00e9').css('color', 'rgb(62, 170, 19)');\r\n                        console.log('\u2705 R\u00e9server coch\u00e9 automatiquement (restauration commande r\u00e9serv\u00e9e)');\r\n                    }\r\n                    sessionStorage.removeItem('_isReservedRestoration');\r\n                    StateManager.set('_isAdRestoration', 'No');\r\n                    \/\/ \u2705 v2.4.7 : updateReserverCheckboxState APR\u00c8S avoir coch\u00e9 la checkbox\r\n                    \/\/ (l'appel synchrone ligne 614 intervient avant le cocher \u2192 label incorrect)\r\n                    if (typeof FormatUIManager !== 'undefined') {\r\n                        FormatUIManager.updateReserverCheckboxState($droppable);\r\n                    }\r\n                }, 150);\r\n            } else {\r\n                \/\/ pendingAd : ne pas cocher, ne pas envoyer au parent\r\n                console.log('\u2705 pendingAd restaur\u00e9 \u2014 R\u00e9server NON coch\u00e9');\r\n                sessionStorage.removeItem('_pendingAdRestoration');\r\n                StateManager.set('_isAdRestoration', 'No');\r\n            }\r\n        }\r\n        \r\n        \/\/ \u2705 Supprimer tout bouton R\u00e9server existant avant insertion (\u00e9vite doublons sur restauration)\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 Cr\u00e9er le bouton \"R\u00e9server\" dynamique avec id unique pour \u00e9viter conflit label\/for Elementor\r\n        const _rankId = $droppable.attr('id') || ('drop_' + Date.now());\r\n        const _cbId = 'reserver-cb-' + _rankId;\r\n        const reserverHTML = `\r\n            <div class=\"reserver-dynamic-container\">\r\n                <span class=\"reserver-dynamic-option\">\r\n                    <input type=\"checkbox\" id=\"${_cbId}\" value=\"R\u00e9server cet espace publicitaire\" \r\n                           class=\"reserver-dynamic-checkbox\"\r\n                           name=\"form_fields[ReserverEspacePublicitaire]\">\r\n                    <span class=\"reserver-dynamic-label\">R\u00e9server cet espace publicitaire<\/span>\r\n                <\/span>\r\n            <\/div>\r\n        `;\r\n        \r\n        \/\/ \u2705 Ins\u00e9rer juste avant .DeplaceAnnonceText (position stable)\r\n        const $anchor = $droppable.find('.DeplaceAnnonceText');\r\n        if ($anchor.length) {\r\n            $anchor.before(reserverHTML);\r\n            $anchor.prev('.reserver-dynamic-container').css('margin-bottom', '-40px');\r\n            if (!UIManager.isMobile()) {\r\n                $anchor.prev('.reserver-dynamic-container').find('.reserver-dynamic-label').css({'font-size': '20px', 'font-weight': '700'});\r\n            }\r\n        } else {\r\n            $droppable.after(reserverHTML);\r\n            const $btn = $droppable.next('.reserver-dynamic-container');\r\n            $btn.css('margin-top', UIManager.isMobile() ? '-10px' : '-140px');\r\n        }\r\n        \r\n        console.log('\u2705 Bouton \"R\u00e9server\" dynamique cr\u00e9\u00e9');\r\n    },\r\n    \r\n    adjustLayoutAfterUpload($dropZone) {\r\n        console.log('\ud83d\udcf1 adjustLayoutAfterUpload \u2014 isMobile():', this.isMobile(), 'outerWidth:', window.outerWidth);\r\n        if (this.isMobile()) {\r\n            this.adjustMobileLayout($dropZone);\r\n            \r\n            \/\/ Repositionner le bouton R\u00e9server APR\u00c8S les ajustements de layout\r\n            setTimeout(() => {\r\n                const $droppable = $dropZone.closest('.droppable');\r\n                const $btn = $droppable.find('.reserver-dynamic-container').add($droppable.next('.reserver-dynamic-container')).first();\r\n                const $lisere = $droppable.find('.HTMLUploadfileConteneur');\r\n                if ($btn.length && $lisere.length) {\r\n                    const lisereBottom = $lisere[0].getBoundingClientRect().bottom;\r\n                    const btnTop = $btn[0].getBoundingClientRect().top;\r\n                    const offset = lisereBottom - btnTop - 48;\r\n                    \r\n                    \/\/ 15px suppl\u00e9mentaires pour homepage et articles\r\n                    let extraOffset = 0;\r\n                    const isHomepage = window.location.pathname === \"\/\" || window.location.pathname === \"\/en\/\";\r\n                    const isSectorPage = $('body').hasClass('page');\r\n                    if (isHomepage) {\r\n                        extraOffset = 13;\r\n                    }\r\n                    if (!isSectorPage) {\r\n                        extraOffset = 15;\r\n                    }\r\n                    \r\n                    \/\/ \u2705 v2.0.9 : +4px pour documents (communiqu\u00e9\/interview\/PDF) avec pr\u00e9sentation HTML\r\n                    if ($droppable.find('.doc-preview-container:visible').length > 0) {\r\n                        extraOffset += 4;\r\n                    }\r\n                    \r\n                    $btn.css({\r\n                        'margin-top': (offset + extraOffset + 20) + 'px',\r\n                        'margin-bottom': (-(offset + extraOffset) - 100) + 'px'\r\n                    });\r\n                    console.log('\ud83d\udcd0 Repositionnement mobile R\u00e9server:', { lisereBottom, btnTop, offset });\r\n                }\r\n            }, 50);\r\n        } else {\r\n            this.adjustDesktopLayout($dropZone);\r\n        }\r\n    },\r\n    \r\n    adjustMobileLayout($dropZone) {\r\n        console.log('\ud83d\udcf1 adjustMobileLayout START');\r\n        console.log('\ud83d\udcf1 AchatEspaceCall:', StateManager.get(\"AchatEspaceCall\"));\r\n        console.log('\ud83d\udcf1 PageAjoutModifAnnonce:', StateManager.get(\"PageAjoutModifAnnonce\"));\r\n        console.log('\ud83d\udcf1 window===window.top:', window === window.top);\r\n        console.log('\ud83d\udcf1 pathname:', location.pathname);\r\n        \r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \r\n        \/\/ \u2705 v2.4.3 : Masquer les textes position\/label\/r\u00e9f\u00e9rence (comme sur desktop)\r\n        $droppable\r\n            .find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 v2.6 : Renseigner .PositionEspacePublicitaire sur mobile (manquait vs desktop)\r\n        (function() {\r\n            var _rankPosMob = StateManager.get('Rank_Emplacement_Page_Web') || $droppable.attr('id') || '';\r\n            var _posLibMob = PreviewRenderer._getPositionLibelle(_rankPosMob);\r\n            if (_posLibMob) {\r\n                $droppable\r\n                    .find('.PositionEspacePublicitaire')\r\n                    .text(_posLibMob)\r\n                    .each(function() {\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        \/\/ \u2705 Scop\u00e9 au $dropZone courant (\u00e9vite d'affecter les autres espaces pub)\r\n        $dropZone.closest('.droppable').find('#CroixResetAnnonce').css({'zoom': '75%'});\r\n\r\n        \/\/ \u2705 v2.4.3 : Remonter la croix reset sur mobile (override margin-top Elementor)\r\n        \/\/ \u2705 v2.4.5 : Poser aussi margin-right ici (Entete.txt ne l'atteint pas pour Ele0A)\r\n        var _croixContainer = $dropZone.closest('.OrdiMobileConteneurClass').find('.CroixResetAnnonceContainer')[0];\r\n        if (_croixContainer) {\r\n            var _isEle0ACroix = ($dropZone.closest('.droppable').attr('id') === 'Ele0A');\r\n            var _mtCroix = StateManager.get(\"PageAjoutModifAnnonce\") === 'Yes' ? '-88px' : '24px';\r\n            \/\/ Ele0A : +40px vers le bas, +15px vers la gauche (margin-right) par rapport \u00e0 Ele1A\r\n            \/\/ Ele0A : margin-top identique aux autres espaces (pas de d\u00e9calage suppl\u00e9mentaire)\r\n            _croixContainer.style.setProperty('margin-top', _mtCroix, 'important');\r\n            _croixContainer.style.setProperty('margin-right', _isEle0ACroix ? '17px' : '12px', 'important');\r\n        }\r\n        \r\n        var _isMiniatureAdj = window._dropFromMiniature;\r\n        window._dropFromMiniature = false;\r\n\r\n        if (_isMiniatureAdj && window.outerWidth <= 1000) {\r\n            \/\/ \u2705 Miniature doc-preview MOBILE : ajuster HTMLUploadfileConteneur \u00e0 la hauteur du contenu\r\n            \/\/ et neutraliser tous les margins Elementor qui d\u00e9calent le $dropZone hors du parent\r\n            var _isDocPreviewMob = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _docH = _isDocPreviewMob ? 144 : 115;\r\n            $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                'height':     _docH + 'px',\r\n                'min-height': _docH + 'px',\r\n                'max-height': _docH + 'px',\r\n                'margin-top': '-55px',\r\n                'margin-bottom': '0px',\r\n                'overflow': 'hidden'\r\n            });\r\n            $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px', 'height': (_docH - 6) + 'px'});\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '65px', 'margin-bottom': '-10px'});\r\n            \/\/ \u2705 v2.4.9 : Doc-preview \u2014 overflow:visible pour que le liser\u00e9 du haut ne soit pas clipp\u00e9\r\n            if (_isDocPreviewMob) {\r\n                $dropZone.closest('.OrdiMobileConteneurClass').css('overflow', 'visible');\r\n                $dropZone.closest('.OrdiMobileConteneurClass').parent().css('overflow', 'visible');\r\n            }\r\n            \/\/ \u2705 v2.4.9 : Ele0A popup mobile \u2014 neutraliser translateY(-32px) pos\u00e9 par Entete sur EnvoiUlterieurTexte\r\n            var _isEle0AMob = ($dropZone.closest('.droppable').attr('id') === 'Ele0A');\r\n            if (_isEle0AMob) {\r\n                var $_euTxt = $dropZone.closest('.droppable').find('.EnvoiUlterieurTexte');\r\n                if ($_euTxt[0]) {\r\n                    $_euTxt[0].style.setProperty('transform', 'translateY(0px)', 'important');\r\n                    $_euTxt[0].style.setProperty('margin-top', '0px', 'important');\r\n                }\r\n            }\r\n            \/\/ \u2705 v2.4.12 : AchatEspaceCall=Yes \u2192 override margins (m\u00eame correction que pour upload direct)\r\n            if (StateManager.get('AchatEspaceCall') === 'Yes') {\r\n                $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px'});\r\n                var _docHAchatMini = _isDocPreviewMob ? 150 : 112;\r\n                $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                    'margin-top': '70px',\r\n                    'margin-bottom': '35px',\r\n                    'min-height': _docHAchatMini + 'px',\r\n                    'height': _isDocPreviewMob ? _docHAchatMini + 'px' : '',\r\n                    'max-height': _isDocPreviewMob ? _docHAchatMini + 'px' : ''\r\n                });\r\n                console.log('\ud83d\udcf1 [miniature] AchatEspaceCall=Yes OVERRIDE: mt=70px | docPreview:', _isDocPreviewMob);\r\n            }\r\n            return;\r\n        }\r\n        \/\/ \u2705 v2.4.10 : Miniature DESKTOP \u2192 layout normal appliqu\u00e9 ci-dessous\r\n        if (_isMiniatureAdj) {\r\n            \/\/ Pas de overflow:hidden \u2014 le liser\u00e9 box-shadow inset doit rester visible\r\n        }\r\n\r\n        $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n            'min-height': '112px',\r\n            'margin-top': '-85px',\r\n            \/\/ \u2705 v2.4.10 : Miniature desktop \u2014 pas de margin-bottom excessif qui fait grandir le droppable\r\n            'margin-bottom': _isMiniatureAdj ? '0px' : '20px' \/\/ \u2705 v2.6 : 195px \u2192 59px \u2192 20px (\u00f73) espace sous checkbox R\u00e9server\r\n        });\r\n        console.log('\ud83d\udcf1 HTMLUploadfileConteneur margins set: mt=-85px mb=20px, el found:', $dropZone.closest('.HTMLUploadfileConteneur').length);\r\n        \r\n        $dropZone.css({\r\n            'margin-top': '-50px',\r\n            'margin-bottom': '-140px'\r\n        });\r\n        \r\n        $dropZone.closest('.OrdiMobileConteneurClass').css({\r\n            'margin-top': '65px',\r\n            'margin-bottom': '-10px'\r\n        });\r\n        console.log('\ud83d\udcf1 OrdiMobile margins set: mt=65px mb=-10px');\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            \/\/ \u2705 v2.4.12 : Reset $dropZone margins (les -50px\/-140px tirent le contenu vers le haut dans l'iframe)\r\n            \/\/ Pour doc-preview (Communiqu\u00e9\/Interview), la hauteur est plus grande \u2192 ajuster min-height\r\n            var _isDocPreviewAchat = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _docHAchat = _isDocPreviewAchat ? 150 : 112;\r\n            $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px'});\r\n            $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                \/\/ \u2705 v2.4.13 : Miniature desktop \u2192 +40px suppl\u00e9mentaires pour compenser le d\u00e9calage\r\n                'margin-top': _isMiniatureAdj ? '110px' : '70px',\r\n                'margin-bottom': '35px',\r\n                'min-height': _docHAchat + 'px',\r\n                'height': _isDocPreviewAchat ? _docHAchat + 'px' : '',\r\n                'max-height': _isDocPreviewAchat ? _docHAchat + 'px' : ''\r\n            });\r\n            console.log('\ud83d\udcf1 AchatEspaceCall=Yes OVERRIDE: mt=' + (_isMiniatureAdj ? '110px' : '70px') + ' | docPreview:', _isDocPreviewAchat, '| h:', _docHAchat);\r\n        }\r\n        \r\n        if (location.pathname === '\/annonce' || location.pathname === '\/annonce\/') {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '70px'});\r\n        }\r\n        \r\n        if (window === window.top) {\r\n            console.log('\ud83d\udcf1 window===window.top OVERRIDE droppable margins');\r\n            $dropZone.closest('.droppable').css({\r\n                'margin-top': '-100px',\r\n                'margin-bottom': '-100px'\r\n            });\r\n            $dropZone.closest('#UploadFileConteneur').css({'width': '80%'});\r\n        }        \r\n    },\r\n    \r\n    adjustDesktopLayout($dropZone) {\r\n        const emplacement = StateManager.get('Commande_Emplacement_Page_Web');\r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \/\/ \u2705 v2.4.13 : Lire et resetter _dropFromMiniature ici aussi (desktop)\r\n        var _fromMiniatureDesktop = window._dropFromMiniature || ($droppable[0] ? $droppable[0].getAttribute('data-kit-drop') === 'true' : false);\r\n        window._dropFromMiniature = false;\r\n        \/\/ \u2705 Nettoyer data-kit-drop apr\u00e8s lecture\r\n        if ($droppable[0]) { $droppable[0].removeAttribute('data-kit-drop'); }\r\n        \r\n        \/\/ \u2705 Masquer les textes enfants (position, label, r\u00e9f\u00e9rence) sans toucher au conteneur\r\n        $droppable\r\n            .find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur > div > .elementor-widget-text-editor')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 +15px sur .droppable \u2014 sauf si drop depuis miniature (dimensions naturelles)\r\n        if (!_fromMiniatureDesktop) {\r\n            const currentMt = parseInt($droppable.css('margin-top')) || 0;\r\n            $droppable.css('margin-top', (currentMt + 15) + 'px');\r\n        } else {\r\n            \/\/ \u2705 v2.4.13 : Drop depuis miniature Kit \u2014 d\u00e9caler de 30px vers le bas\r\n            const currentMt = parseInt($droppable.css('margin-top')) || 0;\r\n            \/\/ \u2705 Homepage : -20px (annonce trop basse sur r\u00e9gie) \u2014 autres pages : +70px\r\n            var _mtOffsetMini = (window.location.pathname === '\/' || window.location.pathname === '\/en\/' || window.location.pathname === '\/fr\/') ? -20 : 70;\r\n            $droppable.css('margin-top', (currentMt + _mtOffsetMini) + 'px');\r\n        }\r\n        \r\n        $dropZone.closest('.OrdiMobileConteneurClass')\r\n            .find('.RefEspacePublicitaire')\r\n            .html(emplacement)\r\n            .attr('id', 'RefEspacePublicitaire')\r\n            .each(function() {\r\n                \/\/ \u2705 Forcer aussi le parent .DeplaceAnnonce visible (display:none !important inline)\r\n                var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                this.style.setProperty('display', 'block', 'important');\r\n            });\r\n        \/\/ \u2705 v2.4.5 : Renseigner et afficher .PositionEspacePublicitaire\r\n        (function() {\r\n            var _rankPos = StateManager.get('Rank_Emplacement_Page_Web') || $droppable.attr('id') || '';\r\n            var _posLib = PreviewRenderer._getPositionLibelle(_rankPos);\r\n            if (_posLib) {\r\n                $dropZone.closest('.OrdiMobileConteneurClass')\r\n                    .find('.PositionEspacePublicitaireDeplacer')\r\n                    .text(_posLib)\r\n                    .each(function() {\r\n                        var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                        if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        if (window.location.pathname === \"\/\" || window.location.pathname === \"\/en\/\") {\r\n            \/\/ \u2705 v2.4.10 : top selon contexte \u2014 espaces hors .remainingContent d\u00e9calent de 60px, ceux dedans de 20px\r\n            var _inRemainingContent = $dropZone.closest('.remainingContent').length > 0;\r\n            var _topOffsetHP = _inRemainingContent ? '20px' : '100px';\r\n            $dropZone.closest('.ToBeHidden')\r\n                .css('top', _topOffsetHP)\r\n                .css('min-height', '300px');\r\n            \/\/ NB : pas de overflow:hidden ici \u2014 le liser\u00e9 vert (box-shadow inset sur HTMLUploadfileConteneur)\r\n            \/\/ doit rester visible sur les 4 c\u00f4t\u00e9s\r\n        }\r\n        \r\n        \/\/ \u2705 Toutes pages desktop : rendre le parent du droppable non-clippant\r\n        \/\/ Le bouton R\u00e9server est ins\u00e9r\u00e9 apr\u00e8s .droppable avec margin-top n\u00e9gatif \u2014\r\n        \/\/ overflow:hidden sur le parent Elementor le masque sinon.\r\n        $droppable.parent().css('overflow', 'visible');\r\n        \r\n        if (location.pathname === '\/annonce' || location.pathname === '\/annonce\/') {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '0px'});\r\n        }\r\n    }\r\n};\r\n\r\n\/**\r\n * \u2705 Module de gestion des formats et du titre .SelectionFormatTitre\r\n *\/\r\nconst FormatUIManager = {\r\n    \r\n    \/**\r\n     * V\u00e9rifie si un format est s\u00e9lectionn\u00e9 dans un espace publicitaire\r\n     * V\u00e9rifie le background-color OU le sessionStorage (format venant de l'accord\u00e9on)\r\n     *\/\r\n    hasSelectedFormat($element) {\r\n        const $droppable = $element.closest('.droppable');\r\n        const isEle0A = $droppable.attr('id') === 'Ele0A';\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            if (isEle0A) {\r\n                \/\/ \u2705 v2.3.4 : Ele0A popup \u2014 vrai seulement si un format sous-jacent (hors FormatIdPopUp) est s\u00e9lectionn\u00e9\r\n                var _hasDomFmt = $droppable.find('.EspPubFormatContainer').not('.FormatIdPopUp').toArray().some(el => {\r\n                    return $(el).css('background-color') === 'rgb(255, 255, 255)';\r\n                });\r\n                if (_hasDomFmt) return true;\r\n                \/\/ \u2705 v2.4.5 : Fallback sessionStorage \u2014 DOM pas encore mis \u00e0 jour (timing MutationObserver)\r\n                return !!sessionStorage.getItem('FormatSelect');\r\n            }\r\n            \/\/ Autres espaces en mode popup \u2192 toujours vrai\r\n            return true;\r\n        }\r\n        const hasWhiteBg = $droppable.find('.EspPubFormatContainer').toArray().some(el => {\r\n            return $(el).css('background-color') === 'rgb(255, 255, 255)';\r\n        });\r\n        if (hasWhiteBg) return true;\r\n        \/\/ \u2705 v1.16.0 : Fallback sessionStorage Formatchoisi\r\n        if (sessionStorage.getItem('Formatchoisi') === 'Yes') return true;\r\n        \/\/ \u2705 v2.4.5 : Fallback FormatSelect \u2014 cas du chargement initial avec format d\u00e9j\u00e0 s\u00e9lectionn\u00e9\r\n        \/\/ (Formatchoisi peut \u00eatre remis \u00e0 No au chargement, mais FormatSelect persiste)\r\n        if (sessionStorage.getItem('FormatSelect')) return true;\r\n        \/\/ \u2705 v2.4.9 : Fallback _FormatSelectApplied \u2014 survit au clear de yearbook-media.js init\r\n        return !!sessionStorage.getItem('_FormatSelectApplied');\r\n    },\r\n    \r\n    \/**\r\n     * Met \u00e0 jour la couleur du titre .SelectionFormatTitre\r\n     * Blanc si un format est s\u00e9lectionn\u00e9, rouge #FB5E2A sinon\r\n     *\/\r\n    updateTitleColor($droppable) {\r\n        \/\/ \u2705 v2.4.5 : Ele0A \u2014 ne jamais afficher SelectionFormatTitre\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes' && $droppable.attr('id') === 'Ele0A') {\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n            return;\r\n        }\r\n\r\n        if (this.hasSelectedFormat($droppable)) {\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n            console.log('\u2705 SelectionFormatTitreBlanc affich\u00e9 (format s\u00e9lectionn\u00e9)');\r\n        } else {\r\n            $droppable.find('.SelectionFormatTitre').show();\r\n            $droppable.find('.SelectionFormatTitreBlanc').hide();\r\n            console.log('\u26a0\ufe0f SelectionFormatTitre affich\u00e9 (aucun format s\u00e9lectionn\u00e9)');\r\n        }\r\n    },\r\n    \r\n    \/**\r\n     * Flash visuel sur le titre pour indiquer qu'un format est requis\r\n     *\/\r\n    flashTitle($element) {\r\n        const $droppable = $element.closest('.droppable');\r\n        const $titre = $droppable.find('.SelectionFormatTitre');\r\n        if (!$titre.length) return;\r\n        \r\n        \/\/ Flash rouge rapide 3 fois\r\n        let count = 0;\r\n        const originalColor = $titre.css('color');\r\n        \r\n        const flash = setInterval(() => {\r\n            $titre.css('color', count % 2 === 0 ? '#FF0000' : '#FB5E2A');\r\n            count++;\r\n            if (count >= 6) {\r\n                clearInterval(flash);\r\n                $titre.css('color', '#FB5E2A');\r\n            }\r\n        }, 250);\r\n        \r\n        console.log('\u26a0\ufe0f Flash titre format - action bloqu\u00e9e (aucun format s\u00e9lectionn\u00e9)');\r\n    },\r\n    \r\n    \/**\r\n     * Met \u00e0 jour l'\u00e9tat de la checkbox \"R\u00e9server cet espace publicitaire\"\r\n     * La checkbox est activable si : format s\u00e9lectionn\u00e9 ET (fichier d\u00e9pos\u00e9 OU envoi diff\u00e9r\u00e9)\r\n     *\/\r\n    updateReserverCheckboxState($droppable) {\r\n        \/\/ \u2705 Chercher le label : dynamique ou Elementor statique\r\n        let $label = null;\r\n        let $container = null;\r\n        \r\n        \/\/ 1. Bouton dynamique dans le droppable\r\n        $container = $droppable.find('.reserver-dynamic-container');\r\n        if (!$container.length) {\r\n            $container = $droppable.next('.reserver-dynamic-container');\r\n        }\r\n        if (!$container.length) {\r\n            \/\/ Mobile : checkbox attach\u00e9e au body avec data-droppable-id\r\n            $container = $('body > .reserver-dynamic-container[data-droppable-id=\"' + $droppable.attr('id') + '\"]');\r\n        }\r\n        if (!$container.length) {\r\n            $container = $('body > .reserver-dynamic-container');\r\n        }\r\n        \r\n        if ($container.length) {\r\n            $label = $container.find('.reserver-dynamic-label');\r\n            $container.find('.reserver-dynamic-option, .elementor-field-option').css('opacity', '1');\r\n        }\r\n        \r\n        \/\/ 2. Bouton Elementor statique - chercher dans le droppable puis globalement\r\n        let $reserverStatique = $droppable.find('.elementor-field-group-ReserverEspacePublicitaire label');\r\n        if (!$reserverStatique.length) {\r\n            $reserverStatique = $droppable.find('label[for^=\"form-field-ReserverEspacePublicitaire\"]');\r\n        }\r\n        if (!$reserverStatique.length) {\r\n            \/\/ Fallback global : le formulaire peut \u00eatre en dehors du droppable\r\n            $reserverStatique = $('.elementor-field-group-ReserverEspacePublicitaire .elementor-field-option label');\r\n        }\r\n        \r\n        const hasFormat = this.hasSelectedFormat($droppable);\r\n        const hasFile = StateManager.get('FileReceived') === 'Yes';\r\n        const hasEnvoiDiffere = $droppable.find('input[name*=\"EnvoiUlterieur\"]:checked').length > 0;\r\n        \r\n        const canReserve = hasFormat && (hasFile || hasEnvoiDiffere);\r\n        \r\n        \/\/ \u2705 Si la checkbox R\u00e9server est coch\u00e9e \u2192 label vert \"Espace publicitaire r\u00e9serv\u00e9\"\r\n        const isChecked = $droppable.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked') ||\r\n                          ($container.length && $container.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked'));\r\n        \/\/ \u2705 v2.4.7 : Signal de restauration r\u00e9serv\u00e9e \u2014 checkbox pas encore coch\u00e9e (setTimeout 150ms)\r\n        \/\/             mais on sait d\u00e9j\u00e0 que l'espace est r\u00e9serv\u00e9 \u2192 traiter comme coch\u00e9\r\n        const _isReservedRestoration = sessionStorage.getItem('_isReservedRestoration') === 'Yes';\r\n        const isCheckedOrReservedRestore = isChecked || _isReservedRestoration;\r\n        \r\n        if ($label && $label.length) {\r\n            if (isCheckedOrReservedRestore) {\r\n                $label.text('Espace publicitaire r\u00e9serv\u00e9').css('color', 'rgb(62, 170, 19)');\r\n            } else {\r\n                $label.text('R\u00e9server cet espace publicitaire').css('color', canReserve ? '#FB5E2A' : '');\r\n            }\r\n        }\r\n        if ($reserverStatique.length) {\r\n            if (isCheckedOrReservedRestore) {\r\n                $reserverStatique.attr('style', 'color: rgb(62, 170, 19) !important;');\r\n            } else if (canReserve) {\r\n                $reserverStatique.attr('style', 'color: #FB5E2A !important;');\r\n            } else {\r\n                $reserverStatique.removeAttr('style');\r\n            }\r\n        }\r\n        \r\n        console.log('\ud83d\udd04 updateReserverCheckboxState:', { hasFormat, hasFile, hasEnvoiDiffere, canReserve, dynamicLabel: !!($label && $label.length), staticLabel: $reserverStatique.length });\r\n    },\r\n    \r\n    \/**\r\n     * Initialise les listeners pour le changement de format et la checkbox R\u00e9server\r\n     *\/\r\n    init() {\r\n        \/\/ \u2705 \u00c9couter les clics sur les conteneurs de format et leurs parents\r\n        jQuery(document).on('click', '.EspPubFormatContainer, .EspPubFormatListe, .EspPubFormatMainContainer', (e) => {\r\n            const $droppable = jQuery(e.target).closest('.droppable');\r\n            if (!$droppable.length) return;\r\n            \r\n            \/\/ Multiples d\u00e9lais pour couvrir les traitements asynchrones\r\n            [50, 200, 500].forEach(delay => {\r\n                setTimeout(() => {\r\n                    this.updateTitleColor($droppable);\r\n                    this.updateReserverCheckboxState($droppable);\r\n                }, delay);\r\n            });\r\n\r\n            \/\/ \u2705 v2.2.0 : Si un format (non Cr\u00e9ation) est cliqu\u00e9, notifier le parent pour mettre \u00e0 jour le Kit\r\n            const $btn = jQuery(e.target).closest('.EspPubFormatContainer');\r\n            if ($btn.length && !$btn.hasClass('FormatIdCreation') && !$btn.hasClass('FormatIdPopUp')) {\r\n                \/\/ \u2705 v2.3.4 : FormatIdPopUp g\u00e9r\u00e9 par clickFormatFromIframe (Entete.txt) \u2014 ne pas doubler\r\n                var classes = $btn.attr('class') || '';\r\n                var match = classes.match(\/FormatId(\\w+)\/);\r\n                if (match && match[1]) {\r\n                    var _rankEP = $droppable.attr('id') || '';\r\n                    setTimeout(function() {\r\n                        MessageManager.sendToParent('formatChangedInIframe', { formatSelect: match[1], rank: _rankEP });\r\n                        console.log('\ud83d\udd04 formatChangedInIframe envoy\u00e9:', match[1], '| rank:', _rankEP);\r\n                    }, 100);\r\n                }\r\n            }\r\n        });\r\n        \r\n        \/\/ \u2705 MutationObserver sur les conteneurs de format pour d\u00e9tecter les changements de style\r\n        setTimeout(() => {\r\n            this.observeFormatChanges();\r\n            \r\n            \/\/ Initialiser les couleurs des titres au chargement\r\n            jQuery('.droppable').each((i, el) => {\r\n                this.updateTitleColor(jQuery(el));\r\n            });\r\n            \r\n            \/\/ \u2705 v2.3.4 : Popup \u2192 restaurer FormatIdPopUp + format sous-jacent (sans \u00e9craser applyFormatState)\r\n            if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n                jQuery('.FormatIdPopUp').css({'background-color': '#ffffff'});\r\n                jQuery('.FormatIdPopUp').find('.EspPubFormat').css({'color': '#37D900'});\r\n                \/\/ Restaurer aussi le format sous-jacent dans Ele0A\r\n                var _fmtSS = sessionStorage.getItem('FormatSelect') || '';\r\n                if (_fmtSS) {\r\n                    var _fmtSSNorm = _fmtSS.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                    jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdCreation').each(function() {\r\n                        var _cls = this.className.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                        if (_cls.includes(_fmtSSNorm)) {\r\n                            jQuery(this).css({'background-color': '#ffffff'});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        }\r\n                    });\r\n                }\r\n                jQuery('.droppable').each((i, el) => {\r\n                    this.updateTitleColor(jQuery(el));\r\n                });\r\n            }\r\n        }, 500);\r\n        \r\n        \/\/ \u2705 v1.16.0 : Re-v\u00e9rifier apr\u00e8s un d\u00e9lai plus long (format venant de l'accord\u00e9on via postMessage)\r\n        [1500, 3000].forEach(delay => {\r\n            setTimeout(() => {\r\n                \/\/ \u2705 v2.3.4 : Popup \u2192 restaurer FormatIdPopUp + format sous-jacent\r\n                if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n                    jQuery('.FormatIdPopUp').css({'background-color': '#ffffff'});\r\n                    jQuery('.FormatIdPopUp').find('.EspPubFormat').css({'color': '#37D900'});\r\n                    var _fmtSSR = sessionStorage.getItem('FormatSelect') || '';\r\n                    if (_fmtSSR) {\r\n                        var _fmtSSRNorm = _fmtSSR.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                        jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdCreation').each(function() {\r\n                            var _cls = this.className.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                            if (_cls.includes(_fmtSSRNorm)) {\r\n                                jQuery(this).css({'background-color': '#ffffff'});\r\n                                jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                            }\r\n                        });\r\n                    }\r\n                    jQuery('.droppable').each((i, el) => {\r\n                        this.updateTitleColor(jQuery(el));\r\n                    });\r\n                    return;\r\n                }\r\n                if (sessionStorage.getItem('Formatchoisi') === 'Yes') {\r\n                    jQuery('.droppable').each((i, el) => {\r\n                        this.updateTitleColor(jQuery(el));\r\n                    });\r\n                }\r\n            }, delay);\r\n        });\r\n    },\r\n    \r\n    \/**\r\n     * Attache un MutationObserver sur chaque .EspPubFormatContainer\r\n     * pour d\u00e9tecter tout changement de style (background-color) \r\n     * quel que soit le script qui le d\u00e9clenche\r\n     *\/\r\n    observeFormatChanges() {\r\n        \/\/ \u2705 Guard global anti-boucle \u2014 un seul verrou pour tous les observers\r\n        window._formatObserverLocked = false;\r\n        \r\n        jQuery('.EspPubFormatContainer').each((i, el) => {\r\n            const observer = new MutationObserver(() => {\r\n                if (window._formatObserverLocked) return;\r\n                window._formatObserverLocked = true;\r\n                \/\/ \u2705 v2.4.12 : Debounce 150ms \u2014 applyFormatState manipule plusieurs containers\r\n                \/\/ en s\u00e9quence rapide, le MutationObserver peut firer sur un \u00e9tat interm\u00e9diaire\r\n                clearTimeout(window._formatObserverTimer);\r\n                window._formatObserverTimer = setTimeout(() => {\r\n                    const $droppable = jQuery(el).closest('.droppable');\r\n                    this.updateTitleColor($droppable);\r\n                    this.updateReserverCheckboxState($droppable);\r\n                    window._formatObserverLocked = false;\r\n                }, 150);\r\n            });\r\n            observer.observe(el, { \r\n                attributes: true, \r\n                attributeFilter: ['style', 'class'] \r\n            });\r\n        });\r\n        console.log('\u2705 MutationObserver attach\u00e9 aux conteneurs de format');\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de communication avec la page parente\r\n *\/\r\nconst MessageManager = {\r\n    sendToParent(type, data = {}) {\r\n        try {\r\n            window.parent.postMessage({\r\n                type: type,\r\n                iframeId: CONFIG.iframeId,\r\n                data: data\r\n            }, '*');\r\n        } catch (error) {\r\n            console.error('Error sending message to parent:', error);\r\n            window.parent.postMessage({\r\n                type: 'error',\r\n                error: error.message,\r\n                iframeId: CONFIG.iframeId\r\n            }, '*');\r\n        }\r\n    },\r\n    \r\n    sendDataToParent(data) {\r\n        this.sendToParent('dataFromIframeEspacePub', data);\r\n    },\r\n    \r\n    sendDelAdToParent(data) {\r\n        this.sendToParent('dataDelAd', data);\r\n    },\r\n    \r\n    prepareUploadData() {\r\n        const keys = [\r\n            'AddNewRefInVosCampagnes',\r\n            'FirstUploadFileorMoved',\r\n            'LoadedPageUrl',\r\n            'codePage',\r\n            'Rank_Emplacement_Page_Web',\r\n            'Commande_Emplacement_Page_Web',\r\n            'dragstart_Commande_Emplacement_Page_Web',\r\n            'dragstart_Rank_Emplacement_Page_Web',  \r\n            'FullPathAdFile',\r\n            'Upload_File_Name',\r\n            'FileReceived',\r\n            'PageWebDisplayed',\r\n            'Commande_Format_Transmis',\r\n            'EspPubLienAnnonce',\r\n            'EnvoiUlterieur',\r\n            'Formatchoisi'\r\n        ];\r\n        \r\n        const data = StateManager.getMultiple(keys);\r\n        \r\n        \/\/ \u2705 v2.3.4 : Popup (Ele0A) \u2014 lire le format sous-jacent depuis le DOM\r\n        \/\/ StateManager contient 'PopUp' (virtuel), mais le vrai format est visuellement s\u00e9lectionn\u00e9 dans #Ele0A\r\n        if (data.Rank_Emplacement_Page_Web === 'Ele0A' || sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            var _ele0AFormatDOM = '';\r\n            jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdPopUp').each(function() {\r\n                if (jQuery(this).css('background-color') === 'rgb(255, 255, 255)') {\r\n                    var _cls = this.className || '';\r\n                    var _match = _cls.match(\/FormatId(\\S+)\/);\r\n                    if (_match) { _ele0AFormatDOM = _match[1]; return false; }\r\n                }\r\n            });\r\n            if (_ele0AFormatDOM) {\r\n                data.Commande_Format_Transmis = _ele0AFormatDOM;\r\n            }\r\n        }\r\n        \r\n        console.log('\ud83d\udce4 prepareUploadData:', {\r\n            FirstUploadFileorMoved: data.FirstUploadFileorMoved,\r\n            dragstart_Commande_Emplacement_Page_Web: data.dragstart_Commande_Emplacement_Page_Web,\r\n            Commande_Emplacement_Page_Web: data.Commande_Emplacement_Page_Web\r\n        });\r\n    \r\n        return data;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de rendu des aper\u00e7us de fichiers\r\n *\/\r\nconst PreviewRenderer = {\r\n    _getPositionLibelle(rankId) {\r\n        if (!rankId) return '';\r\n        var match = rankId.match(\/Ele(\\d+)[A-Z]\/);\r\n        if (!match) return '';\r\n        var rang = parseInt(match[1]);\r\n        if (rang === 0) return 'Pop-up';\r\n        if (rang === 1 || rang === 2) return 'Haut de page';\r\n        return 'Corps de page';\r\n    },\r\n    renderVideo(objectUrl, fileName, $dropZone) {\r\n        const videoElement = jQuery('<video controls autoplay muted>').attr({\r\n            'src': objectUrl,\r\n            'width': 'auto',\r\n            'height': 'auto',\r\n            'id': fileName\r\n        }).css({\r\n            'max-width': '100%',\r\n            'max-height': '100%'\r\n        });\r\n        \r\n        if (UIManager.isDesktop()) {\r\n            $dropZone.empty().append(videoElement.clone());\r\n            jQuery('#ApercuMobile').css({\r\n                'display': 'flex',\r\n                'justify-content': 'center',\r\n                'align-items': 'center'\r\n            }).append(videoElement);\r\n        } else {\r\n            const img = document.createElement('img');\r\n            img.src = objectUrl;\r\n            img.style.width = 'auto';\r\n            img.style.height = 'auto';\r\n            img.style.maxWidth = 'calc(100% - 4px)';  \/\/ \u2705 v2.4.5 : 2px retrait inset box-shadow\r\n            img.style.maxHeight = '115px';\r\n            \r\n            const container = $dropZone[0];\r\n            while (container.firstChild) {\r\n                container.removeChild(container.firstChild);\r\n            }\r\n            container.appendChild(img);\r\n        }\r\n        \r\n        StateManager.setMultiple({\r\n            'Commande_Format': 'Vid\u00e9o',\r\n            'Commande_Format_Transmis': 'Vid\u00e9o',\r\n            'videoSrc': objectUrl,\r\n            'FormatAnnonceSelection': 'Yes',\r\n            'PositionAnnonceSelection': 'Yes'\r\n        });\r\n        \r\n        jQuery('#FormatDataStep3').html('Vid\u00e9o').css({'color': '#56BE50'});\r\n        jQuery('#TarifDataStep3').css({'color': '#96894D'});\r\n    },\r\n    \r\n    renderImage(objectUrl, $dropZone) {\r\n        const maxHeight = UIManager.isMobile() ? 105 : $dropZone.closest('.HTMLUploadfileConteneur').height();\r\n    \r\n        $dropZone.css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center',\r\n            'width': '100%',\r\n            'height': maxHeight + 'px',\r\n            'overflow': 'hidden',\r\n            'position': UIManager.isMobile() ? 'relative' : '',\r\n            'top': UIManager.isMobile() ? '45px' : '',\r\n            'padding': UIManager.isMobile() ? '0 2px' : ''  \/\/ \u2705 v2.4.5 : 2px retrait inset box-shadow mobile\r\n        });\r\n    \r\n        \/\/ \u2705 v1.19.2 : Image charg\u00e9e en arri\u00e8re-plan, remplace le message d'attente au onload\r\n        \/\/ \u2705 v2.4.5 : max-width calc(100%-4px) sur mobile pour ne pas recouvrir le box-shadow inset 2px\r\n        var _mxw = UIManager.isMobile() ? 'calc(100% - 4px)' : '100%';\r\n        var img = new Image();\r\n        img.style.cssText = 'max-width:' + _mxw + '; max-height:' + maxHeight + 'px; width:auto; height:auto; object-fit:contain;';\r\n        img.onload = function() {\r\n            $dropZone.empty().append(img);\r\n        };\r\n        img.onerror = function() {\r\n            $dropZone.html('<img decoding=\"async\" src=\"' + objectUrl + '\" style=\"max-width:' + _mxw + '; max-height:' + maxHeight + 'px; width:auto; height:auto; object-fit:contain;\">');\r\n        };\r\n        img.src = objectUrl;\r\n    \r\n        StateManager.setMultiple({\r\n            'Commande_Format_Transmis': 'Image',\r\n            'FormatAnnonceSelection': 'Yes',\r\n            'PositionAnnonceSelection': 'Yes'\r\n        });\r\n    \r\n        console.log('Image ajout\u00e9e avec succ\u00e8s');\r\n    },\r\n    \r\n    async renderWord(fileObj, $dropZone) {\r\n        return new Promise((resolve, reject) => {\r\n            const reader = new FileReader();\r\n            \r\n            reader.onload = async (e) => {\r\n                try {\r\n                    const arrayBuffer = e.target.result;\r\n                    const result = await mammoth.convertToHtml({arrayBuffer: arrayBuffer});\r\n                    \r\n                    const htmlContent = result.value;\r\n                    const tempContainer = document.createElement('div');\r\n                    tempContainer.innerHTML = htmlContent;\r\n                    \r\n                    const textContent = tempContainer.textContent || \"\";\r\n                    const normalizedText = this.normalizeText(textContent);\r\n                    const firstImage = tempContainer.querySelector('img');\r\n                    \r\n                    const titleText = this.findDocumentTitle(normalizedText);\r\n                    \r\n                    if (firstImage) {\r\n                        this.renderDocumentPreview(\r\n                            $dropZone,\r\n                            firstImage.src,\r\n                            titleText,\r\n                            textContent,\r\n                            htmlContent\r\n                        );\r\n                    } else {\r\n                        \/\/ \u2705 v1.19.0 : Accepter les documents sans image\r\n                        this.renderDocumentPreview(\r\n                            $dropZone,\r\n                            null,\r\n                            titleText,\r\n                            textContent,\r\n                            htmlContent\r\n                        );\r\n                        console.log('\u2139\ufe0f Document Word sans image \u2014 aper\u00e7u texte seul');\r\n                    }\r\n                    resolve();\r\n                } catch (error) {\r\n                    $dropZone.html(`<p style=\"color: #FB5E2A; font-weight: 600; font-family: Roboto, Arial, sans-serif; font-size: 12px; text-align: center; padding: 15px;\">Erreur lors de la lecture du document<\/p>`);\r\n                    reject(error);\r\n                }\r\n            };\r\n            \r\n            reader.readAsArrayBuffer(fileObj);\r\n        });\r\n        \r\n        this.finalizeRedactionnelUpload();\r\n    },\r\n    \r\n    renderDocumentPreview($dropZone, imageSrc, title, text, htmlContent = null) {\r\n        \/\/ \u2705 v1.19.0 : Deux layouts \u2014 avec image ou texte seul\r\n        let previewHtml;\r\n\r\n        if (imageSrc) {\r\n            \/\/ Layout avec miniature image\r\n            previewHtml = `\r\n                <div class=\"doc-preview-container\">\r\n                    <div class=\"doc-preview-thumbnail\">\r\n                        <img decoding=\"async\" src=\"${imageSrc}\" alt=\"Document image\">\r\n                    <\/div>\r\n                    <div class=\"doc-preview-info\">\r\n                        <div class=\"doc-preview-title\" id=\"AdTitle\">${title}<\/div>\r\n                        <div class=\"doc-preview-description\" id=\"AdText\">${this.getTextPreview(text, 13)}<\/div>\r\n                        <div class=\"doc-preview-readmore\" id=\"AdLirelasuite\">Ouvrir et visualiser<\/div>\r\n                        <div class=\"doc-preview-FullPathAdFile\" id=\"AdFullPathAdFile\">${StateManager.get(\"FullPathAdFile\")}<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            `;\r\n        } else {\r\n            \/\/ Layout texte seul (sans image)\r\n            previewHtml = `\r\n                <div class=\"doc-preview-container doc-preview-noimage\">\r\n                    <div class=\"doc-preview-icon\">\r\n                        <svg width=\"36\" height=\"36\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#213864\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n                            <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\/><polyline points=\"14 2 14 8 20 8\"\/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"\/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"\/><polyline points=\"10 9 9 9 8 9\"\/>\r\n                        <\/svg>\r\n                    <\/div>\r\n                    <div class=\"doc-preview-info doc-preview-info-full\">\r\n                        <div class=\"doc-preview-title\" id=\"AdTitle\">${title}<\/div>\r\n                        <div class=\"doc-preview-description\" id=\"AdText\">${this.getTextPreview(text, 25)}<\/div>\r\n                        <div class=\"doc-preview-readmore\" id=\"AdLirelasuite\">Ouvrir et visualiser<\/div>\r\n                        <div class=\"doc-preview-FullPathAdFile\" id=\"AdFullPathAdFile\">${StateManager.get(\"FullPathAdFile\")}<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            `;\r\n        }\r\n        \r\n        $dropZone.html(previewHtml + this.getPreviewStyles());\r\n        \r\n        if (htmlContent) {\r\n            this.attachWordPreviewHandler($dropZone, title, htmlContent);\r\n        }\r\n    },\r\n    \r\n    attachWordPreviewHandler($dropZone, titleText, htmlContent) {\r\n        var $droppable = $dropZone.closest('.droppable');\r\n\r\n        \/\/ \u2705 Adapter le libell\u00e9 selon le type de document\r\n        var isInterview = (titleText || '').toLowerCase().indexOf('interview') !== -1;\r\n        var formatLabel = isInterview ? 'l\\'interview' : 'le communiqu\u00e9';\r\n        $droppable.find('.doc-preview-readmore').text('Ouvrir et visualiser ' + formatLabel);\r\n\r\n        \/\/ \u2705 v2.0.11 : D\u00e9l\u00e9gation d'\u00e9v\u00e9nement \u2014 plus robuste sur mobile (survit aux manipulations DOM)\r\n        $droppable.off('click.docpreview').on('click.docpreview', '.doc-preview-readmore', (event) => {\r\n            event.preventDefault();\r\n            event.stopPropagation();\r\n            \r\n            if (htmlContent) {\r\n                var popupTitle = isInterview ? 'Interview' : 'Communiqu\u00e9';\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    htmlContent: htmlContent\r\n                });\r\n            } else {\r\n                console.warn('Le document est encore en cours de traitement.');\r\n            }\r\n        });\r\n    },\r\n    \r\n    normalizeText(text) {\r\n        return text\r\n            .toLowerCase()\r\n            .normalize(\"NFD\")\r\n            .replace(\/[\\u0300-\\u036f]\/g, \"\");\r\n    },\r\n    \r\n    findDocumentTitle(normalizedText) {\r\n        const foundKeyword = CONFIG.keywords.find(keyword => \r\n            normalizedText.includes(keyword.normal)\r\n        );\r\n        if (foundKeyword) return foundKeyword.display;\r\n        \r\n        \/\/ \u2705 v1.19.1 : Fallback \u2014 utiliser le format s\u00e9lectionn\u00e9 (FormatSelect)\r\n        var formatSelect = (sessionStorage.getItem('FormatSelect') || '').toLowerCase();\r\n        if (formatSelect.indexOf('interview') !== -1) return 'Interview';\r\n        if (formatSelect.indexOf('communiq') !== -1) return 'Communiqu\u00e9';\r\n        \r\n        return \"Document\";\r\n    },\r\n    \r\n    getTextPreview(text, maxWords) {\r\n        const words = text.split(' ');\r\n        if (words.length > maxWords) {\r\n            return words.slice(0, maxWords).join(' ') + ' ...';\r\n        }\r\n        return text;\r\n    },\r\n    \r\n    getPreviewStyles() {\r\n        return `\r\n            <style>\r\n                @import url('https:\/\/fonts.googleapis.com\/css2?family=Roboto:wght@400;600&display=swap');\r\n                \r\n                .doc-preview-container {\r\n                    margin: 0px 0;\r\n                    display: flex;\r\n                    width: 100%;\r\n                    max-height: 140px;\r\n                    overflow: hidden;\r\n                    box-sizing: border-box;  \/* \u2705 v2.4.5 *\/\r\n                    background: white;\r\n                    background-color: #f8f8f8;\r\n                }\r\n                .doc-preview-thumbnail {\r\n                    width: 50%; \r\n                    height: 130px;\r\n                    overflow: hidden;\r\n                    display: flex;\r\n                    align-items: center;\r\n                    justify-content: center;\r\n                    margin-top: 0px;\r\n                }\r\n                .doc-preview-thumbnail img {\r\n                    max-width: 75%;\r\n                    max-height: 75%;\r\n                    object-position: center;\r\n                    object-fit: fill;\r\n                }\r\n                .doc-preview-info {\r\n                    width: 50%;\r\n                    height: 130px; \r\n                    flex: 1;\r\n                    padding: 10px;\r\n                    display: flex;\r\n                    flex-direction: column; \r\n                }\r\n                .doc-preview-title {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #213864;\r\n                    font-size: 14px;\r\n                    font-weight: 600;\r\n                    text-align: left;\r\n                    margin-bottom: 5px;\r\n                }\r\n                .doc-preview-description {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #213864;\r\n                    font-size: 11px;\r\n                    font-weight: 400;\r\n                    text-align: left;\r\n                    overflow: hidden;\r\n                    margin-bottom: 5px;\r\n                    flex: 1;\r\n                }\r\n                .doc-preview-readmore {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #958848;\r\n                    font-size: 13px;\r\n                    font-weight: 600;\r\n                    text-align: left;\r\n                    cursor: pointer;\r\n                    padding: 4px 0;\r\n                    -webkit-tap-highlight-color: rgba(149,136,72,0.2);\r\n                }\r\n                @media (max-width: 999px) {\r\n                    .doc-preview-readmore { font-size: 12px; }\r\n                    \/* \u2705 Laisser 3px tout autour pour que le liser\u00e9 vert (box-shadow\/outline sur parent) soit visible *\/\r\n                    .doc-preview-container {\r\n                        width: calc(100% - 16px) !important;\r\n                        max-height: 109px !important;\r\n                        margin: 3px !important;\r\n                        margin-top: 23px !important;\r\n                        box-sizing: border-box !important;\r\n                    }\r\n                }\r\n                .doc-preview-FullPathAdFile {\r\n                    display: none;\r\n                }\r\n                \/* \u2705 v1.19.0 : Layout sans image *\/\r\n                .doc-preview-noimage {\r\n                    flex-direction: row;\r\n                    align-items: flex-start;\r\n                    gap: 10px;\r\n                    padding: 8px 10px;\r\n                }\r\n                .doc-preview-icon {\r\n                    flex-shrink: 0;\r\n                    display: flex;\r\n                    align-items: center;\r\n                    justify-content: center;\r\n                    width: 44px;\r\n                    height: 44px;\r\n                    background: #eef2f7;\r\n                    border-radius: 6px;\r\n                    margin-top: 4px;\r\n                }\r\n                .doc-preview-info-full {\r\n                    width: 100%;\r\n                    height: auto;\r\n                    max-height: 130px;\r\n                }\r\n                .doc-preview-noimage .doc-preview-description {\r\n                    font-size: 11px;\r\n                    line-height: 1.35;\r\n                    max-height: 60px;\r\n                    overflow: hidden;\r\n                }\r\n            <\/style>\r\n        `;\r\n    },\r\n    \r\n    finalizeRedactionnelUpload() {\r\n        \/\/ \u2705 v1.19.5 : D\u00e9terminer le format r\u00e9dactionnel correct\r\n        \/\/ Si le format s\u00e9lectionn\u00e9 est \"Interview\", on garde \"Interview\"\r\n        \/\/ Sinon on met \"Communiqu\u00e9\" par d\u00e9faut (au lieu de \"R\u00e9dactionnel\" qui n'est pas un format tarifaire valide)\r\n        var formatSelect = sessionStorage.getItem('FormatSelect') || '';\r\n        var formatTransmis = 'Communiqu\u00e9'; \/\/ Par d\u00e9faut\r\n        \r\n        if (formatSelect.toLowerCase().indexOf('interview') !== -1) {\r\n            formatTransmis = 'Interview';\r\n        } else if (formatSelect.toLowerCase().indexOf('communiq') !== -1) {\r\n            formatTransmis = 'Communiqu\u00e9';\r\n        }\r\n        \r\n        StateManager.set('Commande_Format_Transmis', formatTransmis);\r\n        console.log('\u2705 Format r\u00e9dactionnel d\u00e9termin\u00e9:', formatTransmis, '(FormatSelect:', formatSelect, ')');\r\n        \r\n        if (StateManager.get(\"TarifDirectSelectionne\") === 'Yes') {\r\n            const formatText = jQuery('#FormatDataStep3').text();\r\n            if (formatText !== 'Vid\u00e9o' && formatText !== 'Banni\u00e8re') {\r\n                jQuery('#form-field-RedactionnelSelection')\r\n                    .val(formatText)\r\n                    .css({'color': '#56BE50'});\r\n            }\r\n        }\r\n        \r\n        RedactionnelDepose();\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'upload\r\n *\/\r\nconst UploadManager = {\r\n    isRunning: false,\r\n    \r\n    \/\/ \u2705 Reset manuel espace publicitaire\r\n    resetEspaceManuel: function($droppable) {\r\n        console.log('\ud83d\udd27 Reset manuel espace publicitaire');\r\n        \r\n        var $dropZone = $droppable.find('#drop_file_zone_achat');\r\n        var $uploadContainer = $droppable.find('.HTMLUploadfileConteneur');\r\n        var $container = $droppable.find('.OrdiMobileConteneurClass');\r\n        \r\n        \/\/ 1. Vider la zone de drop et restaurer le HTML par d\u00e9faut\r\n        $dropZone.empty().html(\r\n            '<div id=\"drag_upload_file_achat\">' +\r\n                '<p class=\"UploadIci\" style=\"color: #FB5E2A; font-weight: 600;\">Ici glisser \u2013 d\u00e9poser ou<br>t\u00e9l\u00e9charger une annonce<\/p>' +\r\n            '<\/div>'\r\n        );\r\n        \r\n        \/\/ 2. Afficher les \u00e9l\u00e9ments cach\u00e9s lors de l'upload\r\n        $droppable.find('.UploadIci').show();\r\n        $droppable.find('.EnvoiUlterieurTexte').show();\r\n        $droppable.find('.EnvoiUlterieurContainer').show();\r\n        $droppable.find('.EspPubFormatMainContainer').show();\r\n        $droppable.find('.EspPubFormatListe').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireClass').show();\r\n        $droppable.find('.GlisserDeposerConteneur').show();\r\n        $droppable.find('.OUClass').show();\r\n        $droppable.find('.TexteMobileAnnonce').show();\r\n        $droppable.find('.PositionReference').show();\r\n        $droppable.find('.ClassHdpCdp').show();\r\n        $droppable.find('.ClassRefEsp').show();\r\n        \r\n        \/\/ 3. Cacher les \u00e9l\u00e9ments d'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle').hide();\r\n        $droppable.find('#CroixResetAnnonce').hide();\r\n        $droppable.find('.CroixResetAnnonceContainer').hide();\r\n        $droppable.find('.DeplaceAnnonce').hide();\r\n        $droppable.find('.RefEspacePublicitaire').hide();\r\n        $droppable.find('.AdDroppedTextNotDisplayed').hide();\r\n        \r\n        \/\/ 4. Reset des styles\r\n        $uploadContainer.css({\r\n            'border': 'none',\r\n            'background-color': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': ''\r\n        });\r\n        \r\n        $container.css({\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'top': '',\r\n            'height': ''\r\n        });\r\n        \r\n        \/\/ \u2705 Reset des positionnements desktop appliqu\u00e9s par adjustDesktopLayout\r\n        $droppable.closest('.ToBeHidden').css({'top': '', 'min-height': ''});\r\n        $droppable.parent().css('overflow', '');\r\n        \/\/ \u2705 v2.0.11 : Cleanup event namespace docpreview\r\n        $droppable.off('click.docpreview');\r\n        \r\n        \/\/ 5. Reset des formats s\u00e9lectionn\u00e9s\r\n        $droppable.find('.EspPubFormatContainer').css({\r\n            'background-color': '',\r\n            'border': ''\r\n        });\r\n        \r\n        \/\/ 6. Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ 7. Restaurer .PositionEspacePublicitaireContainer et .ReserverContainer\r\n        $droppable.find('.PositionEspacePublicitaireContainer').show();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        console.log('\u2705 Reset manuel termin\u00e9');\r\n    },\r\n    \r\n    async handleFileUpload(fileObj, $dropZone) {\r\n        console.log('fileObj:', fileObj);\r\n        \r\n        \/\/ \u2705 v2.4.6 : Contr\u00f4les d'extension EN PREMIER \u2014 avant tout affichage\r\n        const extension = FileManager.getExtension(fileObj.name);\r\n        StateManager.set('FileExtension', extension);\r\n        console.log('FileExtension:', extension);\r\n        \r\n        \/\/ \u2705 v2.6 : jpg\/jpeg accept\u00e9s sur desktop et mobile\r\n        \r\n        if (!FileManager.isAllowedExtension(extension)) {\r\n            UIManager.showFormatError($dropZone);\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.5 : Afficher le message d'attente seulement si le format est valide\r\n        var _waitMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.html('<div class=\"ad-loading-msg\" style=\"color:#00ff19; background:white; padding:12px 20px; border-radius:6px; font-weight:700; text-align:center; font-size:18px; line-height:1.4;\">' + _waitMsg + '<\/div>');\r\n        \r\n        this.prepareUIForUpload($dropZone);\r\n        \r\n        const formData = new FormData();\r\n        formData.append('file', fileObj);\r\n        formData.append('action', 'upload_annonce_file_v3');\r\n        \r\n        UIManager.showUploadProgress($dropZone);\r\n        \r\n        try {\r\n            const response = await this.sendUploadRequest(formData);\r\n            await this.handleUploadResponse(response, fileObj, $dropZone, extension);\r\n        } catch (error) {\r\n            console.error('Upload error:', error);\r\n        }\r\n    },\r\n    \r\n    prepareUIForUpload($dropZone) {\r\n        if (!UIManager.isMobile()) {\r\n            jQuery('.ChoisirEspacePublicitaireClass').show();\r\n            jQuery('.ChoisirEspacePublicitaire2ndLigne').show();\r\n            jQuery('.GlisserDeposerConteneur').show();\r\n            jQuery('.OUClass').show();\r\n            \/\/ \u2705 Cibler uniquement le droppable courant \u2014 ne pas r\u00e9afficher sur les espaces d\u00e9j\u00e0 upload\u00e9s\r\n            $dropZone.closest('.droppable').find('.UploadIci').show();\r\n        }\r\n        \r\n        if (StateManager.get(\"PopUpChoice\") === 'Yes') {\r\n            \/\/ \u2705 Ne masquer DeplaceAnnonce QUE sur Ele0A \u2014 pas sur Ele1A qui a deja une annonce chargee\r\n            $dropZone.closest('.OrdiMobileConteneurClass').find('.DeplaceAnnonce').each(function() {\r\n                var _d = jQuery(this).closest('.droppable')[0];\r\n                if (_d && _d.getAttribute('data-via-ad-loaded') === 'true') { return; }\r\n                jQuery(this).hide();\r\n            });\r\n            $('.AnnonceDragIcone').show().find('img').attr('alt', '');\r\n        } else {\r\n            $('.AnnonceDragIcone').hide();\r\n        }\r\n        \r\n        if (StateManager.get(\"Commande_Page\") === 'Home Page') {\r\n            jQuery('#HPTarifConteneur').css({'background-color': '#B5FFB1'});\r\n        }\r\n        \r\n        jQuery('.ChoisirEspacePublicitaireClass').css({'color': '#ffffff'});\r\n        jQuery('.InterfaceTitreDore').not('#PageWebTitreDore')\r\n            .html(\"Merci de choisir les \u00e9l\u00e9ments de votre campagne publicitaire\");\r\n        jQuery('#ProcessCommande').show();\r\n    },\r\n    \r\n    sendUploadRequest(formData) {\r\n        \/\/ \u2705 v2.6 : dataType 'text' pour eviter parsererror si texte parasite apres le JSON\r\n        return jQuery.ajax({\r\n            url: CONFIG.ajaxUrl,\r\n            type: 'POST',\r\n            data: formData,\r\n            cache: false,\r\n            contentType: false,\r\n            processData: false,\r\n            dataType: 'text'\r\n        }).then(function(text) {\r\n            \/\/ Extraire le JSON meme si du texte parasite suit\r\n            var _json = null;\r\n            try {\r\n                var _match = text.match(\/(\\{[\\s\\S]*?\\})(?:[^{]|$)\/);\r\n                _json = JSON.parse(_match ? _match[1] : text);\r\n            } catch(_e) {\r\n                return jQuery.Deferred().reject({ responseText: text }).promise();\r\n            }\r\n            \/\/ Normaliser le format vers {success, data} attendu par handleUploadResponse\r\n            if (_json.status === 'success') {\r\n                var _fp = _json.file_path || '';\r\n                var _baseUrl = CONFIG.ajaxUrl.replace('\/wp-admin\/admin-ajax.php', '\/wp-content\/');\r\n                return {\r\n                    success: true,\r\n                    data: {\r\n                        file_url:  _baseUrl + _fp,\r\n                        file_name: _fp.replace(\/^.*\\\/\/, ''),\r\n                        file_path: _fp\r\n                    }\r\n                };\r\n            }\r\n            \/\/ Format WordPress standard {success, data} - retourner tel quel\r\n            return _json;\r\n        });\r\n    },\r\n    \r\n    async handleUploadResponse(response, fileObj, $dropZone, extension) {\r\n        console.log('\u2705 R\u00e9ponse re\u00e7ue');\r\n        \r\n        if (response.responseJSON) {\r\n            response = response.responseJSON;\r\n        }\r\n        \r\n        console.log('\u2705 Response pars\u00e9e:', response);\r\n        \r\n        if (!response.success || !response.data) {\r\n            \/\/ \u2705 v2.1.2 : Si c'est une restauration (_isAdRestoration = 'Yes'),\r\n            \/\/ le fichier existe d\u00e9j\u00e0 sur le serveur \u2192 afficher l'image depuis le fileObj local\r\n            if (StateManager.get('_isAdRestoration') === 'Yes' && fileObj) {\r\n                console.log('\ud83d\udd04 Restauration: upload \u00e9chou\u00e9 (fichier existant) \u2192 rendu local');\r\n                \r\n                FileManager.createObjectUrl(fileObj);\r\n                StateManager.set('FileReceived', 'Yes');\r\n                \r\n                \/\/ \u2705 v2.1.2 : Restaurer l'\u00e9tat EnvoiUlterieur depuis le sessionStorage parent\r\n                var _restoredEnvoi = sessionStorage.getItem('_restoredEnvoiUlterieur');\r\n                if (_restoredEnvoi === 'true') {\r\n                    StateManager.set('EnvoiUlterieur', 'true');\r\n                    StateManager.set('FileReceived', 'No');\r\n                    StateManager.set('FullPathAdFile', '');\r\n                    console.log('\ud83d\udce4 Restauration EnvoiUlterieur = true');\r\n                }\r\n                \r\n                var _objUrl = StateManager.get('objectUrl');\r\n                var _fileType = FileManager.getFileType(extension);\r\n                \r\n                StateManager.set('FormatReconnu', 'No');\r\n                \r\n                switch (_fileType) {\r\n                    case 'video':\r\n                        PreviewRenderer.renderVideo(_objUrl, fileObj.name, $dropZone);\r\n                        StateManager.set('FormatReconnu', 'Yes');\r\n                        break;\r\n                    case 'image':\r\n                        PreviewRenderer.renderImage(_objUrl, $dropZone);\r\n                        StateManager.set('FormatReconnu', 'Yes');\r\n                        break;\r\n                    case 'document':\r\n                        \/\/ \u2705 v2.1.2 : Documents Word\/PDF aussi en restauration\r\n                        await this.handleDocumentUpload(extension, fileObj, $dropZone);\r\n                        break;\r\n                }\r\n                \r\n                UIManager.updateAfterSuccessfulUpload($dropZone);\r\n                \r\n                if (StateManager.get('FormatReconnu') === 'Yes') {\r\n                    this.finalizeUpload($dropZone);\r\n                    $('#MsgSelectEspace').hide();\r\n                }\r\n                \r\n                FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n                console.log('\u2705 Restauration visuelle termin\u00e9e (upload bypass)');\r\n                StateManager.set('_isAdRestoration', 'No');\r\n            }\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 SAUVEGARDER les infos de d\u00e9placement AVANT updateStateAfterUpload\r\n        const isMoved = StateManager.get('FirstUploadFileorMoved') === 'Moved';\r\n        const dragstartRankId = StateManager.get('dragstart_Rank_Emplacement_Page_Web');\r\n        const currentRankId = StateManager.get('Rank_Emplacement_Page_Web');\r\n        const shouldResetOldSpace = isMoved && dragstartRankId && dragstartRankId !== currentRankId;\r\n        \r\n        console.log('\ud83d\udd0d D\u00e9placement?', { isMoved, dragstartRankId, currentRankId, shouldResetOldSpace });\r\n        \r\n        this.updateStateAfterUploadWithoutReset(response, fileObj);\r\n        \r\n        const fileType = FileManager.getFileType(extension);\r\n        \r\n        StateManager.set('FormatReconnu', 'No');\r\n        \r\n        \/\/ \u2705 v1.19.2 : Message d'attente IMM\u00c9DIAT avant le rendu de l'annonce\r\n        var _waitMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.html('<div class=\"ad-loading-msg\" style=\"color:#00ff19; background:white; padding:12px 20px; border-radius:6px; font-weight:700; text-align:center; font-size:18px; line-height:1.4;\">' + _waitMsg + '<\/div>');\r\n        \r\n        switch (fileType) {\r\n            case 'video':\r\n                PreviewRenderer.renderVideo(StateManager.get('objectUrl'), fileObj.name, $dropZone);\r\n                StateManager.set('FormatReconnu', 'Yes');\r\n                break;\r\n                \r\n            case 'image':\r\n                PreviewRenderer.renderImage(StateManager.get('objectUrl'), $dropZone);\r\n                StateManager.set('FormatReconnu', 'Yes');\r\n                break;\r\n                \r\n            case 'document':\r\n                await this.handleDocumentUpload(extension, fileObj, $dropZone);\r\n                break;\r\n        }\r\n        \r\n        UIManager.updateAfterSuccessfulUpload($dropZone);\r\n        \r\n        if (StateManager.get('FormatReconnu') === 'Yes') {\r\n            this.finalizeUpload($dropZone);\r\n            $('#MsgSelectEspace').hide();\r\n        }\r\n        \r\n        \/\/ \u2705 RESET L'ANCIEN ESPACE ICI - APR\u00c8S avoir affich\u00e9 la nouvelle image\r\n        \/\/ \u2705 v2.4.5 : Toujours initialiser \u00e0 false avant le bloc (\u00e9vite la valeur r\u00e9siduelle)\r\n        var _sourceWasReserved = false;\r\n        StateManager.set('_sourceWasReserved', 'No');\r\n        \r\n        if (shouldResetOldSpace) {\r\n            console.log('\ud83d\udd04 Reset ancien espace:', dragstartRankId);\r\n            \r\n            var $oldDroppable = $('#' + dragstartRankId);\r\n            \r\n            if ($oldDroppable.length) {\r\n                var $container = $oldDroppable.find('.OrdiMobileConteneurClass').first();\r\n                \r\n                \/\/ \u2705 v2.4.5 : Utiliser l'\u00e9tat captur\u00e9 au dragstart (fiable vs re-check async)\r\n                if ($container.length) {\r\n                    _sourceWasReserved = StateManager.get('dragstart_ReserverChecked') === 'Yes';\r\n                    console.log('[d\u00e9placement] ReserverChecked au dragstart:', _sourceWasReserved, '| rank:', dragstartRankId);\r\n                    StateManager.set('_sourceWasReserved', _sourceWasReserved ? 'Yes' : 'No');\r\n                    RestoreadSpaceTemplateLocal($container[0]);\r\n                }\r\n            }\r\n        }\r\n        StateManager.set(\"EnvoiUlterieur\", 'false');\r\n        \r\n        \/\/ \u2705 v1.19.1 : Positionner l'espace \u00e0 10px du haut du viewport apr\u00e8s upload\r\n        setTimeout(function() {\r\n            var el = $dropZone.closest('.droppable').find('.HTMLUploadfileConteneur')[0]\r\n                     || $dropZone.closest('.droppable')[0];\r\n            if (el) {\r\n                ScrollHelper.scrollElementTo(el, 10);\r\n            }\r\n        }, 400);\r\n        \r\n        \/\/ \u2705 NE PLUS envoyer automatiquement - c'est la checkbox \"R\u00e9server\" qui d\u00e9clenche\r\n        \/\/ On met \u00e0 jour l'\u00e9tat de la checkbox pour qu'elle devienne activable\r\n        FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n        \r\n        \/\/ \u2705 v2.4.5 : Si l'espace source \u00e9tait r\u00e9serv\u00e9, cocher la checkbox de l'espace cible\r\n        if (StateManager.get('_sourceWasReserved') === 'Yes') {\r\n            var $targetCb = $dropZone.closest('.droppable').find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n            if ($targetCb.length && !$targetCb.prop('checked')) {\r\n                $targetCb.prop('checked', true).trigger('change');\r\n                console.log('\u2705 [d\u00e9placement] Checkbox R\u00e9server coch\u00e9e sur espace cible');\r\n            }\r\n            StateManager.set('_sourceWasReserved', 'No');\r\n        }\r\n        \r\n        console.log('\ud83d\udccb Upload termin\u00e9 - en attente de validation via checkbox \"R\u00e9server\"');\r\n    },\r\n    \r\n    updateStateAfterUploadWithoutReset(response, fileObj) {\r\n        StateManager.setMultiple({\r\n            \"PageWhithADType\": StateManager.get('SelectedPageType'),\r\n            \"PageWhithADSecteur\": StateManager.get('SelectedPageSecteur')\r\n        });\r\n        \r\n        $('#BackPageWebWithADCroix').hide();\r\n        jQuery('#ApercuMobile').empty().css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center'\r\n        });\r\n        \r\n        const firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n        \r\n        if (firstUploadOrMoved === 'FirstUpload') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": response.data.file_url,\r\n                \"fileObj\": fileObj,\r\n                \"Upload_File_Name\": fileObj.name\r\n            });\r\n            \r\n            FileManager.createObjectUrl(fileObj);\r\n            \r\n            console.log('\ud83d\udcc1 Fichier upload\u00e9:', {\r\n                fullUrl: response.data.file_url,\r\n                fileName: response.data.file_name,\r\n                filePath: response.data.file_path\r\n            });\r\n        }\r\n    },\r\n    \r\n    updateStateAfterUpload(response, fileObj) {\r\n        StateManager.setMultiple({\r\n            \"PageWhithADType\": StateManager.get('SelectedPageType'),\r\n            \"PageWhithADSecteur\": StateManager.get('SelectedPageSecteur')\r\n        });\r\n        \r\n        $('#BackPageWebWithADCroix').hide();\r\n        jQuery('#ApercuMobile').empty().css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center'\r\n        });\r\n        \r\n        const firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n        console.log('\ud83d\udd0d FirstUploadFileorMoved:', firstUploadOrMoved);\r\n        \r\n        if (firstUploadOrMoved === 'FirstUpload') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": response.data.file_url,\r\n                \"fileObj\": fileObj,\r\n                \"Upload_File_Name\": fileObj.name\r\n            });\r\n            \r\n            FileManager.createObjectUrl(fileObj);\r\n            \r\n            console.log('\ud83d\udcc1 Fichier upload\u00e9:', {\r\n                fullUrl: response.data.file_url,\r\n                fileName: response.data.file_name,\r\n                filePath: response.data.file_path\r\n            });\r\n        } else if (firstUploadOrMoved === 'Moved') {\r\n            const dragstartRankId = StateManager.get('dragstart_Rank_Emplacement_Page_Web');\r\n            const currentRankId = StateManager.get('Rank_Emplacement_Page_Web');\r\n            \r\n            console.log('\ud83d\udd04 D\u00c9PLACEMENT D\u00c9TECT\u00c9');\r\n            console.log('   Ancien espace (dragstart):', dragstartRankId);\r\n            console.log('   Nouvel espace (current):', currentRankId);\r\n            \r\n            if (dragstartRankId && dragstartRankId !== currentRankId) {\r\n                const $oldDroppable = $('#' + dragstartRankId);\r\n                \r\n                console.log('   $oldDroppable trouv\u00e9:', $oldDroppable.length > 0);\r\n                \r\n                if ($oldDroppable.length) {\r\n                    const $container = $oldDroppable.find('.OrdiMobileConteneurClass');\r\n                    \r\n                    console.log('   $container trouv\u00e9:', $container.length > 0);\r\n                    \r\n                    if ($container.length) {\r\n                        console.log('\ud83d\udd27 Appel RestoreadSpaceTemplate sur:', $container[0]);\r\n                        \r\n                        if (typeof window.RestoreadSpaceTemplate === 'function') {\r\n                            window.RestoreadSpaceTemplate($container[0]);\r\n                            console.log('\u2705 RestoreadSpaceTemplate ex\u00e9cut\u00e9');\r\n                        }\r\n                    } else {\r\n                        console.warn('\u26a0\ufe0f .OrdiMobileConteneurClass non trouv\u00e9 dans', dragstartRankId);\r\n                    }\r\n                }\r\n            } else {\r\n                console.log('\u23ed\ufe0f M\u00eame espace ou dragstartRankId invalide, pas de reset');\r\n            }\r\n        }\r\n    },\r\n        \r\n    async handleDocumentUpload(extension, fileObj, $dropZone) {\r\n        StateManager.set('FormatReconnu', 'Yes');\r\n        \r\n        \/\/ \u2705 Cacher le File r\u00e9dactionnel pour r\u00e9utilisation lors des d\u00e9placements (\u00e9vite CORS)\r\n        window._lastRedactionnelFile = fileObj;\r\n        \r\n        if (extension === 'doc' || extension === 'docx') {\r\n            await new Promise(resolve => window.VIALibraries.loadMammoth(resolve));\r\n            await PreviewRenderer.renderWord(fileObj, $dropZone);\r\n        } else if (extension === 'ppt' || extension === 'pptx') {\r\n            this.renderPowerPoint($dropZone);\r\n            PreviewRenderer.finalizeRedactionnelUpload();\r\n        } else if (extension === 'pdf') {\r\n            await new Promise(resolve => window.VIALibraries.loadPdfJs(resolve));\r\n            await PDFHandler.renderPDF(fileObj, $dropZone);\r\n            PreviewRenderer.finalizeRedactionnelUpload();\r\n        }\r\n    },\r\n    \r\n    renderPowerPoint($dropZone) {\r\n        const img = jQuery('<img \/>', {\r\n            src: '\/wp-content\/uploads\/2024\/06\/microsoft-powerpoint.png',\r\n            css: {\r\n                'width': 'auto',\r\n                'height': 'auto',\r\n                'margin-bottom': '20px',\r\n                'max-width': '150px',\r\n                'max-height': '160px'\r\n            }\r\n        });\r\n        $dropZone.empty().append(img.clone());\r\n        jQuery('#ApercuMobile').append(img);\r\n    },\r\n    \r\n    finalizeUpload($dropZone) {\r\n        \/\/ \u2705 Reset sendDataToParentFlag : nouvel upload = pas encore r\u00e9serv\u00e9\r\n        StateManager.set('sendDataToParentFlag', 'No');\r\n        \r\n        StateManager.setMultiple({\r\n            \"PageAnnonceSelection\": 'Yes',\r\n            \"FormatReconnu\": 'Yes'\r\n        });\r\n        \r\n        jQuery('#MsgChoixPageWeb, #MsgInsererAnnonceConteneur').hide();\r\n        \r\n        if (StateManager.get(\"Commande_Format\") === 'R\u00e9dactionnel') {\r\n            StateManager.set('Commande_Format', '\u00e0 choisir');\r\n            RedactionnelDepose();\r\n        }\r\n        \r\n        if (StateManager.get(\"Commande_Page\") === ' ') {\r\n            jQuery('#HPTarifConteneur').css({'background-color': '#BCFFAD'});\r\n            jQuery('#EmplacementDataStep3').html(\"Home Page\");\r\n            StateManager.setMultiple({\r\n                \"Commande_Page\": 'Home Page',\r\n                \"PageAnnonceSelection\": 'Yes'\r\n            });\r\n        }\r\n        \r\n        $('#PageWeb').css('zoom', '70%');\r\n        $('#PageWebTitreDore').css({'font-size': '14px'});\r\n        \r\n        if (!UIManager.isMobile()) {\r\n            $('#PageWebTitreDore').css({'color': '#213864'});\r\n        }\r\n        \r\n        StateManager.set(\"Page_Web_with_AD_URL\", StateManager.get(\"Page_Web_URL\"));\r\n        \r\n        UIManager.finalizeAdDisplay($dropZone);\r\n        \r\n        \/\/ \u2705 Notifier le parent de l'annonce d\u00e9pos\u00e9e non r\u00e9serv\u00e9e \u2014 pour restauration au retour sur la page\r\n        var _fileRcv = StateManager.get('FileReceived');\r\n        var _isRestoring = StateManager.get('_isAdRestoration') === 'Yes';\r\n        console.log('\ud83d\udfe1 [finalizeUpload] FileReceived:', _fileRcv, '| _isAdRestoration:', _isRestoring);\r\n        if (_fileRcv === 'Yes' && !_isRestoring) {\r\n            var _pendingRank = StateManager.get('Rank_Emplacement_Page_Web') || $dropZone.closest('.droppable').attr('id') || '';\r\n            console.log('\ud83d\udfe1 [finalizeUpload] pendingRank:', _pendingRank, '| FullPathAdFile:', StateManager.get('FullPathAdFile'));\r\n            if (_pendingRank) {\r\n                console.log('\ud83d\udce4 [finalizeUpload] annonceDeposeeSansReservation \u2192 parent rank:', _pendingRank);\r\n                \/\/ \u2705 D\u00e9terminer le vrai format commercial selon le type de fichier d\u00e9pos\u00e9 + format s\u00e9lectionn\u00e9\r\n                var _formatSelect = sessionStorage.getItem('FormatSelect') || StateManager.get('Commande_Format_Transmis') || '';\r\n                var _uploadedExt = (StateManager.get('Upload_File_Name') || '').split('.').pop().toLowerCase();\r\n                var _fileKind = CONFIG.allowedExtensions.video.indexOf(_uploadedExt) !== -1 ? 'video'\r\n                              : CONFIG.allowedExtensions.image.indexOf(_uploadedExt) !== -1 ? 'image'\r\n                              : CONFIG.allowedExtensions.document.indexOf(_uploadedExt) !== -1 ? 'document'\r\n                              : '';\r\n                var _formatPending;\r\n                if (_fileKind === 'video') {\r\n                    \/\/ Vid\u00e9o \u2192 toujours Vid\u00e9o\r\n                    _formatPending = 'Vid\u00e9o';\r\n                } else if (_fileKind === 'image') {\r\n                    \/\/ Image \u2192 Banni\u00e8re ou Parrainage si s\u00e9lectionn\u00e9, sinon Banni\u00e8re par d\u00e9faut\r\n                    var _imgFormats = ['Banni\u00e8re', 'Banniere', 'Parrainage'];\r\n                    _formatPending = (_imgFormats.indexOf(_formatSelect) !== -1) ? _formatSelect : 'Banni\u00e8re';\r\n                } else if (_fileKind === 'document') {\r\n                    \/\/ Document \u2192 Communiqu\u00e9 ou Interview si s\u00e9lectionn\u00e9, sinon Communiqu\u00e9 par d\u00e9faut\r\n                    var _docFormats = ['Communiqu\u00e9', 'Communique', 'Interview'];\r\n                    _formatPending = (_docFormats.indexOf(_formatSelect) !== -1) ? _formatSelect : 'Communiqu\u00e9';\r\n                } else {\r\n                    \/\/ Fallback\r\n                    _formatPending = _formatSelect || StateManager.get('Commande_Format_Transmis') || '';\r\n                }\r\n                \/\/ \u2705 v2.4.9 : Si le format d\u00e9duit diff\u00e8re du format s\u00e9lectionn\u00e9 \u2192 mettre \u00e0 jour vignette + sessionStorage\r\n                if (_formatPending && _formatPending !== _formatSelect) {\r\n                    StateManager.set('FormatSelect', _formatPending);\r\n                    StateManager.set('Commande_Format_Transmis', _formatPending);\r\n                    StateManager.set('Formatchoisi', 'Yes');\r\n                    \/\/ Mettre \u00e0 jour visuellement la vignette dans le droppable courant\r\n                    var _fmtNorm = _formatPending.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    var $_drp = $dropZone.closest('.droppable');\r\n                    $_drp.find('.EspPubFormatContainer').each(function() {\r\n                        var _cls = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                        if (_cls.includes(_fmtNorm)) {\r\n                            jQuery(this).css({'background-color': '#ffffff'});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        } else if (!jQuery(this).hasClass('FormatIdPopUp')) {\r\n                            jQuery(this).css({'background-color': ''});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': ''});\r\n                        }\r\n                    });\r\n                    \/\/ Mettre \u00e0 jour aussi le bandeau parent via postMessage\r\n                    MessageManager.sendToParent('formatChangedInIframe', { formatSelect: _formatPending, rank: _pendingRank });\r\n                    console.log('\ud83d\udd04 [finalizeUpload] Format corrig\u00e9:', _formatSelect, '\u2192', _formatPending);\r\n                }\r\n                var _firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n                var _isMoved = _firstUploadOrMoved === 'Moved';\r\n                var _oldRankMoved = _isMoved ? (StateManager.get('dragstart_Rank_Emplacement_Page_Web') || '') : '';\r\n                MessageManager.sendToParent('annonceDeposeeSansReservation', {\r\n                    Rank_Emplacement_Page_Web: _pendingRank,\r\n                    FullPathAdFile: StateManager.get('FullPathAdFile') || '',\r\n                    Upload_File_Name: StateManager.get('Upload_File_Name') || '',\r\n                    LoadedPageUrl: window.location.href,\r\n                    FileReceived: 'Yes',\r\n                    \/\/ \u2705 Lire EnvoiUlterieur depuis la checkbox du droppable courant (pas le StateManager global)\r\n                    \/\/ StateManager.get('EnvoiUlterieur') est global \u2192 peut valoir 'true' si un autre espace a sa checkbox coch\u00e9e\r\n                    EnvoiUlterieur: ($dropZone.closest('.droppable').find('input[name*=\"EnvoiUlterieur\"]').prop('checked') ? 'true' : 'false'),\r\n                    Commande_Format_Transmis: _formatPending,\r\n                    codeSite: StateManager.get('codeSite') || '',\r\n                    codePage: StateManager.get('codePage') || '',\r\n                    Commande_Emplacement_Page_Web: StateManager.buildEmplacementReference(_pendingRank),\r\n                    isMoved: _isMoved,\r\n                    oldRank: _oldRankMoved\r\n                });\r\n            }\r\n        }\r\n    },\r\n    \r\n    activateSendDataToParent($dropZone) {\r\n        if (StateManager.get(\"sendDataToParentFlag\") !== 'Yes') {\r\n            return;\r\n        }\r\n        \r\n        if (StateManager.get(\"FirstUploadFileorMoved\") === 'Moved') {\r\n            const dragstartRef = StateManager.buildEmplacementReference(\r\n                StateManager.get(\"dragstart_Rank_Emplacement_Page_Web\")\r\n            );\r\n            StateManager.set('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n        }\r\n        \r\n        console.log('Esp Pub Ref FirstUploadFileorMoved:', StateManager.get(\"FirstUploadFileorMoved\"));\r\n        console.log('Esp Pub dragstart_Commande:', StateManager.get(\"dragstart_Commande_Emplacement_Page_Web\"));\r\n        \r\n        if (StateManager.get(\"PageAjoutModifAnnonce\") === 'Yes') {\r\n            this.handlePageModification($dropZone);\r\n        } else {\r\n            this.handleNormalUpload();\r\n        }\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        setTimeout(() => {\r\n            StateManager.set(\"AddNewRefInVosCampagnes\", 'Yes');\r\n        }, 4000);\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            StateManager.set('Commande_Format_Transmis', '');\r\n        }\r\n    },\r\n    \r\n    handlePageModification($dropZone) {\r\n        $('#CroixResetAnnonce, .DeplaceAnnonce').hide();\r\n        $('.PageAjoutModifAnnonceCroixResetAnnonce').show();\r\n        \r\n        const emplacementRef = $dropZone.closest('.CampagnesTemplateClass')\r\n            .find('.ReferenceEspace').text();\r\n        \r\n        console.log('Commande_Emplacement_Page_Web:', emplacementRef);\r\n        \r\n        jQuery.ajax({\r\n            type: \"POST\",\r\n            url: CONFIG.ajaxUrl,\r\n            data: {\r\n                action: 'via_update_fichier_annonce',\r\n                commande_ref_url: StateManager.get(\"commande_ref_url\"),\r\n                emplacement_page_web: emplacementRef,\r\n                chemin_fichier: StateManager.get(\"FullPathAdFile\")\r\n            },\r\n            xhrFields: { withCredentials: true },\r\n            success: (response) => {\r\n                if (response.success) {\r\n                    console.log('\u2705 Fichier annonce mis \u00e0 jour:', response.data.message);\r\n                    location.reload();\r\n                } else {\r\n                    console.error('\u274c Erreur:', response.data.message);\r\n                }\r\n            },\r\n            error: (xhr, status, error) => {\r\n                console.error('\u274c Erreur AJAX:', error);\r\n            }\r\n        });\r\n    },\r\n    \r\n    handleNormalUpload() {\r\n        if (StateManager.get(\"EnvoiUlterieur\") === 'true') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": '',\r\n                \"Upload_File_Name\": ''\r\n            });\r\n        }\r\n        \r\n        StateManager.set(\"LoadedPageUrl\", window.location.href);\r\n        \r\n        console.log('EnvoiUlterieur:', StateManager.get(\"EnvoiUlterieur\"));\r\n        console.log('LoadedPageUrl:', StateManager.get(\"LoadedPageUrl\"));\r\n        console.log('FileReceived:', StateManager.get(\"FileReceived\"));\r\n        \r\n        const data = MessageManager.prepareUploadData();\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            MessageManager.sendDataToParent(data);\r\n        } else {\r\n            const formatChoisi = StateManager.get(\"Formatchoisi\") === 'Yes';\r\n            const fichierDepose = StateManager.get(\"FileReceived\") === 'Yes';\r\n            const envoiDiffere = StateManager.get(\"EnvoiUlterieur\") === 'true';\r\n            \r\n            console.log('\ud83d\udd0d handleNormalUpload - Conditions:', { formatChoisi, fichierDepose, envoiDiffere });\r\n            \r\n            if (formatChoisi && (fichierDepose || envoiDiffere)) {\r\n                if (typeof window.handleEspacePubData === 'function') {\r\n                    window.handleEspacePubData(data);\r\n                } else {\r\n                    console.warn('\u26a0\ufe0f handleEspacePubData non disponible, fallback direct');\r\n                    if (typeof window.executeWithProcessLoaded === 'function') {\r\n                        window.executeWithProcessLoaded(function() {\r\n                            jQuery('#PopupProcessCommandeContainer').show();\r\n                        });\r\n                    } else {\r\n                        jQuery('#PopupProcessCommandeContainer').show();\r\n                    }\r\n                }\r\n            } else if (formatChoisi) {\r\n                console.log('\ud83d\udcdd Mise \u00e0 jour format uniquement');\r\n                \r\n                const borderStyle = {'box-shadow': 'inset 0 0 0 2px #00FF19', 'box-sizing': 'border-box'};  \/\/ \u2705 v2.4.5\r\n                \r\n                jQuery(\".FormatClassique, .FormatPopup\").css({'border': 'none'});\r\n                \r\n                jQuery('.FormatClassique, .FormatPopup').each(function() {\r\n                    \/\/ \u2705 v2.1.1 : NFD normalize both sides\r\n                    var _cn = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    var _cf = (data.Commande_Format_Transmis || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    if (_cn.includes(_cf) && _cf) {\r\n                        jQuery(this).css(borderStyle);\r\n                    }\r\n                });\r\n            }\r\n        }\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        setTimeout(() => {\r\n            StateManager.set(\"AddNewRefInVosCampagnes\", 'Yes');\r\n        }, 4000);\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            StateManager.set('Commande_Format_Transmis', '');\r\n        }\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des fichiers PDF (s\u00e9par\u00e9 pour \u00e9viter la complexit\u00e9)\r\n *\/\r\nconst PDFHandler = {\r\n    pdfData: null,\r\n    pdfDataForViewer: null,\r\n    \r\n    async renderPDF(fileObj, $dropZone) {\r\n        return new Promise((resolve, reject) => {\r\n            const reader = new FileReader();\r\n            \r\n            reader.onload = async (e) => {\r\n                try {\r\n                    const arrayBuffer = e.target.result;\r\n                    this.pdfData = new Uint8Array(arrayBuffer);\r\n                    this.pdfDataForViewer = arrayBuffer;\r\n                    \r\n                    console.log(\"Initial PDF load, size:\", this.pdfData.byteLength);\r\n                    \r\n                    const pdfjsLib = window['pdfjs-dist\/build\/pdf'];\r\n                    pdfjsLib.GlobalWorkerOptions.workerSrc = \r\n                        '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n                    \r\n                    const pdf = await pdfjsLib.getDocument({ data: new Uint8Array(this.pdfData) }).promise;\r\n                    const page = await pdf.getPage(1);\r\n                    \r\n                    const { titleText, pageText } = await this.extractTextFromPage(page);\r\n                    const imageData = await this.extractImageFromPage(page, pdfjsLib);\r\n                    \r\n                    if (imageData) {\r\n                        PreviewRenderer.renderDocumentPreview(\r\n                            $dropZone,\r\n                            imageData.dataUrl,\r\n                            titleText,\r\n                            pageText\r\n                        );\r\n                    } else {\r\n                        \/\/ \u2705 v1.19.0 : Accepter les PDF sans image\r\n                        PreviewRenderer.renderDocumentPreview(\r\n                            $dropZone,\r\n                            null,\r\n                            titleText,\r\n                            pageText\r\n                        );\r\n                        console.log('\u2139\ufe0f PDF sans image \u2014 aper\u00e7u texte seul');\r\n                    }\r\n                    \r\n                    this.attachPDFPreviewHandler($dropZone, titleText);\r\n                    resolve();\r\n                } catch (error) {\r\n                    console.error('Error extracting from PDF:', error);\r\n                    \/\/ \u2705 v1.19.0 : Message d'erreur en fran\u00e7ais\r\n                    $dropZone.html(`\r\n                        <div style=\"padding: 15px; background-color: #f8f8f8; border-radius: 4px; text-align: center;\">\r\n                            <p style=\"color: #FB5E2A; font-weight: 600; font-family: Roboto, Arial, sans-serif; font-size: 12px;\">\r\n                                Erreur lors de la lecture du document\r\n                            <\/p>\r\n                        <\/div>\r\n                    `);\r\n                    reject(error);\r\n                }\r\n            };\r\n            \r\n            reader.readAsArrayBuffer(fileObj);\r\n        });\r\n    },\r\n    \r\n    async extractTextFromPage(page) {\r\n        const textContent = await page.getTextContent();\r\n        \r\n        let text = '';\r\n        let lastX = -1;\r\n        let lastY = -1;\r\n        \r\n        for (const item of textContent.items) {\r\n            if (lastY !== -1 && (Math.abs(lastY - item.transform[5]) > 5)) {\r\n                text += '\\n';\r\n            } else if (lastX !== -1 && (item.transform[4] - lastX > 10)) {\r\n                text += ' ';\r\n            }\r\n            \r\n            text += item.str;\r\n            \r\n            lastX = item.transform[4] + (item.width || 0);\r\n            lastY = item.transform[5];\r\n        }\r\n        \r\n        text = text\r\n            .replace(\/(\\w) (\\w)\/g, (match, p1, p2) => {\r\n                if (\/[\u00e9\u00e8\u00ea\u00eb\u00e0\u00e2\u00e4\u00f4\u00f6\u00fb\u00fc\u00ef\u00ee\u00e7]\/i.test(p2)) {\r\n                    return p1 + p2;\r\n                }\r\n                return match;\r\n            })\r\n            .replace(\/ ([.,;:!?])\/g, '$1');\r\n        \r\n        const normalizedText = PreviewRenderer.normalizeText(text);\r\n        const titleText = PreviewRenderer.findDocumentTitle(normalizedText);\r\n        \r\n        return { titleText, pageText: text };\r\n    },\r\n    \r\n    async extractImageFromPage(page, pdfjsLib) {\r\n        const opList = await page.getOperatorList();\r\n        const imageInfo = [];\r\n        let currentTransform = null;\r\n        \r\n        for (let i = 0; i < opList.fnArray.length; i++) {\r\n            const operator = opList.fnArray[i];\r\n            const args = opList.argsArray[i];\r\n            \r\n            if (operator === pdfjsLib.OPS.transform) {\r\n                currentTransform = args;\r\n            } else if (operator === pdfjsLib.OPS.paintImageXObject) {\r\n                const imageName = args[0];\r\n                \r\n                if (!imageInfo.some(info => info.name === imageName)) {\r\n                    const position = currentTransform ? {\r\n                        x: currentTransform[4] || 0,\r\n                        y: currentTransform[5] || 0\r\n                    } : { x: 0, y: 0 };\r\n                    \r\n                    imageInfo.push({ name: imageName, position: position });\r\n                }\r\n            }\r\n        }\r\n        \r\n        if (imageInfo.length === 0) {\r\n            return null;\r\n        }\r\n        \r\n        imageInfo.sort((a, b) => b.position.y - a.position.y);\r\n        \r\n        const targetImageName = imageInfo[0].name;\r\n        const imageObj = page.objs.get(targetImageName);\r\n        \r\n        if (!imageObj) {\r\n            const img = await page.objs.get(targetImageName, true);\r\n            return this.processImageObject(img);\r\n        }\r\n        \r\n        return this.processImageObject(imageObj);\r\n    },\r\n    \r\n    processImageObject(imageObj) {\r\n        if (!imageObj) {\r\n            throw new Error('Image object is null');\r\n        }\r\n        \r\n        if (imageObj.bitmap instanceof ImageBitmap) {\r\n            const width = imageObj.bitmap.width || imageObj.width || imageObj.w;\r\n            const height = imageObj.bitmap.height || imageObj.height || imageObj.h;\r\n            \r\n            const canvas = document.createElement('canvas');\r\n            canvas.width = width;\r\n            canvas.height = height;\r\n            const ctx = canvas.getContext('2d');\r\n            \r\n            ctx.drawImage(imageObj.bitmap, 0, 0);\r\n            \r\n            return {\r\n                canvas: canvas,\r\n                width: width,\r\n                height: height,\r\n                dataUrl: canvas.toDataURL('image\/jpeg', 0.92)\r\n            };\r\n        }\r\n        \r\n        const width = imageObj.width || imageObj.w;\r\n        const height = imageObj.height || imageObj.h;\r\n        \r\n        if (!width || !height) {\r\n            throw new Error('Could not determine image dimensions');\r\n        }\r\n        \r\n        let imgData = imageObj.data || imageObj.bitmap;\r\n        \r\n        if (!imgData) {\r\n            throw new Error('No valid image data found');\r\n        }\r\n        \r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = width;\r\n        canvas.height = height;\r\n        const ctx = canvas.getContext('2d');\r\n        \r\n        ctx.fillStyle = 'white';\r\n        ctx.fillRect(0, 0, width, height);\r\n        \r\n        const imageData = ctx.createImageData(width, height);\r\n        \r\n        this.fillImageData(imageData, imgData, imageObj.kind, width, height);\r\n        \r\n        ctx.putImageData(imageData, 0, 0);\r\n        \r\n        return {\r\n            canvas: canvas,\r\n            width: width,\r\n            height: height,\r\n            dataUrl: canvas.toDataURL('image\/jpeg', 0.92)\r\n        };\r\n    },\r\n    \r\n    fillImageData(imageData, imgData, kind, width, height) {\r\n        if (kind === 'GRAY') {\r\n            for (let i = 0, j = 0; i < imgData.length; i++, j += 4) {\r\n                const value = imgData[i];\r\n                imageData.data[j] = value;\r\n                imageData.data[j + 1] = value;\r\n                imageData.data[j + 2] = value;\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (kind === 'CMYK') {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 4, j += 4) {\r\n                const c = imgData[i] \/ 255;\r\n                const m = imgData[i + 1] \/ 255;\r\n                const y = imgData[i + 2] \/ 255;\r\n                const k = imgData[i + 3] \/ 255;\r\n                \r\n                imageData.data[j] = 255 * (1 - c) * (1 - k);\r\n                imageData.data[j + 1] = 255 * (1 - m) * (1 - k);\r\n                imageData.data[j + 2] = 255 * (1 - y) * (1 - k);\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (kind === 'RGB24') {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 3, j += 4) {\r\n                imageData.data[j] = imgData[i];\r\n                imageData.data[j + 1] = imgData[i + 1];\r\n                imageData.data[j + 2] = imgData[i + 2];\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (imgData.length === width * height * 3) {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 3, j += 4) {\r\n                imageData.data[j] = imgData[i];\r\n                imageData.data[j + 1] = imgData[i + 1];\r\n                imageData.data[j + 2] = imgData[i + 2];\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else {\r\n            const tempArray = new Uint8ClampedArray(imgData.length);\r\n            for (let i = 0; i < imgData.length; i++) {\r\n                tempArray[i] = imgData[i];\r\n            }\r\n            \r\n            if (tempArray.length === imageData.data.length \/ 4 * 3) {\r\n                for (let i = 0, j = 0; i < tempArray.length; i += 3, j += 4) {\r\n                    imageData.data[j] = tempArray[i];\r\n                    imageData.data[j + 1] = tempArray[i + 1];\r\n                    imageData.data[j + 2] = tempArray[i + 2];\r\n                    imageData.data[j + 3] = 255;\r\n                }\r\n            } else if (tempArray.length === imageData.data.length) {\r\n                imageData.data.set(tempArray);\r\n            } else {\r\n                console.warn('Unknown image format - creating placeholder');\r\n                for (let i = 0; i < imageData.data.length; i += 4) {\r\n                    const x = (i\/4) % width;\r\n                    const y = Math.floor((i\/4) \/ width);\r\n                    imageData.data[i] = x % 256;\r\n                    imageData.data[i + 1] = y % 256;\r\n                    imageData.data[i + 2] = 100;\r\n                    imageData.data[i + 3] = 255;\r\n                }\r\n            }\r\n        }\r\n    },\r\n    \r\n    attachPDFPreviewHandler($dropZone, titleText) {\r\n        var $droppable = $dropZone.closest('.droppable');\r\n        var self = this;\r\n\r\n        \/\/ \u2705 Adapter le libell\u00e9 selon le format (communiqu\u00e9 \/ interview)\r\n        var kitFormat = $droppable.data('kitFormatSelect') || '';\r\n        var isInterview = (kitFormat || titleText || '').toLowerCase().indexOf('interview') !== -1;\r\n        var formatLabel = isInterview ? 'l\\'interview' : 'le communiqu\u00e9';\r\n        $droppable.find('.doc-preview-readmore').text('Ouvrir et visualiser ' + formatLabel);\r\n\r\n        \/\/ \u2705 v2.0.11 : D\u00e9l\u00e9gation d'\u00e9v\u00e9nement \u2014 plus robuste sur mobile\r\n        $droppable.off('click.docpreview').on('click.docpreview', '.doc-preview-readmore', (event) => {\r\n            event.preventDefault();\r\n            event.stopPropagation();\r\n            var popupTitle = isInterview ? 'Interview' : 'Communiqu\u00e9';\r\n\r\n            \/\/ \u2705 Priorit\u00e9 1 : pdfImageDataURL dispo (Kit)\r\n            var kitPdfImage = $droppable.data('kitPdfImageDataURL');\r\n            if (kitPdfImage) {\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    pdfDataURL: kitPdfImage\r\n                });\r\n                return;\r\n            }\r\n\r\n            \/\/ \u2705 Priorit\u00e9 2 : PDF upload\u00e9 manuellement \u2192 popup inline aussi\r\n            if (self.pdfDataForViewer && self.pdfDataForViewer.byteLength > 0) {\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    pdfArrayBuffer: self.pdfDataForViewer\r\n                });\r\n                return;\r\n            }\r\n\r\n            console.error('PDF data is not available');\r\n        });\r\n    },\r\n\r\n    \/\/ \u2705 v1.19.1 : Popup inline document \u2014 position:absolute + ScrollHelper.getVisibleTop()\r\n    \/\/ Le parent envoie visibleTopIframe dans le message scroll \u2192 positionnement fiable.\r\n    showInlineDocPopup($dropZone, options) {\r\n        var existing = document.getElementById('via-pdf-inline-popup');\r\n        if (existing) existing.remove();\r\n\r\n        var $droppable = $dropZone.closest('.droppable');\r\n        var droppableW = $droppable.outerWidth() || 300;\r\n        var popupW = Math.round(droppableW * 1.15);\r\n        \/\/ \u2705 v2.0.11 : Contraindre la largeur au viewport sur mobile (\u00e9vite troncature gauche\/droite)\r\n        var viewportW = document.documentElement.clientWidth || window.innerWidth;\r\n        if (UIManager.isMobile()) {\r\n            popupW = Math.min(popupW, viewportW - 8);\r\n        }\r\n        var popupH = Math.round(popupW * 2.5 * 0.51);\r\n\r\n        \/\/ \u2500\u2500 Position visible r\u00e9elle \u2500\u2500\r\n        var visibleTop = ScrollHelper.getVisibleTop();\r\n        var popupTop = Math.round(visibleTop + 284);\r\n\r\n        \/\/ \u2500\u2500 Popup position:absolute (positionn\u00e9 dans le document iframe) \u2500\u2500\r\n        var popup = document.createElement('div');\r\n        popup.id = 'via-pdf-inline-popup';\r\n        popup.style.cssText =\r\n            'position:absolute;z-index:99999;top:' + popupTop + 'px;' +\r\n            'width:' + popupW + 'px;height:' + popupH + 'px;' +\r\n            'background:#fff;border-radius:8px 8px 0 0;padding:0;' +\r\n            'box-shadow:0 8px 32px rgba(0,0,0,0.35);display:flex;flex-direction:column;' +\r\n            'min-width:200px;min-height:150px;touch-action:none;';\r\n\r\n        \/\/ Centrer horizontalement sur le droppable (coordonn\u00e9es absolues)\r\n        var droppableRect = $droppable[0].getBoundingClientRect();\r\n        var scrollX = window.scrollX || 0;\r\n        var initLeft = Math.round(droppableRect.left + scrollX + (droppableRect.width - popupW) \/ 2);\r\n        initLeft = Math.max(4, initLeft);\r\n        \/\/ \u2705 v2.0.11 : Contraindre \u00e0 droite aussi sur mobile\r\n        if (UIManager.isMobile()) {\r\n            initLeft = Math.min(initLeft, viewportW - popupW - 4);\r\n            initLeft = Math.max(4, initLeft);\r\n        }\r\n        popup.style.left = initLeft + 'px';\r\n\r\n        \/\/ \u2500\u2500 Header \u2500\u2500\r\n        var header = document.createElement('div');\r\n        header.style.cssText =\r\n            'display:flex;align-items:center;justify-content:center;position:relative;' +\r\n            'padding:10px 14px;background:#f0f0f0;color:#494949;flex-shrink:0;' +\r\n            'cursor:grab;user-select:none;border-radius:8px 8px 0 0;';\r\n        var titleEl = document.createElement('span');\r\n        titleEl.style.cssText = 'font-family:Roboto,Arial,sans-serif;font-size:15px;font-weight:600;';\r\n        titleEl.textContent = options.formatTitle || 'Document';\r\n        header.appendChild(titleEl);\r\n\r\n        var closeBtn = document.createElement('button');\r\n        closeBtn.textContent = '\u00d7';\r\n        closeBtn.style.cssText =\r\n            'position:absolute;right:10px;top:50%;transform:translateY(-50%);' +\r\n            'background:transparent;border:none;color:#494949;font-size:20px;' +\r\n            'cursor:pointer;line-height:1;padding:0 4px;';\r\n        closeBtn.addEventListener('click', cleanup);\r\n        header.appendChild(closeBtn);\r\n        popup.appendChild(header);\r\n\r\n        \/\/ \u2500\u2500 Zone scrollable \u2014 pleine largeur \u2500\u2500\r\n        var scrollZone = document.createElement('div');\r\n        scrollZone.style.cssText =\r\n            'flex:1;overflow-y:auto;overflow-x:hidden;padding:0;margin:0;touch-action:pan-y;';\r\n        popup.appendChild(scrollZone);\r\n\r\n        var loader = document.createElement('div');\r\n        loader.style.cssText =\r\n            'text-align:center;padding:30px;font-family:Roboto,Arial,sans-serif;font-size:12px;color:#666;';\r\n        loader.textContent = 'Chargement du document\u2026';\r\n        scrollZone.appendChild(loader);\r\n\r\n        \/\/ \u2500\u2500 8 poign\u00e9es de redimensionnement \u2500\u2500\r\n        var handles = [\r\n            { cursor:'nw-resize', pos:'top:-4px;left:-4px;',       dx:-1, dy:-1 },\r\n            { cursor:'n-resize',  pos:'top:-4px;left:50%;',        dx:0,  dy:-1 },\r\n            { cursor:'ne-resize', pos:'top:-4px;right:-4px;',      dx:1,  dy:-1 },\r\n            { cursor:'w-resize',  pos:'top:50%;left:-4px;',        dx:-1, dy:0  },\r\n            { cursor:'e-resize',  pos:'top:50%;right:-4px;',       dx:1,  dy:0  },\r\n            { cursor:'sw-resize', pos:'bottom:-4px;left:-4px;',    dx:-1, dy:1  },\r\n            { cursor:'s-resize',  pos:'bottom:-4px;left:50%;',     dx:0,  dy:1  },\r\n            { cursor:'se-resize', pos:'bottom:-4px;right:-4px;',   dx:1,  dy:1  }\r\n        ];\r\n        handles.forEach(function(h) {\r\n            var handle = document.createElement('div');\r\n            var isCorner = (h.dx !== 0 && h.dy !== 0);\r\n            handle.style.cssText =\r\n                'position:absolute;touch-action:none;' + h.pos +\r\n                'width:' + (isCorner ? '12px' : (h.dy === 0 ? '8px' : '30px')) + ';' +\r\n                'height:' + (isCorner ? '12px' : (h.dy === 0 ? '30px' : '8px')) + ';' +\r\n                'cursor:' + h.cursor + ';z-index:10;';\r\n            (function(hInfo) {\r\n                handle.addEventListener('pointerdown', function(e) {\r\n                    e.preventDefault(); e.stopPropagation();\r\n                    handle.setPointerCapture(e.pointerId);\r\n                    var startX = e.clientX, startY = e.clientY;\r\n                    var rect0 = popup.getBoundingClientRect();\r\n                    var sY = window.scrollY || 0, sX = window.scrollX || 0;\r\n                    var startW = rect0.width, startH = rect0.height;\r\n                    var startL = rect0.left + sX, startT = rect0.top + sY;\r\n                    function onResize(ev) {\r\n                        ev.preventDefault();\r\n                        var ddx = ev.clientX - startX, ddy = ev.clientY - startY;\r\n                        var newW = startW, newH = startH, newL = startL, newT = startT;\r\n                        if (hInfo.dx === 1)  newW = Math.max(200, startW + ddx);\r\n                        if (hInfo.dx === -1) { newW = Math.max(200, startW - ddx); newL = startL + ddx; }\r\n                        if (hInfo.dy === 1)  newH = Math.max(150, startH + ddy);\r\n                        if (hInfo.dy === -1) { newH = Math.max(150, startH - ddy); newT = startT + ddy; }\r\n                        popup.style.width  = newW + 'px';\r\n                        popup.style.height = newH + 'px';\r\n                        popup.style.left   = newL + 'px';\r\n                        popup.style.top    = newT + 'px';\r\n                    }\r\n                    function onResizeEnd(ev) {\r\n                        handle.releasePointerCapture(ev.pointerId);\r\n                        handle.removeEventListener('pointermove', onResize);\r\n                        handle.removeEventListener('pointerup', onResizeEnd);\r\n                    }\r\n                    handle.addEventListener('pointermove', onResize);\r\n                    handle.addEventListener('pointerup', onResizeEnd);\r\n                });\r\n            })(h);\r\n            popup.appendChild(handle);\r\n        });\r\n\r\n        \/\/ \u2500\u2500 Drag via header \u2500\u2500\r\n        header.style.touchAction = 'none';\r\n        header.addEventListener('pointerdown', function(e) {\r\n            if (e.target === closeBtn) return;\r\n            e.preventDefault();\r\n            header.setPointerCapture(e.pointerId);\r\n            var mx = e.clientX, my = e.clientY;\r\n            var popupRect = popup.getBoundingClientRect();\r\n            var scrollY = window.scrollY || 0;\r\n            var scrollX = window.scrollX || 0;\r\n            var curLeft = popupRect.left + scrollX;\r\n            var curTop  = popupRect.top  + scrollY;\r\n            header.style.cursor = 'grabbing';\r\n            function onMove(ev) {\r\n                ev.preventDefault();\r\n                var dx = ev.clientX - mx;\r\n                var dy = ev.clientY - my;\r\n                curLeft += dx;\r\n                curTop  += dy;\r\n                popup.style.left = curLeft + 'px';\r\n                popup.style.top  = curTop  + 'px';\r\n                mx = ev.clientX;\r\n                my = ev.clientY;\r\n            }\r\n            function onUp(ev) {\r\n                header.releasePointerCapture(ev.pointerId);\r\n                header.style.cursor = 'grab';\r\n                header.removeEventListener('pointermove', onMove);\r\n                header.removeEventListener('pointerup', onUp);\r\n            }\r\n            header.addEventListener('pointermove', onMove);\r\n            header.addEventListener('pointerup', onUp);\r\n        });\r\n\r\n        \/\/ \u2500\u2500 Cleanup \u2500\u2500\r\n        function cleanup() {\r\n            popup.remove();\r\n            document.removeEventListener('keydown', escHandler);\r\n        }\r\n        var escHandler = function(e) { if (e.key === 'Escape') cleanup(); };\r\n        document.addEventListener('keydown', escHandler);\r\n\r\n        document.body.appendChild(popup);\r\n\r\n        \/\/ \u2500\u2500 Rendre le contenu \u2500\u2500\r\n        if (options.pdfDataURL)          this.renderPdfInPopup(scrollZone, options.pdfDataURL, popupW, 'dataurl');\r\n        else if (options.pdfArrayBuffer) this.renderPdfInPopup(scrollZone, options.pdfArrayBuffer, popupW, 'arraybuffer');\r\n        else if (options.htmlContent)    this.renderHtmlInPopup(scrollZone, options.htmlContent);\r\n    },\r\n\r\n    \/\/ Alias pour compatibilit\u00e9\r\n    showInlinePdfPopup($dropZone, pdfImageDataURL, formatTitle) {\r\n        this.showInlineDocPopup($dropZone, { formatTitle: formatTitle, pdfDataURL: pdfImageDataURL });\r\n    },\r\n\r\n    \/\/ \u2705 Rendu PDF dans popup (dataurl ou arraybuffer) \u2014 avec crop des marges blanches\r\n    async renderPdfInPopup(container, pdfData, popupWidth, mode) {\r\n        try {\r\n            var u8;\r\n            if (mode === 'dataurl') {\r\n                var b64 = pdfData.split(',')[1];\r\n                var bstr = atob(b64);\r\n                u8 = new Uint8Array(bstr.length);\r\n                for (var i = 0; i < bstr.length; i++) { u8[i] = bstr.charCodeAt(i); }\r\n            } else {\r\n                u8 = new Uint8Array(pdfData);\r\n            }\r\n\r\n            var pdfjsLib = window['pdfjs-dist\/build\/pdf'];\r\n            if (!pdfjsLib) {\r\n                container.innerHTML = '<div style=\"padding:20px;text-align:center;color:#c00;\">pdf.js non charg\u00e9<\/div>';\r\n                return;\r\n            }\r\n            pdfjsLib.GlobalWorkerOptions.workerSrc =\r\n                '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n\r\n            var pdf = await pdfjsLib.getDocument({ data: u8 }).promise;\r\n            console.log('\ud83d\udcc4 PDF popup :', pdf.numPages, 'pages');\r\n            container.innerHTML = '';\r\n\r\n            var firstPage = await pdf.getPage(1);\r\n            var vpNative = firstPage.getViewport({ scale: 1 });\r\n            var scale = popupWidth \/ vpNative.width;\r\n\r\n            \/\/ \u2705 R\u00e9f\u00e9rence au popup pour ajuster sa hauteur apr\u00e8s rendu\r\n            var _popup = container.closest('#via-pdf-inline-popup');\r\n            var _headerH = _popup ? (_popup.querySelector('div[style*=\"grab\"]') || {offsetHeight: 44}).offsetHeight : 44;\r\n\r\n            \/\/ \u2705 D\u00e9tecte les marges blanches haut\/bas d'un canvas rendu et retourne {top, bottom}\r\n            function detectWhiteMargins(canvas) {\r\n                var ctx = canvas.getContext('2d');\r\n                var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\r\n                var W = canvas.width, H = canvas.height;\r\n                var topRow = 0, bottomRow = H - 1;\r\n                \/\/ Chercher la premi\u00e8re ligne non-blanche (tol\u00e9rance 252 pour les artefacts anti-aliasing)\r\n                outer: for (var y = 0; y < H; y++) {\r\n                    for (var x = 0; x < W; x++) {\r\n                        var i = (y * W + x) * 4;\r\n                        if (data[i] < 252 || data[i+1] < 252 || data[i+2] < 252) { topRow = y; break outer; }\r\n                    }\r\n                }\r\n                outer2: for (var y2 = H - 1; y2 >= topRow; y2--) {\r\n                    for (var x2 = 0; x2 < W; x2++) {\r\n                        var i2 = (y2 * W + x2) * 4;\r\n                        if (data[i2] < 252 || data[i2+1] < 252 || data[i2+2] < 252) { bottomRow = y2; break outer2; }\r\n                    }\r\n                }\r\n                return { top: topRow, bottom: bottomRow };\r\n            }\r\n\r\n            for (var pageNum = 1; pageNum <= pdf.numPages; pageNum++) {\r\n                var page = await pdf.getPage(pageNum);\r\n                var vp = page.getViewport({ scale: scale });\r\n                \/\/ Rendre dans un canvas temporaire\r\n                var tmpCanvas = document.createElement('canvas');\r\n                tmpCanvas.width = vp.width;\r\n                tmpCanvas.height = vp.height;\r\n                await page.render({ canvasContext: tmpCanvas.getContext('2d'), viewport: vp }).promise;\r\n\r\n                \/\/ \u2705 Crop marges blanches\r\n                var margins = detectWhiteMargins(tmpCanvas);\r\n                var cropTop = Math.max(0, margins.top - 4);\r\n                var cropBottom = Math.min(tmpCanvas.height - 1, margins.bottom + 4);\r\n                var croppedH = cropBottom - cropTop + 1;\r\n\r\n                \/\/ Canvas final crop\u00e9\r\n                var canvas = document.createElement('canvas');\r\n                canvas.width = tmpCanvas.width;\r\n                canvas.height = croppedH;\r\n                canvas.getContext('2d').drawImage(tmpCanvas, 0, cropTop, tmpCanvas.width, croppedH, 0, 0, tmpCanvas.width, croppedH);\r\n                canvas.style.cssText = 'display:block;width:100%;height:auto;margin:0;padding:0;';\r\n                container.appendChild(canvas);\r\n                console.log('\ud83d\udcc4 Page', pageNum, '- crop:', cropTop, '\u2192', cropBottom, '(', Math.round(cropTop\/vp.height*100), '% top trimmed)');\r\n            }\r\n\r\n            \/\/ \u2705 Ajuster la hauteur du popup \u00e0 la hauteur r\u00e9elle du contenu rendu\r\n            \/\/ (popup \u00e9tait calcul\u00e9 sur popupW*2.5*0.51 qui peut \u00eatre trop grand ou trop petit)\r\n            if (_popup) {\r\n                var _totalH = 0;\r\n                container.querySelectorAll('canvas').forEach(function(c) { _totalH += c.height * (popupWidth \/ c.width); });\r\n                var _viewportH = window.innerHeight || document.documentElement.clientHeight || 600;\r\n                var _maxPopupH = Math.round(_viewportH * 0.88);\r\n                var _idealH = Math.min(_totalH + _headerH + 8, _maxPopupH);\r\n                _popup.style.height = _idealH + 'px';\r\n                console.log('\ud83d\udcd0 Popup redimensionn\u00e9:', Math.round(_idealH), 'px (contenu:', Math.round(_totalH), ')');\r\n            }\r\n        } catch (err) {\r\n            console.error('\u274c Erreur rendu PDF popup:', err);\r\n            container.innerHTML =\r\n                '<div style=\"padding:20px;text-align:center;color:#c00;font-size:12px;\">Erreur lors du chargement du document<\/div>';\r\n        }\r\n    },\r\n\r\n    \/\/ \u2705 Rendu HTML (Word) dans popup \u2014 avec CSS complet pour mammoth\r\n    renderHtmlInPopup(container, htmlContent) {\r\n        container.innerHTML = '';\r\n        \/\/ \u2705 Nettoyer les <p> vides en d\u00e9but\/fin produits par mammoth (marges parasites)\r\n        htmlContent = htmlContent\r\n            .replace(\/^(\\s*<p[^>]*>\\s*(<br\\s*\\\/?>\\s*)*<\\\/p>\\s*)+\/i, '')\r\n            .replace(\/(\\s*<p[^>]*>\\s*(<br\\s*\\\/?>\\s*)*<\\\/p>\\s*)+$\/i, '');\r\n        \/\/ \u2500\u2500 Styles pour le HTML g\u00e9n\u00e9r\u00e9 par mammoth (titres, paragraphes, listes, images) \u2500\u2500\r\n        var style = document.createElement('style');\r\n        style.textContent = [\r\n            '.via-html-popup-body { padding:20px 24px; background:#fff; color:#222; font-family:Georgia,\"Times New Roman\",serif; font-size:15px; line-height:1.7; }',\r\n            '.via-html-popup-body h1 { font-size:22px; font-weight:700; margin:0 0 12px; line-height:1.3; }',\r\n            '.via-html-popup-body h2 { font-size:18px; font-weight:700; margin:18px 0 8px; line-height:1.3; }',\r\n            '.via-html-popup-body h3 { font-size:15px; font-weight:700; margin:14px 0 6px; }',\r\n            '.via-html-popup-body p  { margin:0 0 10px; }',\r\n            '.via-html-popup-body p:first-child { margin-top:0; }',\r\n            '.via-html-popup-body strong, .via-html-popup-body b { font-weight:700; }',\r\n            '.via-html-popup-body em, .via-html-popup-body i { font-style:italic; }',\r\n            '.via-html-popup-body ul, .via-html-popup-body ol { margin:6px 0 10px 22px; padding:0; }',\r\n            '.via-html-popup-body li { margin-bottom:4px; }',\r\n            '.via-html-popup-body img { max-width:100%; height:auto; display:block; margin:10px auto; border-radius:4px; }',\r\n            '.via-html-popup-body table { width:100%; border-collapse:collapse; margin:10px 0; font-size:13px; }',\r\n            '.via-html-popup-body td, .via-html-popup-body th { border:1px solid #ddd; padding:6px 8px; vertical-align:top; }',\r\n            '.via-html-popup-body th { background:#f0f4f8; font-weight:700; }',\r\n            '.via-html-popup-body a { color:#225da9; text-decoration:underline; }'\r\n        ].join('');\r\n        container.appendChild(style);\r\n        var wrapper = document.createElement('div');\r\n        wrapper.className = 'via-html-popup-body';\r\n        wrapper.innerHTML = htmlContent;\r\n        container.appendChild(wrapper);\r\n    },\r\n    \r\n    async renderPDFInWindow(childWindow, container) {\r\n        container.innerHTML = '';\r\n        \r\n        const script = childWindow.document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.4.120\/pdf.min.js';\r\n        childWindow.document.head.appendChild(script);\r\n        \r\n        script.onload = async () => {\r\n            const pdfjsLib = childWindow.pdfjsLib;\r\n            const viewerContainer = childWindow.document.createElement('div');\r\n            viewerContainer.style.width = '100%';\r\n            viewerContainer.style.backgroundColor = 'white';\r\n            viewerContainer.style.position = 'relative';\r\n            container.appendChild(viewerContainer);\r\n            \r\n            const loadingTask = pdfjsLib.getDocument({data: window.pdfDataToTransfer});\r\n            const pdf = await loadingTask.promise;\r\n            \r\n            const firstPage = await pdf.getPage(1);\r\n            const viewport = firstPage.getViewport({scale: 1.5});\r\n            const pageHeight = viewport.height;\r\n            \r\n            const spacing = -15;\r\n            const totalHeight = (pageHeight * pdf.numPages) + (spacing * (pdf.numPages - 1));\r\n            viewerContainer.style.height = `${totalHeight}px`;\r\n            \r\n            for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {\r\n                const page = await pdf.getPage(pageNum);\r\n                const canvas = childWindow.document.createElement('canvas');\r\n                const context = canvas.getContext('2d');\r\n                \r\n                canvas.width = viewport.width;\r\n                canvas.height = viewport.height;\r\n                \r\n                canvas.style.position = 'absolute';\r\n                canvas.style.left = '50%';\r\n                canvas.style.transform = 'translateX(-50%)';\r\n                canvas.style.top = `${(pageNum - 1) * (pageHeight + spacing)}px`;\r\n                \r\n                await page.render({\r\n                    canvasContext: context,\r\n                    viewport: viewport\r\n                }).promise;\r\n                \r\n                viewerContainer.appendChild(canvas);\r\n            }\r\n        };\r\n    },\r\n    \r\n    arrayBufferToBase64(buffer) {\r\n        let binary = '';\r\n        const bytes = new Uint8Array(buffer);\r\n        const len = bytes.byteLength;\r\n        for (let i = 0; i < len; i++) {\r\n            binary += String.fromCharCode(bytes[i]);\r\n        }\r\n        return window.btoa(binary);\r\n    },\r\n    \r\n    base64ToArrayBuffer(base64) {\r\n        const binaryString = window.atob(base64);\r\n        const len = binaryString.length;\r\n        const bytes = new Uint8Array(len);\r\n        for (let i = 0; i < len; i++) {\r\n            bytes[i] = binaryString.charCodeAt(i);\r\n        }\r\n        return bytes.buffer;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des \u00e9v\u00e9nements de drop et d'upload\r\n *\/\r\nconst DropHandler = {\r\n    async handleDrop(e) {\r\n        e.preventDefault();\r\n        \r\n        const $currentTarget = this.findDropTarget(e);\r\n        \r\n        if (!$currentTarget) {\r\n            console.log('No valid drop target found');\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 V\u00c9RIFIER SI C'EST UN D\u00c9PLACEMENT (pas besoin de v\u00e9rifier le format)\r\n        const isMoved = StateManager.get('FirstUploadFileorMoved') === 'Moved';\r\n        const dragstartRef = StateManager.get('dragstart_Commande_Emplacement_Page_Web');\r\n        let hasDragstartRef = false;\r\n        \r\n        if (dragstartRef) {\r\n            if (dragstartRef !== 'No') {\r\n                hasDragstartRef = true;\r\n            }\r\n        }\r\n        \r\n        let isDeplacementAnnonce = false;\r\n        if (isMoved) {\r\n            if (hasDragstartRef) {\r\n                isDeplacementAnnonce = true;\r\n            }\r\n        }\r\n        \r\n        if (isDeplacementAnnonce) {\r\n            console.log('\ud83d\udd04 D\u00e9placement d\u00e9tect\u00e9 - contr\u00f4le format ignor\u00e9');\r\n        } else {\r\n            \/\/ \u2705 CONTR\u00d4LE FORMAT SEULEMENT POUR NOUVEAU D\u00c9P\u00d4T\r\n            \/\/ Utilise FormatUIManager au lieu de showFormatWarning\r\n            if (StateManager.get('Formatchoisi') === 'No') {\r\n                FormatUIManager.flashTitle($currentTarget);\r\n                return;\r\n            }\r\n            \r\n            if (!FormatUIManager.hasSelectedFormat($currentTarget)) {\r\n                FormatUIManager.flashTitle($currentTarget);\r\n                return;\r\n            }\r\n        }\r\n    \r\n        console.log(\"Drop at:\", $currentTarget);\r\n        \r\n        this.updateEmplacementState($currentTarget);\r\n        \r\n        const shouldProcess = this.shouldProcessDrop(e, $currentTarget);\r\n        \r\n        if (shouldProcess) {\r\n            await this.processFileDrop(e, $currentTarget);\r\n        } else {\r\n            this.processVideoDrop($currentTarget);\r\n        }\r\n        \r\n        DragDropManager.clearDataTransferFiles(e);\r\n    },\r\n    \r\n    findDropTarget(e) {\r\n        \/\/ \u2705 v2.4.3 : Si Ele0A est actif et le drop arrive sur Ele1A \u2192 rediriger vers Ele0A\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            var _ele0ADrop = document.querySelector('#Ele0A #drop_file_zone_achat');\r\n            if (_ele0ADrop) {\r\n                console.log('\ud83c\udfaf findDropTarget \u2014 PopUpChoice=Yes \u2192 cible forc\u00e9e: Ele0A');\r\n                return jQuery(_ele0ADrop);\r\n            }\r\n        }\r\n\r\n        let target = e.target.closest('#drop_file_zone_achat');\r\n        \r\n        if (!target) {\r\n            target = e.currentTarget.closest('#drop_file_zone_achat');\r\n            console.log('Drop target found 1');\r\n        }\r\n        \r\n        if (!target) {\r\n            target = jQuery(e.target).closest('#drop_file_zone_achat')[0];\r\n            console.log('Drop target found 2');\r\n        }\r\n        \r\n        return target ? jQuery(target) : null;\r\n    },\r\n    \r\n    updateEmplacementState($target) {\r\n        const espaceId = $target.closest('.droppable').attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', espaceId);\r\n        StateManager.set('Commande_Emplacement_Page_Web',\r\n            StateManager.buildEmplacementReference(espaceId));\r\n        \r\n        UIManager.updateEmplacementDisplay();\r\n        \r\n        console.log(\"Rank_Emplacement_Page_Web:\", StateManager.get('Rank_Emplacement_Page_Web'));\r\n        console.log(\"Droppable at:\", StateManager.get('Commande_Emplacement_Page_Web'));\r\n    },\r\n    \r\n    shouldProcessDrop(e, $target) {\r\n        const hasFiles = e.dataTransfer.files.length > 0;\r\n        const isRedactionnel = StateManager.get('Commande_Format_Transmis') === 'R\u00e9dactionnel';\r\n        const isValidBackground = window.getComputedStyle(\r\n            $target.closest('#UploadFileConteneur')[0]\r\n        ).backgroundColor !== 'rgba(0, 0, 0, 0)';\r\n        \r\n        return (hasFiles || isRedactionnel) && isValidBackground;\r\n    },\r\n    \r\n    async processFileDrop(e, $target) {\r\n        jQuery('.MsgAdNotDisplayed').hide();\r\n        StateManager.setMultiple({\r\n            \"AdDisplayed\": 'Yes',\r\n            \/\/ \u2705 NE PLUS mettre sendDataToParentFlag ici - c'est la checkbox \"R\u00e9server\" qui le fera\r\n            \/\/ \"sendDataToParentFlag\": 'Yes'\r\n        });\r\n        \r\n        console.log('ajaxFileUpload_achat launched');\r\n        console.log(\"FirstUploadFileorMoved:\", StateManager.get('FirstUploadFileorMoved'));\r\n        \r\n        if (UIManager.isMobile()) {\r\n            $target = jQuery('#Ele1A').find('#drop_file_zone_achat');\r\n        }\r\n        \r\n        if (StateManager.get('Commande_Format_Transmis') === 'R\u00e9dactionnel') {\r\n            const fileURL = StateManager.get('FullPathAdFile');\r\n            const filename = fileURL.substring(fileURL.indexOf('_') + 1);\r\n            \r\n            try {\r\n                \/\/ \u2705 R\u00e9utiliser le File cach\u00e9 (\u00e9vite CORS cross-domain)\r\n                let file;\r\n                if (window._lastRedactionnelFile) {\r\n                    file = window._lastRedactionnelFile;\r\n                    console.log('\u267b\ufe0f R\u00e9utilisation du File cach\u00e9:', file.name, Math.round(file.size \/ 1024) + 'KB');\r\n                } else {\r\n                    file = await FileManager.urlToFile(fileURL, filename);\r\n                }\r\n                await UploadManager.handleFileUpload(file, $target);\r\n            } catch (error) {\r\n                console.error('Error:', error);\r\n            }\r\n        } else {\r\n            await UploadManager.handleFileUpload(e.dataTransfer.files[0], $target);\r\n        }\r\n    },\r\n    \r\n    processVideoDrop($target) {\r\n        const isValidBackground = window.getComputedStyle(\r\n            $target.closest('#UploadFileConteneur')[0]\r\n        ).backgroundColor !== 'rgba(0, 0, 0, 0)';\r\n        \r\n        if (!isValidBackground) {\r\n            jQuery('.MsgAdNotDisplayed').show();\r\n            StateManager.set(\"AdDisplayed\", 'No');\r\n            return;\r\n        }\r\n        \r\n        StateManager.set(\"AdDisplayed\", 'Yes');\r\n        \r\n        const objectUrl = StateManager.get('videoSrc');\r\n        const $previousDropZone = $('.drop_file_zone_achat_class').has(`video[src=\"${objectUrl}\"]`);\r\n        window.RestoreadSpaceTemplate($previousDropZone);\r\n        \r\n        const videoElement = jQuery('<video controls autoplay muted>').attr({\r\n            'src': objectUrl,\r\n            'max-width': '100%',\r\n            'max-height': '100%',\r\n            'draggable': 'true'\r\n        }).css({\r\n            'max-width': '100%',\r\n            'max-height': '100%'\r\n        });\r\n        \r\n        $target.empty().append(videoElement);\r\n        \r\n        $target.closest('#UploadFileConteneur').css({'background-color': '#FFFFFF00'});\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass')\r\n            .find('.RefEspacePublicitaire')\r\n            .html('R\u00e9f\u00e9rence de l\\'espace : ' + StateManager.get('Commande_Emplacement_Page_Web'))\r\n            .attr('id', 'RefEspacePublicitaire')\r\n            .each(function() {\r\n                var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                this.style.setProperty('display', 'block', 'important');\r\n            });\r\n        \/\/ \u2705 v2.4.5 : Renseigner et afficher .PositionEspacePublicitaire\r\n        (function() {\r\n            var _rankPosV = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            var _posLibV = PreviewRenderer._getPositionLibelle(_rankPosV);\r\n            if (_posLibV) {\r\n                $target.closest('.OrdiMobileConteneurClass')\r\n                    .find('.PositionEspacePublicitaireDeplacer')\r\n                    .text(_posLibV)\r\n                    .each(function() {\r\n                        var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                        if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass').find('.AdUploadedTitle').show();\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass')\r\n            .css({'top': '60px', 'margin-bottom': '80px'});\r\n        \r\n        $target.closest('.HTMLUploadfileConteneur')\r\n            .not('.AdUploadedTitle')\r\n            .css({\r\n                'top': '0px',\r\n                'margin-bottom': '0px',\r\n                'box-shadow': 'inset 0 0 0 2px #00FF19',  \/\/ \u2705 v2.4.5\r\n                'background-color': 'white'\r\n            });\r\n        \r\n        $target.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, .ChoisirEspacePublicitaire2ndLigne, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        jQuery('#MsgElementsCommandeValides, #MessageOptionsacompleterConteneur').hide();\r\n        \r\n        StateManager.set(\"FirstUploadFileorMoved\", 'Moved');\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server (au lieu d'envoyer automatiquement)\r\n        FormatUIManager.updateReserverCheckboxState($target.closest('.droppable'));\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'explorateur de fichiers\r\n *\/\r\nconst FileExplorer = {\r\n    isRunning: false,\r\n\r\n    open(e) {\r\n        if (this.isRunning) {\r\n            return;\r\n        }\r\n        \r\n        const $element = jQuery(e.target).closest('.droppable');\r\n        \r\n        \/\/ \u2705 V\u00e9rifier si un format est s\u00e9lectionn\u00e9 (utilise FormatUIManager)\r\n        if (!FormatUIManager.hasSelectedFormat($element)) {\r\n            FormatUIManager.flashTitle($element);\r\n            return;\r\n        }\r\n        \r\n        this.isRunning = true;\r\n        \r\n        const rankId = $element.attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', rankId);\r\n        StateManager.set('Commande_Emplacement_Page_Web',\r\n            StateManager.buildEmplacementReference(rankId));\r\n        \r\n        UIManager.updateEmplacementDisplay();\r\n        \r\n        console.log(\"Drop at:\", StateManager.get('Commande_Emplacement_Page_Web'));\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        \r\n        const $currentTarget = jQuery(e.target).closest('#drop_file_zone_achat');\r\n        const $fileInput = jQuery('#selectfile_achat');\r\n        \r\n        console.log(\"currentTarget\", $currentTarget);\r\n        \r\n        $fileInput.off('change');\r\n        $fileInput.off('click');\r\n        \r\n        const onChange = (event) => {\r\n            this.isRunning = false;\r\n            $fileInput.off('change', onChange);\r\n            \r\n            \/\/ \u2705 NE PLUS mettre sendDataToParentFlag ici\r\n            \/\/ StateManager.set(\"sendDataToParentFlag\", 'Yes');\r\n            \r\n            if ($fileInput[0].files.length > 0) {\r\n                UploadManager.handleFileUpload($fileInput[0].files[0], $currentTarget);\r\n            }\r\n        };\r\n        \r\n        const onClick = () => {\r\n            $fileInput.off('click', onClick);\r\n            $fileInput.on('focus', function onFocus() {\r\n                setTimeout(() => {\r\n                    if (!$fileInput.val()) {\r\n                        FileExplorer.isRunning = false;\r\n                    }\r\n                }, 200);\r\n                $fileInput.off('focus', onFocus);\r\n            });\r\n        };\r\n        \r\n        $fileInput.on('change', onChange);\r\n        $fileInput.on('click', onClick);\r\n        \r\n        $fileInput.click();\r\n        \r\n        setTimeout(() => {\r\n            this.isRunning = false;\r\n        }, 300);\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion du reset d'annonce\r\n *\/\r\nconst AdResetHandler = {\r\n    handle(e) {\r\n        e.preventDefault();\r\n        console.log(\"CroixResetAnnonce click\");\r\n        \r\n        \/\/ Reset l'\u00e9tat EnvoiUlterieur\r\n        StateManager.set('EnvoiUlterieur', 'false');\r\n        \r\n        \/\/ \u2705 v1.19.6 : Reset FileReceived mais garder le format s\u00e9lectionn\u00e9\r\n        StateManager.set('FileReceived', 'No');\r\n        \r\n        const $element = jQuery(e.currentTarget);\r\n        const $droppable = $element.closest('.droppable');\r\n        const resetRef = StateManager.buildEmplacementReference($droppable.attr('id'));\r\n        \r\n        console.log(\"Reset_Commande_Emplacement_Page_Web:\", resetRef);\r\n        \r\n        \/\/ \u2705 Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        var _rankForDel = $droppable.attr('id') || StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            MessageManager.sendDelAdToParent({\r\n                Commande_Emplacement_Page_Web: resetRef,\r\n                Rank_Emplacement_Page_Web: _rankForDel,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n        } else {\r\n            window.processdataDelAd({\r\n                Commande_Emplacement_Page_Web: resetRef,\r\n                Rank_Emplacement_Page_Web: _rankForDel,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n        }\r\n        \r\n        \/\/ \u2705 v1.16.0 : Appeler RestoreadSpaceTemplateLocal directement (accessible dans ce scope)\r\n        RestoreadSpaceTemplateLocal(e.currentTarget);\r\n        \r\n        window.FonctionCroixResetAnnonce(e.currentTarget);\r\n        \r\n        \/\/ \u2705 v2.1.1 : Sauf popup\r\n        var formatWasSelected = sessionStorage.getItem('FormatSelect') \r\n            || sessionStorage.getItem('Commande_Format_Transmis')\r\n            || $droppable.data('kitFormatSelect');\r\n        \r\n        if (sessionStorage.getItem('PopUpChoice') !== 'Yes' && (formatWasSelected || sessionStorage.getItem('Formatchoisi') === 'Yes')) {\r\n            sessionStorage.setItem('Formatchoisi', 'Yes');\r\n            console.log('\u2705 Formatchoisi forc\u00e9 \u00e0 Yes apr\u00e8s reset');\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.6 : Remettre \u00e0 jour le titre format et r\u00e9afficher la checkbox R\u00e9server\r\n        setTimeout(() => {\r\n            FormatUIManager.updateTitleColor($droppable);\r\n            FormatUIManager.updateReserverCheckboxState($droppable);\r\n            \r\n            \/\/ \u2705 R\u00e9afficher le .ReserverContainer statique\r\n            $droppable.find('.ReserverContainer').show();\r\n        }, 150);\r\n    }\r\n};\r\n\r\n\/**\r\n * \u2705 Template pour r\u00e9initialisation des espaces publicitaires (IFRAME)\r\n *\/\r\nvar adSpaceTemplatesLocal = {};\r\n\r\nfunction saveAdSpaceTemplateLocal() {\r\n    var saved = 0;\r\n    jQuery('.droppable').each(function() {\r\n        var droppableId = jQuery(this).attr('id');\r\n        if (!droppableId) return;\r\n        \r\n        \/\/ \u2705 Ne jamais sauvegarder Ele0A (clone temporaire popup, pas un template d'origine)\r\n        if (droppableId === 'Ele0A') return;\r\n        \r\n        \/\/ \u2705 Ne pas r\u00e9-\u00e9craser un template d\u00e9j\u00e0 sauvegard\u00e9\r\n        if (adSpaceTemplatesLocal[droppableId]) return;\r\n        \r\n        \/\/ \u2705 v2.3.4 : Ne pas sauvegarder si template d\u00e9j\u00e0 connu (\u00e9tat propre sauvegard\u00e9)\r\n        \/\/ Le guard hasAd est supprim\u00e9 \u2014 on veut capturer le template le plus t\u00f4t possible\r\n        \/\/ Si le template existe d\u00e9j\u00e0, on ne le r\u00e9\u00e9crase pas\r\n        \/\/ (le guard anti-\u00e9crasement if (adSpaceTemplatesLocal[droppableId]) return; suffit)\r\n        \r\n        var $content = jQuery(this).find('.OrdiMobileConteneurClass').first();\r\n        if ($content.length > 0) {\r\n            adSpaceTemplatesLocal[droppableId] = $content.clone(true, true);\r\n            saved++;\r\n        }\r\n    });\r\n    if (saved > 0) {\r\n        console.log('\u2705 Templates espaces pub sauvegard\u00e9s:', saved, 'espaces -', Object.keys(adSpaceTemplatesLocal));\r\n        return true;\r\n    }\r\n    return false;\r\n}\r\n\r\nfunction RestoreadSpaceTemplateLocal(element) {\r\n    console.log('\ud83d\udd04 RestoreadSpaceTemplateLocal', element);\r\n    \r\n    var $element = jQuery(element);\r\n    var $droppable = $element.closest('.droppable');\r\n    var droppableId = $droppable.attr('id');\r\n    \r\n    \/\/ \u2705 FIX Ele0A : pas de template sauvegard\u00e9 (clone temporaire popup)\r\n    \/\/ \u2192 pas de remplacement DOM, reset visuel direct sur le contenu existant\r\n    var _isEle0A = (droppableId === 'Ele0A');\r\n\r\n    \/\/ \u2705 v1.19.3 : Chercher le template sp\u00e9cifique \u00e0 CET espace (sauf Ele0A)\r\n    if (!_isEle0A) {\r\n        if (!droppableId || !adSpaceTemplatesLocal[droppableId]) {\r\n            if (!saveAdSpaceTemplateLocal()) {\r\n                console.error('\u274c Template non disponible');\r\n                return false;\r\n            }\r\n            if (!adSpaceTemplatesLocal[droppableId]) {\r\n                console.error('\u274c Template non trouv\u00e9 pour', droppableId);\r\n                return false;\r\n            }\r\n        }\r\n    }\r\n    \r\n    var adSpaceElement = $droppable.find('.OrdiMobileConteneurClass').first();\r\n    \r\n    if (!adSpaceElement || !adSpaceElement.length) {\r\n        console.error('\u274c OrdiMobileConteneurClass non trouv\u00e9');\r\n        return false;\r\n    }\r\n    \r\n    var newElement;\r\n    if (_isEle0A) {\r\n        \/\/ Ele0A : pas de clone \u2014 on remet en \u00e9tat le contenu existant directement\r\n        newElement = adSpaceElement;\r\n        console.log('\u2705 [Ele0A] reset visuel direct (pas de template clone)');\r\n        \/\/ \u2705 Vider le contenu du dropzone et restaurer le HTML par d\u00e9faut\r\n        \/\/ (le replaceWith n'ayant pas lieu, l'image d\u00e9pos\u00e9e et le fond blanc restent sinon)\r\n        var $dz0A = $droppable.find('#drop_file_zone_achat');\r\n        $dz0A.empty().html(\r\n            '<div id=\"drag_upload_file_achat\">' +\r\n                '<p class=\"UploadIci\" style=\"color:#FB5E2A;font-weight:600;\">Ici glisser \u2013 d\u00e9poser ou<br>t\u00e9l\u00e9charger une annonce<\/p>' +\r\n            '<\/div>'\r\n        );\r\n        \/\/ Restaurer le fond bleu #9FC5F3 et retirer les styles d'annonce upload\u00e9e\r\n        $droppable.find('#UploadFileConteneur').css({\r\n            'background-color': '#9FC5F3',\r\n            'border': '',\r\n            'box-sizing': ''\r\n        });\r\n        $droppable.find('.HTMLUploadfileConteneur').css({\r\n            'box-shadow': '',\r\n            'background-color': '',\r\n            'border': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': '',\r\n            'overflow': '',\r\n            'height': '',\r\n            'max-height': ''\r\n        });\r\n        \/\/ Masquer la croix et le titre d'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle, #CroixResetAnnonce, .CroixResetAnnonceContainer, .DeplaceAnnonce').hide();\r\n        $droppable.removeAttr('data-via-ad-loaded').removeAttr('data-from-miniature');\r\n        console.log('\u2705 [Ele0A] dropzone vid\u00e9 + fond restaur\u00e9');\r\n    } else {\r\n        \/\/ \u2705 v1.19.3 : Cloner le template SP\u00c9CIFIQUE \u00e0 cet espace (pas le premier)\r\n        newElement = adSpaceTemplatesLocal[droppableId].clone(true, true);\r\n        console.log('\u2705 Template utilis\u00e9 pour', droppableId);\r\n        adSpaceElement.replaceWith(newElement);\r\n        \/\/ \u2705 v2.4.12 : Effacer data-via-ad-loaded (sinon selectEspaceActif masque .ReserverContainer)\r\n        $droppable.removeAttr('data-via-ad-loaded').removeAttr('data-from-miniature');\r\n        if (window.outerWidth < 1000) {\r\n            newElement.css({'margin-top': '-25px', 'bottom': '0px'});\r\n        }\r\n    }\r\n    \r\n    \/\/ D\u00e9cocher la case Envoi diff\u00e9r\u00e9 si elle existe\r\n    newElement.find('input[name*=\"EnvoiUlterieur\"]').prop('checked', false);\r\n    \r\n    \/\/ \u2705 D\u00e9cocher la checkbox \"R\u00e9server\"\r\n    newElement.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked', false);\r\n    \r\n    \/\/ Reset l'\u00e9tat EnvoiUlterieur\r\n    StateManager.set('EnvoiUlterieur', 'false');\r\n    \r\n    \/\/ \u2705 v1.19.3 : R\u00e9initialiser TOUS les styles inline des conteneurs parents modifi\u00e9s pendant le d\u00e9p\u00f4t\r\n    if ($droppable.length) {\r\n        \/\/ \u2705 v2.0.9 : Restaurer les marges de l'algorithme de positionnement (sauvegard\u00e9es par styleUploadedAd)\r\n        var origMt = $droppable.data('orig-mt');\r\n        $droppable.css({\r\n            'margin-top': (origMt !== undefined) ? origMt + 'px' : '',\r\n            'margin-bottom': '',\r\n            'margin-left': '',\r\n            'margin-right': ''\r\n        });\r\n        \/\/ \u2705 v2.0.11 : Cleanup event namespace docpreview\r\n        $droppable.off('click.docpreview');\r\n        \r\n        \/\/ Reset .OrdiMobileConteneurClass margins\r\n        var $container = $droppable.find('.OrdiMobileConteneurClass');\r\n        var origMb = $container.data('orig-mb');\r\n        $container.css({\r\n            'margin-top': '',\r\n            'margin-bottom': (origMb !== undefined) ? origMb + 'px' : ''\r\n        });\r\n        \r\n        \/\/ Reset .HTMLUploadfileConteneur (set by styleUploadedAd: box-shadow inset, background-color:white)\r\n        $droppable.find('.HTMLUploadfileConteneur').css({\r\n            'border': '',\r\n            'box-shadow': '',\r\n            'outline': '',\r\n            'outline-offset': '',\r\n            'background-color': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': '',\r\n            'overflow': '',\r\n            'padding': '',\r\n            'position': ''\r\n        });\r\n        $droppable.find('.via-green-border-overlay').remove();\r\n        \r\n        \/\/ \u2705 Restaurer pointer-events sur OrdiMobileConteneurClass et ses enfants\r\n        $droppable.find('.OrdiMobileConteneurClass').css('pointer-events', '');\r\n        $droppable.find('#CroixResetAnnonce').css({'pointer-events': '', 'position': '', 'z-index': ''});\r\n        \/\/ \u2705 v2.4.5 : Reset margin-right Ele0A (pos\u00e9 par adjustMobileLayout)\r\n        var _croixContReset = $droppable.find('.CroixResetAnnonceContainer')[0];\r\n        if (_croixContReset) { _croixContReset.style.removeProperty('margin-right'); _croixContReset.style.removeProperty('margin-top'); }\r\n        $droppable.find('#PopUpMessageAchattest').css('pointer-events', '');\r\n        \r\n        \/\/ \u2705 v2.0.9 : Restaurer le scale(1.4) sur .UploadFileConteneur (r\u00e9duit \u00e0 scale(1) par styleUploadedAd sur mobile)\r\n        $droppable.find('.UploadFileConteneur').css({\r\n            'transform': '',\r\n            'transform-origin': ''\r\n        });\r\n        \r\n        \/\/ Reset #UploadFileConteneur - Restaurer le fond bleu #9FC5F3 + retirer liser\u00e9 envoi diff\u00e9r\u00e9\r\n        $droppable.find('#UploadFileConteneur').css({\r\n            'width': '',\r\n            'background-color': '#9FC5F3',\r\n            'border': '',\r\n            'box-sizing': ''\r\n        });\r\n        \r\n        \/\/ Reset .ToBeHidden (set by adjustDesktopLayout: top:105px, min-height:300px + overflow mobile)\r\n        $droppable.closest('.ToBeHidden').css({\r\n            'top': '',\r\n            'min-height': '',\r\n            'overflow': ''\r\n        });\r\n        \r\n        \/\/ Reset overflow sur le parent du droppable (set by adjustDesktopLayout)\r\n        $droppable.parent().css('overflow', '');\r\n        \r\n        \/\/ \u2705 v1.19.5 : Gestion device-specific pour les textes\r\n        var isDesktop = window.outerWidth >= 1000;\r\n        \r\n        if (isDesktop) {\r\n            \/\/ Desktop : cacher les textes mobiles, afficher UploadIci\r\n            $droppable.find('.TexteMobile').hide();\r\n            $droppable.find('.TexteMobileAnnonce').hide();\r\n            $droppable.find('.TexteMobileAjoutAnnonce').hide();\r\n            $droppable.find('.UploadIci').show();\r\n        } else {\r\n            \/\/ Mobile : afficher TexteMobileAnnonce\r\n            $droppable.find('.TexteMobileAnnonce').show();\r\n        }\r\n        \r\n        \/\/ R\u00e9-afficher les \u00e9l\u00e9ments masqu\u00e9s pendant l'upload\r\n        $droppable.find('.PositionEspacePublicitaireContainer').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireDisponibiliteConteneur').show();\r\n        $droppable.find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur > div > .elementor-widget-text-editor').show();\r\n        $droppable.find('.AdDroppedTextNotDisplayed').hide();\r\n        \/\/ \u2705 v2.4.5 : Ele0A + PopUpChoice=Yes \u2192 ne pas r\u00e9-afficher le titre si format d\u00e9j\u00e0 s\u00e9lectionn\u00e9\r\n        var _skipTitre = (sessionStorage.getItem('PopUpChoice') === 'Yes' && $droppable.attr('id') === 'Ele0A');\r\n        $droppable.find('.SelectionFormatTitreBlanc').hide();\r\n        if (!_skipTitre) {\r\n            $droppable.find('.SelectionFormatTitre').show();\r\n        }\r\n        $droppable.find('span.ClassHdpCdp, .ClassRefEsp').show();\r\n        $droppable.find('.EspPubFormatMainContainer').show();\r\n        $droppable.find('.EspPubFormatListe').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireClass').show();\r\n        $droppable.find('.GlisserDeposerConteneur').show();\r\n        $droppable.find('.OUClass').show();\r\n        $droppable.find('.PositionReference').show();\r\n        $droppable.find('.ClassHdpCdp').show();\r\n        $droppable.find('.ClassRefEsp').show();\r\n        $droppable.find('.EnvoiUlterieurTexte').show();\r\n        $droppable.find('.EnvoiUlterieurContainer').show();\r\n        \r\n        \/\/ \u2705 v1.19.5 : R\u00e9afficher le .ReserverContainer (bouton Elementor statique)\r\n        $droppable.find('.ReserverContainer').show();\r\n        newElement.find('.ReserverContainer').show();\r\n        \r\n        \/\/ Masquer les \u00e9l\u00e9ments sp\u00e9cifiques \u00e0 l'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle, #CroixResetAnnonce, .CroixResetAnnonceContainer, .DeplaceAnnonce').hide();\r\n        $droppable.find('#CroixResetAnnonce').css({'position': '', 'z-index': ''});\r\n        $droppable.find('.RefEspacePublicitaire').hide();\r\n        \r\n        \/\/ Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 v1.19.6 : Restaurer le format s\u00e9lectionn\u00e9 visuellement\r\n        \/\/ Chercher le format dans plusieurs sources possibles\r\n        var formatSelect = sessionStorage.getItem('FormatSelect') \r\n            || sessionStorage.getItem('Commande_Format_Transmis')\r\n            || $droppable.data('kitFormatSelect')\r\n            || '';\r\n        \r\n        var formatchoisi = sessionStorage.getItem('Formatchoisi');\r\n        console.log('\ud83d\udcd0 Format \u00e0 restaurer:', formatSelect, '| Formatchoisi:', formatchoisi);\r\n        \r\n        \/\/ D'abord reset tous les formats visuellement (sur newElement ET $droppable)\r\n        var $allFormats = newElement.find('.EspPubFormatContainer').add($droppable.find('.EspPubFormatContainer'));\r\n        $allFormats.css({\r\n            'background-color': '',\r\n            'border': ''\r\n        });\r\n        newElement.find('.EspPubFormat').add($droppable.find('.EspPubFormat')).css({\r\n            'color': ''\r\n        });\r\n        \r\n        \/\/ Si un format \u00e9tait s\u00e9lectionn\u00e9 (via sessionStorage OU visuellement avant)\r\n        \/\/ \u2705 v2.1.1 : Sauf popup\r\n        if ((formatSelect || formatchoisi === 'Yes') && sessionStorage.getItem('PopUpChoice') !== 'Yes') {\r\n            var formatFound = false;\r\n            \r\n            if (formatSelect) {\r\n                \/\/ \u2705 v2.1.1 : Normaliser via NFD (plus fiable que les replace manuels)\r\n                var formatLower = formatSelect.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase().replace(\/ \/g, '');\r\n                \r\n                \/\/ Appliquer sur newElement ET $droppable pour \u00eatre s\u00fbr\r\n                var $allContainers = newElement.find('.EspPubFormatContainer').add($droppable.find('.EspPubFormatContainer'));\r\n                \r\n                $allContainers.each(function() {\r\n                    var className = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    \r\n                    if (className.includes(formatLower)) {\r\n                        jQuery(this).css({'background-color': '#ffffff'});\r\n                        jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        formatFound = true;\r\n                        \/\/ \u2705 v2.4.12 : M\u00e9moriser le format restaur\u00e9 (lu par selectEspaceActif pour re-surligner apr\u00e8s reset global)\r\n                        $droppable.attr('data-restored-format', formatSelect);\r\n                        console.log('\u2705 Format restaur\u00e9 visuellement:', formatSelect, '- classe:', this.className);\r\n                    }\r\n                });\r\n            }\r\n            \r\n            \/\/ \u2705 IMPORTANT : Pr\u00e9server Formatchoisi = Yes pour permettre l'upload\r\n            sessionStorage.setItem('Formatchoisi', 'Yes');\r\n            console.log('\u2705 Formatchoisi maintenu \u00e0 Yes');\r\n            \r\n            \/\/ Basculer les titres format (sur newElement ET $droppable)\r\n            newElement.find('.SelectionFormatTitre').hide();\r\n            newElement.find('.SelectionFormatTitreBlanc').show();\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n        }\r\n    }\r\n    \r\n    \/\/ \u2705 v1.19.2 : Relancer InitLoadedPage pour recalculer positions et tailles\r\n    setTimeout(function() {\r\n        if (typeof window.InitLoadedPage === 'function') {\r\n            window.InitLoadedPage();\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.6 : R\u00e9attacher les MutationObservers sur les formats\r\n        if (typeof FormatUIManager !== 'undefined' && FormatUIManager.observeFormatChanges) {\r\n            FormatUIManager.observeFormatChanges();\r\n        }\r\n    }, 100);\r\n    \r\n    console.log('\u2705 Espace publicitaire r\u00e9initialis\u00e9');\r\n    return true;\r\n}\r\n\r\n\/\/ \u2705 Exposer pour appel depuis yearbook-media.js (suppression popup mode=popup)\r\nwindow.RestoreadSpaceTemplateLocal = RestoreadSpaceTemplateLocal;\r\n\r\nwindow.verifierAffichageMsgSelectEspaceLocal = function() {\r\n    const formatChoisi = StateManager.get('Formatchoisi') === 'Yes';\r\n    const fileReceived = StateManager.get('FileReceived');\r\n    const envoiUlterieur = StateManager.get('EnvoiUlterieur');\r\n    \r\n    var dateDebut, dateFin, pays;\r\n    try {\r\n        dateDebut = window.parent.$('#form-field-DebutCampagne').val();\r\n        dateFin = window.parent.$('#form-field-FinCampagne').val();\r\n        pays = window.parent.$('#form-field-Nationalite_Societe').val();\r\n    } catch(e) {\r\n        jQuery('#MsgSelectEspace').hide();\r\n        return;\r\n    }\r\n    \r\n    if (!dateDebut || !dateFin || !pays || !formatChoisi) {\r\n        jQuery('#MsgSelectEspace').hide();\r\n        return;\r\n    }\r\n    \r\n    if (fileReceived !== 'Yes') {\r\n        if (envoiUlterieur !== 'true') {\r\n            jQuery('#MsgSelectEspace').show();\r\n        } else {\r\n            jQuery('#MsgSelectEspace').hide();\r\n        }\r\n    } else {\r\n        jQuery('#MsgSelectEspace').hide();\r\n    }\r\n};\r\n\r\n\/\/ Sauvegarder les templates au chargement (apr\u00e8s rendu complet Elementor)\r\njQuery(document).ready(function() {\r\n    \/\/ \u2705 v1.19.3 : D\u00e9lai augment\u00e9 + double sauvegarde pour garantir les bonnes dimensions\r\n    setTimeout(saveAdSpaceTemplateLocal, 3000);\r\n    setTimeout(saveAdSpaceTemplateLocal, 6000);\r\n    \/\/ \u2705 v2.3.4 : Sauvegarde imm\u00e9diate d\u00e8s que la page est pr\u00eate dans l'iframe\r\n    \/\/ (avant toute interaction utilisateur)\r\n    setTimeout(saveAdSpaceTemplateLocal, 100);\r\n    setTimeout(saveAdSpaceTemplateLocal, 500);\r\n});\r\n\r\n\/\/ \u2705 v2.3.4 : Forcer sauvegarde \u00e0 la r\u00e9ception de elementsRemoved (espaces visibles + vierges)\r\nwindow.addEventListener('message', function(e) {\r\n    if (e.data && e.data.type === 'elementsRemoved') {\r\n        \/\/ Les espaces sont vierges \u00e0 ce stade \u2192 sauvegarder imm\u00e9diatement\r\n        setTimeout(saveAdSpaceTemplateLocal, 50);\r\n        setTimeout(saveAdSpaceTemplateLocal, 300);\r\n    }\r\n});\r\n\r\n\/**\r\n * Fonction helper pour le d\u00e9p\u00f4t r\u00e9dactionnel\r\n *\/\r\nfunction RedactionnelDepose() {\r\n    jQuery('#Tariftobedisplayed').html('-');\r\n    jQuery('#TarifDataStep3').html('\u00e0 choisir').css({'color': '#FB5E2A'});\r\n    jQuery('#FormatDataStep3').html('\u00e0 choisir').css({'color': '#FB5E2A'});\r\n    jQuery('#ListePaysDirect, #ListeThemeDirect, .ListeArticles, #PageAfficheeMessage').hide();\r\n    StateManager.set(\"PositionAnnonceSelection\", 'Yes');\r\n}\r\n\r\n\/**\r\n * Exposition des fonctions globales n\u00e9cessaires\r\n *\/\r\nwindow.uploadFile_achat = (e) => DropHandler.handleDrop(e);\r\nwindow.fileExplorer_achat = (e) => FileExplorer.open(e);\r\nwindow.ajaxFileUpload_achat = (fileObj, dropZone) => UploadManager.handleFileUpload(fileObj, dropZone);\r\nwindow.ActivatesendDataToParent = (dropZone) => UploadManager.activateSendDataToParent(dropZone);\r\n\/\/ \u2705 v2.3.4 : Exposer FormatUIManager pour appel depuis Entete.txt (selectEspaceActif)\r\nwindow.FormatUIManagerRef = FormatUIManager;\r\n\r\n\/**\r\n * Initialisation de l'application\r\n *\/\r\njQuery(document).ready(() => {\r\n    StateManager.init();\r\n    ScrollHelper.init();\r\n    DragDropManager.init();\r\n    FormatUIManager.init();\r\n    \r\n    if (UIManager.isMobile()) {\r\n        UIManager.initMobileUI();\r\n    } else {\r\n        UIManager.initDesktopUI();\r\n    }\r\n    \r\n    jQuery(document).on('click', '#CroixResetAnnonce', (e) => AdResetHandler.handle(e));\r\n    \r\n    \/\/ \u2705 Clic sur le texte du label \u2192 toggle manuel de la checkbox du m\u00eame conteneur\r\n    jQuery(document).on('click', '.reserver-dynamic-label', function(e) {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        const $cb = $(this).closest('.reserver-dynamic-option, .reserver-dynamic-container').find('.reserver-dynamic-checkbox');\r\n        if ($cb.length) {\r\n            $cb.prop('checked', !$cb.prop('checked')).trigger('change');\r\n        }\r\n    });\r\n\r\n    \/\/ \u2705 CHECKBOX \"R\u00e9server cet espace publicitaire\" \u2014 VALIDATION ET ENVOI DES DONN\u00c9ES\r\n    \/\/ \u2705 v2.4.13 : iOS touchend\r\n    \/\/ \u2705 v2.4.13 : Mobile \u2014 \u00e9couter touchend sur input ET click\/touchend sur label\r\n    jQuery(document).on('touchend', 'input[name=\"form_fields[ReserverEspacePublicitaire]\"]', function() {\r\n        if (this._viaResTouch) { return; }\r\n        this._viaResTouch = true;\r\n        var _self = this;\r\n        setTimeout(function() { _self._viaResTouch = false; }, 500);\r\n        setTimeout(function() { jQuery(_self).trigger('change'); }, 100);\r\n    });\r\n    jQuery(document).on('touchend click', '.elementor-field-group-ReserverEspacePublicitaire label, .reserver-dynamic-label, .reserver-dynamic-option label', function(e) {\r\n        \/\/ Trouver l'input associ\u00e9\r\n        var $input = jQuery(this).closest('.elementor-field-option, .reserver-dynamic-option').find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n        if (!$input.length) { $input = jQuery(this).siblings('input[name=\"form_fields[ReserverEspacePublicitaire]\"]'); }\r\n        if (!$input.length) { $input = jQuery('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').first(); }\r\n        if ($input.length) {\r\n            if (e.type === 'touchend') { e.preventDefault(); }\r\n            var _wasChecked = $input.prop('checked');\r\n            $input.prop('checked', !_wasChecked);\r\n            setTimeout(function() {\r\n                $input.trigger('change');\r\n            }, 50);\r\n        }\r\n    });\r\n    jQuery(document).on('change', 'input[name=\"form_fields[ReserverEspacePublicitaire]\"]', function(e) {\r\n        const $checkbox = $(this);\r\n        let $droppable = $checkbox.closest('.droppable');\r\n        if (!$droppable.length) {\r\n            $droppable = $checkbox.closest('.reserver-dynamic-container').prev('.droppable');\r\n        }\r\n        \/\/ \u2705 v2.4.13 : Fallback mobile \u2014 checkbox dans body > .reserver-dynamic-container[data-droppable-id]\r\n        if (!$droppable.length) {\r\n            const $dynContainer = $checkbox.closest('.reserver-dynamic-container');\r\n            const _droppableId = $dynContainer.attr('data-droppable-id') || '';\r\n            if (_droppableId) {\r\n                $droppable = $('#' + _droppableId);\r\n            }\r\n        }\r\n        \/\/ Dernier recours : utiliser le rank en sessionStorage\r\n        if (!$droppable.length) {\r\n            const _rankFallback = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            if (_rankFallback) { $droppable = $('#' + _rankFallback); }\r\n        }\r\n        \r\n        \/\/ Si on d\u00e9coche\r\n        if (!$checkbox.is(':checked')) {\r\n            console.log('\u2610 Checkbox \"R\u00e9server\" d\u00e9coch\u00e9e');\r\n            \/\/ \u2705 Mettre \u00e0 jour le label\r\n            const $lbl = $checkbox.closest('.reserver-dynamic-option, .elementor-field-option').find('.reserver-dynamic-label, label').not('input');\r\n            $lbl.text('R\u00e9server cet espace publicitaire').css('color', '');\r\n            \/\/ \u2705 Notifier le parent pour d\u00e9-r\u00e9server l'item dans le r\u00e9cap\r\n            const _rankDecoche = $droppable.attr('id') || StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            const _emplacementDecoche = StateManager.buildEmplacementReference(_rankDecoche);\r\n            MessageManager.sendToParent('annulationReservation', {\r\n                Rank_Emplacement_Page_Web: _rankDecoche,\r\n                Commande_Emplacement_Page_Web: _emplacementDecoche,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n            \/\/ \u2705 v2.4.5 : M\u00e9moriser que ce rank a \u00e9t\u00e9 explicitement d\u00e9coch\u00e9\r\n            StateManager.set('_reserverDecoche_' + _rankDecoche, 'Yes');\r\n            console.log('\ud83d\udce4 annulationReservation envoy\u00e9 \u2192 parent | rank:', _rankDecoche, '| emplacement:', _emplacementDecoche);\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 V\u00e9rifier les conditions : format s\u00e9lectionn\u00e9 ET (fichier d\u00e9pos\u00e9 OU envoi diff\u00e9r\u00e9)\r\n        const hasFormat = FormatUIManager.hasSelectedFormat($droppable);\r\n        const hasFile = StateManager.get('FileReceived') === 'Yes';\r\n        const hasEnvoiDiffere = $droppable.find('input[name*=\"EnvoiUlterieur\"]:checked').length > 0;\r\n        \r\n        console.log('\ud83d\udd0d Checkbox \"R\u00e9server\" - Validation:', { hasFormat, hasFile, hasEnvoiDiffere });\r\n        \r\n        if (!hasFormat) {\r\n            \/\/ \u2705 Si un fichier est d\u00e9j\u00e0 d\u00e9pos\u00e9 \u2192 d\u00e9duire le format depuis l'extension (ne pas bloquer)\r\n            if (hasFile) {\r\n                const _uploadedName = StateManager.get('Upload_File_Name') || '';\r\n                const _ext = _uploadedName.split('.').pop().toLowerCase();\r\n                const _fileType = FileManager.getFileType(_ext);\r\n                let _deducedFormat = '';\r\n                if (_fileType === 'video') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Video' : 'Vid\u00e9o';\r\n                } else if (_fileType === 'image') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Banner' : 'Banni\u00e8re';\r\n                } else if (_fileType === 'document') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Press release' : 'Communiqu\u00e9';\r\n                }\r\n                if (_deducedFormat) {\r\n                    StateManager.set('Commande_Format_Transmis', _deducedFormat);\r\n                    StateManager.set('FormatSelect', _deducedFormat);\r\n                    StateManager.set('Formatchoisi', 'Yes');\r\n                    console.log('\u2705 Format d\u00e9duit depuis extension (' + _ext + '):', _deducedFormat);\r\n                    \/\/ Continuer vers l'envoi (pas de return false)\r\n                } else {\r\n                    e.preventDefault();\r\n                    $checkbox.prop('checked', false);\r\n                    FormatUIManager.flashTitle($droppable);\r\n                    console.log('\u274c R\u00e9servation bloqu\u00e9e : format non d\u00e9ductible depuis extension:', _ext);\r\n                    return false;\r\n                }\r\n            } else {\r\n                e.preventDefault();\r\n                $checkbox.prop('checked', false);\r\n                FormatUIManager.flashTitle($droppable);\r\n                console.log('\u274c R\u00e9servation bloqu\u00e9e : aucun format s\u00e9lectionn\u00e9');\r\n                return false;\r\n            }\r\n        }\r\n        \r\n        if (!hasFile && !hasEnvoiDiffere) {\r\n            e.preventDefault();\r\n            $checkbox.prop('checked', false);\r\n            console.log('\u274c R\u00e9servation bloqu\u00e9e : ni annonce d\u00e9pos\u00e9e ni envoi diff\u00e9r\u00e9');\r\n            return false;\r\n        }\r\n        \r\n        \/\/ \u2705 Conditions remplies \u2014 Pr\u00e9parer et envoyer les donn\u00e9es\r\n        console.log('\u2705 Checkbox \"R\u00e9server\" valid\u00e9e \u2014 envoi des donn\u00e9es');\r\n        \r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.setMultiple({\r\n            \"sendDataToParentFlag\": \"Yes\",\r\n            \"Formatchoisi\": \"Yes\",\r\n            \"Rank_Emplacement_Page_Web\": rankId,\r\n            \"Commande_Emplacement_Page_Web\": StateManager.buildEmplacementReference(rankId),\r\n            \"LoadedPageUrl\": window.location.href,\r\n            \/\/ \u2705 v2.3.0 : Forcer avant l'envoi \u2014 le setTimeout(4000) dans activateSendDataToParent\r\n            \/\/ arrive trop tard sur le 1er clic \u2192 AddNewRefInVosCampagnes restait null\r\n            \"AddNewRefInVosCampagnes\": \"Yes\"\r\n        });\r\n        \r\n        \/\/ \u2705 D\u00e9clencher l'envoi des donn\u00e9es via activateSendDataToParent\r\n        const $dropZone = $droppable.find('#drop_file_zone_achat');\r\n        UploadManager.activateSendDataToParent($dropZone);\r\n    });\r\n    \r\n    \/\/ G\u00c9RER \"Envoi diff\u00e9r\u00e9\" \u2014 marquer l'\u00e9tat sans envoyer (c'est \"R\u00e9server\" qui envoie)\r\n    \/\/ \u2705 v2.4.13 : iOS touchend\r\n    jQuery(document).on('touchend', 'input[name*=\"EnvoiUlterieur\"]', function() {\r\n        if (this._viaTouch) { return; }\r\n        this._viaTouch = true;\r\n        var _self = this;\r\n        setTimeout(function() { _self._viaTouch = false; }, 500);\r\n        setTimeout(function() { jQuery(_self).trigger('change'); }, 100);\r\n    });\r\n    jQuery(document).on('change', 'input[name*=\"EnvoiUlterieur\"]', function(e) {\r\n        const $checkbox = $(this);\r\n        let $droppable = $checkbox.closest('.droppable');\r\n        \/\/ \u2705 v2.4.13 : Fallback mobile\r\n        if (!$droppable.length) {\r\n            const $dynContainer = $checkbox.closest('.reserver-dynamic-container');\r\n            const _droppableId = $dynContainer.attr('data-droppable-id') || '';\r\n            if (_droppableId) { $droppable = $('#' + _droppableId); }\r\n        }\r\n        if (!$droppable.length) {\r\n            const _rankFallback = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            if (_rankFallback) { $droppable = $('#' + _rankFallback); }\r\n        }\r\n  \r\n        \/\/ Si on d\u00e9coche\r\n        if (!$checkbox.is(':checked')) {\r\n            StateManager.set('EnvoiUlterieur', 'false');\r\n            \r\n            if (typeof window.verifierAffichageMsgSelectEspaceLocal === 'function') {\r\n                window.verifierAffichageMsgSelectEspaceLocal();\r\n            }\r\n            \r\n            \/\/ Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server\r\n            FormatUIManager.updateReserverCheckboxState($droppable);\r\n            return;\r\n        }\r\n        \r\n        \/\/ Si on coche, masquer le message\r\n        jQuery('#MsgSelectEspace').hide();\r\n    \r\n        \/\/ V\u00e9rifier si un format est s\u00e9lectionn\u00e9\r\n        const hasSelectedFormat = FormatUIManager.hasSelectedFormat($droppable);\r\n        \r\n        if (!hasSelectedFormat) {\r\n            e.preventDefault();\r\n            $checkbox.prop('checked', false);\r\n            FormatUIManager.flashTitle($droppable);\r\n            return false;\r\n        }\r\n        \r\n        \/\/ \u2705 FORMAT OK \u2014 Marquer l'\u00e9tat envoi diff\u00e9r\u00e9 (sans envoyer les donn\u00e9es)\r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.setMultiple({\r\n            \"EnvoiUlterieur\": 'true',\r\n            \"Rank_Emplacement_Page_Web\": rankId,\r\n            \"Commande_Emplacement_Page_Web\": StateManager.buildEmplacementReference(rankId),\r\n            \"LoadedPageUrl\": window.location.href,\r\n            \"FileReceived\": \"No\",\r\n            \"FullPathAdFile\": '',\r\n            \"Upload_File_Name\": '',\r\n            \"Formatchoisi\": 'Yes'\r\n        });\r\n        \r\n        console.log('\ud83d\udcdd Envoi diff\u00e9r\u00e9 coch\u00e9 \u2014 en attente de validation via checkbox \"R\u00e9server\"');\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server (maintenant activable)\r\n        FormatUIManager.updateReserverCheckboxState($droppable);\r\n    });\r\n\r\n    \/\/ \u2705 v2.2.0 : Bouton \"Cr\u00e9ation\" dans espace publicitaire \u2192 Kit Ad Creator dans le parent\r\n    jQuery(document).on('click', '.FormatIdCreation', function(e) {\r\n        e.preventDefault();\r\n        var $btn = jQuery(this);\r\n        var isActive = $btn.data('creationActive') === true;\r\n\r\n        if (isActive) {\r\n            \/\/ D\u00e9sactiver\r\n            $btn.data('creationActive', false);\r\n            $btn.find('.EspPubFormat').css({'color': '#ffffff'});\r\n            $btn.css({'background-color': 'transparent'});\r\n            MessageManager.sendToParent('closeAdCreatorFromIframe', {});\r\n            console.log('\ud83c\udfa8 Cr\u00e9ation iframe \u2192 toggle OFF, fermeture popup parent');\r\n        } else {\r\n            \/\/ Activer : texte vert sur fond blanc\r\n            $btn.data('creationActive', true);\r\n            $btn.find('.EspPubFormat').css({'color': '#37D900'});\r\n            $btn.css({'background-color': '#ffffff'});\r\n            var formatSelect = sessionStorage.getItem('FormatSelect') || '';\r\n            var formatTransmis = sessionStorage.getItem('Commande_Format_Transmis') || '';\r\n            \/\/ \u2705 v2.2.1 : Envoyer aussi Commande_Format_Transmis (format cliqu\u00e9 dans l'iframe, sans accent)\r\n            var _rankKit = $btn.closest('.droppable').attr('id') || sessionStorage.getItem('Rank_Emplacement_Page_Web') || '';\r\n            var _cSite = sessionStorage.getItem('codeSite') || '';\r\n            var _cPage = sessionStorage.getItem('codePage') || '';\r\n            var _sfxKit = _rankKit.replace('Ele', '');\r\n            var _emplKit = (_cSite && _cPage && _sfxKit) ? (_cSite + _cPage + 'L' + _sfxKit) : (sessionStorage.getItem('Commande_Emplacement_Page_Web') || '');\r\n            MessageManager.sendToParent('openAdCreatorFromIframe', { formatSelect: formatSelect, formatTransmis: formatTransmis, rankId: _rankKit, emplacement: _emplKit });\r\n            console.log('\ud83c\udfa8 Cr\u00e9ation iframe \u2192 toggle ON (FormatSelect:', formatSelect, '| Commande_Format_Transmis:', formatTransmis, ')');\r\n        }\r\n    });\r\n\r\n    \/\/ \u2705 v2.2.0 : Messages depuis le parent concernant le bouton Cr\u00e9ation\r\n    window.addEventListener('message', function(event) {\r\n        var msg = event.data;\r\n        if (!msg) return;\r\n\r\n        \/\/ \u2705 v2.2.1 : Fournir la position du titre R\u00e9server pour positionner la miniature\r\n        if (msg.type === 'getReserverLabelRect') {\r\n            var $label = jQuery('.reserver-dynamic-label').first();\r\n            if ($label.length) {\r\n                var r = $label[0].getBoundingClientRect();\r\n                var iframeScale = (window.outerWidth > 1000) ? 0.75 : 0.80; \/\/ \u2705 v2.4.12 : 0.85 \u2192 0.75 (scale r\u00e9el du parent)\r\n                event.source.postMessage({\r\n                    type: 'reserVeurLabelRectResult',\r\n                    \/\/ Retourner bottom en coordonn\u00e9es iframe internes (non scal\u00e9es)\r\n                    bottom: r.bottom,\r\n                    left: r.left,\r\n                    right: r.right,\r\n                    iframeScale: iframeScale\r\n                }, '*');\r\n            } else {\r\n                event.source.postMessage({ type: 'reserVeurLabelRectResult', bottom: null }, '*');\r\n            }\r\n        }\r\n\r\n        \/\/ Fermeture du popup \u2192 d\u00e9s\u00e9lectionner le bouton Cr\u00e9ation\r\n        if (msg.type === 'adCreatorClosedFromParent') {\r\n            jQuery('.FormatIdCreation').each(function() {\r\n                jQuery(this).data('creationActive', false);\r\n                jQuery(this).find('.EspPubFormat').css({'color': '#ffffff'});\r\n                jQuery(this).css({'background-color': 'transparent'});\r\n            });\r\n            console.log('\ud83c\udfa8 adCreatorClosedFromParent re\u00e7u \u2192 bouton Cr\u00e9ation d\u00e9s\u00e9lectionn\u00e9');\r\n        }\r\n\r\n        \/\/ Restaurer le style du bouton Cr\u00e9ation apr\u00e8s un reset de removeElements\r\n        if (msg.type === 'restoreCreationButton') {\r\n            jQuery('.FormatIdCreation').each(function() {\r\n                if (jQuery(this).data('creationActive') === true) {\r\n                    jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                    jQuery(this).css({'background-color': '#ffffff'});\r\n                }\r\n            });\r\n            console.log('\ud83c\udfa8 restoreCreationButton re\u00e7u \u2192 style Cr\u00e9ation restaur\u00e9');\r\n        }\r\n    });\r\n\r\n});\r\n\r\n\/\/ =========================================================================\r\n\/\/ \u2705 Listener kitAdCreated \u2014 annonce cr\u00e9\u00e9e par le Kit overlay (mode=kit)\r\n\/\/ Injecte directement dans l'espace pub identifi\u00e9 par rankId\r\nwindow.addEventListener('message', function(event) {\r\n    var msg = event.data;\r\n    if (!msg || msg.action !== 'kitAdCreated') return;\r\n\r\n    var _rankId = msg.rankId || '';\r\n    var _emplacement = msg.emplacement || '';\r\n    console.log('\ud83c\udfa8 [espace_pub] kitAdCreated re\u00e7u | rankId:', _rankId, '| emplacement:', _emplacement);\r\n\r\n    if (!_rankId) { console.warn('\u26a0\ufe0f [kitAdCreated] rankId manquant'); return; }\r\n\r\n    var $droppable = jQuery('#' + _rankId);\r\n    if (!$droppable.length) { console.warn('\u26a0\ufe0f [kitAdCreated] droppable non trouv\u00e9:', _rankId); return; }\r\n    var $dropZone = $droppable.find('.drop_file_zone_achat_class').first();\r\n    if (!$dropZone.length) { $dropZone = $droppable.find('#drop_file_zone_achat').first(); }\r\n    if (!$dropZone.length) { console.warn('\u26a0\ufe0f [kitAdCreated] dropZone non trouv\u00e9e dans', _rankId); return; }\r\n\r\n    var _dataURL = msg.fullResDataURL || msg.pdfDataURL || null;\r\n    var _filename = msg.filename || 'annonce.png';\r\n    var _isPDF = msg.isPDF || false;\r\n    if (!_dataURL) { console.warn('\u26a0\ufe0f [kitAdCreated] aucune donn\u00e9e image'); return; }\r\n\r\n    var _parts = _dataURL.split(',');\r\n    var _mime = (_parts[0].match(\/:(.*?);\/) || [])[1] || (_isPDF ? 'application\/pdf' : 'image\/png');\r\n    var _bStr = atob(_parts[1]);\r\n    var _bytes = new Uint8Array(_bStr.length);\r\n    for (var _i = 0; _i < _bStr.length; _i++) { _bytes[_i] = _bStr.charCodeAt(_i); }\r\n    var _blob = new Blob([_bytes], { type: _mime });\r\n    \/\/ \u2705 Ajouter extension si absente\r\n    var _MIME_EXT = {'image\/png':'.png','image\/jpeg':'.jpg','image\/jpg':'.jpg','image\/webp':'.webp','application\/pdf':'.pdf'};\r\n    if (_filename.indexOf('.') === -1) { _filename = _filename + (_MIME_EXT[_mime] || (_isPDF ? '.pdf' : '.png')); }\r\n    var _file = new File([_blob], _filename, { type: _mime });\r\n\r\n    \/\/ \u2705 Pr\u00e9parer StateManager\r\n    StateManager.set('Rank_Emplacement_Page_Web', _rankId);\r\n    StateManager.set('Commande_Emplacement_Page_Web', _emplacement);\r\n    StateManager.set('Formatchoisi', 'Yes');\r\n    \/\/ \u2705 Marquer le droppable directement en DOM \u2014 r\u00e9siste \u00e0 l'async, lu par styleUploadedAd\r\n    $droppable[0].setAttribute('data-kit-drop', 'true');\r\n    window._dropFromMiniature = true;\r\n\r\n    console.log('\u2705 [kitAdCreated] \u2192 UploadManager.handleFileUpload | rankId:', _rankId);\r\n    UploadManager.handleFileUpload(_file, $dropZone).then(function() {\r\n        console.log('\u2705 [kitAdCreated] handleFileUpload termin\u00e9');\r\n    }).catch(function(err) {\r\n        window._dropFromMiniature = false;\r\n        $droppable[0].removeAttribute('data-kit-drop');\r\n        console.error('\u274c [kitAdCreated] handleFileUpload erreur:', err);\r\n    });\r\n});\r\n\r\n\/\/ \u2705 v1.17.0 : Listener \"thumbnailDropped\" \u2014 d\u00e9p\u00f4t de l'annonce depuis la miniature\r\n\/\/ =========================================================================\r\n\/**\r\n * Re\u00e7oit le drop de l'image-annonce depuis la miniature dans la page parente.\r\n * Identifie l'espace publicitaire sous le curseur, s\u00e9lectionne cet espace,\r\n * et d\u00e9clenche le flux dataFromIframeEspacePub en mode \"envoi diff\u00e9r\u00e9\"\r\n * (l'utilisateur uploadera le vrai fichier depuis le formulaire de commande).\r\n *\r\n * Coordonn\u00e9es re\u00e7ues : viewport de l'iframe (clientX\/clientY relatifs \u00e0 l'iframe)\r\n *\/\r\nwindow.addEventListener('message', function(event) {\r\n    var msg = event.data;\r\n    if (!msg || msg.action !== 'thumbnailDropped') return;\r\n\r\n    console.log('\ud83d\udce8 thumbnailDropped re\u00e7u \u2014 coords iframe:', msg.xRel, msg.yRel);\r\n\r\n    \/\/ \u2705 v1.19.3 : Corriger les coordonn\u00e9es pour le facteur de scale de l'iframe\r\n    \/\/ \u2705 v2.4.10 : 0.75 = scale appliqu\u00e9 par le PARENT sur l'\u00e9l\u00e9ment iframe (et non 0.85 qui est le scale interne OrdiMobileConteneurClass)\r\n    \/\/ Les coords xRel\/yRel viennent de getBoundingClientRect() sur l'iframe scal\u00e9 \u00e0 0.75 dans le parent \u2192 diviser par 0.75\r\n    var iframeScale = (window.outerWidth > 1000) ? 0.75 : 0.80;\r\n    \/\/ \u2705 v2.4.3 : Si Entete a intercept\u00e9 et pos\u00e9 un redirect vers Ele0A, utiliser ces coords\r\n    var _redirect = window._thumbnailDropRedirect || null;\r\n    window._thumbnailDropRedirect = null;\r\n    \/\/ \u2705 v2.4.4 : Les coords de redirect viennent de getBoundingClientRect() dans l'iframe (espace logique)\r\n    \/\/            \u2192 ne pas re-diviser par iframeScale (d\u00e9j\u00e0 en coords iframe-logiques)\r\n    var xAdjusted = _redirect ? _redirect.xRel : (msg.xRel \/ iframeScale);\r\n    var yAdjusted = _redirect ? _redirect.yRel : (msg.yRel \/ iframeScale);\r\n    if (_redirect) { console.log('\ud83d\udd00 [thumbnailDropped] coords redirig\u00e9es vers Ele0A:', Math.round(xAdjusted), Math.round(yAdjusted)); }\r\n    else { console.log('\ud83d\udcd0 Coords ajust\u00e9es (scale', iframeScale, '):', Math.round(xAdjusted), Math.round(yAdjusted)); }\r\n\r\n    \/\/ 1. Identifier l'espace publicitaire le plus proche du point de drop\r\n    \/\/    \u2705 v1.18.1 : Recherche par distance \u2014 coords \u00e9ventuellement redirig\u00e9es par Entete.txt\r\n    var allDroppables = document.querySelectorAll('.droppable');\r\n    var droppableEl = null;\r\n    var closestDist = Infinity;\r\n\r\n    \/\/ \u2705 v2.4.4 : Guard rect Ele0A \u2014 si PopUpChoice=Yes ET curseur dans le rect d'Ele0A \u2192 forcer\r\n    \/\/            (Ele0A est un popup flottant : son centre peut \u00eatre loin du curseur \u2192 algo distance l'ignore)\r\n    \/\/            Ne force PAS si le drop est hors d'Ele0A \u2192 les autres espaces restent accessibles\r\n    if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n        var _ele0ACheck = document.getElementById('Ele0A');\r\n        if (_ele0ACheck) {\r\n            var _r0A = _ele0ACheck.getBoundingClientRect();\r\n            var _margin = 30;\r\n            var _inR0A = (xAdjusted >= _r0A.left - _margin);\r\n            if (_inR0A) { _inR0A = (xAdjusted <= _r0A.right + _margin); }\r\n            if (_inR0A) { _inR0A = (yAdjusted >= _r0A.top - _margin); }\r\n            if (_inR0A) { _inR0A = (yAdjusted <= _r0A.bottom + _margin); }\r\n            if (_inR0A) {\r\n                droppableEl = _ele0ACheck;\r\n                closestDist = 0;\r\n                console.log('\ud83c\udfaf [thumbnailDropped] Ele0A forc\u00e9 (curseur dans rect Ele0A +30px)');\r\n            }\r\n        }\r\n    }\r\n\r\n    if (!droppableEl) {\r\n        allDroppables.forEach(function(d) {\r\n            var r = d.getBoundingClientRect();\r\n            var dCenterX = r.left + r.width  \/ 2;\r\n            var dCenterY = r.top  + r.height \/ 2;\r\n            var dist = Math.abs(dCenterX - xAdjusted) + Math.abs(dCenterY - yAdjusted);\r\n            if (dist < closestDist) { closestDist = dist; droppableEl = d; }\r\n        });\r\n        \/\/ \u2705 v2.4.3 : Si Entete a d\u00e9tect\u00e9 un drop sur Ele0A \u2192 forcer directement\r\n        if (_redirect) { if (_redirect.forceEle0A) {\r\n            var _ele0AForced = document.getElementById('Ele0A');\r\n            if (_ele0AForced) { droppableEl = _ele0AForced; console.log('\ud83c\udfaf [thumbnailDropped] Ele0A forc\u00e9 (redirect Entete)'); }\r\n        } }\r\n    }\r\n\r\n    if (!droppableEl || closestDist > 800) {\r\n        console.warn('thumbnailDropped \u2014 aucun droppable proche (dist min:', closestDist, ')');\r\n        return;\r\n    }\r\n    console.log('\ud83d\udccd Droppable trouv\u00e9:', droppableEl.id, '(dist:', Math.round(closestDist), ')');\r\n\r\n    var $droppable = jQuery(droppableEl);\r\n    var rankId = $droppable.attr('id');\r\n    if (!rankId) { console.warn('thumbnailDropped \u2014 .droppable sans id'); return; }\r\n\r\n    var $dropZone = $droppable.find('#drop_file_zone_achat').first();\r\n    if (!$dropZone.length) { console.warn('thumbnailDropped \u2014 #drop_file_zone_achat introuvable dans', rankId); return; }\r\n\r\n    var emplacementRef = StateManager.buildEmplacementReference(rankId);\r\n    console.log('\u2705 thumbnailDropped \u2014 espace pub:', rankId, '\u2192', emplacementRef);\r\n\r\n    \/\/ 2. Pr\u00e9parer l'\u00e9tat SessionStorage (comme un vrai drop de fichier)\r\n    StateManager.setMultiple({\r\n        'Rank_Emplacement_Page_Web':     rankId,\r\n        'Commande_Emplacement_Page_Web': emplacementRef,\r\n        'FirstUploadFileorMoved':        'FirstUpload',\r\n        'Formatchoisi':                  'Yes',\r\n        'Commande_Format_Transmis':      'Image',\r\n        'EnvoiUlterieur':                'false',\r\n        'FileReceived':                  'No',\r\n        'AdDisplayed':                   'Yes'\r\n    });\r\n\r\n    UIManager.updateEmplacementDisplay();\r\n\r\n    \/\/ 3. Construire le File \u00e0 partir du PDF (communiqu\u00e9\/interview) ou de l'image PNG (autres formats)\r\n    \/\/    puis appeler handleFileUpload \u2192 m\u00eame flux qu'un vrai drag&drop : liser\u00e9 vert, aper\u00e7u, R\u00e9server\r\n    var dataURL, mime, ext;\r\n\r\n    \/\/ \u2705 Stocker le PDF image et le format sur le droppable pour le popup de visualisation inline\r\n    if (msg.pdfImageDataURL) {\r\n        $droppable.data('kitPdfImageDataURL', msg.pdfImageDataURL);\r\n        $droppable.data('kitFormatSelect', msg.FormatSelect || '');\r\n        console.log('\ud83d\udcce pdfImageDataURL stock\u00e9 sur', rankId, '| format:', msg.FormatSelect);\r\n    } else {\r\n        $droppable.removeData('kitPdfImageDataURL');\r\n        $droppable.removeData('kitFormatSelect');\r\n    }\r\n\r\n    if (msg.isPDF && msg.pdfDataURL) {\r\n        \/\/ \u2500\u2500 Format PDF (communiqu\u00e9 \/ interview) \u2500\u2500\u2500\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        dataURL = msg.pdfDataURL;                         \/\/ \"data:application\/pdf;base64,\u2026\"\r\n        mime    = 'application\/pdf';\r\n        ext     = '.pdf';\r\n    } else if (msg.imageDataURL) {\r\n        \/\/ \u2500\u2500 Format image (banni\u00e8re \/ parrainage) \u2500\u2500\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        dataURL = msg.imageDataURL;\r\n        var mimeMatch = dataURL.match(\/^data:([^;]+);base64,\/);\r\n        mime    = mimeMatch ? mimeMatch[1] : 'image\/png';\r\n        ext     = mime === 'image\/jpeg' ? '.jpg' : '.png';\r\n    } else {\r\n        console.warn('thumbnailDropped \u2014 aucune donn\u00e9e image\/pdf disponible');\r\n        return;\r\n    }\r\n\r\n    var baseName = msg.filename ? msg.filename.replace(\/\\.[^.]+$\/, '') : 'annonce-kit';\r\n    var fileName = baseName + ext;\r\n\r\n    \/\/ dataURL \u2192 Uint8Array \u2192 Blob \u2192 File\r\n    var b64  = dataURL.split(',')[1];\r\n    var bstr = atob(b64);\r\n    var u8   = new Uint8Array(bstr.length);\r\n    for (var i = 0; i < bstr.length; i++) { u8[i] = bstr.charCodeAt(i); }\r\n    var blob    = new Blob([u8], { type: mime });\r\n    var fileObj = new File([blob], fileName, { type: mime });\r\n\r\n    console.log('thumbnailDropped \u2192 handleFileUpload:', fileName, Math.round(fileObj.size \/ 1024) + 'KB');\r\n\r\n    \/\/ \u2705 Cacher le File pour r\u00e9utilisation lors des d\u00e9placements (\u00e9vite CORS)\r\n    window._lastRedactionnelFile = fileObj;\r\n\r\n    \/\/ \u2705 v2.4.10 : Signaler \u00e0 adjustDesktopLayout que c'est un drop depuis la miniature\r\n    \/\/ \u2192 applique max-height sur HTMLUploadfileConteneur pour \u00e9viter le d\u00e9bordement vertical (homepage corps de page)\r\n    window._dropFromMiniature = true;\r\n    UploadManager.handleFileUpload(fileObj, $dropZone);\r\n\r\n    \/\/ \u2705 v1.19.1 : Positionner l'espace \u00e0 10px du haut du viewport (tous formats)\r\n    \/\/ \u2705 v2.4.13 : Skip si drop depuis miniature \u2014 selectEspaceActif g\u00e8re d\u00e9j\u00e0 le scroll\r\n    if (!window._dropFromMiniature) {\r\n        setTimeout(function() {\r\n            var el = $droppable.find('.HTMLUploadfileConteneur')[0] || $droppable[0];\r\n            if (el) {\r\n                ScrollHelper.scrollElementTo(el, 10);\r\n            }\r\n        }, 400);\r\n    }\r\n});\r\n\r\nconsole.log('This is a ' + (UIManager.isDesktop() ? 'desktop' : 'non-desktop') + ' device.');\r\n\r\n} \/\/ end _espPubScriptLoaded guard\r\n<\/script>\r\n\r\n<style>\r\n\/* Les styles CSS restent inchang\u00e9s *\/\r\n#drop_file_zone_achat {\r\n    background-color: #FFFFFF00;\r\n    color: #225DA9;\r\n    font-weight: 500;\r\n    text-align: center;\r\n    border: #999 0px dashed;\r\n    width: 100%;\r\n    height: 180px;\r\n    font-size: 11.5px;\r\n    display: flex;\r\n    justify-content: center; \r\n    align-items: center; \r\n    flex-wrap: wrap;\r\n}\r\n\r\n#drag_upload_file_achat {\r\n    margin: 0 auto;\r\n    width: 90%;\r\n    height: 60px;\r\n}\r\n\r\n#drag_upload_file_achat p {\r\n    text-align: center;\r\n}\r\n\r\n\/* \u2705 v1.16.0 : Liser\u00e9 noir fin autour du texte \"Ici glisser \u2013 d\u00e9poser\" *\/\r\n.GlisserDeposerConteneur .elementor-widget-container p {\r\n    border: 1px solid #000000;\r\n    border-radius: 4px;\r\n    padding: 4px 10px;\r\n    display: inline-block;\r\n}\r\n\r\n#selectfile_achat {\r\n    display: none;\r\n}\r\n\r\n.button-2_achat, .button-2_achat-after-reset {\r\n    background-color: #ffffff00!important;\r\n    border: 1px solid white!important;\r\n    border-radius: 8px;\r\n    color: #225DA9!important;\r\n    cursor: pointer;\r\n    display: inline-block;\r\n    font-size: 11px;\r\n    font-weight: 500;\r\n    list-style: none;\r\n    width: 390px;\r\n    height: 62px;\r\n    top: 0px!important; \r\n    margin-top: 0px!important; \r\n    padding-left: 5px!important;\r\n    padding-right: 5px!important;\r\n    margin-bottom: 70px!important;\r\n    margin: 0;\r\n    text-align: center;\r\n    transition: all 200ms;\r\n    vertical-align: baseline;\r\n    white-space: wrap!important;\r\n}\r\n\r\n@media only screen and (max-width: 1000px) {\r\n    .button-2_achat, .button-2_achat-after-reset {\r\n        width: 95%;\r\n        height: 50px;\r\n    }\r\n}\r\n\r\n.newMessageClass {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #56BE50;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 45px;\r\n    bottom: 0px;\r\n    right: 0px;\r\n    left: 0px;\r\n    display: flex;\r\n    justify-content: center;\r\n    align-items: center;\r\n    text-align: center;\r\n}\r\n\r\n.MessageClassFormatnonReconnuTitre {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #FB5E2A;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    margin-top: -300px;\r\n    right: 0px;\r\n    text-align: center;\r\n    line-height: 15px;\r\n}\r\n\r\n.MessageClassFormatnonReconnu {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #ffffff;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    margin-top: -280px;\r\n    right: 0px;\r\n    text-align: center;\r\n    line-height: 15px;\r\n}\r\n\r\n.newButtonClass {\r\n    font-size: 12px; \r\n    font-weight: 500;\r\n    background-color: #ffffff00;\r\n    color: #717171;\r\n    height: 10px;\r\n    width: 100%; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 45px;\r\n    bottom: 0px;\r\n    text-align: center;\r\n    right:  50px;\r\n    line-height: 10px;\r\n    border-radius: 3px;\r\n    border: 0px solid #E8ECF1;\r\n}\r\n\r\n.linkClass {\r\n    width: 15px; \r\n    height: 15px;\r\n    margin-top: -310px;\r\n    margin-bottom: -25px;\r\n    margin-right: -50px;\r\n    position: relative;\r\n    top: 0; \r\n    z-index: 99;\r\n    display: block;\r\n    background-image: url('https:\/\/rdc.via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-blanc.jpg');\r\n    background-size: cover;\r\n}\r\n\r\n.newButtonClassVideo {\r\n    font-size: 12px; \r\n    font-weight: 500;\r\n    background-color: #ffffff00;\r\n    color: #717171;\r\n    height: 10px;\r\n    width: 100%; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 0px;\r\n    bottom: 0px;\r\n    right: 10px;\r\n    text-align: center;\r\n    line-height: 10px;\r\n    border-radius: 3px;\r\n    border: 0px solid #E8ECF1;\r\n}\r\n\r\n.linkClassVideo {\r\n    width: 15px; \r\n    height: 15px;\r\n    margin-top: -438px;\r\n    margin-bottom: -25px;\r\n    margin-right: -15px;\r\n    position: relative;\r\n    top: 0; \r\n    z-index: 99;\r\n    display: block;\r\n    background-image: url('https:\/\/rdc.via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-blanc.jpg');\r\n    background-size: cover;\r\n}\r\n\r\n.FinCampagneMobileClass .elementor-button,\r\n.DebutCampagneMobileClass .elementor-button,\r\n.FormSelectDevisesMobile .elementor-button,\r\n.HideFormButton .elementor-button {\r\n    display: none !important;\r\n}\r\n\r\n#drag_upload_file_achat {\r\n    margin: 0;\r\n    padding: 0;\r\n    position: relative;\r\n}\r\n\r\n.dot-container {\r\n    display: inline-block;\r\n}\r\n\r\n.dot {\r\n    opacity: 0;\r\n    transition: opacity 0.3s ease;\r\n}\r\n\r\n@keyframes firstDot {\r\n    0%, 100% { opacity: 0; }\r\n    10%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n@keyframes secondDot {\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 thirdDot {\r\n    0%, 40%, 100% { opacity: 0; }\r\n    50%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n.dot:nth-child(1) {\r\n    animation: firstDot 3s infinite;\r\n}\r\n\r\n.dot:nth-child(2) {\r\n    animation: secondDot 3s infinite;\r\n}\r\n\r\n.dot:nth-child(3) {\r\n    animation: thirdDot 3s infinite;\r\n}\r\n\r\n.droppable .elementor-field-type-checkbox .elementor-field-option {\r\n    display: flex;\r\n    flex-direction: row-reverse;\r\n    align-items: center;\r\n    gap: 8px;\r\n}\r\n\r\n.droppable .elementor-field-type-checkbox .elementor-field-option input[type=\"checkbox\"] {\r\n    width: 12px;\r\n    height: 12px;\r\n    min-width: 12px;\r\n    min-height: 12px;\r\n}\r\n\r\n\/* \u2705 Bouton \"R\u00e9server\" dynamique *\/\r\n.reserver-dynamic-container {\r\n    text-align: center;\r\n    margin-top: -7px;\r\n    margin-bottom: 15px;\r\n    padding: 5px 0;\r\n    transform: scale(1.4);\r\n    transform-origin: center top;\r\n    position: relative;\r\n    z-index: 200;\r\n}\r\n\r\n@media only screen and (min-width: 1001px) {\r\n    .reserver-dynamic-container {\r\n        transform: scale(1);\r\n        margin-top: -200px;\r\n        margin-bottom: 0;\r\n    }\r\n}\r\n\r\n.reserver-dynamic-option {\r\n    display: inline-flex;\r\n    flex-direction: row-reverse;\r\n    align-items: center;\r\n    gap: 8px;\r\n    cursor: pointer;\r\n    color: #213864;\r\n    background-color: #ffffff;\r\n    padding: 2px 4px;\r\n    border-radius: 6px;\r\n}\r\n\r\n.reserver-dynamic-checkbox {\r\n    width: 16px;\r\n    height: 16px;\r\n    min-width: 16px;\r\n    min-height: 16px;\r\n    cursor: pointer;\r\n    pointer-events: auto;\r\n}\r\n\r\n.reserver-dynamic-label {\r\n    cursor: pointer;\r\n    color: #213864;\r\n    font-size: 16px;\r\n    font-weight: 600;\r\n    user-select: none;\r\n}\r\n\r\n@media only screen and (max-width: 1000px) {\r\n    .reserver-dynamic-container {\r\n        transform: scale(0.98);\r\n        margin-bottom: 20px;\r\n        white-space: nowrap;\r\n        z-index: 300;\r\n        pointer-events: auto;\r\n    }\r\n    .reserver-dynamic-option {\r\n        padding-top: 0px;\r\n        padding-bottom: 0px;\r\n    }\r\n}\r\n\r\n\/* \u2705 v2.1.3 : DeplaceAnnonceText \/ DeplaceAnnonce \u2014 desktop uniquement *\/\r\n@media only screen and (min-width: 1001px) {\r\n    .DeplaceAnnonceText {\r\n        margin-top: -5px;\r\n        position: relative;\r\n        z-index: 201;\r\n    }\r\n    .DeplaceAnnonce {\r\n        margin-bottom: -150px;\r\n    }\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<div class=\"elementor-element elementor-element-54e4e530 e-con-full MsgFormatIncorrectConteneur elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"54e4e530\" data-element_type=\"container\" id=\"NotusedAnymore\">\n\t\t\t\t<div class=\"elementor-element elementor-element-531f3cb1 MsgFormatIncorrect elementor-widget__width-inherit elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"531f3cb1\" data-element_type=\"widget\" data-widget_type=\"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 format du fichier n&rsquo;est pas reconnu<\/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-3a352c3f elementor-hidden-desktop TexteMobile TexteMobileAnnonce elementor-widget elementor-widget-text-editor\" data-id=\"3a352c3f\" data-element_type=\"widget\" data-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 ou cliquer ici<br>pour t\u00e9l\u00e9charger une 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-7abb0aba elementor-hidden-desktop TexteMobileAjoutAnnonce elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"7abb0aba\" data-element_type=\"widget\" data-widget_type=\"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;\">Cliquer ici pour t\u00e9l\u00e9charger une annonce<\/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-68e2b2ca UploadIci elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"68e2b2ca\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ici glisser-d\u00e9poser ou t\u00e9l\u00e9charger une annonce<\/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-8d50d33 e-con-full e-flex e-con e-child\" data-id=\"8d50d33\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6ae6ef83 elementor-button-align-center elementor-widget__width-initial HideFormButton EspPubLienAnnonce elementor-widget-mobile__width-initial elementor-widget elementor-widget-form\" data-id=\"6ae6ef83\" data-element_type=\"widget\" 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_URL_annonce\" aria-label=\"Formulaire_URL_annonce\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249870\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"6ae6ef83\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-LienAnnonce elementor-col-100 elementor-sm-100 elementor-field-required\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-LienAnnonce\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tIci renseigner si n\u00e9cessaire le lien hypertexte de l\u2019annonce\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[LienAnnonce]\" id=\"form-field-LienAnnonce\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Ici renseigner si n\u00e9cessaire le lien hypertexte de l\u2019annonce\" 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-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=\"ButtonValidURLAnnonce\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-66fd4d36 e-con-full EnvoiUlterieurContainer e-flex e-con e-child\" data-id=\"66fd4d36\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4ea8e2b4 elementor-button-align-center elementor-widget__width-auto HideFormButton EnvoiUlterieur elementor-widget elementor-widget-form\" data-id=\"4ea8e2b4\" data-element_type=\"widget\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249870\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"4ea8e2b4\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-EnvoiUlterieur elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-EnvoiUlterieur\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tEnvoi diff\u00e9r\u00e9 de l'annonce\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=\"Envoi diff\u00e9r\u00e9 de l&#039;annonce\" id=\"form-field-EnvoiUlterieur-0\" name=\"form_fields[EnvoiUlterieur]\"> <label for=\"form-field-EnvoiUlterieur-0\">Envoi diff\u00e9r\u00e9 de l'annonce<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-4a59cf88 EnvoiUlterieurTexte elementor-widget elementor-widget-text-editor\" data-id=\"4a59cf88\" data-element_type=\"widget\" data-widget_type=\"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;\">Envoyer l\u2019annonce jusqu\u2019\u00e0 8 jours apr\u00e8s paiement<br>\nUn lien vous sera adress\u00e9 par <span style=\"color: #ffffff;\"><a style=\"color: #ffffff;\" 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<div class=\"elementor-element elementor-element-17d3ad0c e-con-full ReserverContainer e-flex e-con e-child\" data-id=\"17d3ad0c\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-177c9b71 elementor-button-align-center elementor-widget__width-auto HideFormButton ReserverBouton elementor-widget elementor-widget-form\" data-id=\"177c9b71\" data-element_type=\"widget\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249870\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"177c9b71\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-ReserverEspacePublicitaire elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-ReserverEspacePublicitaire\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tR\u00e9server cet espace publicitaire\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=\"R\u00e9server cet espace publicitaire\" id=\"form-field-ReserverEspacePublicitaire-0\" name=\"form_fields[ReserverEspacePublicitaire]\"> <label for=\"form-field-ReserverEspacePublicitaire-0\">R\u00e9server cet espace publicitaire<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-5bafe1f3 e-con-full AdUploadedTitle DeplaceAnnonce elementor-hidden-tablet elementor-hidden-mobile elementor-hidden-desktop e-flex e-con e-child\" data-id=\"5bafe1f3\" data-element_type=\"container\" id=\"DeplaceAnnonceId\">\n\t\t<div class=\"elementor-element elementor-element-432cc2a1 e-con-full DeplaceAnnonceSubContainer e-flex e-con e-child\" data-id=\"432cc2a1\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-446e8565 elementor-hidden-tablet elementor-hidden-mobile EspaceReserve elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"446e8565\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Espace r\u00e9serv\u00e9<br \/>Annonce transmise<\/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-60df49d0 elementor-hidden-tablet elementor-hidden-mobile DeplaceAnnonceText elementor-widget elementor-widget-text-editor\" data-id=\"60df49d0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tSi vous souhaitez un autre emplacement, vous pouvez d\u00e9placer cette annonce\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-62ef38f0 e-con-full e-flex e-con e-child\" data-id=\"62ef38f0\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f4f51cb elementor-hidden-tablet elementor-hidden-mobile PositionEspacePublicitaireDeplacer elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"f4f51cb\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Position<\/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-f214306 elementor-hidden-tablet elementor-hidden-mobile RefEspacePublicitaire elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"f214306\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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>\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-1c5a5ed5 e-con-full AdUploadedOverlay elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"1c5a5ed5\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4740d3e8 e-con-full OverlayHeader e-flex e-con e-child\" data-id=\"4740d3e8\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e964c6b elementor-hidden-tablet elementor-hidden-mobile OverlayRefEspace elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"e964c6b\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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-30eb836c OverlayCroixReset elementor-widget elementor-widget-image\" data-id=\"30eb836c\" data-element_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:\/\/via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-transparent.png\" 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-342c88b1 e-con-full OverlayPreviewZone e-flex e-con e-child\" data-id=\"342c88b1\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3c7e790f OverlayDeplaceTexte elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"3c7e790f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Si vous souhaitez un autre emplacement, vous pouvez d\u00e9placer cette annonce<\/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-51f00578 elementor-button-align-center elementor-widget__width-auto HideFormButton OverlayReserverForm elementor-widget elementor-widget-form\" data-id=\"51f00578\" data-element_type=\"widget\" id=\"Formulaire_Reserver_Overlay\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249870\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"51f00578\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-ReserverEspacePublicitaire elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-ReserverEspacePublicitaire\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tR\u00e9server cet espace publicitaire\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=\"R\u00e9server cet espace publicitaire\" id=\"form-field-ReserverEspacePublicitaire-0\" name=\"form_fields[ReserverEspacePublicitaire]\"> <label for=\"form-field-ReserverEspacePublicitaire-0\">R\u00e9server cet espace publicitaire<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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<\/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<\/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<div class=\"elementor-element elementor-element-96fbce1 e-con-full e-flex e-con e-child\" data-id=\"96fbce1\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8a396e7 elementor-widget elementor-widget-text-editor\" data-id=\"8a396e7\" data-element_type=\"widget\" data-widget_type=\"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=\"container\" data-elementor-id=\"74473\" class=\"elementor elementor-74473\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-695d4e3 e-flex e-con-boxed e-con e-parent\" data-id=\"695d4e3\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-a59548b elementor-widget elementor-widget-text-editor\" data-id=\"a59548b\" data-element_type=\"widget\" id=\"ArticleTitreTexte\" data-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 &#8211; BTP <br>&#8211; De grands chantiers\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<\/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-c223563 e-con-full e-flex e-con e-child\" data-id=\"c223563\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-a5ccdc6 e-con-full e-flex e-con e-child\" data-id=\"a5ccdc6\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d42ef5f elementor-widget elementor-widget-image\" data-id=\"d42ef5f\" data-element_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:\/\/togo-en.yearbook-media.com\/wp-content\/uploads\/elementor\/thumbs\/640px-Route_de_Lome-e1719506931907-revtfbgldoihvqpxny1yr8sk73v30i2yiv6ii1sop2.jpg\" title=\"640px-Route_de_Lom\u00e9\" alt=\"640px-Route_de_Lom\u00e9\" 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<div class=\"elementor-element elementor-element-c1208fc e-flex e-con-boxed e-con e-parent\" data-id=\"c1208fc\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0728861 elementor-widget elementor-widget-text-editor\" data-id=\"0728861\" data-element_type=\"widget\" data-widget_type=\"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=\"text-align: var(--text-align); background-color: var(--base-3);\">Le Togo a connu ces derni\u00e8res ann\u00e9es un d\u00e9veloppement significatif de ses infrastructures gr\u00e2ce principalement \u00e0 l\u2019investissement public : 80% de routes rev\u00eatues projet\u00e9es en 2025, de nombreux ponts construits ou r\u00e9habilit\u00e9s et un souci de l\u2019am\u00e9nagement urbain.<\/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<div class=\"elementor-element elementor-element-e3b7c2e ToBeHidden e-flex e-con-boxed e-con e-child\" data-id=\"e3b7c2e\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-566d50e e-con-full droppable e-flex e-con e-child\" data-id=\"566d50e\" data-element_type=\"container\" id=\"Ele2A\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ec02c2b elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"ec02c2b\" data-element_type=\"widget\" data-widget_type=\"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=\"page\" data-elementor-id=\"83347\" class=\"elementor elementor-83347\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6442de91 e-con-full OrdiMobileConteneurClass e-flex e-con e-child\" data-id=\"6442de91\" data-element_type=\"container\" id=\"testIdTest\">\n\t\t\t\t<div class=\"elementor-element elementor-element-57de103 elementor-widget elementor-widget-text-editor\" data-id=\"57de103\" data-element_type=\"widget\" data-widget_type=\"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-249871 .elementor-element.elementor-element-6da64a60{--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;--justify-content:space-around;--align-items:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:50px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-6da64a60.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-45f807e0{--display:flex;--min-height:0px;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-100px;--margin-bottom:62px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:3;}.elementor-249871 .elementor-element.elementor-element-45f807e0.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-61dcced4{--display:flex;--margin-top:0px;--margin-bottom:-11px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-6c65b106{--display:flex;--margin-top:0px;--margin-bottom:-30px;--margin-left:-25px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-eb74aa8{--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-249871 .elementor-element.elementor-element-eb74aa8:not(.elementor-motion-effects-element-type-background), .elementor-249871 .elementor-element.elementor-element-eb74aa8 > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-1c762c45{--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;--flex-wrap:nowrap;--margin-top:-3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-5be6a53a{--display:flex;--align-items:flex-start;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249871 .elementor-element.elementor-element-5be6a53a.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-75917e71{--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-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-249871 .elementor-element.elementor-element-6be76773 > .elementor-widget-container{margin:38px 5px -38px -40px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-6be76773.elementor-element{--align-self:flex-start;}.elementor-249871 .elementor-element.elementor-element-6be76773{text-align:right;}.elementor-249871 .elementor-element.elementor-element-6be76773 img{width:17px;}.elementor-249871 .elementor-element.elementor-element-5ad25a69{--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-249871 .elementor-element.elementor-element-5ad25a69.e-con{--align-self:flex-end;}.elementor-249871 .elementor-element.elementor-element-52dec736 > .elementor-widget-container{margin:45px -18px -55px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-52dec736{z-index:101;text-align:right;}.elementor-249871 .elementor-element.elementor-element-469b1a7c{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-25px;--margin-bottom:90px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-469b1a7c:not(.elementor-motion-effects-element-type-background), .elementor-249871 .elementor-element.elementor-element-469b1a7c > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#9FC5F3;}.elementor-249871 .elementor-element.elementor-element-3f5f9124{--display:flex;--min-height:30px;--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;--justify-content:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:1px;--margin-bottom:-6px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:99;}.elementor-249871 .elementor-element.elementor-element-3f5f9124.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-48a37689{--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;--justify-content:flex-start;--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--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-249871 .elementor-element.elementor-element-4b68287 > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249871 .elementor-element.elementor-element-4b68287.elementor-element{--align-self:flex-start;}.elementor-249871 .elementor-element.elementor-element-4b68287{text-align:start;font-family:\"Roboto\", Sans-serif;font-size:12px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-79a46db6{--display:flex;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249871 .elementor-element.elementor-element-47d25f98 > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-47d25f98{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:18px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-3aa42503{--display:flex;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:flex-end;--align-items:flex-end;--margin-top:4px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-12d5dc39 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-12d5dc39.elementor-element{--align-self:flex-start;}.elementor-249871 .elementor-element.elementor-element-12d5dc39{text-align:end;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-21535e15{--display:flex;--justify-content:flex-start;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--flex-wrap:wrap;--margin-top:-2px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-21535e15.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-de420c1{--display:flex;--min-height:30px;--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-249871 .elementor-element.elementor-element-2f60f3f > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-2f60f3f.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-2f60f3f{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:500;line-height:1.1em;color:#FB5E2A;}.elementor-249871 .elementor-element.elementor-element-6b485447 > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-6b485447.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-6b485447{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-78e1d9f5{--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;--justify-content:center;--gap:010px 9px;--row-gap:010px;--column-gap:9px;--flex-wrap:wrap;--margin-top:-14px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:100;}.elementor-249871 .elementor-element.elementor-element-78e1d9f5.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-cf3602e{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-7a1bb33 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-7a1bb33.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-7a1bb33{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-6bf72a5{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-1a57dd9 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-1a57dd9.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-1a57dd9{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-34d8bbba{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-32bd35c6 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-32bd35c6.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-32bd35c6{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-5a9252c3{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-8722042 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-8722042.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-8722042{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-19ecc2b3{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-6071d405 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-6071d405.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-6071d405{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-3617569c{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-4b013e71 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-4b013e71.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-4b013e71{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-7450a6f8{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-30970f89 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-30970f89.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-30970f89{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-6aac67a6{--display:flex;--margin-top:-46px;--margin-bottom:-20px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:2;}.elementor-249871 .elementor-element.elementor-element-40d299c{width:100%;max-width:100%;}.elementor-249871 .elementor-element.elementor-element-40d299c.elementor-element{--align-self:flex-end;}.elementor-249871 .elementor-element.elementor-element-1fd15d20{width:100%;max-width:100%;}.elementor-249871 .elementor-element.elementor-element-1fd15d20.elementor-element{--align-self:flex-end;}.elementor-249871 .elementor-element.elementor-element-54e4e530{--display:flex;--justify-content:center;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249871 .elementor-element.elementor-element-531f3cb1{width:100%;max-width:100%;font-family:\"Roboto\", Sans-serif;font-size:10px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249871 .elementor-element.elementor-element-531f3cb1 > .elementor-widget-container{margin:-37px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-531f3cb1.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-3a352c3f > .elementor-widget-container{margin:7px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-3a352c3f.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-3a352c3f{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249871 .elementor-element.elementor-element-7abb0aba > .elementor-widget-container{margin:7px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-7abb0aba.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-7abb0aba{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249871 .elementor-element.elementor-element-68e2b2ca > .elementor-widget-container{margin:-110px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-68e2b2ca.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-68e2b2ca{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:18px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249871 .elementor-element.elementor-element-8d50d33{--display:flex;--margin-top:-85px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-8d50d33.e-con{--align-self:center;}.elementor-widget-form .elementor-field-group > label, .elementor-widget-form .elementor-field-subgroup label{color:var( --e-global-color-text );}.elementor-widget-form .elementor-field-group > label{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .elementor-field-type-html{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-widget-form .elementor-field-group .elementor-field{color:var( --e-global-color-text );}.elementor-widget-form .elementor-field-group .elementor-field, .elementor-widget-form .elementor-field-subgroup label{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .elementor-button{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-widget-form .e-form__buttons__wrapper__button-next{background-color:var( --e-global-color-accent );}.elementor-widget-form .elementor-button[type=\"submit\"]{background-color:var( --e-global-color-accent );}.elementor-widget-form .e-form__buttons__wrapper__button-previous{background-color:var( --e-global-color-accent );}.elementor-widget-form .elementor-message{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .e-form__indicators__indicator, .elementor-widget-form .e-form__indicators__indicator__label{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-widget-form{--e-form-steps-indicator-inactive-primary-color:var( --e-global-color-text );--e-form-steps-indicator-active-primary-color:var( --e-global-color-accent );--e-form-steps-indicator-completed-primary-color:var( --e-global-color-accent );--e-form-steps-indicator-progress-color:var( --e-global-color-accent );--e-form-steps-indicator-progress-background-color:var( --e-global-color-text );--e-form-steps-indicator-progress-meter-color:var( --e-global-color-text );}.elementor-widget-form .e-form__indicators__indicator__progress__meter{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-249871 .elementor-element.elementor-element-6ae6ef83{width:var( --container-widget-width, 75% );max-width:75%;--container-widget-width:75%;--container-widget-flex-grow:0;z-index:120;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group{padding-right:calc( 10px\/2 );padding-left:calc( 10px\/2 );margin-bottom:6px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-form-fields-wrapper{margin-left:calc( -10px\/2 );margin-right:calc( -10px\/2 );margin-bottom:-6px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label, .elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{color:#7B88A3;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-type-html{padding-bottom:0px;color:#7A7A7A;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field{color:#484848;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:01px 01px 01px 01px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:01px 01px 01px 01px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249871 .elementor-element.elementor-element-66fd4d36{--display:flex;--min-height:58px;--gap:0px 0px;--row-gap:0px;--column-gap:0px;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:8px 8px 8px 8px;--margin-top:12px;--margin-bottom:10px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249871 .elementor-element.elementor-element-66fd4d36.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4{width:auto;max-width:auto;z-index:120;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 > .elementor-widget-container{margin:2px 0px 2px 1px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label, .elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field{color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:600;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249871 .elementor-element.elementor-element-4a59cf88 > .elementor-widget-container{margin:-3px 0px -24px 0px;}.elementor-249871 .elementor-element.elementor-element-4a59cf88.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-4a59cf88{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-17d3ad0c{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;border-style:none;--border-style:none;--border-radius:8px 8px 8px 8px;--margin-top:-4px;--margin-bottom:05px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249871 .elementor-element.elementor-element-17d3ad0c.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-177c9b71{width:auto;max-width:auto;z-index:5;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 > .elementor-widget-container{margin:2px 0px 2px 1px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-177c9b71.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label, .elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{color:#000000;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field{color:#000000;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:16px;font-weight:600;line-height:1.1em;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249871 .elementor-element.elementor-element-5bafe1f3{--display:flex;--min-height:0px;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--gap:0px 0px;--row-gap:0px;--column-gap:0px;--overlay-opacity:1;--margin-top:230px;--margin-bottom:-220px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:10;}.elementor-249871 .elementor-element.elementor-element-5bafe1f3::before, .elementor-249871 .elementor-element.elementor-element-5bafe1f3 > .elementor-background-video-container::before, .elementor-249871 .elementor-element.elementor-element-5bafe1f3 > .e-con-inner > .elementor-background-video-container::before, .elementor-249871 .elementor-element.elementor-element-5bafe1f3 > .elementor-background-slideshow::before, .elementor-249871 .elementor-element.elementor-element-5bafe1f3 > .e-con-inner > .elementor-background-slideshow::before, .elementor-249871 .elementor-element.elementor-element-5bafe1f3 > .elementor-motion-effects-container > .elementor-motion-effects-layer::before{--background-overlay:'';background-size:cover;}.elementor-249871 .elementor-element.elementor-element-5bafe1f3.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-432cc2a1{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--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-249871 .elementor-element.elementor-element-446e8565 > .elementor-widget-container{margin:0px 3px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-446e8565.elementor-element{--align-self:flex-end;}.elementor-249871 .elementor-element.elementor-element-446e8565{z-index:5;text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249871 .elementor-element.elementor-element-60df49d0 > .elementor-widget-container{margin:35px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-60df49d0.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-60df49d0{z-index:5;text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:500;line-height:1.1em;color:#6185C0;}.elementor-249871 .elementor-element.elementor-element-62ef38f0{--display:flex;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:space-between;--align-items:flex-start;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-287px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-f4f51cb > .elementor-widget-container{margin:0px 3px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-f4f51cb.elementor-element{--align-self:flex-end;}.elementor-249871 .elementor-element.elementor-element-f4f51cb{z-index:5;text-align:left;font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249871 .elementor-element.elementor-element-f214306 > .elementor-widget-container{margin:0px 0px 0px 3px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-f214306.elementor-element{--align-self:flex-end;}.elementor-249871 .elementor-element.elementor-element-f214306{z-index:5;text-align:start;font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249871 .elementor-element.elementor-element-1c5a5ed5{--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;--justify-content:flex-start;--align-items:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--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-249871 .elementor-element.elementor-element-1c5a5ed5.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-4740d3e8{--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;--justify-content:space-between;--margin-top:5px;--margin-bottom:5px;--margin-left:010px;--margin-right:10px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-e964c6b > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-e964c6b.elementor-element{--align-self:flex-end;}.elementor-249871 .elementor-element.elementor-element-e964c6b{z-index:5;text-align:left;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249871 .elementor-element.elementor-element-30eb836c > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-30eb836c{z-index:101;text-align:right;}.elementor-249871 .elementor-element.elementor-element-342c88b1{--display:flex;--min-height:180px;--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;--justify-content:center;--align-items:center;--overflow:hidden;border-style:solid;--border-style:solid;border-width:4px 4px 4px 4px;--border-top-width:4px;--border-right-width:4px;--border-bottom-width:4px;--border-left-width:4px;border-color:#00FF19;--border-color:#00FF19;--border-radius:0px 0px 0px 0px;--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-249871 .elementor-element.elementor-element-342c88b1:not(.elementor-motion-effects-element-type-background), .elementor-249871 .elementor-element.elementor-element-342c88b1 > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-3c7e790f > .elementor-widget-container{padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-3c7e790f{font-family:\"Roboto\", Sans-serif;font-weight:500;color:#6185C0;}.elementor-249871 .elementor-element.elementor-element-51f00578{width:auto;max-width:auto;z-index:5;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249871 .elementor-element.elementor-element-51f00578 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-51f00578.elementor-element{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group > label, .elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{color:#000000;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field{color:#213864;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:15.5px;font-weight:600;line-height:1.1em;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249871 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249871 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249871 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249871 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-message.elementor-message-success{color:#00FF2700;}@media(max-width:1001px){.elementor-249871 .elementor-element.elementor-element-6ae6ef83{z-index:11;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-size:10px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4{z-index:11;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-size:10px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-177c9b71{z-index:11;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-size:10px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-button{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-51f00578{z-index:11;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-size:10px;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-button{font-size:12px;}}@media(min-width:1001px){.elementor-249871 .elementor-element.elementor-element-6da64a60{--width:500px;}.elementor-249871 .elementor-element.elementor-element-45f807e0{--width:100%;}.elementor-249871 .elementor-element.elementor-element-6c65b106{--width:500px;}.elementor-249871 .elementor-element.elementor-element-75917e71{--width:10px;}.elementor-249871 .elementor-element.elementor-element-5ad25a69{--width:100%;}.elementor-249871 .elementor-element.elementor-element-469b1a7c{--width:500px;}.elementor-249871 .elementor-element.elementor-element-48a37689{--width:22%;}.elementor-249871 .elementor-element.elementor-element-79a46db6{--width:50%;}.elementor-249871 .elementor-element.elementor-element-3aa42503{--width:22%;}.elementor-249871 .elementor-element.elementor-element-78e1d9f5{--width:100%;}.elementor-249871 .elementor-element.elementor-element-cf3602e{--width:103px;}.elementor-249871 .elementor-element.elementor-element-6bf72a5{--width:103px;}.elementor-249871 .elementor-element.elementor-element-34d8bbba{--width:103px;}.elementor-249871 .elementor-element.elementor-element-5a9252c3{--width:103px;}.elementor-249871 .elementor-element.elementor-element-19ecc2b3{--width:103px;}.elementor-249871 .elementor-element.elementor-element-3617569c{--width:103px;}.elementor-249871 .elementor-element.elementor-element-7450a6f8{--width:103px;}.elementor-249871 .elementor-element.elementor-element-8d50d33{--width:100%;}.elementor-249871 .elementor-element.elementor-element-66fd4d36{--width:390px;}.elementor-249871 .elementor-element.elementor-element-17d3ad0c{--width:100%;}.elementor-249871 .elementor-element.elementor-element-5bafe1f3{--width:150%;}.elementor-249871 .elementor-element.elementor-element-62ef38f0{--width:95%;}.elementor-249871 .elementor-element.elementor-element-1c5a5ed5{--width:100%;}.elementor-249871 .elementor-element.elementor-element-4740d3e8{--width:100%;}}@media(max-width:1000px){.elementor-249871 .elementor-element.elementor-element-6da64a60{--width:390px;--margin-top:105px;--margin-bottom:-75px;--margin-left:0px;--margin-right:0px;}.elementor-249871 .elementor-element.elementor-element-45f807e0{--min-height:150px;--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;--margin-top:-47px;--margin-bottom:-32px;--margin-left:0px;--margin-right:0px;--z-index:3;}.elementor-249871 .elementor-element.elementor-element-61dcced4{--width:25%;}.elementor-249871 .elementor-element.elementor-element-6c65b106{--width:100%;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:center;--align-items:center;--flex-wrap:nowrap;--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249871 .elementor-element.elementor-element-6c65b106.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-eb74aa8{--width:75%;--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:center;}.elementor-249871 .elementor-element.elementor-element-eb74aa8.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-1c762c45{--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249871 .elementor-element.elementor-element-6be76773 > .elementor-widget-container{margin:-3px 40px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-5ad25a69{--width:100%;--justify-content:flex-end;--align-items:flex-end;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249871 .elementor-element.elementor-element-52dec736 > .elementor-widget-container{margin:40px 55px -30px 0px;}.elementor-249871 .elementor-element.elementor-element-52dec736{z-index:100;}.elementor-249871 .elementor-element.elementor-element-469b1a7c{--width:78%;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--flex-wrap:nowrap;--margin-top:-103px;--margin-bottom:-7px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-469b1a7c.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-3f5f9124{--justify-content:center;--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249871 .elementor-element.elementor-element-48a37689{--width:25%;--margin-top:2px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-4b68287 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-4b68287{font-size:8px;}.elementor-249871 .elementor-element.elementor-element-79a46db6{--width:46%;--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-249871 .elementor-element.elementor-element-47d25f98 > .elementor-widget-container{margin:0px -20px 0px -20px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-47d25f98{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-3aa42503{--width:25%;--margin-top:4px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-12d5dc39 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-12d5dc39{font-size:7px;}.elementor-249871 .elementor-element.elementor-element-21535e15{--margin-top:-15px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249871 .elementor-element.elementor-element-de420c1{--min-height:15px;--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-249871 .elementor-element.elementor-element-2f60f3f{width:100%;max-width:100%;font-size:10px;}.elementor-249871 .elementor-element.elementor-element-2f60f3f > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-6b485447{width:100%;max-width:100%;font-size:10px;}.elementor-249871 .elementor-element.elementor-element-6b485447 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-78e1d9f5{--width:100%;--gap:6px 4px;--row-gap:6px;--column-gap:4px;--flex-wrap:wrap;--margin-top:-12px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249871 .elementor-element.elementor-element-cf3602e{--width:61px;--min-height:15px;}.elementor-249871 .elementor-element.elementor-element-7a1bb33{font-size:9px;}.elementor-249871 .elementor-element.elementor-element-6bf72a5{--width:61px;--min-height:15px;}.elementor-249871 .elementor-element.elementor-element-1a57dd9{font-size:9px;}.elementor-249871 .elementor-element.elementor-element-34d8bbba{--width:61px;--min-height:15px;}.elementor-249871 .elementor-element.elementor-element-32bd35c6{font-size:9px;}.elementor-249871 .elementor-element.elementor-element-5a9252c3{--width:61px;--min-height:15px;}.elementor-249871 .elementor-element.elementor-element-8722042{font-size:9px;}.elementor-249871 .elementor-element.elementor-element-19ecc2b3{--width:61px;--min-height:15px;}.elementor-249871 .elementor-element.elementor-element-6071d405{font-size:9px;}.elementor-249871 .elementor-element.elementor-element-3617569c{--width:61px;--min-height:15px;}.elementor-249871 .elementor-element.elementor-element-4b013e71{font-size:9px;}.elementor-249871 .elementor-element.elementor-element-7450a6f8{--width:61px;--min-height:15px;}.elementor-249871 .elementor-element.elementor-element-30970f89{font-size:9px;}.elementor-249871 .elementor-element.elementor-element-6aac67a6{--width:96%;--min-height:250px;--margin-top:-56px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-40d299c > .elementor-widget-container{margin:5px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-1fd15d20 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-54e4e530{--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249871 .elementor-element.elementor-element-54e4e530.e-con{--order:-99999 \/* order start hack *\/;}.elementor-249871 .elementor-element.elementor-element-531f3cb1 > .elementor-widget-container{margin:-30px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-3a352c3f > .elementor-widget-container{margin:-181px 0px 1px 0px;}.elementor-249871 .elementor-element.elementor-element-3a352c3f{text-align:center;font-size:10px;line-height:1.2em;}.elementor-249871 .elementor-element.elementor-element-7abb0aba > .elementor-widget-container{margin:-180px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-7abb0aba{text-align:center;font-size:14px;line-height:1.2em;}.elementor-249871 .elementor-element.elementor-element-68e2b2ca > .elementor-widget-container{margin:-110px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-68e2b2ca{font-size:10px;}.elementor-249871 .elementor-element.elementor-element-8d50d33{--width:184px;--margin-top:-156px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249871 .elementor-element.elementor-element-8d50d33.e-con{--align-self:center;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83{width:var( --container-widget-width, 100% );max-width:100%;--container-widget-width:100%;--container-widget-flex-grow:0;z-index:120;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-size:8px;}.elementor-249871 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-size:10.5px;}.elementor-249871 .elementor-element.elementor-element-66fd4d36{--width:85%;--min-height:42px;--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:center;--margin-top:10px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 > .elementor-widget-container{margin:2px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4{z-index:120;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-type-html{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-size:10px;}.elementor-249871 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-size:10.5px;}.elementor-249871 .elementor-element.elementor-element-4a59cf88 > .elementor-widget-container{margin:2px 0px -10px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-4a59cf88{font-size:7.5px;}.elementor-249871 .elementor-element.elementor-element-17d3ad0c{--width:85%;--min-height:42px;--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:center;--margin-top:2px;--margin-bottom:-20px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:251;}.elementor-249871 .elementor-element.elementor-element-177c9b71 > .elementor-widget-container{margin:2px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-177c9b71{z-index:120;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-type-html{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-177c9b71 .elementor-button{font-size:10.5px;}.elementor-249871 .elementor-element.elementor-element-5bafe1f3{--min-height:150px;--margin-top:-149px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249871 .elementor-element.elementor-element-446e8565 > .elementor-widget-container{margin:-133px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-446e8565.elementor-element{--align-self:flex-start;}.elementor-249871 .elementor-element.elementor-element-446e8565{text-align:left;font-size:10px;}.elementor-249871 .elementor-element.elementor-element-f4f51cb > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249871 .elementor-element.elementor-element-f4f51cb.elementor-element{--align-self:flex-start;}.elementor-249871 .elementor-element.elementor-element-f4f51cb{text-align:center;font-size:10px;}.elementor-249871 .elementor-element.elementor-element-f214306 > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249871 .elementor-element.elementor-element-f214306.elementor-element{--align-self:flex-start;}.elementor-249871 .elementor-element.elementor-element-f214306{text-align:center;font-size:10px;}.elementor-249871 .elementor-element.elementor-element-1c5a5ed5{--width:390px;--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-249871 .elementor-element.elementor-element-e964c6b > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249871 .elementor-element.elementor-element-e964c6b.elementor-element{--align-self:flex-start;}.elementor-249871 .elementor-element.elementor-element-e964c6b{text-align:center;font-size:10px;}.elementor-249871 .elementor-element.elementor-element-30eb836c > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-30eb836c{z-index:100;}.elementor-249871 .elementor-element.elementor-element-342c88b1{--min-height:112px;--margin-top:5px;--margin-bottom:5px;--margin-left:5px;--margin-right:5px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249871 .elementor-element.elementor-element-3c7e790f{text-align:center;font-size:15px;}.elementor-249871 .elementor-element.elementor-element-51f00578 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249871 .elementor-element.elementor-element-51f00578{z-index:120;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group > label{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-type-html{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-size:12px;}.elementor-249871 .elementor-element.elementor-element-51f00578 .elementor-button{font-size:10.5px;}}<\/style>\t\t<div data-elementor-type=\"loop-item\" data-elementor-id=\"249871\" class=\"elementor elementor-249871 elementor-bc-flex-widget e-loop-item e-loop-item-38623 post-38623 post type-post status-publish format-standard has-post-thumbnail hentry category-btp category-page-pays-only category-togo category-togo-btp generate-columns tablet-grid-50 mobile-grid-100 grid-parent grid-20\" data-elementor-post-type=\"elementor_library\" data-custom-edit-handle=\"1\">\n\t\t\t<div class=\"elementor-element elementor-element-6da64a60 e-con-full OrdiMobileConteneurClass e-flex e-con e-child\" data-id=\"6da64a60\" data-element_type=\"container\" id=\"testIdTest\">\n\t\t<div class=\"elementor-element elementor-element-45f807e0 e-con-full UploadFileConteneur AdUploadedTitle elementor-hidden-tablet elementor-hidden-mobile elementor-hidden-desktop e-flex e-con e-child\" data-id=\"45f807e0\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-61dcced4 e-con-full e-flex e-con e-child\" data-id=\"61dcced4\" data-element_type=\"container\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6c65b106 e-con-full e-flex e-con e-child\" data-id=\"6c65b106\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-eb74aa8 e-con-full e-flex e-con e-child\" data-id=\"eb74aa8\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1c762c45 e-con-full e-flex e-con e-child\" data-id=\"1c762c45\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5be6a53a e-con-full e-flex e-con e-child\" data-id=\"5be6a53a\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-75917e71 e-con-full e-flex e-con e-child\" data-id=\"75917e71\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6be76773 AnnonceDragIcone elementor-widget elementor-widget-image\" data-id=\"6be76773\" data-element_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\/2025\/05\/arrow-drag-64-bleu.png\" 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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5ad25a69 e-con-full CroixResetAnnonceContainer e-flex e-con e-child\" data-id=\"5ad25a69\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-52dec736 elementor-widget elementor-widget-image\" data-id=\"52dec736\" data-element_type=\"widget\" id=\"CroixResetAnnonce\" 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:\/\/via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-transparent.png\" 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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-469b1a7c e-con-full UploadFileConteneur e-flex e-con e-child\" data-id=\"469b1a7c\" data-element_type=\"container\" id=\"UploadFileConteneur\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-3f5f9124 e-con-full ChoisirEspacePublicitaireDisponibiliteConteneur e-flex e-con e-child\" data-id=\"3f5f9124\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-48a37689 e-con-full e-flex e-con e-child\" data-id=\"48a37689\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b68287 PositionEspacePublicitaire elementor-widget elementor-widget-text-editor\" data-id=\"4b68287\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPosition\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-79a46db6 e-con-full e-flex e-con e-child\" data-id=\"79a46db6\" data-element_type=\"container\" id=\"ChoixEspacePublicitaireTitre\">\n\t\t\t\t<div class=\"elementor-element elementor-element-47d25f98 elementor-widget elementor-widget-text-editor\" data-id=\"47d25f98\" data-element_type=\"widget\" id=\"ChoixEspacePublicitaireTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tChoix d&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-3aa42503 e-con-full e-flex e-con e-child\" data-id=\"3aa42503\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-12d5dc39 ReferenceEspacePublicitaire elementor-widget elementor-widget-text-editor\" data-id=\"12d5dc39\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-21535e15 e-con-full EspPubFormatMainContainer e-flex e-con e-child\" data-id=\"21535e15\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-de420c1 e-con-full e-flex e-con e-child\" data-id=\"de420c1\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2f60f3f elementor-widget-mobile__width-inherit SelectionFormatTitre elementor-widget elementor-widget-text-editor\" data-id=\"2f60f3f\" data-element_type=\"widget\" data-widget_type=\"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 s\u00e9lectionner un format d&rsquo;annonce<\/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-6b485447 elementor-widget-mobile__width-inherit elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile SelectionFormatTitreBlancOLD elementor-widget elementor-widget-text-editor\" data-id=\"6b485447\" data-element_type=\"widget\" data-widget_type=\"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 changer de format d&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-78e1d9f5 e-con-full EspPubFormatListe e-flex e-con e-child\" data-id=\"78e1d9f5\" data-element_type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-cf3602e e-con-full EspPubFormatContainer FormatIdCreation e-flex e-con e-child\" data-id=\"cf3602e\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7a1bb33 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"7a1bb33\" data-element_type=\"widget\" data-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\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-6bf72a5 e-con-full EspPubFormatContainer FormatIdPopUp e-flex e-con e-child\" data-id=\"6bf72a5\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1a57dd9 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"1a57dd9\" data-element_type=\"widget\" data-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-34d8bbba e-con-full EspPubFormatContainer FormatIdBanniere e-flex e-con e-child\" data-id=\"34d8bbba\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-32bd35c6 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"32bd35c6\" data-element_type=\"widget\" data-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-5a9252c3 e-con-full EspPubFormatContainer FormatIdVideo e-flex e-con e-child\" data-id=\"5a9252c3\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8722042 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"8722042\" data-element_type=\"widget\" data-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<a class=\"elementor-element elementor-element-19ecc2b3 e-con-full EspPubFormatContainer FormatIdCommunique e-flex e-con e-child\" data-id=\"19ecc2b3\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6071d405 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"6071d405\" data-element_type=\"widget\" data-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<a class=\"elementor-element elementor-element-3617569c e-con-full EspPubFormatContainer FormatIdInterview e-flex e-con e-child\" data-id=\"3617569c\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b013e71 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"4b013e71\" data-element_type=\"widget\" data-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-7450a6f8 e-con-full EspPubFormatContainer FormatIdParrainage e-flex e-con e-child\" data-id=\"7450a6f8\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-30970f89 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"30970f89\" data-element_type=\"widget\" data-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<div class=\"elementor-element elementor-element-6aac67a6 e-con-full HTMLUploadfileConteneur e-flex e-con e-child\" data-id=\"6aac67a6\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-40d299c elementor-widget__width-inherit HTMLUploadfileClass elementor-widget elementor-widget-html\" data-id=\"40d299c\" data-element_type=\"widget\" id=\"HTMLUploadfile\" 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=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <meta name=\"google\" content=\"notranslate\">\r\n    \r\n    <script data-jetpack-boost=\"ignore\" src=\"https:\/\/code.jquery.com\/jquery-3.6.0.min.js\"><\/script>\r\n    <script data-jetpack-boost=\"ignore\" src=\"https:\/\/code.jquery.com\/ui\/1.12.1\/jquery-ui.min.js\"><\/script>\r\n\r\n<script data-jetpack-boost=\"ignore\">\r\n\/\/ Lazy loading des biblioth\u00e8ques - charg\u00e9es uniquement au besoin\r\nwindow.VIALibraries = {\r\n    mammothLoaded: false,\r\n    pdfLoaded: false,\r\n    \r\n    loadMammoth: function(callback) {\r\n        if (this.mammothLoaded) { callback(); return; }\r\n        var script = document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/mammoth\/1.4.0\/mammoth.browser.min.js';\r\n        script.onload = function() { \r\n            window.VIALibraries.mammothLoaded = true; \r\n            callback(); \r\n        };\r\n        document.head.appendChild(script);\r\n    },\r\n    \r\n    loadPdfJs: function(callback) {\r\n        if (this.pdfLoaded) { callback(); return; }\r\n        var script = document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.11.174\/pdf.min.js';\r\n        script.onload = function() {\r\n            window.VIALibraries.pdfLoaded = true;\r\n            pdfjsLib.GlobalWorkerOptions.workerSrc = '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n            callback();\r\n        };\r\n        document.head.appendChild(script);\r\n    }\r\n};\r\n<\/script>\r\n\r\n<\/head>\r\n<body>\r\n    <div id=\"PopUpMessageAchattest\" class=\"draggable\" draggable=\"true\" style=\"justify-content: center; align-items: flex-start;\">\r\n        <div id=\"drop_file_zone_achat\" class=\"drop_file_zone_achat_class\" ondrop=\"uploadFile_achat(event)\" ondragover=\"return false\">\r\n        <div id=\"drag_upload_file_achat\">\r\n            <p><input class=\"button-2_achat\" type=\"button\" value=\"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\" onclick=\"fileExplorer_achat(event);\" \/><\/p>\r\n                <input type=\"file\" id=\"selectfile_achat\" \/>\r\n        <\/div>\r\n        <\/div>\r\n        <div class=\"img-content\"><\/div>\r\n    <\/div>\r\n<\/body>\r\n<\/html>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1fd15d20 elementor-widget__width-inherit HTMLUploadfileClass elementor-widget elementor-widget-html\" data-id=\"1fd15d20\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script data-jetpack-boost=\"ignore\">\r\nif (!window._espPubScriptLoaded) {\r\nwindow._espPubScriptLoaded = true;\r\n\/**\r\n * Configuration centralis\u00e9e\r\n *\/\r\nconst CONFIG = {\r\n    iframeId: 'yearbook-iframe',\r\n    ajaxUrl: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n    apercuUrl: 'https:\/\/rdc.yearbook-media.com\/apercu',\r\n    \r\n    allowedExtensions: {\r\n        video: ['mp4', 'mov', 'wmv', 'avi', 'flv', 'f4v', 'swf', 'mkv', 'webm', 'mpeg'],\r\n        image: ['jpg', 'jpeg', 'png', 'gif', 'tif', 'svg', 'webp'],\r\n        document: ['doc', 'docx', 'ppt', 'pptx', 'pdf']\r\n    },\r\n    \r\n    mimeTypes: {\r\n        docx: 'application\/vnd.openxmlformats-officedocument.wordprocessingml.document',\r\n        pdf: 'application\/pdf'\r\n    },\r\n    \r\n    dragScroll: {\r\n        threshold: 150,\r\n        maxSpeed: 65,\r\n        throttleDelay: 50\r\n    },\r\n    \r\n    breakpoints: {\r\n        mobile: 1000\r\n    },\r\n    \r\n    keywords: [\r\n        { normal: \"parrainage\", display: \"Parrainage\" },\r\n        { normal: \"communique\", display: \"Communiqu\u00e9\" },\r\n        { normal: \"interview\", display: \"Interview\" }\r\n    ]\r\n};\r\n\r\n\/**\r\n * \u2705 v1.19.1 : Module de positionnement dans l'iframe\r\n * \r\n * PROBL\u00c8ME : L'iframe ne scrolle pas en desktop \u2014 c'est le parent (#PageWebTitrePage) qui scrolle.\r\n * L'iframe est scal\u00e9e \u00e0 0.85 \u2192 les coordonn\u00e9es iframe \u2260 coordonn\u00e9es parent.\r\n * position:fixed dans l'iframe = relatif au CONTENU TOTAL, pas au viewport visible.\r\n * \r\n * SOLUTION : Le parent calcule visibleTopIframe (la position iframe du haut du viewport)\r\n * et l'envoie dans le message 'PageWebTitrePage-scroll'. L'iframe n'a qu'\u00e0 l'utiliser.\r\n * \r\n * Pour scroller, l'iframe envoie 'scrollToIframeY' au parent qui fait la conversion.\r\n *\/\r\nconst ScrollHelper = {\r\n    _visibleTopIframe: 0,\r\n    _iframeScale: 0.85,\r\n\r\n    init() {\r\n        \/\/ \u00c9couter les donn\u00e9es de scroll envoy\u00e9es par le parent\r\n        window.addEventListener('message', (event) => {\r\n            var msg = event.data;\r\n            if (msg && msg.action === 'PageWebTitrePage-scroll') {\r\n                if (typeof msg.visibleTopIframe === 'number') {\r\n                    this._visibleTopIframe = msg.visibleTopIframe;\r\n                }\r\n                if (typeof msg.iframeScale === 'number') {\r\n                    this._iframeScale = msg.iframeScale;\r\n                }\r\n            }\r\n        });\r\n        console.log('\u2705 ScrollHelper initialis\u00e9');\r\n    },\r\n\r\n    \/**\r\n     * Position Y dans le document iframe correspondant au haut du viewport visible\r\n     *\/\r\n    getVisibleTop() {\r\n        if (window === window.top) {\r\n            return window.scrollY || 0;\r\n        }\r\n        return this._visibleTopIframe;\r\n    },\r\n\r\n    \/**\r\n     * Demande au parent de scroller pour positionner `element` \u00e0 `offsetFromTop` px du viewport\r\n     *\/\r\n    scrollElementTo(element, offsetFromTop) {\r\n        if (!element) return;\r\n\r\n        \/\/ getBoundingClientRect().top dans une iframe sans scroll = position absolue Y\r\n        var elementAbsY = element.getBoundingClientRect().top;\r\n\r\n        if (window === window.top) {\r\n            window.scrollTo({ top: elementAbsY - offsetFromTop + (window.scrollY || 0), behavior: 'smooth' });\r\n            return;\r\n        }\r\n\r\n        \/\/ Envoyer au parent \u2014 le parent fait la conversion scale\r\n        window.parent.postMessage({\r\n            type: 'scrollToIframeY',\r\n            iframeId: CONFIG.iframeId,\r\n            iframeY: elementAbsY,\r\n            offsetFromTop: offsetFromTop\r\n        }, '*');\r\n        console.log('\ud83d\udcdc scrollToIframeY:', { iframeY: Math.round(elementAbsY), offsetFromTop });\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'\u00e9tat (SessionStorage)\r\n *\/\r\nconst StateManager = {\r\n    init() {\r\n        if (sessionStorage.getItem(\"AchatEspaceCall\") === 'No') {\r\n            sessionStorage.clear();\r\n        }\r\n        \r\n        this.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        this.set('dragstart_Rank_Emplacement_Page_Web', 'No');\r\n        this.set('dragstart_Commande_Emplacement_Page_Web', 'No');\r\n        \r\n        \/\/ \u2705 v2.1.1 : Popup \u2192 ne jamais pr\u00e9remplir le format\r\n        if (this.get('PopUpChoice') === 'Yes') {\r\n            this.set('Formatchoisi', 'No');\r\n            this.set('FormatSelect', '');\r\n            this.set('Commande_Format_Transmis', '');\r\n        }\r\n    },\r\n    \r\n    get(key) {\r\n        return sessionStorage.getItem(key);\r\n    },\r\n    \r\n    set(key, value) {\r\n        sessionStorage.setItem(key, value);\r\n    },\r\n    \r\n    getMultiple(keys) {\r\n        return keys.reduce((acc, key) => {\r\n            acc[key] = this.get(key);\r\n            return acc;\r\n        }, {});\r\n    },\r\n    \r\n    setMultiple(obj) {\r\n        Object.entries(obj).forEach(([key, value]) => {\r\n            this.set(key, value);\r\n        });\r\n    },\r\n    \r\n    buildEmplacementReference(rank) {\r\n        const codeSite = this.get('codeSite');\r\n        const codePage = this.get('codePage');\r\n        return `${codeSite}${codePage}L${rank.substring(3)}`;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des fichiers\r\n *\/\r\nconst FileManager = {\r\n    getExtension(filename) {\r\n        console.log('filename:', filename);\r\n        const parts = filename.split('.');\r\n        return parts.length > 1 ? parts.pop().toLowerCase() : '';\r\n    },\r\n    \r\n    isAllowedExtension(extension) {\r\n        return Object.values(CONFIG.allowedExtensions)\r\n            .flat()\r\n            .includes(extension);\r\n    },\r\n    \r\n    getFileType(extension) {\r\n        for (const [type, extensions] of Object.entries(CONFIG.allowedExtensions)) {\r\n            if (extensions.includes(extension)) {\r\n                return type;\r\n            }\r\n        }\r\n        return null;\r\n    },\r\n    \r\n    async urlToFile(url, filename) {\r\n        console.log(\"Fetching from URL:\", url);\r\n        \r\n        const mimeType = filename.includes('.docx') \r\n            ? CONFIG.mimeTypes.docx \r\n            : filename.includes('.pdf') \r\n            ? CONFIG.mimeTypes.pdf \r\n            : null;\r\n        \r\n        try {\r\n            const response = await fetch(url);\r\n            \r\n            if (!response.ok) {\r\n                throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`);\r\n            }\r\n            \r\n            const blob = await response.blob();\r\n            return new File([blob], filename, { type: mimeType });\r\n        } catch (error) {\r\n            console.error(\"Error in urlToFile:\", error);\r\n            alert(\"Erreur lors du chargement du fichier. Veuillez r\u00e9essayer.\");\r\n            throw error;\r\n        }\r\n    },\r\n    \r\n    createObjectUrl(file) {\r\n        \/\/ R\u00e9voquer l'ancien URL si existant\r\n        const oldUrl = StateManager.get('objectUrl');\r\n        if (oldUrl && oldUrl.startsWith('blob:')) {\r\n            URL.revokeObjectURL(oldUrl);\r\n            console.log('\ud83d\uddd1\ufe0f Old Object URL revoked');\r\n        }\r\n        \r\n        const url = URL.createObjectURL(file);\r\n        StateManager.set('objectUrl', url);\r\n        return url;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion du Drag & Drop\r\n *\/\r\nconst DragDropManager = {\r\n    state: {\r\n        isFileBeingDragged: false,\r\n        draggedFile: null,\r\n        dragInProgress: false,\r\n        throttleTimeout: null\r\n    },\r\n    \r\n    init() {\r\n        this.attachEventListeners();\r\n    },\r\n    \r\n    attachEventListeners() {\r\n        window.addEventListener('dragstart', (e) => this.handleDragStart(e), true);\r\n        jQuery(document).on('dragover', (e) => this.handleDragOver(e));\r\n        jQuery(document).on('dragleave drop', (e) => this.handleDragEnd(e));\r\n        jQuery(\"#drop_file_zone_achat\").on(\"dragover\", (e) => this.handleDropZoneDragOver(e));\r\n        jQuery(\".draggable\").on(\"dragend\", (e) => this.handleDraggableEnd(e));\r\n    },\r\n    \r\n    handleDragStart(e) {\r\n        console.log('Window-level dragstart', e);\r\n        this.state.dragInProgress = true;\r\n    \r\n        const $target = $(e.target);\r\n        const droppableParent = $target.closest('.droppable');\r\n        const parentId = droppableParent.length ? droppableParent.attr('id') : null;\r\n        \r\n        StateManager.set('dragstart_Rank_Emplacement_Page_Web', parentId);\r\n        console.log('dragstart_Rank_Emplacement_Page_Web', parentId);\r\n        \r\n        \/\/ \u2705 CALCULER IMM\u00c9DIATEMENT dragstart_Commande_Emplacement_Page_Web\r\n        if (parentId) {\r\n            const dragstartRef = StateManager.buildEmplacementReference(parentId);\r\n            StateManager.set('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n            console.log('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n            \/\/ \u2705 v2.4.5 : Capturer l'\u00e9tat checkbox R\u00e9server au moment du dragstart\r\n            \/\/ Si l'utilisateur a explicitement d\u00e9coch\u00e9, forcer \u00e0 No m\u00eame si DOM est coch\u00e9\r\n            var $_dragCb = $('#' + parentId).find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n            var _dragCbChecked = $_dragCb.prop('checked') === true;\r\n            var _expliciteDecocheDrag = StateManager.get('_reserverDecoche_' + parentId) === 'Yes';\r\n            var _reserverDrag = _dragCbChecked && !_expliciteDecocheDrag;\r\n            StateManager.set('dragstart_ReserverChecked', _reserverDrag ? 'Yes' : 'No');\r\n            \/\/ R\u00e9initialiser le flag apr\u00e8s lecture\r\n            StateManager.set('_reserverDecoche_' + parentId, 'No');\r\n            console.log('[dragstart] ReserverChecked dom:', _dragCbChecked, '| d\u00e9coch\u00e9 explicitement:', _expliciteDecocheDrag, '| final:', _reserverDrag);\r\n        }\r\n    \r\n        const dataTransfer = e.dataTransfer || e.originalEvent?.dataTransfer;\r\n        const files = dataTransfer?.files || null;\r\n        \r\n        const imgSrc = $target.closest('.draggable').find('img').attr('src');\r\n        const videoSrc = $target.closest('.draggable').find('video').attr('src') || \r\n                        $target.closest('.draggable').find('video source').attr('src');\r\n        const mediaSrc = imgSrc || videoSrc;\r\n    \r\n        console.log('dragstart target:', e.target);\r\n        console.log('files:', files);\r\n        console.log('mediaSrc:', mediaSrc);\r\n    \r\n        if (!mediaSrc && (!files || files.length === 0)) {\r\n            console.log('No media source or files found, preventing drag');\r\n            e.preventDefault();\r\n            this.state.dragInProgress = false;\r\n            return false;\r\n        }\r\n    \r\n        if (mediaSrc) {\r\n            StateManager.set('objectUrl', mediaSrc);\r\n        }\r\n    \r\n        StateManager.set('Commande_Format_Transmis', '');\r\n        \r\n        if ($target.closest('.droppable').find('.doc-preview-container:visible').length > 0) {\r\n            StateManager.set('Commande_Format_Transmis', 'R\u00e9dactionnel');\r\n            StateManager.set('FullPathAdFile', \r\n                $target.closest('.droppable').find('.doc-preview-FullPathAdFile').text());\r\n        }\r\n    \r\n        if (files && files.length > 0) {\r\n            this.state.isFileBeingDragged = true;\r\n            this.state.draggedFile = files[0];\r\n        }\r\n        \r\n        \/\/ \u2705 TOUJOURS marquer comme \"Moved\" quand on drag depuis un espace existant\r\n        if (parentId && mediaSrc) {\r\n            StateManager.set('FirstUploadFileorMoved', 'Moved');\r\n            console.log('\u2705 Drag depuis espace existant - Moved');\r\n        }\r\n    \r\n        console.log('Drag Started', {\r\n            file: this.state.draggedFile,\r\n            mediaSrc: mediaSrc,\r\n            dragstartRef: StateManager.get('dragstart_Commande_Emplacement_Page_Web')\r\n        });\r\n    },\r\n    \r\n    handleDragOver(e) {\r\n        e.preventDefault();\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            this.handleIframeDragScroll(e);\r\n        } else {\r\n            this.handleDirectPageScroll(e);\r\n        }\r\n    },\r\n    \r\n    handleIframeDragScroll(e) {\r\n        if (!this.state.throttleTimeout) {\r\n            this.state.throttleTimeout = setTimeout(() => {\r\n                MessageManager.sendToParent('dragScroll', { clientY: e.clientY });\r\n                this.state.throttleTimeout = null;\r\n            }, CONFIG.dragScroll.throttleDelay);\r\n        }\r\n    },\r\n    \r\n    handleDirectPageScroll(e) {\r\n        const { threshold, maxSpeed } = CONFIG.dragScroll;\r\n        const windowHeight = window.innerHeight;\r\n        \r\n        if (e.clientY < threshold) {\r\n            const speed = Math.max(1, maxSpeed * (1 - e.clientY \/ threshold));\r\n            window.scrollBy(0, -speed);\r\n        } else if (e.clientY > windowHeight - threshold) {\r\n            const speed = Math.max(1, maxSpeed * (1 - (windowHeight - e.clientY) \/ threshold));\r\n            window.scrollBy(0, speed);\r\n        }\r\n    },\r\n    \r\n    handleDragEnd(e) {\r\n        e.preventDefault();\r\n        MessageManager.sendToParent('dragEnd', {});\r\n        console.log('dragleave drop');\r\n    },\r\n    \r\n    handleDropZoneDragOver(e) {\r\n        e.preventDefault();\r\n        console.log(\"FirstUploadFileorMoved:\", StateManager.get('FirstUploadFileorMoved'));\r\n    },\r\n    \r\n    handleDraggableEnd(e) {\r\n        e.preventDefault();\r\n        this.resetState();\r\n        console.log('dragend');\r\n    },\r\n    \r\n    resetState() {\r\n        this.state.isFileBeingDragged = false;\r\n        this.state.draggedFile = null;\r\n        this.state.dragInProgress = false;\r\n    },\r\n    \r\n    clearDataTransferFiles(e) {\r\n        e.dataTransfer = new DataTransfer();\r\n        console.log('DataTransfer files cleared');\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'interface utilisateur\r\n *\/\r\nconst UIManager = {\r\n    isMobile() {\r\n        return window.outerWidth < CONFIG.breakpoints.mobile;\r\n    },\r\n    \r\n    isDesktop() {\r\n        const userAgent = navigator.userAgent;\r\n        const isWindows = userAgent.indexOf('Windows') > -1;\r\n        const isMac = userAgent.indexOf('Macintosh') > -1;\r\n        const isLinux = userAgent.indexOf('Linux') > -1 && userAgent.indexOf('Android') === -1;\r\n        return isWindows || isMac || isLinux;\r\n    },\r\n    \r\n    initMobileUI() {\r\n        $(document).ready(() => {\r\n            $('label[for=\"form-field-LienAnnonce\"]').each(function() {\r\n                $(this).text('Renseigner le lien hypertexte de l\\'annonce');\r\n            });\r\n            \r\n            $('input[name=\"form_fields[LienAnnonce]\"]').each(function() {\r\n                $(this).attr('placeholder', 'Renseigner le lien hypertexte de l\\'annonce');\r\n            });\r\n        });\r\n        \r\n        jQuery('.MsgDatesText').hide();\r\n        this.attachMobileEventListeners();\r\n    },\r\n    \r\n    attachMobileEventListeners() {\r\n        jQuery('.TransmettreFichierAnnonceContainer').on('click', (e) => {\r\n            this.handleMobileSpaceSelection(e);\r\n        });\r\n        \r\n        jQuery('[id=\"form-field-selected_currency_Mobile\"]').off('change').on('change', (e) => {\r\n            this.handleMobileCurrencyChange(e);\r\n        });\r\n    },\r\n    \r\n    handleMobileSpaceSelection(e) {\r\n        e.preventDefault();\r\n        jQuery('#IndisponibilitesMsg').hide();\r\n        \r\n        jQuery('input[name=\"form_fields[SelectEspacePublicitaireMobile]\"]').prop('checked', false);\r\n        jQuery(e.currentTarget).find('input[name=\"form_fields[SelectEspacePublicitaireMobile]\"]').prop('checked', true);\r\n        \r\n        StateManager.set(\"PageWebDisplayed\", 'Yes');\r\n        \r\n        jQuery('.FormSelectDevisesMobile').hide();\r\n        jQuery(e.target).closest('.EspacePublicitaireMobile').find('.FormSelectDevisesMobile').show();\r\n        \r\n        const $droppable = jQuery(e.currentTarget).closest('.droppable');\r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', rankId);\r\n        StateManager.set('Commande_Emplacement_Page_Web', \r\n            StateManager.buildEmplacementReference(rankId));\r\n        \r\n        this.updateEmplacementDisplay();\r\n        this.handleAvailabilityDisplay(e);\r\n        this.displayUploadedAdIfExists(e);\r\n        this.updateTariffDisplay(e);\r\n    },\r\n    \r\n    updateEmplacementDisplay() {\r\n        const emplacement = StateManager.get('Commande_Emplacement_Page_Web');\r\n        jQuery('#EmplacementAnnonceDataStep3').html(emplacement).css({'color': '#56BE50'});\r\n        console.log(\"Emplacement:\", emplacement);\r\n    },\r\n    \r\n    handleAvailabilityDisplay(e) {\r\n        const $espace = jQuery(e.target).closest('.EspacePublicitaireMobile');\r\n        const dispoText = $espace.find('.ChoisirEspacePublicitaireDisponibilite').text();\r\n        \r\n        if (dispoText.length > 46) {\r\n            const espacePublicitaireDispoFrom = dispoText.slice(-10);\r\n            console.log(\"espacePublicitaireDispoFrom:\", espacePublicitaireDispoFrom);\r\n            console.log(\"Date de debut:\", StateManager.get(\"Debut_de_campagne\"));\r\n        } else {\r\n            jQuery('#form-field-DebutCampagne').val(StateManager.get(\"Debut_de_campagne\"));\r\n        }\r\n    },\r\n    \r\n    displayUploadedAdIfExists(e) {\r\n        if (StateManager.get(\"FileReceived\") === 'Yes') {\r\n            jQuery('.VisualisationAnnonceMobile').hide();\r\n            \r\n            const espaceId = StateManager.get('espaceChoisi');\r\n            const $espace = document.querySelector(`[id=\"${espaceId}\"]`);\r\n            \r\n            jQuery($espace).find('.MessageAnnonceMobileTexte')\r\n                .html('Merci de choisir des dates de campagne<br>afin d\\'obtenir le tarif de cet espace publicitaire');\r\n            jQuery($espace).find('.VisualisationAnnonceMobile').show();\r\n        \r\n            const img = document.createElement('img');\r\n            img.src = StateManager.get('objectUrl');\r\n            img.style.width = 'auto';\r\n            img.style.height = 'auto';\r\n            img.style.maxWidth = '100%';\r\n            img.style.maxHeight = '200px';\r\n            \r\n            jQuery('.VisualisationAnnonceMobile').empty();\r\n            jQuery($espace).find('.VisualisationAnnonceMobile').append(img);\r\n        }\r\n    },\r\n    \r\n    updateTariffDisplay(e) {\r\n        jQuery('.TariftobedisplayedMobile').html('-');\r\n        const newTarif = StateManager.get('NewTarifformatted');\r\n        \r\n        if (newTarif && newTarif !== '-') {\r\n            jQuery(e.target).closest('.EspacePublicitaireMobile')\r\n                .find('.TariftobedisplayedMobile')\r\n                .html(newTarif);\r\n        }\r\n    },\r\n    \r\n    handleMobileCurrencyChange(e) {\r\n        event.preventDefault();\r\n        StateManager.setMultiple({\r\n            \"SelectionCatalogueOuAchat\": 'Catalogue',\r\n            \"selected_currency\": jQuery(e.currentTarget).val()\r\n        });\r\n        \r\n        jQuery('#form-field-selected_currency_2').val(StateManager.get(\"selected_currency\"));\r\n        console.log(\"selected currency:\", StateManager.get(\"selected_currency\"));\r\n        \r\n        setTimeout(() => {\r\n            jQuery(e.target).closest('.EspacePublicitaireMobile')\r\n                .find('.TariftobedisplayedMobile')\r\n                .html(StateManager.get(\"NewTarifformatted\"));\r\n        }, 500);\r\n    },\r\n    \r\n    initDesktopUI() {\r\n        StateManager.setMultiple({\r\n            \"FileReceived\": \"No\",\r\n            \"AdDisplayed\": \"No\"\r\n        });\r\n        jQuery('.MsgAdNotDisplayed').hide();\r\n    },\r\n    \r\n    showUploadProgress($dropZone) {\r\n        \/\/ Cacher les \u00e9l\u00e9ments\r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .TexteMobileAnnonce')\r\n            .hide();\r\n        \r\n        \/\/ Afficher et styler le message de progression\r\n        var _uplMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed')\r\n            .show()\r\n            .html(_uplMsg)\r\n            .css({\r\n                'color': '#00ff19',\r\n                'background-color': 'white',\r\n                'padding': '12px 20px',\r\n                'border-radius': '6px',\r\n                'font-weight': '700',\r\n                'font-size': '18px',\r\n                'line-height': '1.4',\r\n                'display': 'inline-block',\r\n                'margin': '10px auto',\r\n                'text-align': 'center'\r\n            });\r\n        \r\n        \/\/ Cacher les autres \u00e9l\u00e9ments\r\n        $dropZone.closest('.droppable')\r\n            .find('.UploadIci, .EnvoiUlterieurTexte, .EnvoiUlterieurContainer')\r\n            .hide();\r\n            \r\n        $dropZone.closest('.droppable')\r\n            .find('.UploadFileConteneur')\r\n            .css({\r\n                'background-color': 'transparent'\r\n            });\r\n    },\r\n    \r\n    showFormatError($dropZone, message = 'Format de fichier incompatible') {\r\n        \/\/ \u2705 v2.4.6 : M\u00eame rendu overlay que le bloc jpeg \u2014 position absolute sur $dropZone\r\n        var _errId = 'fmt-error-msg-' + Date.now();\r\n        $dropZone.css('position', 'relative');\r\n        var _errHtml = '<div id=\"' + _errId + '\" style=\"'\r\n            + 'position:absolute;top:50px;left:50%;transform:translateX(-50%);width:auto;white-space:nowrap;'\r\n            + 'background:#fff;color:#FB5E2A;font-weight:700;font-size:13px;'\r\n            + 'text-align:center;padding:8px 10px;border-radius:6px;'\r\n            + 'border:2px solid #FB5E2A;box-sizing:border-box;'\r\n            + 'z-index:99999;line-height:1.4;'\r\n            + '\">' + message + '<\/div>';\r\n        $dropZone.append(_errHtml);\r\n        setTimeout(function() { jQuery('#' + _errId).remove(); }, 4000);\r\n    },\r\n    \r\n    updateAfterSuccessfulUpload($dropZone) {\r\n        jQuery('#errorMessageMobileText').hide();\r\n        \r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 Pas de margin-top:150px si d\u00e9p\u00f4t depuis miniature kit (d\u00e9j\u00e0 positionn\u00e9)\r\n        if (!window._dropFromMiniature) {\r\n            $dropZone.closest('.OrdiMobileConteneurClass')\r\n                .css({'margin-top': '150px', 'margin-bottom': '0px'});\r\n        }\r\n    },\r\n    \r\n    finalizeAdDisplay($dropZone) {\r\n        StateManager.setMultiple({\r\n            \"FileReceived\": \"Yes\",\r\n            \"PageWebDisplayed\": \"Yes\"\r\n        });\r\n        \r\n        jQuery('#MsgChoixPageWeb, #MsgInsererAnnonceConteneur').hide();\r\n        jQuery('#ChoixEspacePublicitaire')\r\n            .html('L\\'annonce est plac\u00e9e dans un espace publicitaire')\r\n            .show()\r\n            .css({'color': '#56BE50'});\r\n        \r\n        jQuery('#MsgPlacerAnnoncePosition').hide();\r\n        jQuery('#FonctionMenu4').show();\r\n        jQuery('.AnnonceData').html(\"Transmis\").css({'color': '#56BE50'});\r\n        \r\n        jQuery('#ProcederPaiementConteneur').hide();\r\n        jQuery('#ProcederPaiementTitreIconeUp').hide();\r\n        jQuery('#ProcederPaiementTitreIconeDown').show();\r\n        \r\n        jQuery('#message').remove();\r\n        \r\n        this.styleUploadedAd($dropZone);\r\n        this.adjustLayoutAfterUpload($dropZone);\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox \"R\u00e9server\" apr\u00e8s upload\r\n        FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n    },\r\n    \r\n    styleUploadedAd($dropZone) {\r\n        const $container = $dropZone.closest('.OrdiMobileConteneurClass');\r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \r\n        \/\/ \u2705 v1.19.5 : V\u00e9rifier si c'est une restauration via flag d\u00e9di\u00e9\r\n        const isRestoration = StateManager.get('_isAdRestoration') === 'Yes';\r\n        \r\n        $container\r\n            .find('.PositionReference, .TexteMobile, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        $container\r\n            .find('.AdUploadedTitle, .DimensionsMaximales')\r\n            .show();\r\n        \r\n        \/\/ \u2705 Bug 2 fix : montrer le conteneur parent + la croix (CroixResetAnnonceContainer cach\u00e9 par reset)\r\n        $droppable.find('.CroixResetAnnonceContainer').show();\r\n        $droppable.find('#CroixResetAnnonce').show();\r\n        \r\n        \/\/ \u2705 v2.2 : Marquer le droppable comme occup\u00e9 pour qu'Entete le skip\r\n        $droppable.attr('data-via-ad-loaded', 'true');\r\n        \r\n        \/\/ \u2705 v2.0.11 : AdUploadedTitle ne doit pas bloquer le touch sur doc-preview-readmore (mobile)\r\n        $container.find('.AdUploadedTitle').css('pointer-events', 'none');\r\n        \r\n        \/\/ \u2705 #CroixResetAnnonce au-dessus de tous les conteneurs superpos\u00e9s\r\n        $container.find('#CroixResetAnnonce').css({\r\n            'position': 'relative',\r\n            'z-index': '9999'\r\n        });\r\n        \r\n        \/\/ \u2705 Desktop : les conteneurs superpos\u00e9s bloquent la croix \u2014 les rendre transparents aux clics\r\n        if (!UIManager.isMobile()) {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css('pointer-events', 'none');\r\n            \/\/ R\u00e9activer les \u00e9l\u00e9ments interactifs\r\n            $container.find('#CroixResetAnnonce').css('pointer-events', 'auto');\r\n            $dropZone.closest('#PopUpMessageAchattest').css('pointer-events', 'auto'); \/\/ drag annonce\r\n        }\r\n        \r\n        \/\/ \u2705 v2.4.3 : Sur mobile, masquer titre et logo drag quand annonce d\u00e9pos\u00e9e dans Ele0A\r\n        if (UIManager.isMobile()) {\r\n            if ($droppable.attr('id') === 'Ele0A') {\r\n                $droppable.find('#ChoixEspacePublicitaireTexte').hide();\r\n                $droppable.find('#Ele0ADragHandle').hide();\r\n                \/\/ \u2705 v2.4.12 : UploadFileConteneur a pointer-events:none \u2192 forcer auto sur la croix\r\n                $droppable.find('.CroixResetAnnonceContainer')[0] && $droppable.find('.CroixResetAnnonceContainer')[0].style.setProperty('pointer-events', 'auto', 'important');\r\n                $droppable.find('#CroixResetAnnonce')[0] && $droppable.find('#CroixResetAnnonce')[0].style.setProperty('pointer-events', 'auto', 'important');\r\n            }\r\n        }\r\n        \r\n        jQuery(\".HTMLUploadfileConteneur\").css({\r\n            'border': 'none',\r\n            'background-color': 'transparent'\r\n        });\r\n        \r\n        \/\/ \u2705 v2.4.12 : Retirer le liser\u00e9 envoi diff\u00e9r\u00e9 (#UploadFileConteneur) si pr\u00e9sent\r\n        \/\/ (le d\u00e9p\u00f4t d'une annonce cr\u00e9e son propre liser\u00e9 sur .HTMLUploadfileConteneur)\r\n        var $_ufcEd = $dropZone.closest('.droppable').find('#UploadFileConteneur');\r\n        if ($_ufcEd[0]) {\r\n            $_ufcEd[0].style.removeProperty('box-shadow');\r\n            $_ufcEd[0].style.removeProperty('box-sizing');\r\n            if (UIManager.isMobile()) {\r\n                $_ufcEd[0].style.removeProperty('transform');\r\n                $_ufcEd[0].style.removeProperty('transform-origin');\r\n            }\r\n        }\r\n        \r\n        $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n            'box-shadow': 'inset 0 0 0 2px #00FF19',  \/\/ \u2705 v2.4.5 : inset \u2192 jamais clipp\u00e9 par overflow:hidden\r\n            'background-color': 'white',\r\n            'box-sizing': 'border-box',\r\n            'overflow': 'hidden'\r\n        });\r\n        \r\n        \/\/ \u2705 v2.0.9 : Fix mobile \u2014 r\u00e9duire le scale pour que le liser\u00e9 vert soit visible\r\n        \/\/ \u2705 Pas de scale si annonce d\u00e9pos\u00e9e depuis la miniature kit (d\u00e9j\u00e0 aux bonnes dimensions)\r\n        \/\/ \u2705 v2.4.9 : Pas de scale si AchatEspaceCall=Yes (drop depuis miniature dans iframe)\r\n        \/\/ \u2705 data-kit-drop : marqueur DOM pos\u00e9 par kitAdCreated, r\u00e9siste \u00e0 l'async\r\n        var _fromKitDrop = $droppable[0] ? $droppable[0].getAttribute('data-kit-drop') === 'true' : false;\r\n        if (_fromKitDrop) { window._dropFromMiniature = true; } \/\/ sync le flag window\r\n        var _fromMiniature = window._dropFromMiniature || _fromKitDrop;\r\n        var _fromAchat = StateManager.get('AchatEspaceCall') === 'Yes';\r\n        if (UIManager.isMobile() && !_fromMiniature && !_fromAchat) {\r\n            $dropZone.closest('.UploadFileConteneur').css({\r\n                'transform': 'scale(1.35)',\r\n                'transform-origin': 'top center'\r\n            });\r\n            \/\/ \u2705 v2.4.11 : Corps de page mobile \u2014 le .ToBeHidden clippe le scale(1.35) c\u00f4t\u00e9 droit\r\n            \/\/ \u2192 overflow:visible pour que le liser\u00e9 vert soit visible sur les 4 c\u00f4t\u00e9s\r\n            $dropZone.closest('.ToBeHidden').css('overflow', 'visible');\r\n        }\r\n        \r\n        \/\/ \u2705 v2.2 : Sur restauration, Entete a d\u00e9j\u00e0 positionn\u00e9 le droppable correctement\r\n        \/\/ et est emp\u00each\u00e9 de le retoucher (data-via-ad-loaded). On ne touche pas aux marges.\r\n        \/\/ Sur premier upload, on applique les marges normalement.\r\n        \/\/ \u2705 Pas de marges si d\u00e9p\u00f4t depuis miniature kit (dimensions naturelles conserv\u00e9es)\r\n        if (!isRestoration && !_fromMiniature) {\r\n            if ($container.data('orig-mb') === undefined) {\r\n                $container.data('orig-mb', parseInt($container.css('margin-bottom')) || 0);\r\n            }\r\n            if ($droppable.data('orig-mt') === undefined) {\r\n                $droppable.data('orig-mt', parseInt($droppable.css('margin-top')) || 0);\r\n            }\r\n            var _isDocPreview = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _marginAdd = _isDocPreview ? 60 : 130;\r\n            var _marginReduce = _isDocPreview ? 60 : 130;\r\n            $container.css({\r\n                'margin-bottom': ($container.data('orig-mb') + _marginAdd) + 'px'\r\n            });\r\n            $droppable.css({\r\n                'margin-top': ($droppable.data('orig-mt') - _marginReduce + 75) + 'px'\r\n            });\r\n        } else {\r\n            \/\/ \u2705 Sur restauration, ajouter 50px en dessous pour \u00e9viter que le contenu soit trop coll\u00e9\r\n            var _curMb = parseInt($container.css('margin-bottom')) || 0;\r\n            $container.css('margin-bottom', (_curMb + 50) + 'px');\r\n        }\r\n        \r\n        \/\/ \u2705 Masquer .PositionEspacePublicitaireContainer et l'ancien .ReserverContainer\r\n        $droppable.find('.PositionEspacePublicitaireContainer').hide();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        \/\/ \u2705 Supprimer tout ancien bouton dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 v2.1.2 : Cr\u00e9er le bouton R\u00e9server m\u00eame lors d'une restauration\r\n        if (isRestoration) {\r\n            console.log('\ud83d\udd04 Restauration d\u00e9tect\u00e9e - affichage bouton R\u00e9server + DeplaceAnnonce');\r\n            $droppable.find('.DeplaceAnnonce').show();\r\n            \/\/ S'assurer que FileReceived est d\u00e9fini pour la validation\r\n            StateManager.set('FileReceived', 'Yes');\r\n            \/\/ Cocher automatiquement SEULEMENT si c'est une restauration de commande r\u00e9serv\u00e9e (pas pendingAd)\r\n            var _isPendingAdRestore = sessionStorage.getItem('_pendingAdRestoration') === 'Yes';\r\n            if (!_isPendingAdRestore) {\r\n                var _isReservedRestore = sessionStorage.getItem('_isReservedRestoration') === 'Yes';\r\n                setTimeout(function() {\r\n                    var $checkbox = $droppable.find('.reserver-dynamic-checkbox');\r\n                    if ($checkbox.length && _isReservedRestore) {\r\n                        $checkbox.prop('checked', true);\r\n                        $droppable.find('.reserver-dynamic-label').text('Espace publicitaire r\u00e9serv\u00e9').css('color', 'rgb(62, 170, 19)');\r\n                        console.log('\u2705 R\u00e9server coch\u00e9 automatiquement (restauration commande r\u00e9serv\u00e9e)');\r\n                    }\r\n                    sessionStorage.removeItem('_isReservedRestoration');\r\n                    StateManager.set('_isAdRestoration', 'No');\r\n                    \/\/ \u2705 v2.4.7 : updateReserverCheckboxState APR\u00c8S avoir coch\u00e9 la checkbox\r\n                    \/\/ (l'appel synchrone ligne 614 intervient avant le cocher \u2192 label incorrect)\r\n                    if (typeof FormatUIManager !== 'undefined') {\r\n                        FormatUIManager.updateReserverCheckboxState($droppable);\r\n                    }\r\n                }, 150);\r\n            } else {\r\n                \/\/ pendingAd : ne pas cocher, ne pas envoyer au parent\r\n                console.log('\u2705 pendingAd restaur\u00e9 \u2014 R\u00e9server NON coch\u00e9');\r\n                sessionStorage.removeItem('_pendingAdRestoration');\r\n                StateManager.set('_isAdRestoration', 'No');\r\n            }\r\n        }\r\n        \r\n        \/\/ \u2705 Supprimer tout bouton R\u00e9server existant avant insertion (\u00e9vite doublons sur restauration)\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 Cr\u00e9er le bouton \"R\u00e9server\" dynamique avec id unique pour \u00e9viter conflit label\/for Elementor\r\n        const _rankId = $droppable.attr('id') || ('drop_' + Date.now());\r\n        const _cbId = 'reserver-cb-' + _rankId;\r\n        const reserverHTML = `\r\n            <div class=\"reserver-dynamic-container\">\r\n                <span class=\"reserver-dynamic-option\">\r\n                    <input type=\"checkbox\" id=\"${_cbId}\" value=\"R\u00e9server cet espace publicitaire\" \r\n                           class=\"reserver-dynamic-checkbox\"\r\n                           name=\"form_fields[ReserverEspacePublicitaire]\">\r\n                    <span class=\"reserver-dynamic-label\">R\u00e9server cet espace publicitaire<\/span>\r\n                <\/span>\r\n            <\/div>\r\n        `;\r\n        \r\n        \/\/ \u2705 Ins\u00e9rer juste avant .DeplaceAnnonceText (position stable)\r\n        const $anchor = $droppable.find('.DeplaceAnnonceText');\r\n        if ($anchor.length) {\r\n            $anchor.before(reserverHTML);\r\n            $anchor.prev('.reserver-dynamic-container').css('margin-bottom', '-40px');\r\n            if (!UIManager.isMobile()) {\r\n                $anchor.prev('.reserver-dynamic-container').find('.reserver-dynamic-label').css({'font-size': '20px', 'font-weight': '700'});\r\n            }\r\n        } else {\r\n            $droppable.after(reserverHTML);\r\n            const $btn = $droppable.next('.reserver-dynamic-container');\r\n            $btn.css('margin-top', UIManager.isMobile() ? '-10px' : '-140px');\r\n        }\r\n        \r\n        console.log('\u2705 Bouton \"R\u00e9server\" dynamique cr\u00e9\u00e9');\r\n    },\r\n    \r\n    adjustLayoutAfterUpload($dropZone) {\r\n        console.log('\ud83d\udcf1 adjustLayoutAfterUpload \u2014 isMobile():', this.isMobile(), 'outerWidth:', window.outerWidth);\r\n        if (this.isMobile()) {\r\n            this.adjustMobileLayout($dropZone);\r\n            \r\n            \/\/ Repositionner le bouton R\u00e9server APR\u00c8S les ajustements de layout\r\n            setTimeout(() => {\r\n                const $droppable = $dropZone.closest('.droppable');\r\n                const $btn = $droppable.find('.reserver-dynamic-container').add($droppable.next('.reserver-dynamic-container')).first();\r\n                const $lisere = $droppable.find('.HTMLUploadfileConteneur');\r\n                if ($btn.length && $lisere.length) {\r\n                    const lisereBottom = $lisere[0].getBoundingClientRect().bottom;\r\n                    const btnTop = $btn[0].getBoundingClientRect().top;\r\n                    const offset = lisereBottom - btnTop - 48;\r\n                    \r\n                    \/\/ 15px suppl\u00e9mentaires pour homepage et articles\r\n                    let extraOffset = 0;\r\n                    const isHomepage = window.location.pathname === \"\/\" || window.location.pathname === \"\/en\/\";\r\n                    const isSectorPage = $('body').hasClass('page');\r\n                    if (isHomepage) {\r\n                        extraOffset = 13;\r\n                    }\r\n                    if (!isSectorPage) {\r\n                        extraOffset = 15;\r\n                    }\r\n                    \r\n                    \/\/ \u2705 v2.0.9 : +4px pour documents (communiqu\u00e9\/interview\/PDF) avec pr\u00e9sentation HTML\r\n                    if ($droppable.find('.doc-preview-container:visible').length > 0) {\r\n                        extraOffset += 4;\r\n                    }\r\n                    \r\n                    $btn.css({\r\n                        'margin-top': (offset + extraOffset + 20) + 'px',\r\n                        'margin-bottom': (-(offset + extraOffset) - 100) + 'px'\r\n                    });\r\n                    console.log('\ud83d\udcd0 Repositionnement mobile R\u00e9server:', { lisereBottom, btnTop, offset });\r\n                }\r\n            }, 50);\r\n        } else {\r\n            this.adjustDesktopLayout($dropZone);\r\n        }\r\n    },\r\n    \r\n    adjustMobileLayout($dropZone) {\r\n        console.log('\ud83d\udcf1 adjustMobileLayout START');\r\n        console.log('\ud83d\udcf1 AchatEspaceCall:', StateManager.get(\"AchatEspaceCall\"));\r\n        console.log('\ud83d\udcf1 PageAjoutModifAnnonce:', StateManager.get(\"PageAjoutModifAnnonce\"));\r\n        console.log('\ud83d\udcf1 window===window.top:', window === window.top);\r\n        console.log('\ud83d\udcf1 pathname:', location.pathname);\r\n        \r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \r\n        \/\/ \u2705 v2.4.3 : Masquer les textes position\/label\/r\u00e9f\u00e9rence (comme sur desktop)\r\n        $droppable\r\n            .find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 v2.6 : Renseigner .PositionEspacePublicitaire sur mobile (manquait vs desktop)\r\n        (function() {\r\n            var _rankPosMob = StateManager.get('Rank_Emplacement_Page_Web') || $droppable.attr('id') || '';\r\n            var _posLibMob = PreviewRenderer._getPositionLibelle(_rankPosMob);\r\n            if (_posLibMob) {\r\n                $droppable\r\n                    .find('.PositionEspacePublicitaire')\r\n                    .text(_posLibMob)\r\n                    .each(function() {\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        \/\/ \u2705 Scop\u00e9 au $dropZone courant (\u00e9vite d'affecter les autres espaces pub)\r\n        $dropZone.closest('.droppable').find('#CroixResetAnnonce').css({'zoom': '75%'});\r\n\r\n        \/\/ \u2705 v2.4.3 : Remonter la croix reset sur mobile (override margin-top Elementor)\r\n        \/\/ \u2705 v2.4.5 : Poser aussi margin-right ici (Entete.txt ne l'atteint pas pour Ele0A)\r\n        var _croixContainer = $dropZone.closest('.OrdiMobileConteneurClass').find('.CroixResetAnnonceContainer')[0];\r\n        if (_croixContainer) {\r\n            var _isEle0ACroix = ($dropZone.closest('.droppable').attr('id') === 'Ele0A');\r\n            var _mtCroix = StateManager.get(\"PageAjoutModifAnnonce\") === 'Yes' ? '-88px' : '24px';\r\n            \/\/ Ele0A : +40px vers le bas, +15px vers la gauche (margin-right) par rapport \u00e0 Ele1A\r\n            \/\/ Ele0A : margin-top identique aux autres espaces (pas de d\u00e9calage suppl\u00e9mentaire)\r\n            _croixContainer.style.setProperty('margin-top', _mtCroix, 'important');\r\n            _croixContainer.style.setProperty('margin-right', _isEle0ACroix ? '17px' : '12px', 'important');\r\n        }\r\n        \r\n        var _isMiniatureAdj = window._dropFromMiniature;\r\n        window._dropFromMiniature = false;\r\n\r\n        if (_isMiniatureAdj && window.outerWidth <= 1000) {\r\n            \/\/ \u2705 Miniature doc-preview MOBILE : ajuster HTMLUploadfileConteneur \u00e0 la hauteur du contenu\r\n            \/\/ et neutraliser tous les margins Elementor qui d\u00e9calent le $dropZone hors du parent\r\n            var _isDocPreviewMob = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _docH = _isDocPreviewMob ? 144 : 115;\r\n            $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                'height':     _docH + 'px',\r\n                'min-height': _docH + 'px',\r\n                'max-height': _docH + 'px',\r\n                'margin-top': '-55px',\r\n                'margin-bottom': '0px',\r\n                'overflow': 'hidden'\r\n            });\r\n            $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px', 'height': (_docH - 6) + 'px'});\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '65px', 'margin-bottom': '-10px'});\r\n            \/\/ \u2705 v2.4.9 : Doc-preview \u2014 overflow:visible pour que le liser\u00e9 du haut ne soit pas clipp\u00e9\r\n            if (_isDocPreviewMob) {\r\n                $dropZone.closest('.OrdiMobileConteneurClass').css('overflow', 'visible');\r\n                $dropZone.closest('.OrdiMobileConteneurClass').parent().css('overflow', 'visible');\r\n            }\r\n            \/\/ \u2705 v2.4.9 : Ele0A popup mobile \u2014 neutraliser translateY(-32px) pos\u00e9 par Entete sur EnvoiUlterieurTexte\r\n            var _isEle0AMob = ($dropZone.closest('.droppable').attr('id') === 'Ele0A');\r\n            if (_isEle0AMob) {\r\n                var $_euTxt = $dropZone.closest('.droppable').find('.EnvoiUlterieurTexte');\r\n                if ($_euTxt[0]) {\r\n                    $_euTxt[0].style.setProperty('transform', 'translateY(0px)', 'important');\r\n                    $_euTxt[0].style.setProperty('margin-top', '0px', 'important');\r\n                }\r\n            }\r\n            \/\/ \u2705 v2.4.12 : AchatEspaceCall=Yes \u2192 override margins (m\u00eame correction que pour upload direct)\r\n            if (StateManager.get('AchatEspaceCall') === 'Yes') {\r\n                $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px'});\r\n                var _docHAchatMini = _isDocPreviewMob ? 150 : 112;\r\n                $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                    'margin-top': '70px',\r\n                    'margin-bottom': '35px',\r\n                    'min-height': _docHAchatMini + 'px',\r\n                    'height': _isDocPreviewMob ? _docHAchatMini + 'px' : '',\r\n                    'max-height': _isDocPreviewMob ? _docHAchatMini + 'px' : ''\r\n                });\r\n                console.log('\ud83d\udcf1 [miniature] AchatEspaceCall=Yes OVERRIDE: mt=70px | docPreview:', _isDocPreviewMob);\r\n            }\r\n            return;\r\n        }\r\n        \/\/ \u2705 v2.4.10 : Miniature DESKTOP \u2192 layout normal appliqu\u00e9 ci-dessous\r\n        if (_isMiniatureAdj) {\r\n            \/\/ Pas de overflow:hidden \u2014 le liser\u00e9 box-shadow inset doit rester visible\r\n        }\r\n\r\n        $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n            'min-height': '112px',\r\n            'margin-top': '-85px',\r\n            \/\/ \u2705 v2.4.10 : Miniature desktop \u2014 pas de margin-bottom excessif qui fait grandir le droppable\r\n            'margin-bottom': _isMiniatureAdj ? '0px' : '20px' \/\/ \u2705 v2.6 : 195px \u2192 59px \u2192 20px (\u00f73) espace sous checkbox R\u00e9server\r\n        });\r\n        console.log('\ud83d\udcf1 HTMLUploadfileConteneur margins set: mt=-85px mb=20px, el found:', $dropZone.closest('.HTMLUploadfileConteneur').length);\r\n        \r\n        $dropZone.css({\r\n            'margin-top': '-50px',\r\n            'margin-bottom': '-140px'\r\n        });\r\n        \r\n        $dropZone.closest('.OrdiMobileConteneurClass').css({\r\n            'margin-top': '65px',\r\n            'margin-bottom': '-10px'\r\n        });\r\n        console.log('\ud83d\udcf1 OrdiMobile margins set: mt=65px mb=-10px');\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            \/\/ \u2705 v2.4.12 : Reset $dropZone margins (les -50px\/-140px tirent le contenu vers le haut dans l'iframe)\r\n            \/\/ Pour doc-preview (Communiqu\u00e9\/Interview), la hauteur est plus grande \u2192 ajuster min-height\r\n            var _isDocPreviewAchat = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _docHAchat = _isDocPreviewAchat ? 150 : 112;\r\n            $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px'});\r\n            $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                \/\/ \u2705 v2.4.13 : Miniature desktop \u2192 +40px suppl\u00e9mentaires pour compenser le d\u00e9calage\r\n                'margin-top': _isMiniatureAdj ? '110px' : '70px',\r\n                'margin-bottom': '35px',\r\n                'min-height': _docHAchat + 'px',\r\n                'height': _isDocPreviewAchat ? _docHAchat + 'px' : '',\r\n                'max-height': _isDocPreviewAchat ? _docHAchat + 'px' : ''\r\n            });\r\n            console.log('\ud83d\udcf1 AchatEspaceCall=Yes OVERRIDE: mt=' + (_isMiniatureAdj ? '110px' : '70px') + ' | docPreview:', _isDocPreviewAchat, '| h:', _docHAchat);\r\n        }\r\n        \r\n        if (location.pathname === '\/annonce' || location.pathname === '\/annonce\/') {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '70px'});\r\n        }\r\n        \r\n        if (window === window.top) {\r\n            console.log('\ud83d\udcf1 window===window.top OVERRIDE droppable margins');\r\n            $dropZone.closest('.droppable').css({\r\n                'margin-top': '-100px',\r\n                'margin-bottom': '-100px'\r\n            });\r\n            $dropZone.closest('#UploadFileConteneur').css({'width': '80%'});\r\n        }        \r\n    },\r\n    \r\n    adjustDesktopLayout($dropZone) {\r\n        const emplacement = StateManager.get('Commande_Emplacement_Page_Web');\r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \/\/ \u2705 v2.4.13 : Lire et resetter _dropFromMiniature ici aussi (desktop)\r\n        var _fromMiniatureDesktop = window._dropFromMiniature || ($droppable[0] ? $droppable[0].getAttribute('data-kit-drop') === 'true' : false);\r\n        window._dropFromMiniature = false;\r\n        \/\/ \u2705 Nettoyer data-kit-drop apr\u00e8s lecture\r\n        if ($droppable[0]) { $droppable[0].removeAttribute('data-kit-drop'); }\r\n        \r\n        \/\/ \u2705 Masquer les textes enfants (position, label, r\u00e9f\u00e9rence) sans toucher au conteneur\r\n        $droppable\r\n            .find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur > div > .elementor-widget-text-editor')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 +15px sur .droppable \u2014 sauf si drop depuis miniature (dimensions naturelles)\r\n        if (!_fromMiniatureDesktop) {\r\n            const currentMt = parseInt($droppable.css('margin-top')) || 0;\r\n            $droppable.css('margin-top', (currentMt + 15) + 'px');\r\n        } else {\r\n            \/\/ \u2705 v2.4.13 : Drop depuis miniature Kit \u2014 d\u00e9caler de 30px vers le bas\r\n            const currentMt = parseInt($droppable.css('margin-top')) || 0;\r\n            \/\/ \u2705 Homepage : -20px (annonce trop basse sur r\u00e9gie) \u2014 autres pages : +70px\r\n            var _mtOffsetMini = (window.location.pathname === '\/' || window.location.pathname === '\/en\/' || window.location.pathname === '\/fr\/') ? -20 : 70;\r\n            $droppable.css('margin-top', (currentMt + _mtOffsetMini) + 'px');\r\n        }\r\n        \r\n        $dropZone.closest('.OrdiMobileConteneurClass')\r\n            .find('.RefEspacePublicitaire')\r\n            .html(emplacement)\r\n            .attr('id', 'RefEspacePublicitaire')\r\n            .each(function() {\r\n                \/\/ \u2705 Forcer aussi le parent .DeplaceAnnonce visible (display:none !important inline)\r\n                var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                this.style.setProperty('display', 'block', 'important');\r\n            });\r\n        \/\/ \u2705 v2.4.5 : Renseigner et afficher .PositionEspacePublicitaire\r\n        (function() {\r\n            var _rankPos = StateManager.get('Rank_Emplacement_Page_Web') || $droppable.attr('id') || '';\r\n            var _posLib = PreviewRenderer._getPositionLibelle(_rankPos);\r\n            if (_posLib) {\r\n                $dropZone.closest('.OrdiMobileConteneurClass')\r\n                    .find('.PositionEspacePublicitaireDeplacer')\r\n                    .text(_posLib)\r\n                    .each(function() {\r\n                        var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                        if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        if (window.location.pathname === \"\/\" || window.location.pathname === \"\/en\/\") {\r\n            \/\/ \u2705 v2.4.10 : top selon contexte \u2014 espaces hors .remainingContent d\u00e9calent de 60px, ceux dedans de 20px\r\n            var _inRemainingContent = $dropZone.closest('.remainingContent').length > 0;\r\n            var _topOffsetHP = _inRemainingContent ? '20px' : '100px';\r\n            $dropZone.closest('.ToBeHidden')\r\n                .css('top', _topOffsetHP)\r\n                .css('min-height', '300px');\r\n            \/\/ NB : pas de overflow:hidden ici \u2014 le liser\u00e9 vert (box-shadow inset sur HTMLUploadfileConteneur)\r\n            \/\/ doit rester visible sur les 4 c\u00f4t\u00e9s\r\n        }\r\n        \r\n        \/\/ \u2705 Toutes pages desktop : rendre le parent du droppable non-clippant\r\n        \/\/ Le bouton R\u00e9server est ins\u00e9r\u00e9 apr\u00e8s .droppable avec margin-top n\u00e9gatif \u2014\r\n        \/\/ overflow:hidden sur le parent Elementor le masque sinon.\r\n        $droppable.parent().css('overflow', 'visible');\r\n        \r\n        if (location.pathname === '\/annonce' || location.pathname === '\/annonce\/') {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '0px'});\r\n        }\r\n    }\r\n};\r\n\r\n\/**\r\n * \u2705 Module de gestion des formats et du titre .SelectionFormatTitre\r\n *\/\r\nconst FormatUIManager = {\r\n    \r\n    \/**\r\n     * V\u00e9rifie si un format est s\u00e9lectionn\u00e9 dans un espace publicitaire\r\n     * V\u00e9rifie le background-color OU le sessionStorage (format venant de l'accord\u00e9on)\r\n     *\/\r\n    hasSelectedFormat($element) {\r\n        const $droppable = $element.closest('.droppable');\r\n        const isEle0A = $droppable.attr('id') === 'Ele0A';\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            if (isEle0A) {\r\n                \/\/ \u2705 v2.3.4 : Ele0A popup \u2014 vrai seulement si un format sous-jacent (hors FormatIdPopUp) est s\u00e9lectionn\u00e9\r\n                var _hasDomFmt = $droppable.find('.EspPubFormatContainer').not('.FormatIdPopUp').toArray().some(el => {\r\n                    return $(el).css('background-color') === 'rgb(255, 255, 255)';\r\n                });\r\n                if (_hasDomFmt) return true;\r\n                \/\/ \u2705 v2.4.5 : Fallback sessionStorage \u2014 DOM pas encore mis \u00e0 jour (timing MutationObserver)\r\n                return !!sessionStorage.getItem('FormatSelect');\r\n            }\r\n            \/\/ Autres espaces en mode popup \u2192 toujours vrai\r\n            return true;\r\n        }\r\n        const hasWhiteBg = $droppable.find('.EspPubFormatContainer').toArray().some(el => {\r\n            return $(el).css('background-color') === 'rgb(255, 255, 255)';\r\n        });\r\n        if (hasWhiteBg) return true;\r\n        \/\/ \u2705 v1.16.0 : Fallback sessionStorage Formatchoisi\r\n        if (sessionStorage.getItem('Formatchoisi') === 'Yes') return true;\r\n        \/\/ \u2705 v2.4.5 : Fallback FormatSelect \u2014 cas du chargement initial avec format d\u00e9j\u00e0 s\u00e9lectionn\u00e9\r\n        \/\/ (Formatchoisi peut \u00eatre remis \u00e0 No au chargement, mais FormatSelect persiste)\r\n        if (sessionStorage.getItem('FormatSelect')) return true;\r\n        \/\/ \u2705 v2.4.9 : Fallback _FormatSelectApplied \u2014 survit au clear de yearbook-media.js init\r\n        return !!sessionStorage.getItem('_FormatSelectApplied');\r\n    },\r\n    \r\n    \/**\r\n     * Met \u00e0 jour la couleur du titre .SelectionFormatTitre\r\n     * Blanc si un format est s\u00e9lectionn\u00e9, rouge #FB5E2A sinon\r\n     *\/\r\n    updateTitleColor($droppable) {\r\n        \/\/ \u2705 v2.4.5 : Ele0A \u2014 ne jamais afficher SelectionFormatTitre\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes' && $droppable.attr('id') === 'Ele0A') {\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n            return;\r\n        }\r\n\r\n        if (this.hasSelectedFormat($droppable)) {\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n            console.log('\u2705 SelectionFormatTitreBlanc affich\u00e9 (format s\u00e9lectionn\u00e9)');\r\n        } else {\r\n            $droppable.find('.SelectionFormatTitre').show();\r\n            $droppable.find('.SelectionFormatTitreBlanc').hide();\r\n            console.log('\u26a0\ufe0f SelectionFormatTitre affich\u00e9 (aucun format s\u00e9lectionn\u00e9)');\r\n        }\r\n    },\r\n    \r\n    \/**\r\n     * Flash visuel sur le titre pour indiquer qu'un format est requis\r\n     *\/\r\n    flashTitle($element) {\r\n        const $droppable = $element.closest('.droppable');\r\n        const $titre = $droppable.find('.SelectionFormatTitre');\r\n        if (!$titre.length) return;\r\n        \r\n        \/\/ Flash rouge rapide 3 fois\r\n        let count = 0;\r\n        const originalColor = $titre.css('color');\r\n        \r\n        const flash = setInterval(() => {\r\n            $titre.css('color', count % 2 === 0 ? '#FF0000' : '#FB5E2A');\r\n            count++;\r\n            if (count >= 6) {\r\n                clearInterval(flash);\r\n                $titre.css('color', '#FB5E2A');\r\n            }\r\n        }, 250);\r\n        \r\n        console.log('\u26a0\ufe0f Flash titre format - action bloqu\u00e9e (aucun format s\u00e9lectionn\u00e9)');\r\n    },\r\n    \r\n    \/**\r\n     * Met \u00e0 jour l'\u00e9tat de la checkbox \"R\u00e9server cet espace publicitaire\"\r\n     * La checkbox est activable si : format s\u00e9lectionn\u00e9 ET (fichier d\u00e9pos\u00e9 OU envoi diff\u00e9r\u00e9)\r\n     *\/\r\n    updateReserverCheckboxState($droppable) {\r\n        \/\/ \u2705 Chercher le label : dynamique ou Elementor statique\r\n        let $label = null;\r\n        let $container = null;\r\n        \r\n        \/\/ 1. Bouton dynamique dans le droppable\r\n        $container = $droppable.find('.reserver-dynamic-container');\r\n        if (!$container.length) {\r\n            $container = $droppable.next('.reserver-dynamic-container');\r\n        }\r\n        if (!$container.length) {\r\n            \/\/ Mobile : checkbox attach\u00e9e au body avec data-droppable-id\r\n            $container = $('body > .reserver-dynamic-container[data-droppable-id=\"' + $droppable.attr('id') + '\"]');\r\n        }\r\n        if (!$container.length) {\r\n            $container = $('body > .reserver-dynamic-container');\r\n        }\r\n        \r\n        if ($container.length) {\r\n            $label = $container.find('.reserver-dynamic-label');\r\n            $container.find('.reserver-dynamic-option, .elementor-field-option').css('opacity', '1');\r\n        }\r\n        \r\n        \/\/ 2. Bouton Elementor statique - chercher dans le droppable puis globalement\r\n        let $reserverStatique = $droppable.find('.elementor-field-group-ReserverEspacePublicitaire label');\r\n        if (!$reserverStatique.length) {\r\n            $reserverStatique = $droppable.find('label[for^=\"form-field-ReserverEspacePublicitaire\"]');\r\n        }\r\n        if (!$reserverStatique.length) {\r\n            \/\/ Fallback global : le formulaire peut \u00eatre en dehors du droppable\r\n            $reserverStatique = $('.elementor-field-group-ReserverEspacePublicitaire .elementor-field-option label');\r\n        }\r\n        \r\n        const hasFormat = this.hasSelectedFormat($droppable);\r\n        const hasFile = StateManager.get('FileReceived') === 'Yes';\r\n        const hasEnvoiDiffere = $droppable.find('input[name*=\"EnvoiUlterieur\"]:checked').length > 0;\r\n        \r\n        const canReserve = hasFormat && (hasFile || hasEnvoiDiffere);\r\n        \r\n        \/\/ \u2705 Si la checkbox R\u00e9server est coch\u00e9e \u2192 label vert \"Espace publicitaire r\u00e9serv\u00e9\"\r\n        const isChecked = $droppable.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked') ||\r\n                          ($container.length && $container.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked'));\r\n        \/\/ \u2705 v2.4.7 : Signal de restauration r\u00e9serv\u00e9e \u2014 checkbox pas encore coch\u00e9e (setTimeout 150ms)\r\n        \/\/             mais on sait d\u00e9j\u00e0 que l'espace est r\u00e9serv\u00e9 \u2192 traiter comme coch\u00e9\r\n        const _isReservedRestoration = sessionStorage.getItem('_isReservedRestoration') === 'Yes';\r\n        const isCheckedOrReservedRestore = isChecked || _isReservedRestoration;\r\n        \r\n        if ($label && $label.length) {\r\n            if (isCheckedOrReservedRestore) {\r\n                $label.text('Espace publicitaire r\u00e9serv\u00e9').css('color', 'rgb(62, 170, 19)');\r\n            } else {\r\n                $label.text('R\u00e9server cet espace publicitaire').css('color', canReserve ? '#FB5E2A' : '');\r\n            }\r\n        }\r\n        if ($reserverStatique.length) {\r\n            if (isCheckedOrReservedRestore) {\r\n                $reserverStatique.attr('style', 'color: rgb(62, 170, 19) !important;');\r\n            } else if (canReserve) {\r\n                $reserverStatique.attr('style', 'color: #FB5E2A !important;');\r\n            } else {\r\n                $reserverStatique.removeAttr('style');\r\n            }\r\n        }\r\n        \r\n        console.log('\ud83d\udd04 updateReserverCheckboxState:', { hasFormat, hasFile, hasEnvoiDiffere, canReserve, dynamicLabel: !!($label && $label.length), staticLabel: $reserverStatique.length });\r\n    },\r\n    \r\n    \/**\r\n     * Initialise les listeners pour le changement de format et la checkbox R\u00e9server\r\n     *\/\r\n    init() {\r\n        \/\/ \u2705 \u00c9couter les clics sur les conteneurs de format et leurs parents\r\n        jQuery(document).on('click', '.EspPubFormatContainer, .EspPubFormatListe, .EspPubFormatMainContainer', (e) => {\r\n            const $droppable = jQuery(e.target).closest('.droppable');\r\n            if (!$droppable.length) return;\r\n            \r\n            \/\/ Multiples d\u00e9lais pour couvrir les traitements asynchrones\r\n            [50, 200, 500].forEach(delay => {\r\n                setTimeout(() => {\r\n                    this.updateTitleColor($droppable);\r\n                    this.updateReserverCheckboxState($droppable);\r\n                }, delay);\r\n            });\r\n\r\n            \/\/ \u2705 v2.2.0 : Si un format (non Cr\u00e9ation) est cliqu\u00e9, notifier le parent pour mettre \u00e0 jour le Kit\r\n            const $btn = jQuery(e.target).closest('.EspPubFormatContainer');\r\n            if ($btn.length && !$btn.hasClass('FormatIdCreation') && !$btn.hasClass('FormatIdPopUp')) {\r\n                \/\/ \u2705 v2.3.4 : FormatIdPopUp g\u00e9r\u00e9 par clickFormatFromIframe (Entete.txt) \u2014 ne pas doubler\r\n                var classes = $btn.attr('class') || '';\r\n                var match = classes.match(\/FormatId(\\w+)\/);\r\n                if (match && match[1]) {\r\n                    var _rankEP = $droppable.attr('id') || '';\r\n                    setTimeout(function() {\r\n                        MessageManager.sendToParent('formatChangedInIframe', { formatSelect: match[1], rank: _rankEP });\r\n                        console.log('\ud83d\udd04 formatChangedInIframe envoy\u00e9:', match[1], '| rank:', _rankEP);\r\n                    }, 100);\r\n                }\r\n            }\r\n        });\r\n        \r\n        \/\/ \u2705 MutationObserver sur les conteneurs de format pour d\u00e9tecter les changements de style\r\n        setTimeout(() => {\r\n            this.observeFormatChanges();\r\n            \r\n            \/\/ Initialiser les couleurs des titres au chargement\r\n            jQuery('.droppable').each((i, el) => {\r\n                this.updateTitleColor(jQuery(el));\r\n            });\r\n            \r\n            \/\/ \u2705 v2.3.4 : Popup \u2192 restaurer FormatIdPopUp + format sous-jacent (sans \u00e9craser applyFormatState)\r\n            if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n                jQuery('.FormatIdPopUp').css({'background-color': '#ffffff'});\r\n                jQuery('.FormatIdPopUp').find('.EspPubFormat').css({'color': '#37D900'});\r\n                \/\/ Restaurer aussi le format sous-jacent dans Ele0A\r\n                var _fmtSS = sessionStorage.getItem('FormatSelect') || '';\r\n                if (_fmtSS) {\r\n                    var _fmtSSNorm = _fmtSS.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                    jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdCreation').each(function() {\r\n                        var _cls = this.className.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                        if (_cls.includes(_fmtSSNorm)) {\r\n                            jQuery(this).css({'background-color': '#ffffff'});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        }\r\n                    });\r\n                }\r\n                jQuery('.droppable').each((i, el) => {\r\n                    this.updateTitleColor(jQuery(el));\r\n                });\r\n            }\r\n        }, 500);\r\n        \r\n        \/\/ \u2705 v1.16.0 : Re-v\u00e9rifier apr\u00e8s un d\u00e9lai plus long (format venant de l'accord\u00e9on via postMessage)\r\n        [1500, 3000].forEach(delay => {\r\n            setTimeout(() => {\r\n                \/\/ \u2705 v2.3.4 : Popup \u2192 restaurer FormatIdPopUp + format sous-jacent\r\n                if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n                    jQuery('.FormatIdPopUp').css({'background-color': '#ffffff'});\r\n                    jQuery('.FormatIdPopUp').find('.EspPubFormat').css({'color': '#37D900'});\r\n                    var _fmtSSR = sessionStorage.getItem('FormatSelect') || '';\r\n                    if (_fmtSSR) {\r\n                        var _fmtSSRNorm = _fmtSSR.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                        jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdCreation').each(function() {\r\n                            var _cls = this.className.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                            if (_cls.includes(_fmtSSRNorm)) {\r\n                                jQuery(this).css({'background-color': '#ffffff'});\r\n                                jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                            }\r\n                        });\r\n                    }\r\n                    jQuery('.droppable').each((i, el) => {\r\n                        this.updateTitleColor(jQuery(el));\r\n                    });\r\n                    return;\r\n                }\r\n                if (sessionStorage.getItem('Formatchoisi') === 'Yes') {\r\n                    jQuery('.droppable').each((i, el) => {\r\n                        this.updateTitleColor(jQuery(el));\r\n                    });\r\n                }\r\n            }, delay);\r\n        });\r\n    },\r\n    \r\n    \/**\r\n     * Attache un MutationObserver sur chaque .EspPubFormatContainer\r\n     * pour d\u00e9tecter tout changement de style (background-color) \r\n     * quel que soit le script qui le d\u00e9clenche\r\n     *\/\r\n    observeFormatChanges() {\r\n        \/\/ \u2705 Guard global anti-boucle \u2014 un seul verrou pour tous les observers\r\n        window._formatObserverLocked = false;\r\n        \r\n        jQuery('.EspPubFormatContainer').each((i, el) => {\r\n            const observer = new MutationObserver(() => {\r\n                if (window._formatObserverLocked) return;\r\n                window._formatObserverLocked = true;\r\n                \/\/ \u2705 v2.4.12 : Debounce 150ms \u2014 applyFormatState manipule plusieurs containers\r\n                \/\/ en s\u00e9quence rapide, le MutationObserver peut firer sur un \u00e9tat interm\u00e9diaire\r\n                clearTimeout(window._formatObserverTimer);\r\n                window._formatObserverTimer = setTimeout(() => {\r\n                    const $droppable = jQuery(el).closest('.droppable');\r\n                    this.updateTitleColor($droppable);\r\n                    this.updateReserverCheckboxState($droppable);\r\n                    window._formatObserverLocked = false;\r\n                }, 150);\r\n            });\r\n            observer.observe(el, { \r\n                attributes: true, \r\n                attributeFilter: ['style', 'class'] \r\n            });\r\n        });\r\n        console.log('\u2705 MutationObserver attach\u00e9 aux conteneurs de format');\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de communication avec la page parente\r\n *\/\r\nconst MessageManager = {\r\n    sendToParent(type, data = {}) {\r\n        try {\r\n            window.parent.postMessage({\r\n                type: type,\r\n                iframeId: CONFIG.iframeId,\r\n                data: data\r\n            }, '*');\r\n        } catch (error) {\r\n            console.error('Error sending message to parent:', error);\r\n            window.parent.postMessage({\r\n                type: 'error',\r\n                error: error.message,\r\n                iframeId: CONFIG.iframeId\r\n            }, '*');\r\n        }\r\n    },\r\n    \r\n    sendDataToParent(data) {\r\n        this.sendToParent('dataFromIframeEspacePub', data);\r\n    },\r\n    \r\n    sendDelAdToParent(data) {\r\n        this.sendToParent('dataDelAd', data);\r\n    },\r\n    \r\n    prepareUploadData() {\r\n        const keys = [\r\n            'AddNewRefInVosCampagnes',\r\n            'FirstUploadFileorMoved',\r\n            'LoadedPageUrl',\r\n            'codePage',\r\n            'Rank_Emplacement_Page_Web',\r\n            'Commande_Emplacement_Page_Web',\r\n            'dragstart_Commande_Emplacement_Page_Web',\r\n            'dragstart_Rank_Emplacement_Page_Web',  \r\n            'FullPathAdFile',\r\n            'Upload_File_Name',\r\n            'FileReceived',\r\n            'PageWebDisplayed',\r\n            'Commande_Format_Transmis',\r\n            'EspPubLienAnnonce',\r\n            'EnvoiUlterieur',\r\n            'Formatchoisi'\r\n        ];\r\n        \r\n        const data = StateManager.getMultiple(keys);\r\n        \r\n        \/\/ \u2705 v2.3.4 : Popup (Ele0A) \u2014 lire le format sous-jacent depuis le DOM\r\n        \/\/ StateManager contient 'PopUp' (virtuel), mais le vrai format est visuellement s\u00e9lectionn\u00e9 dans #Ele0A\r\n        if (data.Rank_Emplacement_Page_Web === 'Ele0A' || sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            var _ele0AFormatDOM = '';\r\n            jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdPopUp').each(function() {\r\n                if (jQuery(this).css('background-color') === 'rgb(255, 255, 255)') {\r\n                    var _cls = this.className || '';\r\n                    var _match = _cls.match(\/FormatId(\\S+)\/);\r\n                    if (_match) { _ele0AFormatDOM = _match[1]; return false; }\r\n                }\r\n            });\r\n            if (_ele0AFormatDOM) {\r\n                data.Commande_Format_Transmis = _ele0AFormatDOM;\r\n            }\r\n        }\r\n        \r\n        console.log('\ud83d\udce4 prepareUploadData:', {\r\n            FirstUploadFileorMoved: data.FirstUploadFileorMoved,\r\n            dragstart_Commande_Emplacement_Page_Web: data.dragstart_Commande_Emplacement_Page_Web,\r\n            Commande_Emplacement_Page_Web: data.Commande_Emplacement_Page_Web\r\n        });\r\n    \r\n        return data;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de rendu des aper\u00e7us de fichiers\r\n *\/\r\nconst PreviewRenderer = {\r\n    _getPositionLibelle(rankId) {\r\n        if (!rankId) return '';\r\n        var match = rankId.match(\/Ele(\\d+)[A-Z]\/);\r\n        if (!match) return '';\r\n        var rang = parseInt(match[1]);\r\n        if (rang === 0) return 'Pop-up';\r\n        if (rang === 1 || rang === 2) return 'Haut de page';\r\n        return 'Corps de page';\r\n    },\r\n    renderVideo(objectUrl, fileName, $dropZone) {\r\n        const videoElement = jQuery('<video controls autoplay muted>').attr({\r\n            'src': objectUrl,\r\n            'width': 'auto',\r\n            'height': 'auto',\r\n            'id': fileName\r\n        }).css({\r\n            'max-width': '100%',\r\n            'max-height': '100%'\r\n        });\r\n        \r\n        if (UIManager.isDesktop()) {\r\n            $dropZone.empty().append(videoElement.clone());\r\n            jQuery('#ApercuMobile').css({\r\n                'display': 'flex',\r\n                'justify-content': 'center',\r\n                'align-items': 'center'\r\n            }).append(videoElement);\r\n        } else {\r\n            const img = document.createElement('img');\r\n            img.src = objectUrl;\r\n            img.style.width = 'auto';\r\n            img.style.height = 'auto';\r\n            img.style.maxWidth = 'calc(100% - 4px)';  \/\/ \u2705 v2.4.5 : 2px retrait inset box-shadow\r\n            img.style.maxHeight = '115px';\r\n            \r\n            const container = $dropZone[0];\r\n            while (container.firstChild) {\r\n                container.removeChild(container.firstChild);\r\n            }\r\n            container.appendChild(img);\r\n        }\r\n        \r\n        StateManager.setMultiple({\r\n            'Commande_Format': 'Vid\u00e9o',\r\n            'Commande_Format_Transmis': 'Vid\u00e9o',\r\n            'videoSrc': objectUrl,\r\n            'FormatAnnonceSelection': 'Yes',\r\n            'PositionAnnonceSelection': 'Yes'\r\n        });\r\n        \r\n        jQuery('#FormatDataStep3').html('Vid\u00e9o').css({'color': '#56BE50'});\r\n        jQuery('#TarifDataStep3').css({'color': '#96894D'});\r\n    },\r\n    \r\n    renderImage(objectUrl, $dropZone) {\r\n        const maxHeight = UIManager.isMobile() ? 105 : $dropZone.closest('.HTMLUploadfileConteneur').height();\r\n    \r\n        $dropZone.css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center',\r\n            'width': '100%',\r\n            'height': maxHeight + 'px',\r\n            'overflow': 'hidden',\r\n            'position': UIManager.isMobile() ? 'relative' : '',\r\n            'top': UIManager.isMobile() ? '45px' : '',\r\n            'padding': UIManager.isMobile() ? '0 2px' : ''  \/\/ \u2705 v2.4.5 : 2px retrait inset box-shadow mobile\r\n        });\r\n    \r\n        \/\/ \u2705 v1.19.2 : Image charg\u00e9e en arri\u00e8re-plan, remplace le message d'attente au onload\r\n        \/\/ \u2705 v2.4.5 : max-width calc(100%-4px) sur mobile pour ne pas recouvrir le box-shadow inset 2px\r\n        var _mxw = UIManager.isMobile() ? 'calc(100% - 4px)' : '100%';\r\n        var img = new Image();\r\n        img.style.cssText = 'max-width:' + _mxw + '; max-height:' + maxHeight + 'px; width:auto; height:auto; object-fit:contain;';\r\n        img.onload = function() {\r\n            $dropZone.empty().append(img);\r\n        };\r\n        img.onerror = function() {\r\n            $dropZone.html('<img decoding=\"async\" src=\"' + objectUrl + '\" style=\"max-width:' + _mxw + '; max-height:' + maxHeight + 'px; width:auto; height:auto; object-fit:contain;\">');\r\n        };\r\n        img.src = objectUrl;\r\n    \r\n        StateManager.setMultiple({\r\n            'Commande_Format_Transmis': 'Image',\r\n            'FormatAnnonceSelection': 'Yes',\r\n            'PositionAnnonceSelection': 'Yes'\r\n        });\r\n    \r\n        console.log('Image ajout\u00e9e avec succ\u00e8s');\r\n    },\r\n    \r\n    async renderWord(fileObj, $dropZone) {\r\n        return new Promise((resolve, reject) => {\r\n            const reader = new FileReader();\r\n            \r\n            reader.onload = async (e) => {\r\n                try {\r\n                    const arrayBuffer = e.target.result;\r\n                    const result = await mammoth.convertToHtml({arrayBuffer: arrayBuffer});\r\n                    \r\n                    const htmlContent = result.value;\r\n                    const tempContainer = document.createElement('div');\r\n                    tempContainer.innerHTML = htmlContent;\r\n                    \r\n                    const textContent = tempContainer.textContent || \"\";\r\n                    const normalizedText = this.normalizeText(textContent);\r\n                    const firstImage = tempContainer.querySelector('img');\r\n                    \r\n                    const titleText = this.findDocumentTitle(normalizedText);\r\n                    \r\n                    if (firstImage) {\r\n                        this.renderDocumentPreview(\r\n                            $dropZone,\r\n                            firstImage.src,\r\n                            titleText,\r\n                            textContent,\r\n                            htmlContent\r\n                        );\r\n                    } else {\r\n                        \/\/ \u2705 v1.19.0 : Accepter les documents sans image\r\n                        this.renderDocumentPreview(\r\n                            $dropZone,\r\n                            null,\r\n                            titleText,\r\n                            textContent,\r\n                            htmlContent\r\n                        );\r\n                        console.log('\u2139\ufe0f Document Word sans image \u2014 aper\u00e7u texte seul');\r\n                    }\r\n                    resolve();\r\n                } catch (error) {\r\n                    $dropZone.html(`<p style=\"color: #FB5E2A; font-weight: 600; font-family: Roboto, Arial, sans-serif; font-size: 12px; text-align: center; padding: 15px;\">Erreur lors de la lecture du document<\/p>`);\r\n                    reject(error);\r\n                }\r\n            };\r\n            \r\n            reader.readAsArrayBuffer(fileObj);\r\n        });\r\n        \r\n        this.finalizeRedactionnelUpload();\r\n    },\r\n    \r\n    renderDocumentPreview($dropZone, imageSrc, title, text, htmlContent = null) {\r\n        \/\/ \u2705 v1.19.0 : Deux layouts \u2014 avec image ou texte seul\r\n        let previewHtml;\r\n\r\n        if (imageSrc) {\r\n            \/\/ Layout avec miniature image\r\n            previewHtml = `\r\n                <div class=\"doc-preview-container\">\r\n                    <div class=\"doc-preview-thumbnail\">\r\n                        <img decoding=\"async\" src=\"${imageSrc}\" alt=\"Document image\">\r\n                    <\/div>\r\n                    <div class=\"doc-preview-info\">\r\n                        <div class=\"doc-preview-title\" id=\"AdTitle\">${title}<\/div>\r\n                        <div class=\"doc-preview-description\" id=\"AdText\">${this.getTextPreview(text, 13)}<\/div>\r\n                        <div class=\"doc-preview-readmore\" id=\"AdLirelasuite\">Ouvrir et visualiser<\/div>\r\n                        <div class=\"doc-preview-FullPathAdFile\" id=\"AdFullPathAdFile\">${StateManager.get(\"FullPathAdFile\")}<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            `;\r\n        } else {\r\n            \/\/ Layout texte seul (sans image)\r\n            previewHtml = `\r\n                <div class=\"doc-preview-container doc-preview-noimage\">\r\n                    <div class=\"doc-preview-icon\">\r\n                        <svg width=\"36\" height=\"36\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#213864\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n                            <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\/><polyline points=\"14 2 14 8 20 8\"\/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"\/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"\/><polyline points=\"10 9 9 9 8 9\"\/>\r\n                        <\/svg>\r\n                    <\/div>\r\n                    <div class=\"doc-preview-info doc-preview-info-full\">\r\n                        <div class=\"doc-preview-title\" id=\"AdTitle\">${title}<\/div>\r\n                        <div class=\"doc-preview-description\" id=\"AdText\">${this.getTextPreview(text, 25)}<\/div>\r\n                        <div class=\"doc-preview-readmore\" id=\"AdLirelasuite\">Ouvrir et visualiser<\/div>\r\n                        <div class=\"doc-preview-FullPathAdFile\" id=\"AdFullPathAdFile\">${StateManager.get(\"FullPathAdFile\")}<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            `;\r\n        }\r\n        \r\n        $dropZone.html(previewHtml + this.getPreviewStyles());\r\n        \r\n        if (htmlContent) {\r\n            this.attachWordPreviewHandler($dropZone, title, htmlContent);\r\n        }\r\n    },\r\n    \r\n    attachWordPreviewHandler($dropZone, titleText, htmlContent) {\r\n        var $droppable = $dropZone.closest('.droppable');\r\n\r\n        \/\/ \u2705 Adapter le libell\u00e9 selon le type de document\r\n        var isInterview = (titleText || '').toLowerCase().indexOf('interview') !== -1;\r\n        var formatLabel = isInterview ? 'l\\'interview' : 'le communiqu\u00e9';\r\n        $droppable.find('.doc-preview-readmore').text('Ouvrir et visualiser ' + formatLabel);\r\n\r\n        \/\/ \u2705 v2.0.11 : D\u00e9l\u00e9gation d'\u00e9v\u00e9nement \u2014 plus robuste sur mobile (survit aux manipulations DOM)\r\n        $droppable.off('click.docpreview').on('click.docpreview', '.doc-preview-readmore', (event) => {\r\n            event.preventDefault();\r\n            event.stopPropagation();\r\n            \r\n            if (htmlContent) {\r\n                var popupTitle = isInterview ? 'Interview' : 'Communiqu\u00e9';\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    htmlContent: htmlContent\r\n                });\r\n            } else {\r\n                console.warn('Le document est encore en cours de traitement.');\r\n            }\r\n        });\r\n    },\r\n    \r\n    normalizeText(text) {\r\n        return text\r\n            .toLowerCase()\r\n            .normalize(\"NFD\")\r\n            .replace(\/[\\u0300-\\u036f]\/g, \"\");\r\n    },\r\n    \r\n    findDocumentTitle(normalizedText) {\r\n        const foundKeyword = CONFIG.keywords.find(keyword => \r\n            normalizedText.includes(keyword.normal)\r\n        );\r\n        if (foundKeyword) return foundKeyword.display;\r\n        \r\n        \/\/ \u2705 v1.19.1 : Fallback \u2014 utiliser le format s\u00e9lectionn\u00e9 (FormatSelect)\r\n        var formatSelect = (sessionStorage.getItem('FormatSelect') || '').toLowerCase();\r\n        if (formatSelect.indexOf('interview') !== -1) return 'Interview';\r\n        if (formatSelect.indexOf('communiq') !== -1) return 'Communiqu\u00e9';\r\n        \r\n        return \"Document\";\r\n    },\r\n    \r\n    getTextPreview(text, maxWords) {\r\n        const words = text.split(' ');\r\n        if (words.length > maxWords) {\r\n            return words.slice(0, maxWords).join(' ') + ' ...';\r\n        }\r\n        return text;\r\n    },\r\n    \r\n    getPreviewStyles() {\r\n        return `\r\n            <style>\r\n                @import url('https:\/\/fonts.googleapis.com\/css2?family=Roboto:wght@400;600&display=swap');\r\n                \r\n                .doc-preview-container {\r\n                    margin: 0px 0;\r\n                    display: flex;\r\n                    width: 100%;\r\n                    max-height: 140px;\r\n                    overflow: hidden;\r\n                    box-sizing: border-box;  \/* \u2705 v2.4.5 *\/\r\n                    background: white;\r\n                    background-color: #f8f8f8;\r\n                }\r\n                .doc-preview-thumbnail {\r\n                    width: 50%; \r\n                    height: 130px;\r\n                    overflow: hidden;\r\n                    display: flex;\r\n                    align-items: center;\r\n                    justify-content: center;\r\n                    margin-top: 0px;\r\n                }\r\n                .doc-preview-thumbnail img {\r\n                    max-width: 75%;\r\n                    max-height: 75%;\r\n                    object-position: center;\r\n                    object-fit: fill;\r\n                }\r\n                .doc-preview-info {\r\n                    width: 50%;\r\n                    height: 130px; \r\n                    flex: 1;\r\n                    padding: 10px;\r\n                    display: flex;\r\n                    flex-direction: column; \r\n                }\r\n                .doc-preview-title {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #213864;\r\n                    font-size: 14px;\r\n                    font-weight: 600;\r\n                    text-align: left;\r\n                    margin-bottom: 5px;\r\n                }\r\n                .doc-preview-description {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #213864;\r\n                    font-size: 11px;\r\n                    font-weight: 400;\r\n                    text-align: left;\r\n                    overflow: hidden;\r\n                    margin-bottom: 5px;\r\n                    flex: 1;\r\n                }\r\n                .doc-preview-readmore {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #958848;\r\n                    font-size: 13px;\r\n                    font-weight: 600;\r\n                    text-align: left;\r\n                    cursor: pointer;\r\n                    padding: 4px 0;\r\n                    -webkit-tap-highlight-color: rgba(149,136,72,0.2);\r\n                }\r\n                @media (max-width: 999px) {\r\n                    .doc-preview-readmore { font-size: 12px; }\r\n                    \/* \u2705 Laisser 3px tout autour pour que le liser\u00e9 vert (box-shadow\/outline sur parent) soit visible *\/\r\n                    .doc-preview-container {\r\n                        width: calc(100% - 16px) !important;\r\n                        max-height: 109px !important;\r\n                        margin: 3px !important;\r\n                        margin-top: 23px !important;\r\n                        box-sizing: border-box !important;\r\n                    }\r\n                }\r\n                .doc-preview-FullPathAdFile {\r\n                    display: none;\r\n                }\r\n                \/* \u2705 v1.19.0 : Layout sans image *\/\r\n                .doc-preview-noimage {\r\n                    flex-direction: row;\r\n                    align-items: flex-start;\r\n                    gap: 10px;\r\n                    padding: 8px 10px;\r\n                }\r\n                .doc-preview-icon {\r\n                    flex-shrink: 0;\r\n                    display: flex;\r\n                    align-items: center;\r\n                    justify-content: center;\r\n                    width: 44px;\r\n                    height: 44px;\r\n                    background: #eef2f7;\r\n                    border-radius: 6px;\r\n                    margin-top: 4px;\r\n                }\r\n                .doc-preview-info-full {\r\n                    width: 100%;\r\n                    height: auto;\r\n                    max-height: 130px;\r\n                }\r\n                .doc-preview-noimage .doc-preview-description {\r\n                    font-size: 11px;\r\n                    line-height: 1.35;\r\n                    max-height: 60px;\r\n                    overflow: hidden;\r\n                }\r\n            <\/style>\r\n        `;\r\n    },\r\n    \r\n    finalizeRedactionnelUpload() {\r\n        \/\/ \u2705 v1.19.5 : D\u00e9terminer le format r\u00e9dactionnel correct\r\n        \/\/ Si le format s\u00e9lectionn\u00e9 est \"Interview\", on garde \"Interview\"\r\n        \/\/ Sinon on met \"Communiqu\u00e9\" par d\u00e9faut (au lieu de \"R\u00e9dactionnel\" qui n'est pas un format tarifaire valide)\r\n        var formatSelect = sessionStorage.getItem('FormatSelect') || '';\r\n        var formatTransmis = 'Communiqu\u00e9'; \/\/ Par d\u00e9faut\r\n        \r\n        if (formatSelect.toLowerCase().indexOf('interview') !== -1) {\r\n            formatTransmis = 'Interview';\r\n        } else if (formatSelect.toLowerCase().indexOf('communiq') !== -1) {\r\n            formatTransmis = 'Communiqu\u00e9';\r\n        }\r\n        \r\n        StateManager.set('Commande_Format_Transmis', formatTransmis);\r\n        console.log('\u2705 Format r\u00e9dactionnel d\u00e9termin\u00e9:', formatTransmis, '(FormatSelect:', formatSelect, ')');\r\n        \r\n        if (StateManager.get(\"TarifDirectSelectionne\") === 'Yes') {\r\n            const formatText = jQuery('#FormatDataStep3').text();\r\n            if (formatText !== 'Vid\u00e9o' && formatText !== 'Banni\u00e8re') {\r\n                jQuery('#form-field-RedactionnelSelection')\r\n                    .val(formatText)\r\n                    .css({'color': '#56BE50'});\r\n            }\r\n        }\r\n        \r\n        RedactionnelDepose();\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'upload\r\n *\/\r\nconst UploadManager = {\r\n    isRunning: false,\r\n    \r\n    \/\/ \u2705 Reset manuel espace publicitaire\r\n    resetEspaceManuel: function($droppable) {\r\n        console.log('\ud83d\udd27 Reset manuel espace publicitaire');\r\n        \r\n        var $dropZone = $droppable.find('#drop_file_zone_achat');\r\n        var $uploadContainer = $droppable.find('.HTMLUploadfileConteneur');\r\n        var $container = $droppable.find('.OrdiMobileConteneurClass');\r\n        \r\n        \/\/ 1. Vider la zone de drop et restaurer le HTML par d\u00e9faut\r\n        $dropZone.empty().html(\r\n            '<div id=\"drag_upload_file_achat\">' +\r\n                '<p class=\"UploadIci\" style=\"color: #FB5E2A; font-weight: 600;\">Ici glisser \u2013 d\u00e9poser ou<br>t\u00e9l\u00e9charger une annonce<\/p>' +\r\n            '<\/div>'\r\n        );\r\n        \r\n        \/\/ 2. Afficher les \u00e9l\u00e9ments cach\u00e9s lors de l'upload\r\n        $droppable.find('.UploadIci').show();\r\n        $droppable.find('.EnvoiUlterieurTexte').show();\r\n        $droppable.find('.EnvoiUlterieurContainer').show();\r\n        $droppable.find('.EspPubFormatMainContainer').show();\r\n        $droppable.find('.EspPubFormatListe').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireClass').show();\r\n        $droppable.find('.GlisserDeposerConteneur').show();\r\n        $droppable.find('.OUClass').show();\r\n        $droppable.find('.TexteMobileAnnonce').show();\r\n        $droppable.find('.PositionReference').show();\r\n        $droppable.find('.ClassHdpCdp').show();\r\n        $droppable.find('.ClassRefEsp').show();\r\n        \r\n        \/\/ 3. Cacher les \u00e9l\u00e9ments d'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle').hide();\r\n        $droppable.find('#CroixResetAnnonce').hide();\r\n        $droppable.find('.CroixResetAnnonceContainer').hide();\r\n        $droppable.find('.DeplaceAnnonce').hide();\r\n        $droppable.find('.RefEspacePublicitaire').hide();\r\n        $droppable.find('.AdDroppedTextNotDisplayed').hide();\r\n        \r\n        \/\/ 4. Reset des styles\r\n        $uploadContainer.css({\r\n            'border': 'none',\r\n            'background-color': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': ''\r\n        });\r\n        \r\n        $container.css({\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'top': '',\r\n            'height': ''\r\n        });\r\n        \r\n        \/\/ \u2705 Reset des positionnements desktop appliqu\u00e9s par adjustDesktopLayout\r\n        $droppable.closest('.ToBeHidden').css({'top': '', 'min-height': ''});\r\n        $droppable.parent().css('overflow', '');\r\n        \/\/ \u2705 v2.0.11 : Cleanup event namespace docpreview\r\n        $droppable.off('click.docpreview');\r\n        \r\n        \/\/ 5. Reset des formats s\u00e9lectionn\u00e9s\r\n        $droppable.find('.EspPubFormatContainer').css({\r\n            'background-color': '',\r\n            'border': ''\r\n        });\r\n        \r\n        \/\/ 6. Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ 7. Restaurer .PositionEspacePublicitaireContainer et .ReserverContainer\r\n        $droppable.find('.PositionEspacePublicitaireContainer').show();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        console.log('\u2705 Reset manuel termin\u00e9');\r\n    },\r\n    \r\n    async handleFileUpload(fileObj, $dropZone) {\r\n        console.log('fileObj:', fileObj);\r\n        \r\n        \/\/ \u2705 v2.4.6 : Contr\u00f4les d'extension EN PREMIER \u2014 avant tout affichage\r\n        const extension = FileManager.getExtension(fileObj.name);\r\n        StateManager.set('FileExtension', extension);\r\n        console.log('FileExtension:', extension);\r\n        \r\n        \/\/ \u2705 v2.6 : jpg\/jpeg accept\u00e9s sur desktop et mobile\r\n        \r\n        if (!FileManager.isAllowedExtension(extension)) {\r\n            UIManager.showFormatError($dropZone);\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.5 : Afficher le message d'attente seulement si le format est valide\r\n        var _waitMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.html('<div class=\"ad-loading-msg\" style=\"color:#00ff19; background:white; padding:12px 20px; border-radius:6px; font-weight:700; text-align:center; font-size:18px; line-height:1.4;\">' + _waitMsg + '<\/div>');\r\n        \r\n        this.prepareUIForUpload($dropZone);\r\n        \r\n        const formData = new FormData();\r\n        formData.append('file', fileObj);\r\n        formData.append('action', 'upload_annonce_file_v3');\r\n        \r\n        UIManager.showUploadProgress($dropZone);\r\n        \r\n        try {\r\n            const response = await this.sendUploadRequest(formData);\r\n            await this.handleUploadResponse(response, fileObj, $dropZone, extension);\r\n        } catch (error) {\r\n            console.error('Upload error:', error);\r\n        }\r\n    },\r\n    \r\n    prepareUIForUpload($dropZone) {\r\n        if (!UIManager.isMobile()) {\r\n            jQuery('.ChoisirEspacePublicitaireClass').show();\r\n            jQuery('.ChoisirEspacePublicitaire2ndLigne').show();\r\n            jQuery('.GlisserDeposerConteneur').show();\r\n            jQuery('.OUClass').show();\r\n            \/\/ \u2705 Cibler uniquement le droppable courant \u2014 ne pas r\u00e9afficher sur les espaces d\u00e9j\u00e0 upload\u00e9s\r\n            $dropZone.closest('.droppable').find('.UploadIci').show();\r\n        }\r\n        \r\n        if (StateManager.get(\"PopUpChoice\") === 'Yes') {\r\n            \/\/ \u2705 Ne masquer DeplaceAnnonce QUE sur Ele0A \u2014 pas sur Ele1A qui a deja une annonce chargee\r\n            $dropZone.closest('.OrdiMobileConteneurClass').find('.DeplaceAnnonce').each(function() {\r\n                var _d = jQuery(this).closest('.droppable')[0];\r\n                if (_d && _d.getAttribute('data-via-ad-loaded') === 'true') { return; }\r\n                jQuery(this).hide();\r\n            });\r\n            $('.AnnonceDragIcone').show().find('img').attr('alt', '');\r\n        } else {\r\n            $('.AnnonceDragIcone').hide();\r\n        }\r\n        \r\n        if (StateManager.get(\"Commande_Page\") === 'Home Page') {\r\n            jQuery('#HPTarifConteneur').css({'background-color': '#B5FFB1'});\r\n        }\r\n        \r\n        jQuery('.ChoisirEspacePublicitaireClass').css({'color': '#ffffff'});\r\n        jQuery('.InterfaceTitreDore').not('#PageWebTitreDore')\r\n            .html(\"Merci de choisir les \u00e9l\u00e9ments de votre campagne publicitaire\");\r\n        jQuery('#ProcessCommande').show();\r\n    },\r\n    \r\n    sendUploadRequest(formData) {\r\n        \/\/ \u2705 v2.6 : dataType 'text' pour eviter parsererror si texte parasite apres le JSON\r\n        return jQuery.ajax({\r\n            url: CONFIG.ajaxUrl,\r\n            type: 'POST',\r\n            data: formData,\r\n            cache: false,\r\n            contentType: false,\r\n            processData: false,\r\n            dataType: 'text'\r\n        }).then(function(text) {\r\n            \/\/ Extraire le JSON meme si du texte parasite suit\r\n            var _json = null;\r\n            try {\r\n                var _match = text.match(\/(\\{[\\s\\S]*?\\})(?:[^{]|$)\/);\r\n                _json = JSON.parse(_match ? _match[1] : text);\r\n            } catch(_e) {\r\n                return jQuery.Deferred().reject({ responseText: text }).promise();\r\n            }\r\n            \/\/ Normaliser le format vers {success, data} attendu par handleUploadResponse\r\n            if (_json.status === 'success') {\r\n                var _fp = _json.file_path || '';\r\n                var _baseUrl = CONFIG.ajaxUrl.replace('\/wp-admin\/admin-ajax.php', '\/wp-content\/');\r\n                return {\r\n                    success: true,\r\n                    data: {\r\n                        file_url:  _baseUrl + _fp,\r\n                        file_name: _fp.replace(\/^.*\\\/\/, ''),\r\n                        file_path: _fp\r\n                    }\r\n                };\r\n            }\r\n            \/\/ Format WordPress standard {success, data} - retourner tel quel\r\n            return _json;\r\n        });\r\n    },\r\n    \r\n    async handleUploadResponse(response, fileObj, $dropZone, extension) {\r\n        console.log('\u2705 R\u00e9ponse re\u00e7ue');\r\n        \r\n        if (response.responseJSON) {\r\n            response = response.responseJSON;\r\n        }\r\n        \r\n        console.log('\u2705 Response pars\u00e9e:', response);\r\n        \r\n        if (!response.success || !response.data) {\r\n            \/\/ \u2705 v2.1.2 : Si c'est une restauration (_isAdRestoration = 'Yes'),\r\n            \/\/ le fichier existe d\u00e9j\u00e0 sur le serveur \u2192 afficher l'image depuis le fileObj local\r\n            if (StateManager.get('_isAdRestoration') === 'Yes' && fileObj) {\r\n                console.log('\ud83d\udd04 Restauration: upload \u00e9chou\u00e9 (fichier existant) \u2192 rendu local');\r\n                \r\n                FileManager.createObjectUrl(fileObj);\r\n                StateManager.set('FileReceived', 'Yes');\r\n                \r\n                \/\/ \u2705 v2.1.2 : Restaurer l'\u00e9tat EnvoiUlterieur depuis le sessionStorage parent\r\n                var _restoredEnvoi = sessionStorage.getItem('_restoredEnvoiUlterieur');\r\n                if (_restoredEnvoi === 'true') {\r\n                    StateManager.set('EnvoiUlterieur', 'true');\r\n                    StateManager.set('FileReceived', 'No');\r\n                    StateManager.set('FullPathAdFile', '');\r\n                    console.log('\ud83d\udce4 Restauration EnvoiUlterieur = true');\r\n                }\r\n                \r\n                var _objUrl = StateManager.get('objectUrl');\r\n                var _fileType = FileManager.getFileType(extension);\r\n                \r\n                StateManager.set('FormatReconnu', 'No');\r\n                \r\n                switch (_fileType) {\r\n                    case 'video':\r\n                        PreviewRenderer.renderVideo(_objUrl, fileObj.name, $dropZone);\r\n                        StateManager.set('FormatReconnu', 'Yes');\r\n                        break;\r\n                    case 'image':\r\n                        PreviewRenderer.renderImage(_objUrl, $dropZone);\r\n                        StateManager.set('FormatReconnu', 'Yes');\r\n                        break;\r\n                    case 'document':\r\n                        \/\/ \u2705 v2.1.2 : Documents Word\/PDF aussi en restauration\r\n                        await this.handleDocumentUpload(extension, fileObj, $dropZone);\r\n                        break;\r\n                }\r\n                \r\n                UIManager.updateAfterSuccessfulUpload($dropZone);\r\n                \r\n                if (StateManager.get('FormatReconnu') === 'Yes') {\r\n                    this.finalizeUpload($dropZone);\r\n                    $('#MsgSelectEspace').hide();\r\n                }\r\n                \r\n                FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n                console.log('\u2705 Restauration visuelle termin\u00e9e (upload bypass)');\r\n                StateManager.set('_isAdRestoration', 'No');\r\n            }\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 SAUVEGARDER les infos de d\u00e9placement AVANT updateStateAfterUpload\r\n        const isMoved = StateManager.get('FirstUploadFileorMoved') === 'Moved';\r\n        const dragstartRankId = StateManager.get('dragstart_Rank_Emplacement_Page_Web');\r\n        const currentRankId = StateManager.get('Rank_Emplacement_Page_Web');\r\n        const shouldResetOldSpace = isMoved && dragstartRankId && dragstartRankId !== currentRankId;\r\n        \r\n        console.log('\ud83d\udd0d D\u00e9placement?', { isMoved, dragstartRankId, currentRankId, shouldResetOldSpace });\r\n        \r\n        this.updateStateAfterUploadWithoutReset(response, fileObj);\r\n        \r\n        const fileType = FileManager.getFileType(extension);\r\n        \r\n        StateManager.set('FormatReconnu', 'No');\r\n        \r\n        \/\/ \u2705 v1.19.2 : Message d'attente IMM\u00c9DIAT avant le rendu de l'annonce\r\n        var _waitMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.html('<div class=\"ad-loading-msg\" style=\"color:#00ff19; background:white; padding:12px 20px; border-radius:6px; font-weight:700; text-align:center; font-size:18px; line-height:1.4;\">' + _waitMsg + '<\/div>');\r\n        \r\n        switch (fileType) {\r\n            case 'video':\r\n                PreviewRenderer.renderVideo(StateManager.get('objectUrl'), fileObj.name, $dropZone);\r\n                StateManager.set('FormatReconnu', 'Yes');\r\n                break;\r\n                \r\n            case 'image':\r\n                PreviewRenderer.renderImage(StateManager.get('objectUrl'), $dropZone);\r\n                StateManager.set('FormatReconnu', 'Yes');\r\n                break;\r\n                \r\n            case 'document':\r\n                await this.handleDocumentUpload(extension, fileObj, $dropZone);\r\n                break;\r\n        }\r\n        \r\n        UIManager.updateAfterSuccessfulUpload($dropZone);\r\n        \r\n        if (StateManager.get('FormatReconnu') === 'Yes') {\r\n            this.finalizeUpload($dropZone);\r\n            $('#MsgSelectEspace').hide();\r\n        }\r\n        \r\n        \/\/ \u2705 RESET L'ANCIEN ESPACE ICI - APR\u00c8S avoir affich\u00e9 la nouvelle image\r\n        \/\/ \u2705 v2.4.5 : Toujours initialiser \u00e0 false avant le bloc (\u00e9vite la valeur r\u00e9siduelle)\r\n        var _sourceWasReserved = false;\r\n        StateManager.set('_sourceWasReserved', 'No');\r\n        \r\n        if (shouldResetOldSpace) {\r\n            console.log('\ud83d\udd04 Reset ancien espace:', dragstartRankId);\r\n            \r\n            var $oldDroppable = $('#' + dragstartRankId);\r\n            \r\n            if ($oldDroppable.length) {\r\n                var $container = $oldDroppable.find('.OrdiMobileConteneurClass').first();\r\n                \r\n                \/\/ \u2705 v2.4.5 : Utiliser l'\u00e9tat captur\u00e9 au dragstart (fiable vs re-check async)\r\n                if ($container.length) {\r\n                    _sourceWasReserved = StateManager.get('dragstart_ReserverChecked') === 'Yes';\r\n                    console.log('[d\u00e9placement] ReserverChecked au dragstart:', _sourceWasReserved, '| rank:', dragstartRankId);\r\n                    StateManager.set('_sourceWasReserved', _sourceWasReserved ? 'Yes' : 'No');\r\n                    RestoreadSpaceTemplateLocal($container[0]);\r\n                }\r\n            }\r\n        }\r\n        StateManager.set(\"EnvoiUlterieur\", 'false');\r\n        \r\n        \/\/ \u2705 v1.19.1 : Positionner l'espace \u00e0 10px du haut du viewport apr\u00e8s upload\r\n        setTimeout(function() {\r\n            var el = $dropZone.closest('.droppable').find('.HTMLUploadfileConteneur')[0]\r\n                     || $dropZone.closest('.droppable')[0];\r\n            if (el) {\r\n                ScrollHelper.scrollElementTo(el, 10);\r\n            }\r\n        }, 400);\r\n        \r\n        \/\/ \u2705 NE PLUS envoyer automatiquement - c'est la checkbox \"R\u00e9server\" qui d\u00e9clenche\r\n        \/\/ On met \u00e0 jour l'\u00e9tat de la checkbox pour qu'elle devienne activable\r\n        FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n        \r\n        \/\/ \u2705 v2.4.5 : Si l'espace source \u00e9tait r\u00e9serv\u00e9, cocher la checkbox de l'espace cible\r\n        if (StateManager.get('_sourceWasReserved') === 'Yes') {\r\n            var $targetCb = $dropZone.closest('.droppable').find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n            if ($targetCb.length && !$targetCb.prop('checked')) {\r\n                $targetCb.prop('checked', true).trigger('change');\r\n                console.log('\u2705 [d\u00e9placement] Checkbox R\u00e9server coch\u00e9e sur espace cible');\r\n            }\r\n            StateManager.set('_sourceWasReserved', 'No');\r\n        }\r\n        \r\n        console.log('\ud83d\udccb Upload termin\u00e9 - en attente de validation via checkbox \"R\u00e9server\"');\r\n    },\r\n    \r\n    updateStateAfterUploadWithoutReset(response, fileObj) {\r\n        StateManager.setMultiple({\r\n            \"PageWhithADType\": StateManager.get('SelectedPageType'),\r\n            \"PageWhithADSecteur\": StateManager.get('SelectedPageSecteur')\r\n        });\r\n        \r\n        $('#BackPageWebWithADCroix').hide();\r\n        jQuery('#ApercuMobile').empty().css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center'\r\n        });\r\n        \r\n        const firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n        \r\n        if (firstUploadOrMoved === 'FirstUpload') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": response.data.file_url,\r\n                \"fileObj\": fileObj,\r\n                \"Upload_File_Name\": fileObj.name\r\n            });\r\n            \r\n            FileManager.createObjectUrl(fileObj);\r\n            \r\n            console.log('\ud83d\udcc1 Fichier upload\u00e9:', {\r\n                fullUrl: response.data.file_url,\r\n                fileName: response.data.file_name,\r\n                filePath: response.data.file_path\r\n            });\r\n        }\r\n    },\r\n    \r\n    updateStateAfterUpload(response, fileObj) {\r\n        StateManager.setMultiple({\r\n            \"PageWhithADType\": StateManager.get('SelectedPageType'),\r\n            \"PageWhithADSecteur\": StateManager.get('SelectedPageSecteur')\r\n        });\r\n        \r\n        $('#BackPageWebWithADCroix').hide();\r\n        jQuery('#ApercuMobile').empty().css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center'\r\n        });\r\n        \r\n        const firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n        console.log('\ud83d\udd0d FirstUploadFileorMoved:', firstUploadOrMoved);\r\n        \r\n        if (firstUploadOrMoved === 'FirstUpload') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": response.data.file_url,\r\n                \"fileObj\": fileObj,\r\n                \"Upload_File_Name\": fileObj.name\r\n            });\r\n            \r\n            FileManager.createObjectUrl(fileObj);\r\n            \r\n            console.log('\ud83d\udcc1 Fichier upload\u00e9:', {\r\n                fullUrl: response.data.file_url,\r\n                fileName: response.data.file_name,\r\n                filePath: response.data.file_path\r\n            });\r\n        } else if (firstUploadOrMoved === 'Moved') {\r\n            const dragstartRankId = StateManager.get('dragstart_Rank_Emplacement_Page_Web');\r\n            const currentRankId = StateManager.get('Rank_Emplacement_Page_Web');\r\n            \r\n            console.log('\ud83d\udd04 D\u00c9PLACEMENT D\u00c9TECT\u00c9');\r\n            console.log('   Ancien espace (dragstart):', dragstartRankId);\r\n            console.log('   Nouvel espace (current):', currentRankId);\r\n            \r\n            if (dragstartRankId && dragstartRankId !== currentRankId) {\r\n                const $oldDroppable = $('#' + dragstartRankId);\r\n                \r\n                console.log('   $oldDroppable trouv\u00e9:', $oldDroppable.length > 0);\r\n                \r\n                if ($oldDroppable.length) {\r\n                    const $container = $oldDroppable.find('.OrdiMobileConteneurClass');\r\n                    \r\n                    console.log('   $container trouv\u00e9:', $container.length > 0);\r\n                    \r\n                    if ($container.length) {\r\n                        console.log('\ud83d\udd27 Appel RestoreadSpaceTemplate sur:', $container[0]);\r\n                        \r\n                        if (typeof window.RestoreadSpaceTemplate === 'function') {\r\n                            window.RestoreadSpaceTemplate($container[0]);\r\n                            console.log('\u2705 RestoreadSpaceTemplate ex\u00e9cut\u00e9');\r\n                        }\r\n                    } else {\r\n                        console.warn('\u26a0\ufe0f .OrdiMobileConteneurClass non trouv\u00e9 dans', dragstartRankId);\r\n                    }\r\n                }\r\n            } else {\r\n                console.log('\u23ed\ufe0f M\u00eame espace ou dragstartRankId invalide, pas de reset');\r\n            }\r\n        }\r\n    },\r\n        \r\n    async handleDocumentUpload(extension, fileObj, $dropZone) {\r\n        StateManager.set('FormatReconnu', 'Yes');\r\n        \r\n        \/\/ \u2705 Cacher le File r\u00e9dactionnel pour r\u00e9utilisation lors des d\u00e9placements (\u00e9vite CORS)\r\n        window._lastRedactionnelFile = fileObj;\r\n        \r\n        if (extension === 'doc' || extension === 'docx') {\r\n            await new Promise(resolve => window.VIALibraries.loadMammoth(resolve));\r\n            await PreviewRenderer.renderWord(fileObj, $dropZone);\r\n        } else if (extension === 'ppt' || extension === 'pptx') {\r\n            this.renderPowerPoint($dropZone);\r\n            PreviewRenderer.finalizeRedactionnelUpload();\r\n        } else if (extension === 'pdf') {\r\n            await new Promise(resolve => window.VIALibraries.loadPdfJs(resolve));\r\n            await PDFHandler.renderPDF(fileObj, $dropZone);\r\n            PreviewRenderer.finalizeRedactionnelUpload();\r\n        }\r\n    },\r\n    \r\n    renderPowerPoint($dropZone) {\r\n        const img = jQuery('<img \/>', {\r\n            src: '\/wp-content\/uploads\/2024\/06\/microsoft-powerpoint.png',\r\n            css: {\r\n                'width': 'auto',\r\n                'height': 'auto',\r\n                'margin-bottom': '20px',\r\n                'max-width': '150px',\r\n                'max-height': '160px'\r\n            }\r\n        });\r\n        $dropZone.empty().append(img.clone());\r\n        jQuery('#ApercuMobile').append(img);\r\n    },\r\n    \r\n    finalizeUpload($dropZone) {\r\n        \/\/ \u2705 Reset sendDataToParentFlag : nouvel upload = pas encore r\u00e9serv\u00e9\r\n        StateManager.set('sendDataToParentFlag', 'No');\r\n        \r\n        StateManager.setMultiple({\r\n            \"PageAnnonceSelection\": 'Yes',\r\n            \"FormatReconnu\": 'Yes'\r\n        });\r\n        \r\n        jQuery('#MsgChoixPageWeb, #MsgInsererAnnonceConteneur').hide();\r\n        \r\n        if (StateManager.get(\"Commande_Format\") === 'R\u00e9dactionnel') {\r\n            StateManager.set('Commande_Format', '\u00e0 choisir');\r\n            RedactionnelDepose();\r\n        }\r\n        \r\n        if (StateManager.get(\"Commande_Page\") === ' ') {\r\n            jQuery('#HPTarifConteneur').css({'background-color': '#BCFFAD'});\r\n            jQuery('#EmplacementDataStep3').html(\"Home Page\");\r\n            StateManager.setMultiple({\r\n                \"Commande_Page\": 'Home Page',\r\n                \"PageAnnonceSelection\": 'Yes'\r\n            });\r\n        }\r\n        \r\n        $('#PageWeb').css('zoom', '70%');\r\n        $('#PageWebTitreDore').css({'font-size': '14px'});\r\n        \r\n        if (!UIManager.isMobile()) {\r\n            $('#PageWebTitreDore').css({'color': '#213864'});\r\n        }\r\n        \r\n        StateManager.set(\"Page_Web_with_AD_URL\", StateManager.get(\"Page_Web_URL\"));\r\n        \r\n        UIManager.finalizeAdDisplay($dropZone);\r\n        \r\n        \/\/ \u2705 Notifier le parent de l'annonce d\u00e9pos\u00e9e non r\u00e9serv\u00e9e \u2014 pour restauration au retour sur la page\r\n        var _fileRcv = StateManager.get('FileReceived');\r\n        var _isRestoring = StateManager.get('_isAdRestoration') === 'Yes';\r\n        console.log('\ud83d\udfe1 [finalizeUpload] FileReceived:', _fileRcv, '| _isAdRestoration:', _isRestoring);\r\n        if (_fileRcv === 'Yes' && !_isRestoring) {\r\n            var _pendingRank = StateManager.get('Rank_Emplacement_Page_Web') || $dropZone.closest('.droppable').attr('id') || '';\r\n            console.log('\ud83d\udfe1 [finalizeUpload] pendingRank:', _pendingRank, '| FullPathAdFile:', StateManager.get('FullPathAdFile'));\r\n            if (_pendingRank) {\r\n                console.log('\ud83d\udce4 [finalizeUpload] annonceDeposeeSansReservation \u2192 parent rank:', _pendingRank);\r\n                \/\/ \u2705 D\u00e9terminer le vrai format commercial selon le type de fichier d\u00e9pos\u00e9 + format s\u00e9lectionn\u00e9\r\n                var _formatSelect = sessionStorage.getItem('FormatSelect') || StateManager.get('Commande_Format_Transmis') || '';\r\n                var _uploadedExt = (StateManager.get('Upload_File_Name') || '').split('.').pop().toLowerCase();\r\n                var _fileKind = CONFIG.allowedExtensions.video.indexOf(_uploadedExt) !== -1 ? 'video'\r\n                              : CONFIG.allowedExtensions.image.indexOf(_uploadedExt) !== -1 ? 'image'\r\n                              : CONFIG.allowedExtensions.document.indexOf(_uploadedExt) !== -1 ? 'document'\r\n                              : '';\r\n                var _formatPending;\r\n                if (_fileKind === 'video') {\r\n                    \/\/ Vid\u00e9o \u2192 toujours Vid\u00e9o\r\n                    _formatPending = 'Vid\u00e9o';\r\n                } else if (_fileKind === 'image') {\r\n                    \/\/ Image \u2192 Banni\u00e8re ou Parrainage si s\u00e9lectionn\u00e9, sinon Banni\u00e8re par d\u00e9faut\r\n                    var _imgFormats = ['Banni\u00e8re', 'Banniere', 'Parrainage'];\r\n                    _formatPending = (_imgFormats.indexOf(_formatSelect) !== -1) ? _formatSelect : 'Banni\u00e8re';\r\n                } else if (_fileKind === 'document') {\r\n                    \/\/ Document \u2192 Communiqu\u00e9 ou Interview si s\u00e9lectionn\u00e9, sinon Communiqu\u00e9 par d\u00e9faut\r\n                    var _docFormats = ['Communiqu\u00e9', 'Communique', 'Interview'];\r\n                    _formatPending = (_docFormats.indexOf(_formatSelect) !== -1) ? _formatSelect : 'Communiqu\u00e9';\r\n                } else {\r\n                    \/\/ Fallback\r\n                    _formatPending = _formatSelect || StateManager.get('Commande_Format_Transmis') || '';\r\n                }\r\n                \/\/ \u2705 v2.4.9 : Si le format d\u00e9duit diff\u00e8re du format s\u00e9lectionn\u00e9 \u2192 mettre \u00e0 jour vignette + sessionStorage\r\n                if (_formatPending && _formatPending !== _formatSelect) {\r\n                    StateManager.set('FormatSelect', _formatPending);\r\n                    StateManager.set('Commande_Format_Transmis', _formatPending);\r\n                    StateManager.set('Formatchoisi', 'Yes');\r\n                    \/\/ Mettre \u00e0 jour visuellement la vignette dans le droppable courant\r\n                    var _fmtNorm = _formatPending.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    var $_drp = $dropZone.closest('.droppable');\r\n                    $_drp.find('.EspPubFormatContainer').each(function() {\r\n                        var _cls = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                        if (_cls.includes(_fmtNorm)) {\r\n                            jQuery(this).css({'background-color': '#ffffff'});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        } else if (!jQuery(this).hasClass('FormatIdPopUp')) {\r\n                            jQuery(this).css({'background-color': ''});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': ''});\r\n                        }\r\n                    });\r\n                    \/\/ Mettre \u00e0 jour aussi le bandeau parent via postMessage\r\n                    MessageManager.sendToParent('formatChangedInIframe', { formatSelect: _formatPending, rank: _pendingRank });\r\n                    console.log('\ud83d\udd04 [finalizeUpload] Format corrig\u00e9:', _formatSelect, '\u2192', _formatPending);\r\n                }\r\n                var _firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n                var _isMoved = _firstUploadOrMoved === 'Moved';\r\n                var _oldRankMoved = _isMoved ? (StateManager.get('dragstart_Rank_Emplacement_Page_Web') || '') : '';\r\n                MessageManager.sendToParent('annonceDeposeeSansReservation', {\r\n                    Rank_Emplacement_Page_Web: _pendingRank,\r\n                    FullPathAdFile: StateManager.get('FullPathAdFile') || '',\r\n                    Upload_File_Name: StateManager.get('Upload_File_Name') || '',\r\n                    LoadedPageUrl: window.location.href,\r\n                    FileReceived: 'Yes',\r\n                    \/\/ \u2705 Lire EnvoiUlterieur depuis la checkbox du droppable courant (pas le StateManager global)\r\n                    \/\/ StateManager.get('EnvoiUlterieur') est global \u2192 peut valoir 'true' si un autre espace a sa checkbox coch\u00e9e\r\n                    EnvoiUlterieur: ($dropZone.closest('.droppable').find('input[name*=\"EnvoiUlterieur\"]').prop('checked') ? 'true' : 'false'),\r\n                    Commande_Format_Transmis: _formatPending,\r\n                    codeSite: StateManager.get('codeSite') || '',\r\n                    codePage: StateManager.get('codePage') || '',\r\n                    Commande_Emplacement_Page_Web: StateManager.buildEmplacementReference(_pendingRank),\r\n                    isMoved: _isMoved,\r\n                    oldRank: _oldRankMoved\r\n                });\r\n            }\r\n        }\r\n    },\r\n    \r\n    activateSendDataToParent($dropZone) {\r\n        if (StateManager.get(\"sendDataToParentFlag\") !== 'Yes') {\r\n            return;\r\n        }\r\n        \r\n        if (StateManager.get(\"FirstUploadFileorMoved\") === 'Moved') {\r\n            const dragstartRef = StateManager.buildEmplacementReference(\r\n                StateManager.get(\"dragstart_Rank_Emplacement_Page_Web\")\r\n            );\r\n            StateManager.set('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n        }\r\n        \r\n        console.log('Esp Pub Ref FirstUploadFileorMoved:', StateManager.get(\"FirstUploadFileorMoved\"));\r\n        console.log('Esp Pub dragstart_Commande:', StateManager.get(\"dragstart_Commande_Emplacement_Page_Web\"));\r\n        \r\n        if (StateManager.get(\"PageAjoutModifAnnonce\") === 'Yes') {\r\n            this.handlePageModification($dropZone);\r\n        } else {\r\n            this.handleNormalUpload();\r\n        }\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        setTimeout(() => {\r\n            StateManager.set(\"AddNewRefInVosCampagnes\", 'Yes');\r\n        }, 4000);\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            StateManager.set('Commande_Format_Transmis', '');\r\n        }\r\n    },\r\n    \r\n    handlePageModification($dropZone) {\r\n        $('#CroixResetAnnonce, .DeplaceAnnonce').hide();\r\n        $('.PageAjoutModifAnnonceCroixResetAnnonce').show();\r\n        \r\n        const emplacementRef = $dropZone.closest('.CampagnesTemplateClass')\r\n            .find('.ReferenceEspace').text();\r\n        \r\n        console.log('Commande_Emplacement_Page_Web:', emplacementRef);\r\n        \r\n        jQuery.ajax({\r\n            type: \"POST\",\r\n            url: CONFIG.ajaxUrl,\r\n            data: {\r\n                action: 'via_update_fichier_annonce',\r\n                commande_ref_url: StateManager.get(\"commande_ref_url\"),\r\n                emplacement_page_web: emplacementRef,\r\n                chemin_fichier: StateManager.get(\"FullPathAdFile\")\r\n            },\r\n            xhrFields: { withCredentials: true },\r\n            success: (response) => {\r\n                if (response.success) {\r\n                    console.log('\u2705 Fichier annonce mis \u00e0 jour:', response.data.message);\r\n                    location.reload();\r\n                } else {\r\n                    console.error('\u274c Erreur:', response.data.message);\r\n                }\r\n            },\r\n            error: (xhr, status, error) => {\r\n                console.error('\u274c Erreur AJAX:', error);\r\n            }\r\n        });\r\n    },\r\n    \r\n    handleNormalUpload() {\r\n        if (StateManager.get(\"EnvoiUlterieur\") === 'true') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": '',\r\n                \"Upload_File_Name\": ''\r\n            });\r\n        }\r\n        \r\n        StateManager.set(\"LoadedPageUrl\", window.location.href);\r\n        \r\n        console.log('EnvoiUlterieur:', StateManager.get(\"EnvoiUlterieur\"));\r\n        console.log('LoadedPageUrl:', StateManager.get(\"LoadedPageUrl\"));\r\n        console.log('FileReceived:', StateManager.get(\"FileReceived\"));\r\n        \r\n        const data = MessageManager.prepareUploadData();\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            MessageManager.sendDataToParent(data);\r\n        } else {\r\n            const formatChoisi = StateManager.get(\"Formatchoisi\") === 'Yes';\r\n            const fichierDepose = StateManager.get(\"FileReceived\") === 'Yes';\r\n            const envoiDiffere = StateManager.get(\"EnvoiUlterieur\") === 'true';\r\n            \r\n            console.log('\ud83d\udd0d handleNormalUpload - Conditions:', { formatChoisi, fichierDepose, envoiDiffere });\r\n            \r\n            if (formatChoisi && (fichierDepose || envoiDiffere)) {\r\n                if (typeof window.handleEspacePubData === 'function') {\r\n                    window.handleEspacePubData(data);\r\n                } else {\r\n                    console.warn('\u26a0\ufe0f handleEspacePubData non disponible, fallback direct');\r\n                    if (typeof window.executeWithProcessLoaded === 'function') {\r\n                        window.executeWithProcessLoaded(function() {\r\n                            jQuery('#PopupProcessCommandeContainer').show();\r\n                        });\r\n                    } else {\r\n                        jQuery('#PopupProcessCommandeContainer').show();\r\n                    }\r\n                }\r\n            } else if (formatChoisi) {\r\n                console.log('\ud83d\udcdd Mise \u00e0 jour format uniquement');\r\n                \r\n                const borderStyle = {'box-shadow': 'inset 0 0 0 2px #00FF19', 'box-sizing': 'border-box'};  \/\/ \u2705 v2.4.5\r\n                \r\n                jQuery(\".FormatClassique, .FormatPopup\").css({'border': 'none'});\r\n                \r\n                jQuery('.FormatClassique, .FormatPopup').each(function() {\r\n                    \/\/ \u2705 v2.1.1 : NFD normalize both sides\r\n                    var _cn = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    var _cf = (data.Commande_Format_Transmis || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    if (_cn.includes(_cf) && _cf) {\r\n                        jQuery(this).css(borderStyle);\r\n                    }\r\n                });\r\n            }\r\n        }\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        setTimeout(() => {\r\n            StateManager.set(\"AddNewRefInVosCampagnes\", 'Yes');\r\n        }, 4000);\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            StateManager.set('Commande_Format_Transmis', '');\r\n        }\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des fichiers PDF (s\u00e9par\u00e9 pour \u00e9viter la complexit\u00e9)\r\n *\/\r\nconst PDFHandler = {\r\n    pdfData: null,\r\n    pdfDataForViewer: null,\r\n    \r\n    async renderPDF(fileObj, $dropZone) {\r\n        return new Promise((resolve, reject) => {\r\n            const reader = new FileReader();\r\n            \r\n            reader.onload = async (e) => {\r\n                try {\r\n                    const arrayBuffer = e.target.result;\r\n                    this.pdfData = new Uint8Array(arrayBuffer);\r\n                    this.pdfDataForViewer = arrayBuffer;\r\n                    \r\n                    console.log(\"Initial PDF load, size:\", this.pdfData.byteLength);\r\n                    \r\n                    const pdfjsLib = window['pdfjs-dist\/build\/pdf'];\r\n                    pdfjsLib.GlobalWorkerOptions.workerSrc = \r\n                        '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n                    \r\n                    const pdf = await pdfjsLib.getDocument({ data: new Uint8Array(this.pdfData) }).promise;\r\n                    const page = await pdf.getPage(1);\r\n                    \r\n                    const { titleText, pageText } = await this.extractTextFromPage(page);\r\n                    const imageData = await this.extractImageFromPage(page, pdfjsLib);\r\n                    \r\n                    if (imageData) {\r\n                        PreviewRenderer.renderDocumentPreview(\r\n                            $dropZone,\r\n                            imageData.dataUrl,\r\n                            titleText,\r\n                            pageText\r\n                        );\r\n                    } else {\r\n                        \/\/ \u2705 v1.19.0 : Accepter les PDF sans image\r\n                        PreviewRenderer.renderDocumentPreview(\r\n                            $dropZone,\r\n                            null,\r\n                            titleText,\r\n                            pageText\r\n                        );\r\n                        console.log('\u2139\ufe0f PDF sans image \u2014 aper\u00e7u texte seul');\r\n                    }\r\n                    \r\n                    this.attachPDFPreviewHandler($dropZone, titleText);\r\n                    resolve();\r\n                } catch (error) {\r\n                    console.error('Error extracting from PDF:', error);\r\n                    \/\/ \u2705 v1.19.0 : Message d'erreur en fran\u00e7ais\r\n                    $dropZone.html(`\r\n                        <div style=\"padding: 15px; background-color: #f8f8f8; border-radius: 4px; text-align: center;\">\r\n                            <p style=\"color: #FB5E2A; font-weight: 600; font-family: Roboto, Arial, sans-serif; font-size: 12px;\">\r\n                                Erreur lors de la lecture du document\r\n                            <\/p>\r\n                        <\/div>\r\n                    `);\r\n                    reject(error);\r\n                }\r\n            };\r\n            \r\n            reader.readAsArrayBuffer(fileObj);\r\n        });\r\n    },\r\n    \r\n    async extractTextFromPage(page) {\r\n        const textContent = await page.getTextContent();\r\n        \r\n        let text = '';\r\n        let lastX = -1;\r\n        let lastY = -1;\r\n        \r\n        for (const item of textContent.items) {\r\n            if (lastY !== -1 && (Math.abs(lastY - item.transform[5]) > 5)) {\r\n                text += '\\n';\r\n            } else if (lastX !== -1 && (item.transform[4] - lastX > 10)) {\r\n                text += ' ';\r\n            }\r\n            \r\n            text += item.str;\r\n            \r\n            lastX = item.transform[4] + (item.width || 0);\r\n            lastY = item.transform[5];\r\n        }\r\n        \r\n        text = text\r\n            .replace(\/(\\w) (\\w)\/g, (match, p1, p2) => {\r\n                if (\/[\u00e9\u00e8\u00ea\u00eb\u00e0\u00e2\u00e4\u00f4\u00f6\u00fb\u00fc\u00ef\u00ee\u00e7]\/i.test(p2)) {\r\n                    return p1 + p2;\r\n                }\r\n                return match;\r\n            })\r\n            .replace(\/ ([.,;:!?])\/g, '$1');\r\n        \r\n        const normalizedText = PreviewRenderer.normalizeText(text);\r\n        const titleText = PreviewRenderer.findDocumentTitle(normalizedText);\r\n        \r\n        return { titleText, pageText: text };\r\n    },\r\n    \r\n    async extractImageFromPage(page, pdfjsLib) {\r\n        const opList = await page.getOperatorList();\r\n        const imageInfo = [];\r\n        let currentTransform = null;\r\n        \r\n        for (let i = 0; i < opList.fnArray.length; i++) {\r\n            const operator = opList.fnArray[i];\r\n            const args = opList.argsArray[i];\r\n            \r\n            if (operator === pdfjsLib.OPS.transform) {\r\n                currentTransform = args;\r\n            } else if (operator === pdfjsLib.OPS.paintImageXObject) {\r\n                const imageName = args[0];\r\n                \r\n                if (!imageInfo.some(info => info.name === imageName)) {\r\n                    const position = currentTransform ? {\r\n                        x: currentTransform[4] || 0,\r\n                        y: currentTransform[5] || 0\r\n                    } : { x: 0, y: 0 };\r\n                    \r\n                    imageInfo.push({ name: imageName, position: position });\r\n                }\r\n            }\r\n        }\r\n        \r\n        if (imageInfo.length === 0) {\r\n            return null;\r\n        }\r\n        \r\n        imageInfo.sort((a, b) => b.position.y - a.position.y);\r\n        \r\n        const targetImageName = imageInfo[0].name;\r\n        const imageObj = page.objs.get(targetImageName);\r\n        \r\n        if (!imageObj) {\r\n            const img = await page.objs.get(targetImageName, true);\r\n            return this.processImageObject(img);\r\n        }\r\n        \r\n        return this.processImageObject(imageObj);\r\n    },\r\n    \r\n    processImageObject(imageObj) {\r\n        if (!imageObj) {\r\n            throw new Error('Image object is null');\r\n        }\r\n        \r\n        if (imageObj.bitmap instanceof ImageBitmap) {\r\n            const width = imageObj.bitmap.width || imageObj.width || imageObj.w;\r\n            const height = imageObj.bitmap.height || imageObj.height || imageObj.h;\r\n            \r\n            const canvas = document.createElement('canvas');\r\n            canvas.width = width;\r\n            canvas.height = height;\r\n            const ctx = canvas.getContext('2d');\r\n            \r\n            ctx.drawImage(imageObj.bitmap, 0, 0);\r\n            \r\n            return {\r\n                canvas: canvas,\r\n                width: width,\r\n                height: height,\r\n                dataUrl: canvas.toDataURL('image\/jpeg', 0.92)\r\n            };\r\n        }\r\n        \r\n        const width = imageObj.width || imageObj.w;\r\n        const height = imageObj.height || imageObj.h;\r\n        \r\n        if (!width || !height) {\r\n            throw new Error('Could not determine image dimensions');\r\n        }\r\n        \r\n        let imgData = imageObj.data || imageObj.bitmap;\r\n        \r\n        if (!imgData) {\r\n            throw new Error('No valid image data found');\r\n        }\r\n        \r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = width;\r\n        canvas.height = height;\r\n        const ctx = canvas.getContext('2d');\r\n        \r\n        ctx.fillStyle = 'white';\r\n        ctx.fillRect(0, 0, width, height);\r\n        \r\n        const imageData = ctx.createImageData(width, height);\r\n        \r\n        this.fillImageData(imageData, imgData, imageObj.kind, width, height);\r\n        \r\n        ctx.putImageData(imageData, 0, 0);\r\n        \r\n        return {\r\n            canvas: canvas,\r\n            width: width,\r\n            height: height,\r\n            dataUrl: canvas.toDataURL('image\/jpeg', 0.92)\r\n        };\r\n    },\r\n    \r\n    fillImageData(imageData, imgData, kind, width, height) {\r\n        if (kind === 'GRAY') {\r\n            for (let i = 0, j = 0; i < imgData.length; i++, j += 4) {\r\n                const value = imgData[i];\r\n                imageData.data[j] = value;\r\n                imageData.data[j + 1] = value;\r\n                imageData.data[j + 2] = value;\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (kind === 'CMYK') {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 4, j += 4) {\r\n                const c = imgData[i] \/ 255;\r\n                const m = imgData[i + 1] \/ 255;\r\n                const y = imgData[i + 2] \/ 255;\r\n                const k = imgData[i + 3] \/ 255;\r\n                \r\n                imageData.data[j] = 255 * (1 - c) * (1 - k);\r\n                imageData.data[j + 1] = 255 * (1 - m) * (1 - k);\r\n                imageData.data[j + 2] = 255 * (1 - y) * (1 - k);\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (kind === 'RGB24') {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 3, j += 4) {\r\n                imageData.data[j] = imgData[i];\r\n                imageData.data[j + 1] = imgData[i + 1];\r\n                imageData.data[j + 2] = imgData[i + 2];\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (imgData.length === width * height * 3) {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 3, j += 4) {\r\n                imageData.data[j] = imgData[i];\r\n                imageData.data[j + 1] = imgData[i + 1];\r\n                imageData.data[j + 2] = imgData[i + 2];\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else {\r\n            const tempArray = new Uint8ClampedArray(imgData.length);\r\n            for (let i = 0; i < imgData.length; i++) {\r\n                tempArray[i] = imgData[i];\r\n            }\r\n            \r\n            if (tempArray.length === imageData.data.length \/ 4 * 3) {\r\n                for (let i = 0, j = 0; i < tempArray.length; i += 3, j += 4) {\r\n                    imageData.data[j] = tempArray[i];\r\n                    imageData.data[j + 1] = tempArray[i + 1];\r\n                    imageData.data[j + 2] = tempArray[i + 2];\r\n                    imageData.data[j + 3] = 255;\r\n                }\r\n            } else if (tempArray.length === imageData.data.length) {\r\n                imageData.data.set(tempArray);\r\n            } else {\r\n                console.warn('Unknown image format - creating placeholder');\r\n                for (let i = 0; i < imageData.data.length; i += 4) {\r\n                    const x = (i\/4) % width;\r\n                    const y = Math.floor((i\/4) \/ width);\r\n                    imageData.data[i] = x % 256;\r\n                    imageData.data[i + 1] = y % 256;\r\n                    imageData.data[i + 2] = 100;\r\n                    imageData.data[i + 3] = 255;\r\n                }\r\n            }\r\n        }\r\n    },\r\n    \r\n    attachPDFPreviewHandler($dropZone, titleText) {\r\n        var $droppable = $dropZone.closest('.droppable');\r\n        var self = this;\r\n\r\n        \/\/ \u2705 Adapter le libell\u00e9 selon le format (communiqu\u00e9 \/ interview)\r\n        var kitFormat = $droppable.data('kitFormatSelect') || '';\r\n        var isInterview = (kitFormat || titleText || '').toLowerCase().indexOf('interview') !== -1;\r\n        var formatLabel = isInterview ? 'l\\'interview' : 'le communiqu\u00e9';\r\n        $droppable.find('.doc-preview-readmore').text('Ouvrir et visualiser ' + formatLabel);\r\n\r\n        \/\/ \u2705 v2.0.11 : D\u00e9l\u00e9gation d'\u00e9v\u00e9nement \u2014 plus robuste sur mobile\r\n        $droppable.off('click.docpreview').on('click.docpreview', '.doc-preview-readmore', (event) => {\r\n            event.preventDefault();\r\n            event.stopPropagation();\r\n            var popupTitle = isInterview ? 'Interview' : 'Communiqu\u00e9';\r\n\r\n            \/\/ \u2705 Priorit\u00e9 1 : pdfImageDataURL dispo (Kit)\r\n            var kitPdfImage = $droppable.data('kitPdfImageDataURL');\r\n            if (kitPdfImage) {\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    pdfDataURL: kitPdfImage\r\n                });\r\n                return;\r\n            }\r\n\r\n            \/\/ \u2705 Priorit\u00e9 2 : PDF upload\u00e9 manuellement \u2192 popup inline aussi\r\n            if (self.pdfDataForViewer && self.pdfDataForViewer.byteLength > 0) {\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    pdfArrayBuffer: self.pdfDataForViewer\r\n                });\r\n                return;\r\n            }\r\n\r\n            console.error('PDF data is not available');\r\n        });\r\n    },\r\n\r\n    \/\/ \u2705 v1.19.1 : Popup inline document \u2014 position:absolute + ScrollHelper.getVisibleTop()\r\n    \/\/ Le parent envoie visibleTopIframe dans le message scroll \u2192 positionnement fiable.\r\n    showInlineDocPopup($dropZone, options) {\r\n        var existing = document.getElementById('via-pdf-inline-popup');\r\n        if (existing) existing.remove();\r\n\r\n        var $droppable = $dropZone.closest('.droppable');\r\n        var droppableW = $droppable.outerWidth() || 300;\r\n        var popupW = Math.round(droppableW * 1.15);\r\n        \/\/ \u2705 v2.0.11 : Contraindre la largeur au viewport sur mobile (\u00e9vite troncature gauche\/droite)\r\n        var viewportW = document.documentElement.clientWidth || window.innerWidth;\r\n        if (UIManager.isMobile()) {\r\n            popupW = Math.min(popupW, viewportW - 8);\r\n        }\r\n        var popupH = Math.round(popupW * 2.5 * 0.51);\r\n\r\n        \/\/ \u2500\u2500 Position visible r\u00e9elle \u2500\u2500\r\n        var visibleTop = ScrollHelper.getVisibleTop();\r\n        var popupTop = Math.round(visibleTop + 284);\r\n\r\n        \/\/ \u2500\u2500 Popup position:absolute (positionn\u00e9 dans le document iframe) \u2500\u2500\r\n        var popup = document.createElement('div');\r\n        popup.id = 'via-pdf-inline-popup';\r\n        popup.style.cssText =\r\n            'position:absolute;z-index:99999;top:' + popupTop + 'px;' +\r\n            'width:' + popupW + 'px;height:' + popupH + 'px;' +\r\n            'background:#fff;border-radius:8px 8px 0 0;padding:0;' +\r\n            'box-shadow:0 8px 32px rgba(0,0,0,0.35);display:flex;flex-direction:column;' +\r\n            'min-width:200px;min-height:150px;touch-action:none;';\r\n\r\n        \/\/ Centrer horizontalement sur le droppable (coordonn\u00e9es absolues)\r\n        var droppableRect = $droppable[0].getBoundingClientRect();\r\n        var scrollX = window.scrollX || 0;\r\n        var initLeft = Math.round(droppableRect.left + scrollX + (droppableRect.width - popupW) \/ 2);\r\n        initLeft = Math.max(4, initLeft);\r\n        \/\/ \u2705 v2.0.11 : Contraindre \u00e0 droite aussi sur mobile\r\n        if (UIManager.isMobile()) {\r\n            initLeft = Math.min(initLeft, viewportW - popupW - 4);\r\n            initLeft = Math.max(4, initLeft);\r\n        }\r\n        popup.style.left = initLeft + 'px';\r\n\r\n        \/\/ \u2500\u2500 Header \u2500\u2500\r\n        var header = document.createElement('div');\r\n        header.style.cssText =\r\n            'display:flex;align-items:center;justify-content:center;position:relative;' +\r\n            'padding:10px 14px;background:#f0f0f0;color:#494949;flex-shrink:0;' +\r\n            'cursor:grab;user-select:none;border-radius:8px 8px 0 0;';\r\n        var titleEl = document.createElement('span');\r\n        titleEl.style.cssText = 'font-family:Roboto,Arial,sans-serif;font-size:15px;font-weight:600;';\r\n        titleEl.textContent = options.formatTitle || 'Document';\r\n        header.appendChild(titleEl);\r\n\r\n        var closeBtn = document.createElement('button');\r\n        closeBtn.textContent = '\u00d7';\r\n        closeBtn.style.cssText =\r\n            'position:absolute;right:10px;top:50%;transform:translateY(-50%);' +\r\n            'background:transparent;border:none;color:#494949;font-size:20px;' +\r\n            'cursor:pointer;line-height:1;padding:0 4px;';\r\n        closeBtn.addEventListener('click', cleanup);\r\n        header.appendChild(closeBtn);\r\n        popup.appendChild(header);\r\n\r\n        \/\/ \u2500\u2500 Zone scrollable \u2014 pleine largeur \u2500\u2500\r\n        var scrollZone = document.createElement('div');\r\n        scrollZone.style.cssText =\r\n            'flex:1;overflow-y:auto;overflow-x:hidden;padding:0;margin:0;touch-action:pan-y;';\r\n        popup.appendChild(scrollZone);\r\n\r\n        var loader = document.createElement('div');\r\n        loader.style.cssText =\r\n            'text-align:center;padding:30px;font-family:Roboto,Arial,sans-serif;font-size:12px;color:#666;';\r\n        loader.textContent = 'Chargement du document\u2026';\r\n        scrollZone.appendChild(loader);\r\n\r\n        \/\/ \u2500\u2500 8 poign\u00e9es de redimensionnement \u2500\u2500\r\n        var handles = [\r\n            { cursor:'nw-resize', pos:'top:-4px;left:-4px;',       dx:-1, dy:-1 },\r\n            { cursor:'n-resize',  pos:'top:-4px;left:50%;',        dx:0,  dy:-1 },\r\n            { cursor:'ne-resize', pos:'top:-4px;right:-4px;',      dx:1,  dy:-1 },\r\n            { cursor:'w-resize',  pos:'top:50%;left:-4px;',        dx:-1, dy:0  },\r\n            { cursor:'e-resize',  pos:'top:50%;right:-4px;',       dx:1,  dy:0  },\r\n            { cursor:'sw-resize', pos:'bottom:-4px;left:-4px;',    dx:-1, dy:1  },\r\n            { cursor:'s-resize',  pos:'bottom:-4px;left:50%;',     dx:0,  dy:1  },\r\n            { cursor:'se-resize', pos:'bottom:-4px;right:-4px;',   dx:1,  dy:1  }\r\n        ];\r\n        handles.forEach(function(h) {\r\n            var handle = document.createElement('div');\r\n            var isCorner = (h.dx !== 0 && h.dy !== 0);\r\n            handle.style.cssText =\r\n                'position:absolute;touch-action:none;' + h.pos +\r\n                'width:' + (isCorner ? '12px' : (h.dy === 0 ? '8px' : '30px')) + ';' +\r\n                'height:' + (isCorner ? '12px' : (h.dy === 0 ? '30px' : '8px')) + ';' +\r\n                'cursor:' + h.cursor + ';z-index:10;';\r\n            (function(hInfo) {\r\n                handle.addEventListener('pointerdown', function(e) {\r\n                    e.preventDefault(); e.stopPropagation();\r\n                    handle.setPointerCapture(e.pointerId);\r\n                    var startX = e.clientX, startY = e.clientY;\r\n                    var rect0 = popup.getBoundingClientRect();\r\n                    var sY = window.scrollY || 0, sX = window.scrollX || 0;\r\n                    var startW = rect0.width, startH = rect0.height;\r\n                    var startL = rect0.left + sX, startT = rect0.top + sY;\r\n                    function onResize(ev) {\r\n                        ev.preventDefault();\r\n                        var ddx = ev.clientX - startX, ddy = ev.clientY - startY;\r\n                        var newW = startW, newH = startH, newL = startL, newT = startT;\r\n                        if (hInfo.dx === 1)  newW = Math.max(200, startW + ddx);\r\n                        if (hInfo.dx === -1) { newW = Math.max(200, startW - ddx); newL = startL + ddx; }\r\n                        if (hInfo.dy === 1)  newH = Math.max(150, startH + ddy);\r\n                        if (hInfo.dy === -1) { newH = Math.max(150, startH - ddy); newT = startT + ddy; }\r\n                        popup.style.width  = newW + 'px';\r\n                        popup.style.height = newH + 'px';\r\n                        popup.style.left   = newL + 'px';\r\n                        popup.style.top    = newT + 'px';\r\n                    }\r\n                    function onResizeEnd(ev) {\r\n                        handle.releasePointerCapture(ev.pointerId);\r\n                        handle.removeEventListener('pointermove', onResize);\r\n                        handle.removeEventListener('pointerup', onResizeEnd);\r\n                    }\r\n                    handle.addEventListener('pointermove', onResize);\r\n                    handle.addEventListener('pointerup', onResizeEnd);\r\n                });\r\n            })(h);\r\n            popup.appendChild(handle);\r\n        });\r\n\r\n        \/\/ \u2500\u2500 Drag via header \u2500\u2500\r\n        header.style.touchAction = 'none';\r\n        header.addEventListener('pointerdown', function(e) {\r\n            if (e.target === closeBtn) return;\r\n            e.preventDefault();\r\n            header.setPointerCapture(e.pointerId);\r\n            var mx = e.clientX, my = e.clientY;\r\n            var popupRect = popup.getBoundingClientRect();\r\n            var scrollY = window.scrollY || 0;\r\n            var scrollX = window.scrollX || 0;\r\n            var curLeft = popupRect.left + scrollX;\r\n            var curTop  = popupRect.top  + scrollY;\r\n            header.style.cursor = 'grabbing';\r\n            function onMove(ev) {\r\n                ev.preventDefault();\r\n                var dx = ev.clientX - mx;\r\n                var dy = ev.clientY - my;\r\n                curLeft += dx;\r\n                curTop  += dy;\r\n                popup.style.left = curLeft + 'px';\r\n                popup.style.top  = curTop  + 'px';\r\n                mx = ev.clientX;\r\n                my = ev.clientY;\r\n            }\r\n            function onUp(ev) {\r\n                header.releasePointerCapture(ev.pointerId);\r\n                header.style.cursor = 'grab';\r\n                header.removeEventListener('pointermove', onMove);\r\n                header.removeEventListener('pointerup', onUp);\r\n            }\r\n            header.addEventListener('pointermove', onMove);\r\n            header.addEventListener('pointerup', onUp);\r\n        });\r\n\r\n        \/\/ \u2500\u2500 Cleanup \u2500\u2500\r\n        function cleanup() {\r\n            popup.remove();\r\n            document.removeEventListener('keydown', escHandler);\r\n        }\r\n        var escHandler = function(e) { if (e.key === 'Escape') cleanup(); };\r\n        document.addEventListener('keydown', escHandler);\r\n\r\n        document.body.appendChild(popup);\r\n\r\n        \/\/ \u2500\u2500 Rendre le contenu \u2500\u2500\r\n        if (options.pdfDataURL)          this.renderPdfInPopup(scrollZone, options.pdfDataURL, popupW, 'dataurl');\r\n        else if (options.pdfArrayBuffer) this.renderPdfInPopup(scrollZone, options.pdfArrayBuffer, popupW, 'arraybuffer');\r\n        else if (options.htmlContent)    this.renderHtmlInPopup(scrollZone, options.htmlContent);\r\n    },\r\n\r\n    \/\/ Alias pour compatibilit\u00e9\r\n    showInlinePdfPopup($dropZone, pdfImageDataURL, formatTitle) {\r\n        this.showInlineDocPopup($dropZone, { formatTitle: formatTitle, pdfDataURL: pdfImageDataURL });\r\n    },\r\n\r\n    \/\/ \u2705 Rendu PDF dans popup (dataurl ou arraybuffer) \u2014 avec crop des marges blanches\r\n    async renderPdfInPopup(container, pdfData, popupWidth, mode) {\r\n        try {\r\n            var u8;\r\n            if (mode === 'dataurl') {\r\n                var b64 = pdfData.split(',')[1];\r\n                var bstr = atob(b64);\r\n                u8 = new Uint8Array(bstr.length);\r\n                for (var i = 0; i < bstr.length; i++) { u8[i] = bstr.charCodeAt(i); }\r\n            } else {\r\n                u8 = new Uint8Array(pdfData);\r\n            }\r\n\r\n            var pdfjsLib = window['pdfjs-dist\/build\/pdf'];\r\n            if (!pdfjsLib) {\r\n                container.innerHTML = '<div style=\"padding:20px;text-align:center;color:#c00;\">pdf.js non charg\u00e9<\/div>';\r\n                return;\r\n            }\r\n            pdfjsLib.GlobalWorkerOptions.workerSrc =\r\n                '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n\r\n            var pdf = await pdfjsLib.getDocument({ data: u8 }).promise;\r\n            console.log('\ud83d\udcc4 PDF popup :', pdf.numPages, 'pages');\r\n            container.innerHTML = '';\r\n\r\n            var firstPage = await pdf.getPage(1);\r\n            var vpNative = firstPage.getViewport({ scale: 1 });\r\n            var scale = popupWidth \/ vpNative.width;\r\n\r\n            \/\/ \u2705 R\u00e9f\u00e9rence au popup pour ajuster sa hauteur apr\u00e8s rendu\r\n            var _popup = container.closest('#via-pdf-inline-popup');\r\n            var _headerH = _popup ? (_popup.querySelector('div[style*=\"grab\"]') || {offsetHeight: 44}).offsetHeight : 44;\r\n\r\n            \/\/ \u2705 D\u00e9tecte les marges blanches haut\/bas d'un canvas rendu et retourne {top, bottom}\r\n            function detectWhiteMargins(canvas) {\r\n                var ctx = canvas.getContext('2d');\r\n                var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\r\n                var W = canvas.width, H = canvas.height;\r\n                var topRow = 0, bottomRow = H - 1;\r\n                \/\/ Chercher la premi\u00e8re ligne non-blanche (tol\u00e9rance 252 pour les artefacts anti-aliasing)\r\n                outer: for (var y = 0; y < H; y++) {\r\n                    for (var x = 0; x < W; x++) {\r\n                        var i = (y * W + x) * 4;\r\n                        if (data[i] < 252 || data[i+1] < 252 || data[i+2] < 252) { topRow = y; break outer; }\r\n                    }\r\n                }\r\n                outer2: for (var y2 = H - 1; y2 >= topRow; y2--) {\r\n                    for (var x2 = 0; x2 < W; x2++) {\r\n                        var i2 = (y2 * W + x2) * 4;\r\n                        if (data[i2] < 252 || data[i2+1] < 252 || data[i2+2] < 252) { bottomRow = y2; break outer2; }\r\n                    }\r\n                }\r\n                return { top: topRow, bottom: bottomRow };\r\n            }\r\n\r\n            for (var pageNum = 1; pageNum <= pdf.numPages; pageNum++) {\r\n                var page = await pdf.getPage(pageNum);\r\n                var vp = page.getViewport({ scale: scale });\r\n                \/\/ Rendre dans un canvas temporaire\r\n                var tmpCanvas = document.createElement('canvas');\r\n                tmpCanvas.width = vp.width;\r\n                tmpCanvas.height = vp.height;\r\n                await page.render({ canvasContext: tmpCanvas.getContext('2d'), viewport: vp }).promise;\r\n\r\n                \/\/ \u2705 Crop marges blanches\r\n                var margins = detectWhiteMargins(tmpCanvas);\r\n                var cropTop = Math.max(0, margins.top - 4);\r\n                var cropBottom = Math.min(tmpCanvas.height - 1, margins.bottom + 4);\r\n                var croppedH = cropBottom - cropTop + 1;\r\n\r\n                \/\/ Canvas final crop\u00e9\r\n                var canvas = document.createElement('canvas');\r\n                canvas.width = tmpCanvas.width;\r\n                canvas.height = croppedH;\r\n                canvas.getContext('2d').drawImage(tmpCanvas, 0, cropTop, tmpCanvas.width, croppedH, 0, 0, tmpCanvas.width, croppedH);\r\n                canvas.style.cssText = 'display:block;width:100%;height:auto;margin:0;padding:0;';\r\n                container.appendChild(canvas);\r\n                console.log('\ud83d\udcc4 Page', pageNum, '- crop:', cropTop, '\u2192', cropBottom, '(', Math.round(cropTop\/vp.height*100), '% top trimmed)');\r\n            }\r\n\r\n            \/\/ \u2705 Ajuster la hauteur du popup \u00e0 la hauteur r\u00e9elle du contenu rendu\r\n            \/\/ (popup \u00e9tait calcul\u00e9 sur popupW*2.5*0.51 qui peut \u00eatre trop grand ou trop petit)\r\n            if (_popup) {\r\n                var _totalH = 0;\r\n                container.querySelectorAll('canvas').forEach(function(c) { _totalH += c.height * (popupWidth \/ c.width); });\r\n                var _viewportH = window.innerHeight || document.documentElement.clientHeight || 600;\r\n                var _maxPopupH = Math.round(_viewportH * 0.88);\r\n                var _idealH = Math.min(_totalH + _headerH + 8, _maxPopupH);\r\n                _popup.style.height = _idealH + 'px';\r\n                console.log('\ud83d\udcd0 Popup redimensionn\u00e9:', Math.round(_idealH), 'px (contenu:', Math.round(_totalH), ')');\r\n            }\r\n        } catch (err) {\r\n            console.error('\u274c Erreur rendu PDF popup:', err);\r\n            container.innerHTML =\r\n                '<div style=\"padding:20px;text-align:center;color:#c00;font-size:12px;\">Erreur lors du chargement du document<\/div>';\r\n        }\r\n    },\r\n\r\n    \/\/ \u2705 Rendu HTML (Word) dans popup \u2014 avec CSS complet pour mammoth\r\n    renderHtmlInPopup(container, htmlContent) {\r\n        container.innerHTML = '';\r\n        \/\/ \u2705 Nettoyer les <p> vides en d\u00e9but\/fin produits par mammoth (marges parasites)\r\n        htmlContent = htmlContent\r\n            .replace(\/^(\\s*<p[^>]*>\\s*(<br\\s*\\\/?>\\s*)*<\\\/p>\\s*)+\/i, '')\r\n            .replace(\/(\\s*<p[^>]*>\\s*(<br\\s*\\\/?>\\s*)*<\\\/p>\\s*)+$\/i, '');\r\n        \/\/ \u2500\u2500 Styles pour le HTML g\u00e9n\u00e9r\u00e9 par mammoth (titres, paragraphes, listes, images) \u2500\u2500\r\n        var style = document.createElement('style');\r\n        style.textContent = [\r\n            '.via-html-popup-body { padding:20px 24px; background:#fff; color:#222; font-family:Georgia,\"Times New Roman\",serif; font-size:15px; line-height:1.7; }',\r\n            '.via-html-popup-body h1 { font-size:22px; font-weight:700; margin:0 0 12px; line-height:1.3; }',\r\n            '.via-html-popup-body h2 { font-size:18px; font-weight:700; margin:18px 0 8px; line-height:1.3; }',\r\n            '.via-html-popup-body h3 { font-size:15px; font-weight:700; margin:14px 0 6px; }',\r\n            '.via-html-popup-body p  { margin:0 0 10px; }',\r\n            '.via-html-popup-body p:first-child { margin-top:0; }',\r\n            '.via-html-popup-body strong, .via-html-popup-body b { font-weight:700; }',\r\n            '.via-html-popup-body em, .via-html-popup-body i { font-style:italic; }',\r\n            '.via-html-popup-body ul, .via-html-popup-body ol { margin:6px 0 10px 22px; padding:0; }',\r\n            '.via-html-popup-body li { margin-bottom:4px; }',\r\n            '.via-html-popup-body img { max-width:100%; height:auto; display:block; margin:10px auto; border-radius:4px; }',\r\n            '.via-html-popup-body table { width:100%; border-collapse:collapse; margin:10px 0; font-size:13px; }',\r\n            '.via-html-popup-body td, .via-html-popup-body th { border:1px solid #ddd; padding:6px 8px; vertical-align:top; }',\r\n            '.via-html-popup-body th { background:#f0f4f8; font-weight:700; }',\r\n            '.via-html-popup-body a { color:#225da9; text-decoration:underline; }'\r\n        ].join('');\r\n        container.appendChild(style);\r\n        var wrapper = document.createElement('div');\r\n        wrapper.className = 'via-html-popup-body';\r\n        wrapper.innerHTML = htmlContent;\r\n        container.appendChild(wrapper);\r\n    },\r\n    \r\n    async renderPDFInWindow(childWindow, container) {\r\n        container.innerHTML = '';\r\n        \r\n        const script = childWindow.document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.4.120\/pdf.min.js';\r\n        childWindow.document.head.appendChild(script);\r\n        \r\n        script.onload = async () => {\r\n            const pdfjsLib = childWindow.pdfjsLib;\r\n            const viewerContainer = childWindow.document.createElement('div');\r\n            viewerContainer.style.width = '100%';\r\n            viewerContainer.style.backgroundColor = 'white';\r\n            viewerContainer.style.position = 'relative';\r\n            container.appendChild(viewerContainer);\r\n            \r\n            const loadingTask = pdfjsLib.getDocument({data: window.pdfDataToTransfer});\r\n            const pdf = await loadingTask.promise;\r\n            \r\n            const firstPage = await pdf.getPage(1);\r\n            const viewport = firstPage.getViewport({scale: 1.5});\r\n            const pageHeight = viewport.height;\r\n            \r\n            const spacing = -15;\r\n            const totalHeight = (pageHeight * pdf.numPages) + (spacing * (pdf.numPages - 1));\r\n            viewerContainer.style.height = `${totalHeight}px`;\r\n            \r\n            for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {\r\n                const page = await pdf.getPage(pageNum);\r\n                const canvas = childWindow.document.createElement('canvas');\r\n                const context = canvas.getContext('2d');\r\n                \r\n                canvas.width = viewport.width;\r\n                canvas.height = viewport.height;\r\n                \r\n                canvas.style.position = 'absolute';\r\n                canvas.style.left = '50%';\r\n                canvas.style.transform = 'translateX(-50%)';\r\n                canvas.style.top = `${(pageNum - 1) * (pageHeight + spacing)}px`;\r\n                \r\n                await page.render({\r\n                    canvasContext: context,\r\n                    viewport: viewport\r\n                }).promise;\r\n                \r\n                viewerContainer.appendChild(canvas);\r\n            }\r\n        };\r\n    },\r\n    \r\n    arrayBufferToBase64(buffer) {\r\n        let binary = '';\r\n        const bytes = new Uint8Array(buffer);\r\n        const len = bytes.byteLength;\r\n        for (let i = 0; i < len; i++) {\r\n            binary += String.fromCharCode(bytes[i]);\r\n        }\r\n        return window.btoa(binary);\r\n    },\r\n    \r\n    base64ToArrayBuffer(base64) {\r\n        const binaryString = window.atob(base64);\r\n        const len = binaryString.length;\r\n        const bytes = new Uint8Array(len);\r\n        for (let i = 0; i < len; i++) {\r\n            bytes[i] = binaryString.charCodeAt(i);\r\n        }\r\n        return bytes.buffer;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des \u00e9v\u00e9nements de drop et d'upload\r\n *\/\r\nconst DropHandler = {\r\n    async handleDrop(e) {\r\n        e.preventDefault();\r\n        \r\n        const $currentTarget = this.findDropTarget(e);\r\n        \r\n        if (!$currentTarget) {\r\n            console.log('No valid drop target found');\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 V\u00c9RIFIER SI C'EST UN D\u00c9PLACEMENT (pas besoin de v\u00e9rifier le format)\r\n        const isMoved = StateManager.get('FirstUploadFileorMoved') === 'Moved';\r\n        const dragstartRef = StateManager.get('dragstart_Commande_Emplacement_Page_Web');\r\n        let hasDragstartRef = false;\r\n        \r\n        if (dragstartRef) {\r\n            if (dragstartRef !== 'No') {\r\n                hasDragstartRef = true;\r\n            }\r\n        }\r\n        \r\n        let isDeplacementAnnonce = false;\r\n        if (isMoved) {\r\n            if (hasDragstartRef) {\r\n                isDeplacementAnnonce = true;\r\n            }\r\n        }\r\n        \r\n        if (isDeplacementAnnonce) {\r\n            console.log('\ud83d\udd04 D\u00e9placement d\u00e9tect\u00e9 - contr\u00f4le format ignor\u00e9');\r\n        } else {\r\n            \/\/ \u2705 CONTR\u00d4LE FORMAT SEULEMENT POUR NOUVEAU D\u00c9P\u00d4T\r\n            \/\/ Utilise FormatUIManager au lieu de showFormatWarning\r\n            if (StateManager.get('Formatchoisi') === 'No') {\r\n                FormatUIManager.flashTitle($currentTarget);\r\n                return;\r\n            }\r\n            \r\n            if (!FormatUIManager.hasSelectedFormat($currentTarget)) {\r\n                FormatUIManager.flashTitle($currentTarget);\r\n                return;\r\n            }\r\n        }\r\n    \r\n        console.log(\"Drop at:\", $currentTarget);\r\n        \r\n        this.updateEmplacementState($currentTarget);\r\n        \r\n        const shouldProcess = this.shouldProcessDrop(e, $currentTarget);\r\n        \r\n        if (shouldProcess) {\r\n            await this.processFileDrop(e, $currentTarget);\r\n        } else {\r\n            this.processVideoDrop($currentTarget);\r\n        }\r\n        \r\n        DragDropManager.clearDataTransferFiles(e);\r\n    },\r\n    \r\n    findDropTarget(e) {\r\n        \/\/ \u2705 v2.4.3 : Si Ele0A est actif et le drop arrive sur Ele1A \u2192 rediriger vers Ele0A\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            var _ele0ADrop = document.querySelector('#Ele0A #drop_file_zone_achat');\r\n            if (_ele0ADrop) {\r\n                console.log('\ud83c\udfaf findDropTarget \u2014 PopUpChoice=Yes \u2192 cible forc\u00e9e: Ele0A');\r\n                return jQuery(_ele0ADrop);\r\n            }\r\n        }\r\n\r\n        let target = e.target.closest('#drop_file_zone_achat');\r\n        \r\n        if (!target) {\r\n            target = e.currentTarget.closest('#drop_file_zone_achat');\r\n            console.log('Drop target found 1');\r\n        }\r\n        \r\n        if (!target) {\r\n            target = jQuery(e.target).closest('#drop_file_zone_achat')[0];\r\n            console.log('Drop target found 2');\r\n        }\r\n        \r\n        return target ? jQuery(target) : null;\r\n    },\r\n    \r\n    updateEmplacementState($target) {\r\n        const espaceId = $target.closest('.droppable').attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', espaceId);\r\n        StateManager.set('Commande_Emplacement_Page_Web',\r\n            StateManager.buildEmplacementReference(espaceId));\r\n        \r\n        UIManager.updateEmplacementDisplay();\r\n        \r\n        console.log(\"Rank_Emplacement_Page_Web:\", StateManager.get('Rank_Emplacement_Page_Web'));\r\n        console.log(\"Droppable at:\", StateManager.get('Commande_Emplacement_Page_Web'));\r\n    },\r\n    \r\n    shouldProcessDrop(e, $target) {\r\n        const hasFiles = e.dataTransfer.files.length > 0;\r\n        const isRedactionnel = StateManager.get('Commande_Format_Transmis') === 'R\u00e9dactionnel';\r\n        const isValidBackground = window.getComputedStyle(\r\n            $target.closest('#UploadFileConteneur')[0]\r\n        ).backgroundColor !== 'rgba(0, 0, 0, 0)';\r\n        \r\n        return (hasFiles || isRedactionnel) && isValidBackground;\r\n    },\r\n    \r\n    async processFileDrop(e, $target) {\r\n        jQuery('.MsgAdNotDisplayed').hide();\r\n        StateManager.setMultiple({\r\n            \"AdDisplayed\": 'Yes',\r\n            \/\/ \u2705 NE PLUS mettre sendDataToParentFlag ici - c'est la checkbox \"R\u00e9server\" qui le fera\r\n            \/\/ \"sendDataToParentFlag\": 'Yes'\r\n        });\r\n        \r\n        console.log('ajaxFileUpload_achat launched');\r\n        console.log(\"FirstUploadFileorMoved:\", StateManager.get('FirstUploadFileorMoved'));\r\n        \r\n        if (UIManager.isMobile()) {\r\n            $target = jQuery('#Ele1A').find('#drop_file_zone_achat');\r\n        }\r\n        \r\n        if (StateManager.get('Commande_Format_Transmis') === 'R\u00e9dactionnel') {\r\n            const fileURL = StateManager.get('FullPathAdFile');\r\n            const filename = fileURL.substring(fileURL.indexOf('_') + 1);\r\n            \r\n            try {\r\n                \/\/ \u2705 R\u00e9utiliser le File cach\u00e9 (\u00e9vite CORS cross-domain)\r\n                let file;\r\n                if (window._lastRedactionnelFile) {\r\n                    file = window._lastRedactionnelFile;\r\n                    console.log('\u267b\ufe0f R\u00e9utilisation du File cach\u00e9:', file.name, Math.round(file.size \/ 1024) + 'KB');\r\n                } else {\r\n                    file = await FileManager.urlToFile(fileURL, filename);\r\n                }\r\n                await UploadManager.handleFileUpload(file, $target);\r\n            } catch (error) {\r\n                console.error('Error:', error);\r\n            }\r\n        } else {\r\n            await UploadManager.handleFileUpload(e.dataTransfer.files[0], $target);\r\n        }\r\n    },\r\n    \r\n    processVideoDrop($target) {\r\n        const isValidBackground = window.getComputedStyle(\r\n            $target.closest('#UploadFileConteneur')[0]\r\n        ).backgroundColor !== 'rgba(0, 0, 0, 0)';\r\n        \r\n        if (!isValidBackground) {\r\n            jQuery('.MsgAdNotDisplayed').show();\r\n            StateManager.set(\"AdDisplayed\", 'No');\r\n            return;\r\n        }\r\n        \r\n        StateManager.set(\"AdDisplayed\", 'Yes');\r\n        \r\n        const objectUrl = StateManager.get('videoSrc');\r\n        const $previousDropZone = $('.drop_file_zone_achat_class').has(`video[src=\"${objectUrl}\"]`);\r\n        window.RestoreadSpaceTemplate($previousDropZone);\r\n        \r\n        const videoElement = jQuery('<video controls autoplay muted>').attr({\r\n            'src': objectUrl,\r\n            'max-width': '100%',\r\n            'max-height': '100%',\r\n            'draggable': 'true'\r\n        }).css({\r\n            'max-width': '100%',\r\n            'max-height': '100%'\r\n        });\r\n        \r\n        $target.empty().append(videoElement);\r\n        \r\n        $target.closest('#UploadFileConteneur').css({'background-color': '#FFFFFF00'});\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass')\r\n            .find('.RefEspacePublicitaire')\r\n            .html('R\u00e9f\u00e9rence de l\\'espace : ' + StateManager.get('Commande_Emplacement_Page_Web'))\r\n            .attr('id', 'RefEspacePublicitaire')\r\n            .each(function() {\r\n                var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                this.style.setProperty('display', 'block', 'important');\r\n            });\r\n        \/\/ \u2705 v2.4.5 : Renseigner et afficher .PositionEspacePublicitaire\r\n        (function() {\r\n            var _rankPosV = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            var _posLibV = PreviewRenderer._getPositionLibelle(_rankPosV);\r\n            if (_posLibV) {\r\n                $target.closest('.OrdiMobileConteneurClass')\r\n                    .find('.PositionEspacePublicitaireDeplacer')\r\n                    .text(_posLibV)\r\n                    .each(function() {\r\n                        var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                        if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass').find('.AdUploadedTitle').show();\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass')\r\n            .css({'top': '60px', 'margin-bottom': '80px'});\r\n        \r\n        $target.closest('.HTMLUploadfileConteneur')\r\n            .not('.AdUploadedTitle')\r\n            .css({\r\n                'top': '0px',\r\n                'margin-bottom': '0px',\r\n                'box-shadow': 'inset 0 0 0 2px #00FF19',  \/\/ \u2705 v2.4.5\r\n                'background-color': 'white'\r\n            });\r\n        \r\n        $target.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, .ChoisirEspacePublicitaire2ndLigne, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        jQuery('#MsgElementsCommandeValides, #MessageOptionsacompleterConteneur').hide();\r\n        \r\n        StateManager.set(\"FirstUploadFileorMoved\", 'Moved');\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server (au lieu d'envoyer automatiquement)\r\n        FormatUIManager.updateReserverCheckboxState($target.closest('.droppable'));\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'explorateur de fichiers\r\n *\/\r\nconst FileExplorer = {\r\n    isRunning: false,\r\n\r\n    open(e) {\r\n        if (this.isRunning) {\r\n            return;\r\n        }\r\n        \r\n        const $element = jQuery(e.target).closest('.droppable');\r\n        \r\n        \/\/ \u2705 V\u00e9rifier si un format est s\u00e9lectionn\u00e9 (utilise FormatUIManager)\r\n        if (!FormatUIManager.hasSelectedFormat($element)) {\r\n            FormatUIManager.flashTitle($element);\r\n            return;\r\n        }\r\n        \r\n        this.isRunning = true;\r\n        \r\n        const rankId = $element.attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', rankId);\r\n        StateManager.set('Commande_Emplacement_Page_Web',\r\n            StateManager.buildEmplacementReference(rankId));\r\n        \r\n        UIManager.updateEmplacementDisplay();\r\n        \r\n        console.log(\"Drop at:\", StateManager.get('Commande_Emplacement_Page_Web'));\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        \r\n        const $currentTarget = jQuery(e.target).closest('#drop_file_zone_achat');\r\n        const $fileInput = jQuery('#selectfile_achat');\r\n        \r\n        console.log(\"currentTarget\", $currentTarget);\r\n        \r\n        $fileInput.off('change');\r\n        $fileInput.off('click');\r\n        \r\n        const onChange = (event) => {\r\n            this.isRunning = false;\r\n            $fileInput.off('change', onChange);\r\n            \r\n            \/\/ \u2705 NE PLUS mettre sendDataToParentFlag ici\r\n            \/\/ StateManager.set(\"sendDataToParentFlag\", 'Yes');\r\n            \r\n            if ($fileInput[0].files.length > 0) {\r\n                UploadManager.handleFileUpload($fileInput[0].files[0], $currentTarget);\r\n            }\r\n        };\r\n        \r\n        const onClick = () => {\r\n            $fileInput.off('click', onClick);\r\n            $fileInput.on('focus', function onFocus() {\r\n                setTimeout(() => {\r\n                    if (!$fileInput.val()) {\r\n                        FileExplorer.isRunning = false;\r\n                    }\r\n                }, 200);\r\n                $fileInput.off('focus', onFocus);\r\n            });\r\n        };\r\n        \r\n        $fileInput.on('change', onChange);\r\n        $fileInput.on('click', onClick);\r\n        \r\n        $fileInput.click();\r\n        \r\n        setTimeout(() => {\r\n            this.isRunning = false;\r\n        }, 300);\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion du reset d'annonce\r\n *\/\r\nconst AdResetHandler = {\r\n    handle(e) {\r\n        e.preventDefault();\r\n        console.log(\"CroixResetAnnonce click\");\r\n        \r\n        \/\/ Reset l'\u00e9tat EnvoiUlterieur\r\n        StateManager.set('EnvoiUlterieur', 'false');\r\n        \r\n        \/\/ \u2705 v1.19.6 : Reset FileReceived mais garder le format s\u00e9lectionn\u00e9\r\n        StateManager.set('FileReceived', 'No');\r\n        \r\n        const $element = jQuery(e.currentTarget);\r\n        const $droppable = $element.closest('.droppable');\r\n        const resetRef = StateManager.buildEmplacementReference($droppable.attr('id'));\r\n        \r\n        console.log(\"Reset_Commande_Emplacement_Page_Web:\", resetRef);\r\n        \r\n        \/\/ \u2705 Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        var _rankForDel = $droppable.attr('id') || StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            MessageManager.sendDelAdToParent({\r\n                Commande_Emplacement_Page_Web: resetRef,\r\n                Rank_Emplacement_Page_Web: _rankForDel,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n        } else {\r\n            window.processdataDelAd({\r\n                Commande_Emplacement_Page_Web: resetRef,\r\n                Rank_Emplacement_Page_Web: _rankForDel,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n        }\r\n        \r\n        \/\/ \u2705 v1.16.0 : Appeler RestoreadSpaceTemplateLocal directement (accessible dans ce scope)\r\n        RestoreadSpaceTemplateLocal(e.currentTarget);\r\n        \r\n        window.FonctionCroixResetAnnonce(e.currentTarget);\r\n        \r\n        \/\/ \u2705 v2.1.1 : Sauf popup\r\n        var formatWasSelected = sessionStorage.getItem('FormatSelect') \r\n            || sessionStorage.getItem('Commande_Format_Transmis')\r\n            || $droppable.data('kitFormatSelect');\r\n        \r\n        if (sessionStorage.getItem('PopUpChoice') !== 'Yes' && (formatWasSelected || sessionStorage.getItem('Formatchoisi') === 'Yes')) {\r\n            sessionStorage.setItem('Formatchoisi', 'Yes');\r\n            console.log('\u2705 Formatchoisi forc\u00e9 \u00e0 Yes apr\u00e8s reset');\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.6 : Remettre \u00e0 jour le titre format et r\u00e9afficher la checkbox R\u00e9server\r\n        setTimeout(() => {\r\n            FormatUIManager.updateTitleColor($droppable);\r\n            FormatUIManager.updateReserverCheckboxState($droppable);\r\n            \r\n            \/\/ \u2705 R\u00e9afficher le .ReserverContainer statique\r\n            $droppable.find('.ReserverContainer').show();\r\n        }, 150);\r\n    }\r\n};\r\n\r\n\/**\r\n * \u2705 Template pour r\u00e9initialisation des espaces publicitaires (IFRAME)\r\n *\/\r\nvar adSpaceTemplatesLocal = {};\r\n\r\nfunction saveAdSpaceTemplateLocal() {\r\n    var saved = 0;\r\n    jQuery('.droppable').each(function() {\r\n        var droppableId = jQuery(this).attr('id');\r\n        if (!droppableId) return;\r\n        \r\n        \/\/ \u2705 Ne jamais sauvegarder Ele0A (clone temporaire popup, pas un template d'origine)\r\n        if (droppableId === 'Ele0A') return;\r\n        \r\n        \/\/ \u2705 Ne pas r\u00e9-\u00e9craser un template d\u00e9j\u00e0 sauvegard\u00e9\r\n        if (adSpaceTemplatesLocal[droppableId]) return;\r\n        \r\n        \/\/ \u2705 v2.3.4 : Ne pas sauvegarder si template d\u00e9j\u00e0 connu (\u00e9tat propre sauvegard\u00e9)\r\n        \/\/ Le guard hasAd est supprim\u00e9 \u2014 on veut capturer le template le plus t\u00f4t possible\r\n        \/\/ Si le template existe d\u00e9j\u00e0, on ne le r\u00e9\u00e9crase pas\r\n        \/\/ (le guard anti-\u00e9crasement if (adSpaceTemplatesLocal[droppableId]) return; suffit)\r\n        \r\n        var $content = jQuery(this).find('.OrdiMobileConteneurClass').first();\r\n        if ($content.length > 0) {\r\n            adSpaceTemplatesLocal[droppableId] = $content.clone(true, true);\r\n            saved++;\r\n        }\r\n    });\r\n    if (saved > 0) {\r\n        console.log('\u2705 Templates espaces pub sauvegard\u00e9s:', saved, 'espaces -', Object.keys(adSpaceTemplatesLocal));\r\n        return true;\r\n    }\r\n    return false;\r\n}\r\n\r\nfunction RestoreadSpaceTemplateLocal(element) {\r\n    console.log('\ud83d\udd04 RestoreadSpaceTemplateLocal', element);\r\n    \r\n    var $element = jQuery(element);\r\n    var $droppable = $element.closest('.droppable');\r\n    var droppableId = $droppable.attr('id');\r\n    \r\n    \/\/ \u2705 FIX Ele0A : pas de template sauvegard\u00e9 (clone temporaire popup)\r\n    \/\/ \u2192 pas de remplacement DOM, reset visuel direct sur le contenu existant\r\n    var _isEle0A = (droppableId === 'Ele0A');\r\n\r\n    \/\/ \u2705 v1.19.3 : Chercher le template sp\u00e9cifique \u00e0 CET espace (sauf Ele0A)\r\n    if (!_isEle0A) {\r\n        if (!droppableId || !adSpaceTemplatesLocal[droppableId]) {\r\n            if (!saveAdSpaceTemplateLocal()) {\r\n                console.error('\u274c Template non disponible');\r\n                return false;\r\n            }\r\n            if (!adSpaceTemplatesLocal[droppableId]) {\r\n                console.error('\u274c Template non trouv\u00e9 pour', droppableId);\r\n                return false;\r\n            }\r\n        }\r\n    }\r\n    \r\n    var adSpaceElement = $droppable.find('.OrdiMobileConteneurClass').first();\r\n    \r\n    if (!adSpaceElement || !adSpaceElement.length) {\r\n        console.error('\u274c OrdiMobileConteneurClass non trouv\u00e9');\r\n        return false;\r\n    }\r\n    \r\n    var newElement;\r\n    if (_isEle0A) {\r\n        \/\/ Ele0A : pas de clone \u2014 on remet en \u00e9tat le contenu existant directement\r\n        newElement = adSpaceElement;\r\n        console.log('\u2705 [Ele0A] reset visuel direct (pas de template clone)');\r\n        \/\/ \u2705 Vider le contenu du dropzone et restaurer le HTML par d\u00e9faut\r\n        \/\/ (le replaceWith n'ayant pas lieu, l'image d\u00e9pos\u00e9e et le fond blanc restent sinon)\r\n        var $dz0A = $droppable.find('#drop_file_zone_achat');\r\n        $dz0A.empty().html(\r\n            '<div id=\"drag_upload_file_achat\">' +\r\n                '<p class=\"UploadIci\" style=\"color:#FB5E2A;font-weight:600;\">Ici glisser \u2013 d\u00e9poser ou<br>t\u00e9l\u00e9charger une annonce<\/p>' +\r\n            '<\/div>'\r\n        );\r\n        \/\/ Restaurer le fond bleu #9FC5F3 et retirer les styles d'annonce upload\u00e9e\r\n        $droppable.find('#UploadFileConteneur').css({\r\n            'background-color': '#9FC5F3',\r\n            'border': '',\r\n            'box-sizing': ''\r\n        });\r\n        $droppable.find('.HTMLUploadfileConteneur').css({\r\n            'box-shadow': '',\r\n            'background-color': '',\r\n            'border': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': '',\r\n            'overflow': '',\r\n            'height': '',\r\n            'max-height': ''\r\n        });\r\n        \/\/ Masquer la croix et le titre d'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle, #CroixResetAnnonce, .CroixResetAnnonceContainer, .DeplaceAnnonce').hide();\r\n        $droppable.removeAttr('data-via-ad-loaded').removeAttr('data-from-miniature');\r\n        console.log('\u2705 [Ele0A] dropzone vid\u00e9 + fond restaur\u00e9');\r\n    } else {\r\n        \/\/ \u2705 v1.19.3 : Cloner le template SP\u00c9CIFIQUE \u00e0 cet espace (pas le premier)\r\n        newElement = adSpaceTemplatesLocal[droppableId].clone(true, true);\r\n        console.log('\u2705 Template utilis\u00e9 pour', droppableId);\r\n        adSpaceElement.replaceWith(newElement);\r\n        \/\/ \u2705 v2.4.12 : Effacer data-via-ad-loaded (sinon selectEspaceActif masque .ReserverContainer)\r\n        $droppable.removeAttr('data-via-ad-loaded').removeAttr('data-from-miniature');\r\n        if (window.outerWidth < 1000) {\r\n            newElement.css({'margin-top': '-25px', 'bottom': '0px'});\r\n        }\r\n    }\r\n    \r\n    \/\/ D\u00e9cocher la case Envoi diff\u00e9r\u00e9 si elle existe\r\n    newElement.find('input[name*=\"EnvoiUlterieur\"]').prop('checked', false);\r\n    \r\n    \/\/ \u2705 D\u00e9cocher la checkbox \"R\u00e9server\"\r\n    newElement.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked', false);\r\n    \r\n    \/\/ Reset l'\u00e9tat EnvoiUlterieur\r\n    StateManager.set('EnvoiUlterieur', 'false');\r\n    \r\n    \/\/ \u2705 v1.19.3 : R\u00e9initialiser TOUS les styles inline des conteneurs parents modifi\u00e9s pendant le d\u00e9p\u00f4t\r\n    if ($droppable.length) {\r\n        \/\/ \u2705 v2.0.9 : Restaurer les marges de l'algorithme de positionnement (sauvegard\u00e9es par styleUploadedAd)\r\n        var origMt = $droppable.data('orig-mt');\r\n        $droppable.css({\r\n            'margin-top': (origMt !== undefined) ? origMt + 'px' : '',\r\n            'margin-bottom': '',\r\n            'margin-left': '',\r\n            'margin-right': ''\r\n        });\r\n        \/\/ \u2705 v2.0.11 : Cleanup event namespace docpreview\r\n        $droppable.off('click.docpreview');\r\n        \r\n        \/\/ Reset .OrdiMobileConteneurClass margins\r\n        var $container = $droppable.find('.OrdiMobileConteneurClass');\r\n        var origMb = $container.data('orig-mb');\r\n        $container.css({\r\n            'margin-top': '',\r\n            'margin-bottom': (origMb !== undefined) ? origMb + 'px' : ''\r\n        });\r\n        \r\n        \/\/ Reset .HTMLUploadfileConteneur (set by styleUploadedAd: box-shadow inset, background-color:white)\r\n        $droppable.find('.HTMLUploadfileConteneur').css({\r\n            'border': '',\r\n            'box-shadow': '',\r\n            'outline': '',\r\n            'outline-offset': '',\r\n            'background-color': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': '',\r\n            'overflow': '',\r\n            'padding': '',\r\n            'position': ''\r\n        });\r\n        $droppable.find('.via-green-border-overlay').remove();\r\n        \r\n        \/\/ \u2705 Restaurer pointer-events sur OrdiMobileConteneurClass et ses enfants\r\n        $droppable.find('.OrdiMobileConteneurClass').css('pointer-events', '');\r\n        $droppable.find('#CroixResetAnnonce').css({'pointer-events': '', 'position': '', 'z-index': ''});\r\n        \/\/ \u2705 v2.4.5 : Reset margin-right Ele0A (pos\u00e9 par adjustMobileLayout)\r\n        var _croixContReset = $droppable.find('.CroixResetAnnonceContainer')[0];\r\n        if (_croixContReset) { _croixContReset.style.removeProperty('margin-right'); _croixContReset.style.removeProperty('margin-top'); }\r\n        $droppable.find('#PopUpMessageAchattest').css('pointer-events', '');\r\n        \r\n        \/\/ \u2705 v2.0.9 : Restaurer le scale(1.4) sur .UploadFileConteneur (r\u00e9duit \u00e0 scale(1) par styleUploadedAd sur mobile)\r\n        $droppable.find('.UploadFileConteneur').css({\r\n            'transform': '',\r\n            'transform-origin': ''\r\n        });\r\n        \r\n        \/\/ Reset #UploadFileConteneur - Restaurer le fond bleu #9FC5F3 + retirer liser\u00e9 envoi diff\u00e9r\u00e9\r\n        $droppable.find('#UploadFileConteneur').css({\r\n            'width': '',\r\n            'background-color': '#9FC5F3',\r\n            'border': '',\r\n            'box-sizing': ''\r\n        });\r\n        \r\n        \/\/ Reset .ToBeHidden (set by adjustDesktopLayout: top:105px, min-height:300px + overflow mobile)\r\n        $droppable.closest('.ToBeHidden').css({\r\n            'top': '',\r\n            'min-height': '',\r\n            'overflow': ''\r\n        });\r\n        \r\n        \/\/ Reset overflow sur le parent du droppable (set by adjustDesktopLayout)\r\n        $droppable.parent().css('overflow', '');\r\n        \r\n        \/\/ \u2705 v1.19.5 : Gestion device-specific pour les textes\r\n        var isDesktop = window.outerWidth >= 1000;\r\n        \r\n        if (isDesktop) {\r\n            \/\/ Desktop : cacher les textes mobiles, afficher UploadIci\r\n            $droppable.find('.TexteMobile').hide();\r\n            $droppable.find('.TexteMobileAnnonce').hide();\r\n            $droppable.find('.TexteMobileAjoutAnnonce').hide();\r\n            $droppable.find('.UploadIci').show();\r\n        } else {\r\n            \/\/ Mobile : afficher TexteMobileAnnonce\r\n            $droppable.find('.TexteMobileAnnonce').show();\r\n        }\r\n        \r\n        \/\/ R\u00e9-afficher les \u00e9l\u00e9ments masqu\u00e9s pendant l'upload\r\n        $droppable.find('.PositionEspacePublicitaireContainer').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireDisponibiliteConteneur').show();\r\n        $droppable.find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur > div > .elementor-widget-text-editor').show();\r\n        $droppable.find('.AdDroppedTextNotDisplayed').hide();\r\n        \/\/ \u2705 v2.4.5 : Ele0A + PopUpChoice=Yes \u2192 ne pas r\u00e9-afficher le titre si format d\u00e9j\u00e0 s\u00e9lectionn\u00e9\r\n        var _skipTitre = (sessionStorage.getItem('PopUpChoice') === 'Yes' && $droppable.attr('id') === 'Ele0A');\r\n        $droppable.find('.SelectionFormatTitreBlanc').hide();\r\n        if (!_skipTitre) {\r\n            $droppable.find('.SelectionFormatTitre').show();\r\n        }\r\n        $droppable.find('span.ClassHdpCdp, .ClassRefEsp').show();\r\n        $droppable.find('.EspPubFormatMainContainer').show();\r\n        $droppable.find('.EspPubFormatListe').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireClass').show();\r\n        $droppable.find('.GlisserDeposerConteneur').show();\r\n        $droppable.find('.OUClass').show();\r\n        $droppable.find('.PositionReference').show();\r\n        $droppable.find('.ClassHdpCdp').show();\r\n        $droppable.find('.ClassRefEsp').show();\r\n        $droppable.find('.EnvoiUlterieurTexte').show();\r\n        $droppable.find('.EnvoiUlterieurContainer').show();\r\n        \r\n        \/\/ \u2705 v1.19.5 : R\u00e9afficher le .ReserverContainer (bouton Elementor statique)\r\n        $droppable.find('.ReserverContainer').show();\r\n        newElement.find('.ReserverContainer').show();\r\n        \r\n        \/\/ Masquer les \u00e9l\u00e9ments sp\u00e9cifiques \u00e0 l'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle, #CroixResetAnnonce, .CroixResetAnnonceContainer, .DeplaceAnnonce').hide();\r\n        $droppable.find('#CroixResetAnnonce').css({'position': '', 'z-index': ''});\r\n        $droppable.find('.RefEspacePublicitaire').hide();\r\n        \r\n        \/\/ Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 v1.19.6 : Restaurer le format s\u00e9lectionn\u00e9 visuellement\r\n        \/\/ Chercher le format dans plusieurs sources possibles\r\n        var formatSelect = sessionStorage.getItem('FormatSelect') \r\n            || sessionStorage.getItem('Commande_Format_Transmis')\r\n            || $droppable.data('kitFormatSelect')\r\n            || '';\r\n        \r\n        var formatchoisi = sessionStorage.getItem('Formatchoisi');\r\n        console.log('\ud83d\udcd0 Format \u00e0 restaurer:', formatSelect, '| Formatchoisi:', formatchoisi);\r\n        \r\n        \/\/ D'abord reset tous les formats visuellement (sur newElement ET $droppable)\r\n        var $allFormats = newElement.find('.EspPubFormatContainer').add($droppable.find('.EspPubFormatContainer'));\r\n        $allFormats.css({\r\n            'background-color': '',\r\n            'border': ''\r\n        });\r\n        newElement.find('.EspPubFormat').add($droppable.find('.EspPubFormat')).css({\r\n            'color': ''\r\n        });\r\n        \r\n        \/\/ Si un format \u00e9tait s\u00e9lectionn\u00e9 (via sessionStorage OU visuellement avant)\r\n        \/\/ \u2705 v2.1.1 : Sauf popup\r\n        if ((formatSelect || formatchoisi === 'Yes') && sessionStorage.getItem('PopUpChoice') !== 'Yes') {\r\n            var formatFound = false;\r\n            \r\n            if (formatSelect) {\r\n                \/\/ \u2705 v2.1.1 : Normaliser via NFD (plus fiable que les replace manuels)\r\n                var formatLower = formatSelect.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase().replace(\/ \/g, '');\r\n                \r\n                \/\/ Appliquer sur newElement ET $droppable pour \u00eatre s\u00fbr\r\n                var $allContainers = newElement.find('.EspPubFormatContainer').add($droppable.find('.EspPubFormatContainer'));\r\n                \r\n                $allContainers.each(function() {\r\n                    var className = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    \r\n                    if (className.includes(formatLower)) {\r\n                        jQuery(this).css({'background-color': '#ffffff'});\r\n                        jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        formatFound = true;\r\n                        \/\/ \u2705 v2.4.12 : M\u00e9moriser le format restaur\u00e9 (lu par selectEspaceActif pour re-surligner apr\u00e8s reset global)\r\n                        $droppable.attr('data-restored-format', formatSelect);\r\n                        console.log('\u2705 Format restaur\u00e9 visuellement:', formatSelect, '- classe:', this.className);\r\n                    }\r\n                });\r\n            }\r\n            \r\n            \/\/ \u2705 IMPORTANT : Pr\u00e9server Formatchoisi = Yes pour permettre l'upload\r\n            sessionStorage.setItem('Formatchoisi', 'Yes');\r\n            console.log('\u2705 Formatchoisi maintenu \u00e0 Yes');\r\n            \r\n            \/\/ Basculer les titres format (sur newElement ET $droppable)\r\n            newElement.find('.SelectionFormatTitre').hide();\r\n            newElement.find('.SelectionFormatTitreBlanc').show();\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n        }\r\n    }\r\n    \r\n    \/\/ \u2705 v1.19.2 : Relancer InitLoadedPage pour recalculer positions et tailles\r\n    setTimeout(function() {\r\n        if (typeof window.InitLoadedPage === 'function') {\r\n            window.InitLoadedPage();\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.6 : R\u00e9attacher les MutationObservers sur les formats\r\n        if (typeof FormatUIManager !== 'undefined' && FormatUIManager.observeFormatChanges) {\r\n            FormatUIManager.observeFormatChanges();\r\n        }\r\n    }, 100);\r\n    \r\n    console.log('\u2705 Espace publicitaire r\u00e9initialis\u00e9');\r\n    return true;\r\n}\r\n\r\n\/\/ \u2705 Exposer pour appel depuis yearbook-media.js (suppression popup mode=popup)\r\nwindow.RestoreadSpaceTemplateLocal = RestoreadSpaceTemplateLocal;\r\n\r\nwindow.verifierAffichageMsgSelectEspaceLocal = function() {\r\n    const formatChoisi = StateManager.get('Formatchoisi') === 'Yes';\r\n    const fileReceived = StateManager.get('FileReceived');\r\n    const envoiUlterieur = StateManager.get('EnvoiUlterieur');\r\n    \r\n    var dateDebut, dateFin, pays;\r\n    try {\r\n        dateDebut = window.parent.$('#form-field-DebutCampagne').val();\r\n        dateFin = window.parent.$('#form-field-FinCampagne').val();\r\n        pays = window.parent.$('#form-field-Nationalite_Societe').val();\r\n    } catch(e) {\r\n        jQuery('#MsgSelectEspace').hide();\r\n        return;\r\n    }\r\n    \r\n    if (!dateDebut || !dateFin || !pays || !formatChoisi) {\r\n        jQuery('#MsgSelectEspace').hide();\r\n        return;\r\n    }\r\n    \r\n    if (fileReceived !== 'Yes') {\r\n        if (envoiUlterieur !== 'true') {\r\n            jQuery('#MsgSelectEspace').show();\r\n        } else {\r\n            jQuery('#MsgSelectEspace').hide();\r\n        }\r\n    } else {\r\n        jQuery('#MsgSelectEspace').hide();\r\n    }\r\n};\r\n\r\n\/\/ Sauvegarder les templates au chargement (apr\u00e8s rendu complet Elementor)\r\njQuery(document).ready(function() {\r\n    \/\/ \u2705 v1.19.3 : D\u00e9lai augment\u00e9 + double sauvegarde pour garantir les bonnes dimensions\r\n    setTimeout(saveAdSpaceTemplateLocal, 3000);\r\n    setTimeout(saveAdSpaceTemplateLocal, 6000);\r\n    \/\/ \u2705 v2.3.4 : Sauvegarde imm\u00e9diate d\u00e8s que la page est pr\u00eate dans l'iframe\r\n    \/\/ (avant toute interaction utilisateur)\r\n    setTimeout(saveAdSpaceTemplateLocal, 100);\r\n    setTimeout(saveAdSpaceTemplateLocal, 500);\r\n});\r\n\r\n\/\/ \u2705 v2.3.4 : Forcer sauvegarde \u00e0 la r\u00e9ception de elementsRemoved (espaces visibles + vierges)\r\nwindow.addEventListener('message', function(e) {\r\n    if (e.data && e.data.type === 'elementsRemoved') {\r\n        \/\/ Les espaces sont vierges \u00e0 ce stade \u2192 sauvegarder imm\u00e9diatement\r\n        setTimeout(saveAdSpaceTemplateLocal, 50);\r\n        setTimeout(saveAdSpaceTemplateLocal, 300);\r\n    }\r\n});\r\n\r\n\/**\r\n * Fonction helper pour le d\u00e9p\u00f4t r\u00e9dactionnel\r\n *\/\r\nfunction RedactionnelDepose() {\r\n    jQuery('#Tariftobedisplayed').html('-');\r\n    jQuery('#TarifDataStep3').html('\u00e0 choisir').css({'color': '#FB5E2A'});\r\n    jQuery('#FormatDataStep3').html('\u00e0 choisir').css({'color': '#FB5E2A'});\r\n    jQuery('#ListePaysDirect, #ListeThemeDirect, .ListeArticles, #PageAfficheeMessage').hide();\r\n    StateManager.set(\"PositionAnnonceSelection\", 'Yes');\r\n}\r\n\r\n\/**\r\n * Exposition des fonctions globales n\u00e9cessaires\r\n *\/\r\nwindow.uploadFile_achat = (e) => DropHandler.handleDrop(e);\r\nwindow.fileExplorer_achat = (e) => FileExplorer.open(e);\r\nwindow.ajaxFileUpload_achat = (fileObj, dropZone) => UploadManager.handleFileUpload(fileObj, dropZone);\r\nwindow.ActivatesendDataToParent = (dropZone) => UploadManager.activateSendDataToParent(dropZone);\r\n\/\/ \u2705 v2.3.4 : Exposer FormatUIManager pour appel depuis Entete.txt (selectEspaceActif)\r\nwindow.FormatUIManagerRef = FormatUIManager;\r\n\r\n\/**\r\n * Initialisation de l'application\r\n *\/\r\njQuery(document).ready(() => {\r\n    StateManager.init();\r\n    ScrollHelper.init();\r\n    DragDropManager.init();\r\n    FormatUIManager.init();\r\n    \r\n    if (UIManager.isMobile()) {\r\n        UIManager.initMobileUI();\r\n    } else {\r\n        UIManager.initDesktopUI();\r\n    }\r\n    \r\n    jQuery(document).on('click', '#CroixResetAnnonce', (e) => AdResetHandler.handle(e));\r\n    \r\n    \/\/ \u2705 Clic sur le texte du label \u2192 toggle manuel de la checkbox du m\u00eame conteneur\r\n    jQuery(document).on('click', '.reserver-dynamic-label', function(e) {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        const $cb = $(this).closest('.reserver-dynamic-option, .reserver-dynamic-container').find('.reserver-dynamic-checkbox');\r\n        if ($cb.length) {\r\n            $cb.prop('checked', !$cb.prop('checked')).trigger('change');\r\n        }\r\n    });\r\n\r\n    \/\/ \u2705 CHECKBOX \"R\u00e9server cet espace publicitaire\" \u2014 VALIDATION ET ENVOI DES DONN\u00c9ES\r\n    \/\/ \u2705 v2.4.13 : iOS touchend\r\n    \/\/ \u2705 v2.4.13 : Mobile \u2014 \u00e9couter touchend sur input ET click\/touchend sur label\r\n    jQuery(document).on('touchend', 'input[name=\"form_fields[ReserverEspacePublicitaire]\"]', function() {\r\n        if (this._viaResTouch) { return; }\r\n        this._viaResTouch = true;\r\n        var _self = this;\r\n        setTimeout(function() { _self._viaResTouch = false; }, 500);\r\n        setTimeout(function() { jQuery(_self).trigger('change'); }, 100);\r\n    });\r\n    jQuery(document).on('touchend click', '.elementor-field-group-ReserverEspacePublicitaire label, .reserver-dynamic-label, .reserver-dynamic-option label', function(e) {\r\n        \/\/ Trouver l'input associ\u00e9\r\n        var $input = jQuery(this).closest('.elementor-field-option, .reserver-dynamic-option').find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n        if (!$input.length) { $input = jQuery(this).siblings('input[name=\"form_fields[ReserverEspacePublicitaire]\"]'); }\r\n        if (!$input.length) { $input = jQuery('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').first(); }\r\n        if ($input.length) {\r\n            if (e.type === 'touchend') { e.preventDefault(); }\r\n            var _wasChecked = $input.prop('checked');\r\n            $input.prop('checked', !_wasChecked);\r\n            setTimeout(function() {\r\n                $input.trigger('change');\r\n            }, 50);\r\n        }\r\n    });\r\n    jQuery(document).on('change', 'input[name=\"form_fields[ReserverEspacePublicitaire]\"]', function(e) {\r\n        const $checkbox = $(this);\r\n        let $droppable = $checkbox.closest('.droppable');\r\n        if (!$droppable.length) {\r\n            $droppable = $checkbox.closest('.reserver-dynamic-container').prev('.droppable');\r\n        }\r\n        \/\/ \u2705 v2.4.13 : Fallback mobile \u2014 checkbox dans body > .reserver-dynamic-container[data-droppable-id]\r\n        if (!$droppable.length) {\r\n            const $dynContainer = $checkbox.closest('.reserver-dynamic-container');\r\n            const _droppableId = $dynContainer.attr('data-droppable-id') || '';\r\n            if (_droppableId) {\r\n                $droppable = $('#' + _droppableId);\r\n            }\r\n        }\r\n        \/\/ Dernier recours : utiliser le rank en sessionStorage\r\n        if (!$droppable.length) {\r\n            const _rankFallback = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            if (_rankFallback) { $droppable = $('#' + _rankFallback); }\r\n        }\r\n        \r\n        \/\/ Si on d\u00e9coche\r\n        if (!$checkbox.is(':checked')) {\r\n            console.log('\u2610 Checkbox \"R\u00e9server\" d\u00e9coch\u00e9e');\r\n            \/\/ \u2705 Mettre \u00e0 jour le label\r\n            const $lbl = $checkbox.closest('.reserver-dynamic-option, .elementor-field-option').find('.reserver-dynamic-label, label').not('input');\r\n            $lbl.text('R\u00e9server cet espace publicitaire').css('color', '');\r\n            \/\/ \u2705 Notifier le parent pour d\u00e9-r\u00e9server l'item dans le r\u00e9cap\r\n            const _rankDecoche = $droppable.attr('id') || StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            const _emplacementDecoche = StateManager.buildEmplacementReference(_rankDecoche);\r\n            MessageManager.sendToParent('annulationReservation', {\r\n                Rank_Emplacement_Page_Web: _rankDecoche,\r\n                Commande_Emplacement_Page_Web: _emplacementDecoche,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n            \/\/ \u2705 v2.4.5 : M\u00e9moriser que ce rank a \u00e9t\u00e9 explicitement d\u00e9coch\u00e9\r\n            StateManager.set('_reserverDecoche_' + _rankDecoche, 'Yes');\r\n            console.log('\ud83d\udce4 annulationReservation envoy\u00e9 \u2192 parent | rank:', _rankDecoche, '| emplacement:', _emplacementDecoche);\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 V\u00e9rifier les conditions : format s\u00e9lectionn\u00e9 ET (fichier d\u00e9pos\u00e9 OU envoi diff\u00e9r\u00e9)\r\n        const hasFormat = FormatUIManager.hasSelectedFormat($droppable);\r\n        const hasFile = StateManager.get('FileReceived') === 'Yes';\r\n        const hasEnvoiDiffere = $droppable.find('input[name*=\"EnvoiUlterieur\"]:checked').length > 0;\r\n        \r\n        console.log('\ud83d\udd0d Checkbox \"R\u00e9server\" - Validation:', { hasFormat, hasFile, hasEnvoiDiffere });\r\n        \r\n        if (!hasFormat) {\r\n            \/\/ \u2705 Si un fichier est d\u00e9j\u00e0 d\u00e9pos\u00e9 \u2192 d\u00e9duire le format depuis l'extension (ne pas bloquer)\r\n            if (hasFile) {\r\n                const _uploadedName = StateManager.get('Upload_File_Name') || '';\r\n                const _ext = _uploadedName.split('.').pop().toLowerCase();\r\n                const _fileType = FileManager.getFileType(_ext);\r\n                let _deducedFormat = '';\r\n                if (_fileType === 'video') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Video' : 'Vid\u00e9o';\r\n                } else if (_fileType === 'image') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Banner' : 'Banni\u00e8re';\r\n                } else if (_fileType === 'document') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Press release' : 'Communiqu\u00e9';\r\n                }\r\n                if (_deducedFormat) {\r\n                    StateManager.set('Commande_Format_Transmis', _deducedFormat);\r\n                    StateManager.set('FormatSelect', _deducedFormat);\r\n                    StateManager.set('Formatchoisi', 'Yes');\r\n                    console.log('\u2705 Format d\u00e9duit depuis extension (' + _ext + '):', _deducedFormat);\r\n                    \/\/ Continuer vers l'envoi (pas de return false)\r\n                } else {\r\n                    e.preventDefault();\r\n                    $checkbox.prop('checked', false);\r\n                    FormatUIManager.flashTitle($droppable);\r\n                    console.log('\u274c R\u00e9servation bloqu\u00e9e : format non d\u00e9ductible depuis extension:', _ext);\r\n                    return false;\r\n                }\r\n            } else {\r\n                e.preventDefault();\r\n                $checkbox.prop('checked', false);\r\n                FormatUIManager.flashTitle($droppable);\r\n                console.log('\u274c R\u00e9servation bloqu\u00e9e : aucun format s\u00e9lectionn\u00e9');\r\n                return false;\r\n            }\r\n        }\r\n        \r\n        if (!hasFile && !hasEnvoiDiffere) {\r\n            e.preventDefault();\r\n            $checkbox.prop('checked', false);\r\n            console.log('\u274c R\u00e9servation bloqu\u00e9e : ni annonce d\u00e9pos\u00e9e ni envoi diff\u00e9r\u00e9');\r\n            return false;\r\n        }\r\n        \r\n        \/\/ \u2705 Conditions remplies \u2014 Pr\u00e9parer et envoyer les donn\u00e9es\r\n        console.log('\u2705 Checkbox \"R\u00e9server\" valid\u00e9e \u2014 envoi des donn\u00e9es');\r\n        \r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.setMultiple({\r\n            \"sendDataToParentFlag\": \"Yes\",\r\n            \"Formatchoisi\": \"Yes\",\r\n            \"Rank_Emplacement_Page_Web\": rankId,\r\n            \"Commande_Emplacement_Page_Web\": StateManager.buildEmplacementReference(rankId),\r\n            \"LoadedPageUrl\": window.location.href,\r\n            \/\/ \u2705 v2.3.0 : Forcer avant l'envoi \u2014 le setTimeout(4000) dans activateSendDataToParent\r\n            \/\/ arrive trop tard sur le 1er clic \u2192 AddNewRefInVosCampagnes restait null\r\n            \"AddNewRefInVosCampagnes\": \"Yes\"\r\n        });\r\n        \r\n        \/\/ \u2705 D\u00e9clencher l'envoi des donn\u00e9es via activateSendDataToParent\r\n        const $dropZone = $droppable.find('#drop_file_zone_achat');\r\n        UploadManager.activateSendDataToParent($dropZone);\r\n    });\r\n    \r\n    \/\/ G\u00c9RER \"Envoi diff\u00e9r\u00e9\" \u2014 marquer l'\u00e9tat sans envoyer (c'est \"R\u00e9server\" qui envoie)\r\n    \/\/ \u2705 v2.4.13 : iOS touchend\r\n    jQuery(document).on('touchend', 'input[name*=\"EnvoiUlterieur\"]', function() {\r\n        if (this._viaTouch) { return; }\r\n        this._viaTouch = true;\r\n        var _self = this;\r\n        setTimeout(function() { _self._viaTouch = false; }, 500);\r\n        setTimeout(function() { jQuery(_self).trigger('change'); }, 100);\r\n    });\r\n    jQuery(document).on('change', 'input[name*=\"EnvoiUlterieur\"]', function(e) {\r\n        const $checkbox = $(this);\r\n        let $droppable = $checkbox.closest('.droppable');\r\n        \/\/ \u2705 v2.4.13 : Fallback mobile\r\n        if (!$droppable.length) {\r\n            const $dynContainer = $checkbox.closest('.reserver-dynamic-container');\r\n            const _droppableId = $dynContainer.attr('data-droppable-id') || '';\r\n            if (_droppableId) { $droppable = $('#' + _droppableId); }\r\n        }\r\n        if (!$droppable.length) {\r\n            const _rankFallback = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            if (_rankFallback) { $droppable = $('#' + _rankFallback); }\r\n        }\r\n  \r\n        \/\/ Si on d\u00e9coche\r\n        if (!$checkbox.is(':checked')) {\r\n            StateManager.set('EnvoiUlterieur', 'false');\r\n            \r\n            if (typeof window.verifierAffichageMsgSelectEspaceLocal === 'function') {\r\n                window.verifierAffichageMsgSelectEspaceLocal();\r\n            }\r\n            \r\n            \/\/ Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server\r\n            FormatUIManager.updateReserverCheckboxState($droppable);\r\n            return;\r\n        }\r\n        \r\n        \/\/ Si on coche, masquer le message\r\n        jQuery('#MsgSelectEspace').hide();\r\n    \r\n        \/\/ V\u00e9rifier si un format est s\u00e9lectionn\u00e9\r\n        const hasSelectedFormat = FormatUIManager.hasSelectedFormat($droppable);\r\n        \r\n        if (!hasSelectedFormat) {\r\n            e.preventDefault();\r\n            $checkbox.prop('checked', false);\r\n            FormatUIManager.flashTitle($droppable);\r\n            return false;\r\n        }\r\n        \r\n        \/\/ \u2705 FORMAT OK \u2014 Marquer l'\u00e9tat envoi diff\u00e9r\u00e9 (sans envoyer les donn\u00e9es)\r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.setMultiple({\r\n            \"EnvoiUlterieur\": 'true',\r\n            \"Rank_Emplacement_Page_Web\": rankId,\r\n            \"Commande_Emplacement_Page_Web\": StateManager.buildEmplacementReference(rankId),\r\n            \"LoadedPageUrl\": window.location.href,\r\n            \"FileReceived\": \"No\",\r\n            \"FullPathAdFile\": '',\r\n            \"Upload_File_Name\": '',\r\n            \"Formatchoisi\": 'Yes'\r\n        });\r\n        \r\n        console.log('\ud83d\udcdd Envoi diff\u00e9r\u00e9 coch\u00e9 \u2014 en attente de validation via checkbox \"R\u00e9server\"');\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server (maintenant activable)\r\n        FormatUIManager.updateReserverCheckboxState($droppable);\r\n    });\r\n\r\n    \/\/ \u2705 v2.2.0 : Bouton \"Cr\u00e9ation\" dans espace publicitaire \u2192 Kit Ad Creator dans le parent\r\n    jQuery(document).on('click', '.FormatIdCreation', function(e) {\r\n        e.preventDefault();\r\n        var $btn = jQuery(this);\r\n        var isActive = $btn.data('creationActive') === true;\r\n\r\n        if (isActive) {\r\n            \/\/ D\u00e9sactiver\r\n            $btn.data('creationActive', false);\r\n            $btn.find('.EspPubFormat').css({'color': '#ffffff'});\r\n            $btn.css({'background-color': 'transparent'});\r\n            MessageManager.sendToParent('closeAdCreatorFromIframe', {});\r\n            console.log('\ud83c\udfa8 Cr\u00e9ation iframe \u2192 toggle OFF, fermeture popup parent');\r\n        } else {\r\n            \/\/ Activer : texte vert sur fond blanc\r\n            $btn.data('creationActive', true);\r\n            $btn.find('.EspPubFormat').css({'color': '#37D900'});\r\n            $btn.css({'background-color': '#ffffff'});\r\n            var formatSelect = sessionStorage.getItem('FormatSelect') || '';\r\n            var formatTransmis = sessionStorage.getItem('Commande_Format_Transmis') || '';\r\n            \/\/ \u2705 v2.2.1 : Envoyer aussi Commande_Format_Transmis (format cliqu\u00e9 dans l'iframe, sans accent)\r\n            var _rankKit = $btn.closest('.droppable').attr('id') || sessionStorage.getItem('Rank_Emplacement_Page_Web') || '';\r\n            var _cSite = sessionStorage.getItem('codeSite') || '';\r\n            var _cPage = sessionStorage.getItem('codePage') || '';\r\n            var _sfxKit = _rankKit.replace('Ele', '');\r\n            var _emplKit = (_cSite && _cPage && _sfxKit) ? (_cSite + _cPage + 'L' + _sfxKit) : (sessionStorage.getItem('Commande_Emplacement_Page_Web') || '');\r\n            MessageManager.sendToParent('openAdCreatorFromIframe', { formatSelect: formatSelect, formatTransmis: formatTransmis, rankId: _rankKit, emplacement: _emplKit });\r\n            console.log('\ud83c\udfa8 Cr\u00e9ation iframe \u2192 toggle ON (FormatSelect:', formatSelect, '| Commande_Format_Transmis:', formatTransmis, ')');\r\n        }\r\n    });\r\n\r\n    \/\/ \u2705 v2.2.0 : Messages depuis le parent concernant le bouton Cr\u00e9ation\r\n    window.addEventListener('message', function(event) {\r\n        var msg = event.data;\r\n        if (!msg) return;\r\n\r\n        \/\/ \u2705 v2.2.1 : Fournir la position du titre R\u00e9server pour positionner la miniature\r\n        if (msg.type === 'getReserverLabelRect') {\r\n            var $label = jQuery('.reserver-dynamic-label').first();\r\n            if ($label.length) {\r\n                var r = $label[0].getBoundingClientRect();\r\n                var iframeScale = (window.outerWidth > 1000) ? 0.75 : 0.80; \/\/ \u2705 v2.4.12 : 0.85 \u2192 0.75 (scale r\u00e9el du parent)\r\n                event.source.postMessage({\r\n                    type: 'reserVeurLabelRectResult',\r\n                    \/\/ Retourner bottom en coordonn\u00e9es iframe internes (non scal\u00e9es)\r\n                    bottom: r.bottom,\r\n                    left: r.left,\r\n                    right: r.right,\r\n                    iframeScale: iframeScale\r\n                }, '*');\r\n            } else {\r\n                event.source.postMessage({ type: 'reserVeurLabelRectResult', bottom: null }, '*');\r\n            }\r\n        }\r\n\r\n        \/\/ Fermeture du popup \u2192 d\u00e9s\u00e9lectionner le bouton Cr\u00e9ation\r\n        if (msg.type === 'adCreatorClosedFromParent') {\r\n            jQuery('.FormatIdCreation').each(function() {\r\n                jQuery(this).data('creationActive', false);\r\n                jQuery(this).find('.EspPubFormat').css({'color': '#ffffff'});\r\n                jQuery(this).css({'background-color': 'transparent'});\r\n            });\r\n            console.log('\ud83c\udfa8 adCreatorClosedFromParent re\u00e7u \u2192 bouton Cr\u00e9ation d\u00e9s\u00e9lectionn\u00e9');\r\n        }\r\n\r\n        \/\/ Restaurer le style du bouton Cr\u00e9ation apr\u00e8s un reset de removeElements\r\n        if (msg.type === 'restoreCreationButton') {\r\n            jQuery('.FormatIdCreation').each(function() {\r\n                if (jQuery(this).data('creationActive') === true) {\r\n                    jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                    jQuery(this).css({'background-color': '#ffffff'});\r\n                }\r\n            });\r\n            console.log('\ud83c\udfa8 restoreCreationButton re\u00e7u \u2192 style Cr\u00e9ation restaur\u00e9');\r\n        }\r\n    });\r\n\r\n});\r\n\r\n\/\/ =========================================================================\r\n\/\/ \u2705 Listener kitAdCreated \u2014 annonce cr\u00e9\u00e9e par le Kit overlay (mode=kit)\r\n\/\/ Injecte directement dans l'espace pub identifi\u00e9 par rankId\r\nwindow.addEventListener('message', function(event) {\r\n    var msg = event.data;\r\n    if (!msg || msg.action !== 'kitAdCreated') return;\r\n\r\n    var _rankId = msg.rankId || '';\r\n    var _emplacement = msg.emplacement || '';\r\n    console.log('\ud83c\udfa8 [espace_pub] kitAdCreated re\u00e7u | rankId:', _rankId, '| emplacement:', _emplacement);\r\n\r\n    if (!_rankId) { console.warn('\u26a0\ufe0f [kitAdCreated] rankId manquant'); return; }\r\n\r\n    var $droppable = jQuery('#' + _rankId);\r\n    if (!$droppable.length) { console.warn('\u26a0\ufe0f [kitAdCreated] droppable non trouv\u00e9:', _rankId); return; }\r\n    var $dropZone = $droppable.find('.drop_file_zone_achat_class').first();\r\n    if (!$dropZone.length) { $dropZone = $droppable.find('#drop_file_zone_achat').first(); }\r\n    if (!$dropZone.length) { console.warn('\u26a0\ufe0f [kitAdCreated] dropZone non trouv\u00e9e dans', _rankId); return; }\r\n\r\n    var _dataURL = msg.fullResDataURL || msg.pdfDataURL || null;\r\n    var _filename = msg.filename || 'annonce.png';\r\n    var _isPDF = msg.isPDF || false;\r\n    if (!_dataURL) { console.warn('\u26a0\ufe0f [kitAdCreated] aucune donn\u00e9e image'); return; }\r\n\r\n    var _parts = _dataURL.split(',');\r\n    var _mime = (_parts[0].match(\/:(.*?);\/) || [])[1] || (_isPDF ? 'application\/pdf' : 'image\/png');\r\n    var _bStr = atob(_parts[1]);\r\n    var _bytes = new Uint8Array(_bStr.length);\r\n    for (var _i = 0; _i < _bStr.length; _i++) { _bytes[_i] = _bStr.charCodeAt(_i); }\r\n    var _blob = new Blob([_bytes], { type: _mime });\r\n    \/\/ \u2705 Ajouter extension si absente\r\n    var _MIME_EXT = {'image\/png':'.png','image\/jpeg':'.jpg','image\/jpg':'.jpg','image\/webp':'.webp','application\/pdf':'.pdf'};\r\n    if (_filename.indexOf('.') === -1) { _filename = _filename + (_MIME_EXT[_mime] || (_isPDF ? '.pdf' : '.png')); }\r\n    var _file = new File([_blob], _filename, { type: _mime });\r\n\r\n    \/\/ \u2705 Pr\u00e9parer StateManager\r\n    StateManager.set('Rank_Emplacement_Page_Web', _rankId);\r\n    StateManager.set('Commande_Emplacement_Page_Web', _emplacement);\r\n    StateManager.set('Formatchoisi', 'Yes');\r\n    \/\/ \u2705 Marquer le droppable directement en DOM \u2014 r\u00e9siste \u00e0 l'async, lu par styleUploadedAd\r\n    $droppable[0].setAttribute('data-kit-drop', 'true');\r\n    window._dropFromMiniature = true;\r\n\r\n    console.log('\u2705 [kitAdCreated] \u2192 UploadManager.handleFileUpload | rankId:', _rankId);\r\n    UploadManager.handleFileUpload(_file, $dropZone).then(function() {\r\n        console.log('\u2705 [kitAdCreated] handleFileUpload termin\u00e9');\r\n    }).catch(function(err) {\r\n        window._dropFromMiniature = false;\r\n        $droppable[0].removeAttribute('data-kit-drop');\r\n        console.error('\u274c [kitAdCreated] handleFileUpload erreur:', err);\r\n    });\r\n});\r\n\r\n\/\/ \u2705 v1.17.0 : Listener \"thumbnailDropped\" \u2014 d\u00e9p\u00f4t de l'annonce depuis la miniature\r\n\/\/ =========================================================================\r\n\/**\r\n * Re\u00e7oit le drop de l'image-annonce depuis la miniature dans la page parente.\r\n * Identifie l'espace publicitaire sous le curseur, s\u00e9lectionne cet espace,\r\n * et d\u00e9clenche le flux dataFromIframeEspacePub en mode \"envoi diff\u00e9r\u00e9\"\r\n * (l'utilisateur uploadera le vrai fichier depuis le formulaire de commande).\r\n *\r\n * Coordonn\u00e9es re\u00e7ues : viewport de l'iframe (clientX\/clientY relatifs \u00e0 l'iframe)\r\n *\/\r\nwindow.addEventListener('message', function(event) {\r\n    var msg = event.data;\r\n    if (!msg || msg.action !== 'thumbnailDropped') return;\r\n\r\n    console.log('\ud83d\udce8 thumbnailDropped re\u00e7u \u2014 coords iframe:', msg.xRel, msg.yRel);\r\n\r\n    \/\/ \u2705 v1.19.3 : Corriger les coordonn\u00e9es pour le facteur de scale de l'iframe\r\n    \/\/ \u2705 v2.4.10 : 0.75 = scale appliqu\u00e9 par le PARENT sur l'\u00e9l\u00e9ment iframe (et non 0.85 qui est le scale interne OrdiMobileConteneurClass)\r\n    \/\/ Les coords xRel\/yRel viennent de getBoundingClientRect() sur l'iframe scal\u00e9 \u00e0 0.75 dans le parent \u2192 diviser par 0.75\r\n    var iframeScale = (window.outerWidth > 1000) ? 0.75 : 0.80;\r\n    \/\/ \u2705 v2.4.3 : Si Entete a intercept\u00e9 et pos\u00e9 un redirect vers Ele0A, utiliser ces coords\r\n    var _redirect = window._thumbnailDropRedirect || null;\r\n    window._thumbnailDropRedirect = null;\r\n    \/\/ \u2705 v2.4.4 : Les coords de redirect viennent de getBoundingClientRect() dans l'iframe (espace logique)\r\n    \/\/            \u2192 ne pas re-diviser par iframeScale (d\u00e9j\u00e0 en coords iframe-logiques)\r\n    var xAdjusted = _redirect ? _redirect.xRel : (msg.xRel \/ iframeScale);\r\n    var yAdjusted = _redirect ? _redirect.yRel : (msg.yRel \/ iframeScale);\r\n    if (_redirect) { console.log('\ud83d\udd00 [thumbnailDropped] coords redirig\u00e9es vers Ele0A:', Math.round(xAdjusted), Math.round(yAdjusted)); }\r\n    else { console.log('\ud83d\udcd0 Coords ajust\u00e9es (scale', iframeScale, '):', Math.round(xAdjusted), Math.round(yAdjusted)); }\r\n\r\n    \/\/ 1. Identifier l'espace publicitaire le plus proche du point de drop\r\n    \/\/    \u2705 v1.18.1 : Recherche par distance \u2014 coords \u00e9ventuellement redirig\u00e9es par Entete.txt\r\n    var allDroppables = document.querySelectorAll('.droppable');\r\n    var droppableEl = null;\r\n    var closestDist = Infinity;\r\n\r\n    \/\/ \u2705 v2.4.4 : Guard rect Ele0A \u2014 si PopUpChoice=Yes ET curseur dans le rect d'Ele0A \u2192 forcer\r\n    \/\/            (Ele0A est un popup flottant : son centre peut \u00eatre loin du curseur \u2192 algo distance l'ignore)\r\n    \/\/            Ne force PAS si le drop est hors d'Ele0A \u2192 les autres espaces restent accessibles\r\n    if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n        var _ele0ACheck = document.getElementById('Ele0A');\r\n        if (_ele0ACheck) {\r\n            var _r0A = _ele0ACheck.getBoundingClientRect();\r\n            var _margin = 30;\r\n            var _inR0A = (xAdjusted >= _r0A.left - _margin);\r\n            if (_inR0A) { _inR0A = (xAdjusted <= _r0A.right + _margin); }\r\n            if (_inR0A) { _inR0A = (yAdjusted >= _r0A.top - _margin); }\r\n            if (_inR0A) { _inR0A = (yAdjusted <= _r0A.bottom + _margin); }\r\n            if (_inR0A) {\r\n                droppableEl = _ele0ACheck;\r\n                closestDist = 0;\r\n                console.log('\ud83c\udfaf [thumbnailDropped] Ele0A forc\u00e9 (curseur dans rect Ele0A +30px)');\r\n            }\r\n        }\r\n    }\r\n\r\n    if (!droppableEl) {\r\n        allDroppables.forEach(function(d) {\r\n            var r = d.getBoundingClientRect();\r\n            var dCenterX = r.left + r.width  \/ 2;\r\n            var dCenterY = r.top  + r.height \/ 2;\r\n            var dist = Math.abs(dCenterX - xAdjusted) + Math.abs(dCenterY - yAdjusted);\r\n            if (dist < closestDist) { closestDist = dist; droppableEl = d; }\r\n        });\r\n        \/\/ \u2705 v2.4.3 : Si Entete a d\u00e9tect\u00e9 un drop sur Ele0A \u2192 forcer directement\r\n        if (_redirect) { if (_redirect.forceEle0A) {\r\n            var _ele0AForced = document.getElementById('Ele0A');\r\n            if (_ele0AForced) { droppableEl = _ele0AForced; console.log('\ud83c\udfaf [thumbnailDropped] Ele0A forc\u00e9 (redirect Entete)'); }\r\n        } }\r\n    }\r\n\r\n    if (!droppableEl || closestDist > 800) {\r\n        console.warn('thumbnailDropped \u2014 aucun droppable proche (dist min:', closestDist, ')');\r\n        return;\r\n    }\r\n    console.log('\ud83d\udccd Droppable trouv\u00e9:', droppableEl.id, '(dist:', Math.round(closestDist), ')');\r\n\r\n    var $droppable = jQuery(droppableEl);\r\n    var rankId = $droppable.attr('id');\r\n    if (!rankId) { console.warn('thumbnailDropped \u2014 .droppable sans id'); return; }\r\n\r\n    var $dropZone = $droppable.find('#drop_file_zone_achat').first();\r\n    if (!$dropZone.length) { console.warn('thumbnailDropped \u2014 #drop_file_zone_achat introuvable dans', rankId); return; }\r\n\r\n    var emplacementRef = StateManager.buildEmplacementReference(rankId);\r\n    console.log('\u2705 thumbnailDropped \u2014 espace pub:', rankId, '\u2192', emplacementRef);\r\n\r\n    \/\/ 2. Pr\u00e9parer l'\u00e9tat SessionStorage (comme un vrai drop de fichier)\r\n    StateManager.setMultiple({\r\n        'Rank_Emplacement_Page_Web':     rankId,\r\n        'Commande_Emplacement_Page_Web': emplacementRef,\r\n        'FirstUploadFileorMoved':        'FirstUpload',\r\n        'Formatchoisi':                  'Yes',\r\n        'Commande_Format_Transmis':      'Image',\r\n        'EnvoiUlterieur':                'false',\r\n        'FileReceived':                  'No',\r\n        'AdDisplayed':                   'Yes'\r\n    });\r\n\r\n    UIManager.updateEmplacementDisplay();\r\n\r\n    \/\/ 3. Construire le File \u00e0 partir du PDF (communiqu\u00e9\/interview) ou de l'image PNG (autres formats)\r\n    \/\/    puis appeler handleFileUpload \u2192 m\u00eame flux qu'un vrai drag&drop : liser\u00e9 vert, aper\u00e7u, R\u00e9server\r\n    var dataURL, mime, ext;\r\n\r\n    \/\/ \u2705 Stocker le PDF image et le format sur le droppable pour le popup de visualisation inline\r\n    if (msg.pdfImageDataURL) {\r\n        $droppable.data('kitPdfImageDataURL', msg.pdfImageDataURL);\r\n        $droppable.data('kitFormatSelect', msg.FormatSelect || '');\r\n        console.log('\ud83d\udcce pdfImageDataURL stock\u00e9 sur', rankId, '| format:', msg.FormatSelect);\r\n    } else {\r\n        $droppable.removeData('kitPdfImageDataURL');\r\n        $droppable.removeData('kitFormatSelect');\r\n    }\r\n\r\n    if (msg.isPDF && msg.pdfDataURL) {\r\n        \/\/ \u2500\u2500 Format PDF (communiqu\u00e9 \/ interview) \u2500\u2500\u2500\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        dataURL = msg.pdfDataURL;                         \/\/ \"data:application\/pdf;base64,\u2026\"\r\n        mime    = 'application\/pdf';\r\n        ext     = '.pdf';\r\n    } else if (msg.imageDataURL) {\r\n        \/\/ \u2500\u2500 Format image (banni\u00e8re \/ parrainage) \u2500\u2500\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        dataURL = msg.imageDataURL;\r\n        var mimeMatch = dataURL.match(\/^data:([^;]+);base64,\/);\r\n        mime    = mimeMatch ? mimeMatch[1] : 'image\/png';\r\n        ext     = mime === 'image\/jpeg' ? '.jpg' : '.png';\r\n    } else {\r\n        console.warn('thumbnailDropped \u2014 aucune donn\u00e9e image\/pdf disponible');\r\n        return;\r\n    }\r\n\r\n    var baseName = msg.filename ? msg.filename.replace(\/\\.[^.]+$\/, '') : 'annonce-kit';\r\n    var fileName = baseName + ext;\r\n\r\n    \/\/ dataURL \u2192 Uint8Array \u2192 Blob \u2192 File\r\n    var b64  = dataURL.split(',')[1];\r\n    var bstr = atob(b64);\r\n    var u8   = new Uint8Array(bstr.length);\r\n    for (var i = 0; i < bstr.length; i++) { u8[i] = bstr.charCodeAt(i); }\r\n    var blob    = new Blob([u8], { type: mime });\r\n    var fileObj = new File([blob], fileName, { type: mime });\r\n\r\n    console.log('thumbnailDropped \u2192 handleFileUpload:', fileName, Math.round(fileObj.size \/ 1024) + 'KB');\r\n\r\n    \/\/ \u2705 Cacher le File pour r\u00e9utilisation lors des d\u00e9placements (\u00e9vite CORS)\r\n    window._lastRedactionnelFile = fileObj;\r\n\r\n    \/\/ \u2705 v2.4.10 : Signaler \u00e0 adjustDesktopLayout que c'est un drop depuis la miniature\r\n    \/\/ \u2192 applique max-height sur HTMLUploadfileConteneur pour \u00e9viter le d\u00e9bordement vertical (homepage corps de page)\r\n    window._dropFromMiniature = true;\r\n    UploadManager.handleFileUpload(fileObj, $dropZone);\r\n\r\n    \/\/ \u2705 v1.19.1 : Positionner l'espace \u00e0 10px du haut du viewport (tous formats)\r\n    \/\/ \u2705 v2.4.13 : Skip si drop depuis miniature \u2014 selectEspaceActif g\u00e8re d\u00e9j\u00e0 le scroll\r\n    if (!window._dropFromMiniature) {\r\n        setTimeout(function() {\r\n            var el = $droppable.find('.HTMLUploadfileConteneur')[0] || $droppable[0];\r\n            if (el) {\r\n                ScrollHelper.scrollElementTo(el, 10);\r\n            }\r\n        }, 400);\r\n    }\r\n});\r\n\r\nconsole.log('This is a ' + (UIManager.isDesktop() ? 'desktop' : 'non-desktop') + ' device.');\r\n\r\n} \/\/ end _espPubScriptLoaded guard\r\n<\/script>\r\n\r\n<style>\r\n\/* Les styles CSS restent inchang\u00e9s *\/\r\n#drop_file_zone_achat {\r\n    background-color: #FFFFFF00;\r\n    color: #225DA9;\r\n    font-weight: 500;\r\n    text-align: center;\r\n    border: #999 0px dashed;\r\n    width: 100%;\r\n    height: 180px;\r\n    font-size: 11.5px;\r\n    display: flex;\r\n    justify-content: center; \r\n    align-items: center; \r\n    flex-wrap: wrap;\r\n}\r\n\r\n#drag_upload_file_achat {\r\n    margin: 0 auto;\r\n    width: 90%;\r\n    height: 60px;\r\n}\r\n\r\n#drag_upload_file_achat p {\r\n    text-align: center;\r\n}\r\n\r\n\/* \u2705 v1.16.0 : Liser\u00e9 noir fin autour du texte \"Ici glisser \u2013 d\u00e9poser\" *\/\r\n.GlisserDeposerConteneur .elementor-widget-container p {\r\n    border: 1px solid #000000;\r\n    border-radius: 4px;\r\n    padding: 4px 10px;\r\n    display: inline-block;\r\n}\r\n\r\n#selectfile_achat {\r\n    display: none;\r\n}\r\n\r\n.button-2_achat, .button-2_achat-after-reset {\r\n    background-color: #ffffff00!important;\r\n    border: 1px solid white!important;\r\n    border-radius: 8px;\r\n    color: #225DA9!important;\r\n    cursor: pointer;\r\n    display: inline-block;\r\n    font-size: 11px;\r\n    font-weight: 500;\r\n    list-style: none;\r\n    width: 390px;\r\n    height: 62px;\r\n    top: 0px!important; \r\n    margin-top: 0px!important; \r\n    padding-left: 5px!important;\r\n    padding-right: 5px!important;\r\n    margin-bottom: 70px!important;\r\n    margin: 0;\r\n    text-align: center;\r\n    transition: all 200ms;\r\n    vertical-align: baseline;\r\n    white-space: wrap!important;\r\n}\r\n\r\n@media only screen and (max-width: 1000px) {\r\n    .button-2_achat, .button-2_achat-after-reset {\r\n        width: 95%;\r\n        height: 50px;\r\n    }\r\n}\r\n\r\n.newMessageClass {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #56BE50;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 45px;\r\n    bottom: 0px;\r\n    right: 0px;\r\n    left: 0px;\r\n    display: flex;\r\n    justify-content: center;\r\n    align-items: center;\r\n    text-align: center;\r\n}\r\n\r\n.MessageClassFormatnonReconnuTitre {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #FB5E2A;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    margin-top: -300px;\r\n    right: 0px;\r\n    text-align: center;\r\n    line-height: 15px;\r\n}\r\n\r\n.MessageClassFormatnonReconnu {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #ffffff;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    margin-top: -280px;\r\n    right: 0px;\r\n    text-align: center;\r\n    line-height: 15px;\r\n}\r\n\r\n.newButtonClass {\r\n    font-size: 12px; \r\n    font-weight: 500;\r\n    background-color: #ffffff00;\r\n    color: #717171;\r\n    height: 10px;\r\n    width: 100%; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 45px;\r\n    bottom: 0px;\r\n    text-align: center;\r\n    right:  50px;\r\n    line-height: 10px;\r\n    border-radius: 3px;\r\n    border: 0px solid #E8ECF1;\r\n}\r\n\r\n.linkClass {\r\n    width: 15px; \r\n    height: 15px;\r\n    margin-top: -310px;\r\n    margin-bottom: -25px;\r\n    margin-right: -50px;\r\n    position: relative;\r\n    top: 0; \r\n    z-index: 99;\r\n    display: block;\r\n    background-image: url('https:\/\/rdc.via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-blanc.jpg');\r\n    background-size: cover;\r\n}\r\n\r\n.newButtonClassVideo {\r\n    font-size: 12px; \r\n    font-weight: 500;\r\n    background-color: #ffffff00;\r\n    color: #717171;\r\n    height: 10px;\r\n    width: 100%; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 0px;\r\n    bottom: 0px;\r\n    right: 10px;\r\n    text-align: center;\r\n    line-height: 10px;\r\n    border-radius: 3px;\r\n    border: 0px solid #E8ECF1;\r\n}\r\n\r\n.linkClassVideo {\r\n    width: 15px; \r\n    height: 15px;\r\n    margin-top: -438px;\r\n    margin-bottom: -25px;\r\n    margin-right: -15px;\r\n    position: relative;\r\n    top: 0; \r\n    z-index: 99;\r\n    display: block;\r\n    background-image: url('https:\/\/rdc.via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-blanc.jpg');\r\n    background-size: cover;\r\n}\r\n\r\n.FinCampagneMobileClass .elementor-button,\r\n.DebutCampagneMobileClass .elementor-button,\r\n.FormSelectDevisesMobile .elementor-button,\r\n.HideFormButton .elementor-button {\r\n    display: none !important;\r\n}\r\n\r\n#drag_upload_file_achat {\r\n    margin: 0;\r\n    padding: 0;\r\n    position: relative;\r\n}\r\n\r\n.dot-container {\r\n    display: inline-block;\r\n}\r\n\r\n.dot {\r\n    opacity: 0;\r\n    transition: opacity 0.3s ease;\r\n}\r\n\r\n@keyframes firstDot {\r\n    0%, 100% { opacity: 0; }\r\n    10%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n@keyframes secondDot {\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 thirdDot {\r\n    0%, 40%, 100% { opacity: 0; }\r\n    50%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n.dot:nth-child(1) {\r\n    animation: firstDot 3s infinite;\r\n}\r\n\r\n.dot:nth-child(2) {\r\n    animation: secondDot 3s infinite;\r\n}\r\n\r\n.dot:nth-child(3) {\r\n    animation: thirdDot 3s infinite;\r\n}\r\n\r\n.droppable .elementor-field-type-checkbox .elementor-field-option {\r\n    display: flex;\r\n    flex-direction: row-reverse;\r\n    align-items: center;\r\n    gap: 8px;\r\n}\r\n\r\n.droppable .elementor-field-type-checkbox .elementor-field-option input[type=\"checkbox\"] {\r\n    width: 12px;\r\n    height: 12px;\r\n    min-width: 12px;\r\n    min-height: 12px;\r\n}\r\n\r\n\/* \u2705 Bouton \"R\u00e9server\" dynamique *\/\r\n.reserver-dynamic-container {\r\n    text-align: center;\r\n    margin-top: -7px;\r\n    margin-bottom: 15px;\r\n    padding: 5px 0;\r\n    transform: scale(1.4);\r\n    transform-origin: center top;\r\n    position: relative;\r\n    z-index: 200;\r\n}\r\n\r\n@media only screen and (min-width: 1001px) {\r\n    .reserver-dynamic-container {\r\n        transform: scale(1);\r\n        margin-top: -200px;\r\n        margin-bottom: 0;\r\n    }\r\n}\r\n\r\n.reserver-dynamic-option {\r\n    display: inline-flex;\r\n    flex-direction: row-reverse;\r\n    align-items: center;\r\n    gap: 8px;\r\n    cursor: pointer;\r\n    color: #213864;\r\n    background-color: #ffffff;\r\n    padding: 2px 4px;\r\n    border-radius: 6px;\r\n}\r\n\r\n.reserver-dynamic-checkbox {\r\n    width: 16px;\r\n    height: 16px;\r\n    min-width: 16px;\r\n    min-height: 16px;\r\n    cursor: pointer;\r\n    pointer-events: auto;\r\n}\r\n\r\n.reserver-dynamic-label {\r\n    cursor: pointer;\r\n    color: #213864;\r\n    font-size: 16px;\r\n    font-weight: 600;\r\n    user-select: none;\r\n}\r\n\r\n@media only screen and (max-width: 1000px) {\r\n    .reserver-dynamic-container {\r\n        transform: scale(0.98);\r\n        margin-bottom: 20px;\r\n        white-space: nowrap;\r\n        z-index: 300;\r\n        pointer-events: auto;\r\n    }\r\n    .reserver-dynamic-option {\r\n        padding-top: 0px;\r\n        padding-bottom: 0px;\r\n    }\r\n}\r\n\r\n\/* \u2705 v2.1.3 : DeplaceAnnonceText \/ DeplaceAnnonce \u2014 desktop uniquement *\/\r\n@media only screen and (min-width: 1001px) {\r\n    .DeplaceAnnonceText {\r\n        margin-top: -5px;\r\n        position: relative;\r\n        z-index: 201;\r\n    }\r\n    .DeplaceAnnonce {\r\n        margin-bottom: -150px;\r\n    }\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<div class=\"elementor-element elementor-element-54e4e530 e-con-full MsgFormatIncorrectConteneur elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"54e4e530\" data-element_type=\"container\" id=\"NotusedAnymore\">\n\t\t\t\t<div class=\"elementor-element elementor-element-531f3cb1 MsgFormatIncorrect elementor-widget__width-inherit elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"531f3cb1\" data-element_type=\"widget\" data-widget_type=\"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 format du fichier n&rsquo;est pas reconnu<\/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-3a352c3f elementor-hidden-desktop TexteMobile TexteMobileAnnonce elementor-widget elementor-widget-text-editor\" data-id=\"3a352c3f\" data-element_type=\"widget\" data-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 ou cliquer ici<br>pour t\u00e9l\u00e9charger une 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-7abb0aba elementor-hidden-desktop TexteMobileAjoutAnnonce elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"7abb0aba\" data-element_type=\"widget\" data-widget_type=\"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;\">Cliquer ici pour t\u00e9l\u00e9charger une annonce<\/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-68e2b2ca UploadIci elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"68e2b2ca\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ici glisser-d\u00e9poser ou t\u00e9l\u00e9charger une annonce<\/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-8d50d33 e-con-full e-flex e-con e-child\" data-id=\"8d50d33\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6ae6ef83 elementor-button-align-center elementor-widget__width-initial HideFormButton EspPubLienAnnonce elementor-widget-mobile__width-initial elementor-widget elementor-widget-form\" data-id=\"6ae6ef83\" data-element_type=\"widget\" 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_URL_annonce\" aria-label=\"Formulaire_URL_annonce\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249871\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"6ae6ef83\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-LienAnnonce elementor-col-100 elementor-sm-100 elementor-field-required\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-LienAnnonce\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tIci renseigner si n\u00e9cessaire le lien hypertexte de l\u2019annonce\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[LienAnnonce]\" id=\"form-field-LienAnnonce\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Ici renseigner si n\u00e9cessaire le lien hypertexte de l\u2019annonce\" 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-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=\"ButtonValidURLAnnonce\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-66fd4d36 e-con-full EnvoiUlterieurContainer e-flex e-con e-child\" data-id=\"66fd4d36\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4ea8e2b4 elementor-button-align-center elementor-widget__width-auto HideFormButton EnvoiUlterieur elementor-widget elementor-widget-form\" data-id=\"4ea8e2b4\" data-element_type=\"widget\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249871\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"4ea8e2b4\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-EnvoiUlterieur elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-EnvoiUlterieur\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tEnvoi diff\u00e9r\u00e9 de l'annonce\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=\"Envoi diff\u00e9r\u00e9 de l&#039;annonce\" id=\"form-field-EnvoiUlterieur-0\" name=\"form_fields[EnvoiUlterieur]\"> <label for=\"form-field-EnvoiUlterieur-0\">Envoi diff\u00e9r\u00e9 de l'annonce<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-4a59cf88 EnvoiUlterieurTexte elementor-widget elementor-widget-text-editor\" data-id=\"4a59cf88\" data-element_type=\"widget\" data-widget_type=\"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;\">Envoyer l\u2019annonce jusqu\u2019\u00e0 8 jours apr\u00e8s paiement<br>\nUn lien vous sera adress\u00e9 par <span style=\"color: #ffffff;\"><a style=\"color: #ffffff;\" 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<div class=\"elementor-element elementor-element-17d3ad0c e-con-full ReserverContainer e-flex e-con e-child\" data-id=\"17d3ad0c\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-177c9b71 elementor-button-align-center elementor-widget__width-auto HideFormButton ReserverBouton elementor-widget elementor-widget-form\" data-id=\"177c9b71\" data-element_type=\"widget\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249871\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"177c9b71\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-ReserverEspacePublicitaire elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-ReserverEspacePublicitaire\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tR\u00e9server cet espace publicitaire\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=\"R\u00e9server cet espace publicitaire\" id=\"form-field-ReserverEspacePublicitaire-0\" name=\"form_fields[ReserverEspacePublicitaire]\"> <label for=\"form-field-ReserverEspacePublicitaire-0\">R\u00e9server cet espace publicitaire<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-5bafe1f3 e-con-full AdUploadedTitle DeplaceAnnonce elementor-hidden-tablet elementor-hidden-mobile elementor-hidden-desktop e-flex e-con e-child\" data-id=\"5bafe1f3\" data-element_type=\"container\" id=\"DeplaceAnnonceId\">\n\t\t<div class=\"elementor-element elementor-element-432cc2a1 e-con-full DeplaceAnnonceSubContainer e-flex e-con e-child\" data-id=\"432cc2a1\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-446e8565 elementor-hidden-tablet elementor-hidden-mobile EspaceReserve elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"446e8565\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Espace r\u00e9serv\u00e9<br \/>Annonce transmise<\/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-60df49d0 elementor-hidden-tablet elementor-hidden-mobile DeplaceAnnonceText elementor-widget elementor-widget-text-editor\" data-id=\"60df49d0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tSi vous souhaitez un autre emplacement, vous pouvez d\u00e9placer cette annonce\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-62ef38f0 e-con-full e-flex e-con e-child\" data-id=\"62ef38f0\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f4f51cb elementor-hidden-tablet elementor-hidden-mobile PositionEspacePublicitaireDeplacer elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"f4f51cb\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Position<\/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-f214306 elementor-hidden-tablet elementor-hidden-mobile RefEspacePublicitaire elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"f214306\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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>\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-1c5a5ed5 e-con-full AdUploadedOverlay elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"1c5a5ed5\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4740d3e8 e-con-full OverlayHeader e-flex e-con e-child\" data-id=\"4740d3e8\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e964c6b elementor-hidden-tablet elementor-hidden-mobile OverlayRefEspace elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"e964c6b\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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-30eb836c OverlayCroixReset elementor-widget elementor-widget-image\" data-id=\"30eb836c\" data-element_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:\/\/via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-transparent.png\" 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-342c88b1 e-con-full OverlayPreviewZone e-flex e-con e-child\" data-id=\"342c88b1\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3c7e790f OverlayDeplaceTexte elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"3c7e790f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Si vous souhaitez un autre emplacement, vous pouvez d\u00e9placer cette annonce<\/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-51f00578 elementor-button-align-center elementor-widget__width-auto HideFormButton OverlayReserverForm elementor-widget elementor-widget-form\" data-id=\"51f00578\" data-element_type=\"widget\" id=\"Formulaire_Reserver_Overlay\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249871\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"51f00578\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-ReserverEspacePublicitaire elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-ReserverEspacePublicitaire\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tR\u00e9server cet espace publicitaire\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=\"R\u00e9server cet espace publicitaire\" id=\"form-field-ReserverEspacePublicitaire-0\" name=\"form_fields[ReserverEspacePublicitaire]\"> <label for=\"form-field-ReserverEspacePublicitaire-0\">R\u00e9server cet espace publicitaire<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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<\/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<\/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<div class=\"elementor-element elementor-element-deab21b e-flex e-con-boxed e-con e-parent\" data-id=\"deab21b\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ea61b46 e-transform elementor-widget elementor-widget-text-editor\" data-id=\"ea61b46\" data-element_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>L\u2019enjeu d\u00e9sormais est de capitaliser sur ces r\u00e9alisations en d\u00e9veloppant une nouvelle g\u00e9n\u00e9ration d\u2019infrastructures mettant ainsi en place les connexions n\u00e9cessaires au d\u00e9veloppement du corridor logistique naturel que constitue le Togo.<\/p>\n<p>Afin de d\u00e9velopper les \u00e9changes transfrontaliers et de stimuler sa croissance, le Togo, appuy\u00e9 par de solides partenaires, \u0153uvre \u00e0 la modernisation de trois axes strat\u00e9giques.<\/p>\n<p>Apr\u00e8s avoir achev\u00e9 il y a cinq ans la voie de contournement de la capitale, ainsi que les routes de la Pr\u00e9fecture d\u2019Ago\u00e8-Nyiv\u00e9, dans le nord de l\u2019agglom\u00e9ration, trois routes strat\u00e9giques sont en cours de modernisation. Les travaux sont pr\u00e9vus pour \u00eatre termin\u00e9s en 2022.&nbsp;<\/p>\n<p>Les travaux de la route nationale 2 (RN2) Lom\u00e9-Sanvee Condji Fre B\u00e9nin, vers l\u2019Est qui consistent en la construction d\u2019une chauss\u00e9e \u00e0 2&#215;2 voies sur 30 km avec un terre-plein central (TPC) pour fluidifier le trafic sur ce corridor r\u00e9gional majeur entre Abidjan et Lagos, mais aussi lutter contre l\u2019\u00e9rosion c\u00f4ti\u00e8re.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:paragraph --><\/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<div class=\"elementor-element elementor-element-83bdfe5 ToBeHidden e-flex e-con-boxed e-con e-child\" data-id=\"83bdfe5\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-eec56a5 e-con-full droppable e-flex e-con e-child\" data-id=\"eec56a5\" data-element_type=\"container\" id=\"Ele3A\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4289705 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"4289705\" data-element_type=\"widget\" data-widget_type=\"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=\"page\" data-elementor-id=\"83347\" class=\"elementor elementor-83347\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6442de91 e-con-full OrdiMobileConteneurClass e-flex e-con e-child\" data-id=\"6442de91\" data-element_type=\"container\" id=\"testIdTest\">\n\t\t\t\t<div class=\"elementor-element elementor-element-57de103 elementor-widget elementor-widget-text-editor\" data-id=\"57de103\" data-element_type=\"widget\" data-widget_type=\"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-249874 .elementor-element.elementor-element-6da64a60{--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;--justify-content:space-around;--align-items:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:50px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-6da64a60.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-45f807e0{--display:flex;--min-height:0px;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-100px;--margin-bottom:62px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:3;}.elementor-249874 .elementor-element.elementor-element-45f807e0.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-61dcced4{--display:flex;--margin-top:0px;--margin-bottom:-11px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-6c65b106{--display:flex;--margin-top:0px;--margin-bottom:-30px;--margin-left:-25px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-eb74aa8{--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-249874 .elementor-element.elementor-element-eb74aa8:not(.elementor-motion-effects-element-type-background), .elementor-249874 .elementor-element.elementor-element-eb74aa8 > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-1c762c45{--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;--flex-wrap:nowrap;--margin-top:-3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-5be6a53a{--display:flex;--align-items:flex-start;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249874 .elementor-element.elementor-element-5be6a53a.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-75917e71{--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-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-249874 .elementor-element.elementor-element-6be76773 > .elementor-widget-container{margin:38px 5px -38px -40px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-6be76773.elementor-element{--align-self:flex-start;}.elementor-249874 .elementor-element.elementor-element-6be76773{text-align:right;}.elementor-249874 .elementor-element.elementor-element-6be76773 img{width:17px;}.elementor-249874 .elementor-element.elementor-element-5ad25a69{--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-249874 .elementor-element.elementor-element-5ad25a69.e-con{--align-self:flex-end;}.elementor-249874 .elementor-element.elementor-element-52dec736 > .elementor-widget-container{margin:45px -18px -55px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-52dec736{z-index:101;text-align:right;}.elementor-249874 .elementor-element.elementor-element-469b1a7c{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-25px;--margin-bottom:90px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-469b1a7c:not(.elementor-motion-effects-element-type-background), .elementor-249874 .elementor-element.elementor-element-469b1a7c > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#9FC5F3;}.elementor-249874 .elementor-element.elementor-element-3f5f9124{--display:flex;--min-height:30px;--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;--justify-content:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:1px;--margin-bottom:-6px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:99;}.elementor-249874 .elementor-element.elementor-element-3f5f9124.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-48a37689{--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;--justify-content:flex-start;--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--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-249874 .elementor-element.elementor-element-4b68287 > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249874 .elementor-element.elementor-element-4b68287.elementor-element{--align-self:flex-start;}.elementor-249874 .elementor-element.elementor-element-4b68287{text-align:start;font-family:\"Roboto\", Sans-serif;font-size:12px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-79a46db6{--display:flex;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249874 .elementor-element.elementor-element-47d25f98 > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-47d25f98{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:18px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-3aa42503{--display:flex;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:flex-end;--align-items:flex-end;--margin-top:4px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-12d5dc39 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-12d5dc39.elementor-element{--align-self:flex-start;}.elementor-249874 .elementor-element.elementor-element-12d5dc39{text-align:end;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-21535e15{--display:flex;--justify-content:flex-start;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--flex-wrap:wrap;--margin-top:-2px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-21535e15.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-de420c1{--display:flex;--min-height:30px;--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-249874 .elementor-element.elementor-element-2f60f3f > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-2f60f3f.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-2f60f3f{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:500;line-height:1.1em;color:#FB5E2A;}.elementor-249874 .elementor-element.elementor-element-6b485447 > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-6b485447.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-6b485447{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-78e1d9f5{--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;--justify-content:center;--gap:010px 9px;--row-gap:010px;--column-gap:9px;--flex-wrap:wrap;--margin-top:-14px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:100;}.elementor-249874 .elementor-element.elementor-element-78e1d9f5.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-cf3602e{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-7a1bb33 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-7a1bb33.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-7a1bb33{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-6bf72a5{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-1a57dd9 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-1a57dd9.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-1a57dd9{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-34d8bbba{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-32bd35c6 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-32bd35c6.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-32bd35c6{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-5a9252c3{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-8722042 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-8722042.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-8722042{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-19ecc2b3{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-6071d405 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-6071d405.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-6071d405{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-3617569c{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-4b013e71 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-4b013e71.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-4b013e71{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-7450a6f8{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-30970f89 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-30970f89.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-30970f89{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-6aac67a6{--display:flex;--margin-top:-46px;--margin-bottom:-20px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:2;}.elementor-249874 .elementor-element.elementor-element-40d299c{width:100%;max-width:100%;}.elementor-249874 .elementor-element.elementor-element-40d299c.elementor-element{--align-self:flex-end;}.elementor-249874 .elementor-element.elementor-element-1fd15d20{width:100%;max-width:100%;}.elementor-249874 .elementor-element.elementor-element-1fd15d20.elementor-element{--align-self:flex-end;}.elementor-249874 .elementor-element.elementor-element-54e4e530{--display:flex;--justify-content:center;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249874 .elementor-element.elementor-element-531f3cb1{width:100%;max-width:100%;font-family:\"Roboto\", Sans-serif;font-size:10px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249874 .elementor-element.elementor-element-531f3cb1 > .elementor-widget-container{margin:-37px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-531f3cb1.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-3a352c3f > .elementor-widget-container{margin:7px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-3a352c3f.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-3a352c3f{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249874 .elementor-element.elementor-element-7abb0aba > .elementor-widget-container{margin:7px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-7abb0aba.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-7abb0aba{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249874 .elementor-element.elementor-element-68e2b2ca > .elementor-widget-container{margin:-110px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-68e2b2ca.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-68e2b2ca{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:18px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249874 .elementor-element.elementor-element-8d50d33{--display:flex;--margin-top:-85px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-8d50d33.e-con{--align-self:center;}.elementor-widget-form .elementor-field-group > label, .elementor-widget-form .elementor-field-subgroup label{color:var( --e-global-color-text );}.elementor-widget-form .elementor-field-group > label{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .elementor-field-type-html{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-widget-form .elementor-field-group .elementor-field{color:var( --e-global-color-text );}.elementor-widget-form .elementor-field-group .elementor-field, .elementor-widget-form .elementor-field-subgroup label{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .elementor-button{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-widget-form .e-form__buttons__wrapper__button-next{background-color:var( --e-global-color-accent );}.elementor-widget-form .elementor-button[type=\"submit\"]{background-color:var( --e-global-color-accent );}.elementor-widget-form .e-form__buttons__wrapper__button-previous{background-color:var( --e-global-color-accent );}.elementor-widget-form .elementor-message{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .e-form__indicators__indicator, .elementor-widget-form .e-form__indicators__indicator__label{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-widget-form{--e-form-steps-indicator-inactive-primary-color:var( --e-global-color-text );--e-form-steps-indicator-active-primary-color:var( --e-global-color-accent );--e-form-steps-indicator-completed-primary-color:var( --e-global-color-accent );--e-form-steps-indicator-progress-color:var( --e-global-color-accent );--e-form-steps-indicator-progress-background-color:var( --e-global-color-text );--e-form-steps-indicator-progress-meter-color:var( --e-global-color-text );}.elementor-widget-form .e-form__indicators__indicator__progress__meter{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-249874 .elementor-element.elementor-element-6ae6ef83{width:var( --container-widget-width, 75% );max-width:75%;--container-widget-width:75%;--container-widget-flex-grow:0;z-index:120;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group{padding-right:calc( 10px\/2 );padding-left:calc( 10px\/2 );margin-bottom:6px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-form-fields-wrapper{margin-left:calc( -10px\/2 );margin-right:calc( -10px\/2 );margin-bottom:-6px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label, .elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{color:#7B88A3;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-type-html{padding-bottom:0px;color:#7A7A7A;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field{color:#484848;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:01px 01px 01px 01px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:01px 01px 01px 01px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249874 .elementor-element.elementor-element-66fd4d36{--display:flex;--min-height:58px;--gap:0px 0px;--row-gap:0px;--column-gap:0px;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:8px 8px 8px 8px;--margin-top:12px;--margin-bottom:10px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249874 .elementor-element.elementor-element-66fd4d36.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4{width:auto;max-width:auto;z-index:120;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 > .elementor-widget-container{margin:2px 0px 2px 1px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label, .elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field{color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:600;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249874 .elementor-element.elementor-element-4a59cf88 > .elementor-widget-container{margin:-3px 0px -24px 0px;}.elementor-249874 .elementor-element.elementor-element-4a59cf88.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-4a59cf88{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-17d3ad0c{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;border-style:none;--border-style:none;--border-radius:8px 8px 8px 8px;--margin-top:-4px;--margin-bottom:05px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249874 .elementor-element.elementor-element-17d3ad0c.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-177c9b71{width:auto;max-width:auto;z-index:5;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 > .elementor-widget-container{margin:2px 0px 2px 1px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-177c9b71.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label, .elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{color:#000000;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field{color:#000000;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:16px;font-weight:600;line-height:1.1em;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249874 .elementor-element.elementor-element-5bafe1f3{--display:flex;--min-height:0px;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--gap:0px 0px;--row-gap:0px;--column-gap:0px;--overlay-opacity:1;--margin-top:230px;--margin-bottom:-220px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:10;}.elementor-249874 .elementor-element.elementor-element-5bafe1f3::before, .elementor-249874 .elementor-element.elementor-element-5bafe1f3 > .elementor-background-video-container::before, .elementor-249874 .elementor-element.elementor-element-5bafe1f3 > .e-con-inner > .elementor-background-video-container::before, .elementor-249874 .elementor-element.elementor-element-5bafe1f3 > .elementor-background-slideshow::before, .elementor-249874 .elementor-element.elementor-element-5bafe1f3 > .e-con-inner > .elementor-background-slideshow::before, .elementor-249874 .elementor-element.elementor-element-5bafe1f3 > .elementor-motion-effects-container > .elementor-motion-effects-layer::before{--background-overlay:'';background-size:cover;}.elementor-249874 .elementor-element.elementor-element-5bafe1f3.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-432cc2a1{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--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-249874 .elementor-element.elementor-element-446e8565 > .elementor-widget-container{margin:0px 3px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-446e8565.elementor-element{--align-self:flex-end;}.elementor-249874 .elementor-element.elementor-element-446e8565{z-index:5;text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249874 .elementor-element.elementor-element-60df49d0 > .elementor-widget-container{margin:35px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-60df49d0.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-60df49d0{z-index:5;text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:500;line-height:1.1em;color:#6185C0;}.elementor-249874 .elementor-element.elementor-element-62ef38f0{--display:flex;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:space-between;--align-items:flex-start;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-287px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-f4f51cb > .elementor-widget-container{margin:0px 3px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-f4f51cb.elementor-element{--align-self:flex-end;}.elementor-249874 .elementor-element.elementor-element-f4f51cb{z-index:5;text-align:left;font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249874 .elementor-element.elementor-element-f214306 > .elementor-widget-container{margin:0px 0px 0px 3px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-f214306.elementor-element{--align-self:flex-end;}.elementor-249874 .elementor-element.elementor-element-f214306{z-index:5;text-align:start;font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249874 .elementor-element.elementor-element-1c5a5ed5{--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;--justify-content:flex-start;--align-items:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--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-249874 .elementor-element.elementor-element-1c5a5ed5.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-4740d3e8{--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;--justify-content:space-between;--margin-top:5px;--margin-bottom:5px;--margin-left:010px;--margin-right:10px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-e964c6b > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-e964c6b.elementor-element{--align-self:flex-end;}.elementor-249874 .elementor-element.elementor-element-e964c6b{z-index:5;text-align:left;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249874 .elementor-element.elementor-element-30eb836c > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-30eb836c{z-index:101;text-align:right;}.elementor-249874 .elementor-element.elementor-element-342c88b1{--display:flex;--min-height:180px;--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;--justify-content:center;--align-items:center;--overflow:hidden;border-style:solid;--border-style:solid;border-width:4px 4px 4px 4px;--border-top-width:4px;--border-right-width:4px;--border-bottom-width:4px;--border-left-width:4px;border-color:#00FF19;--border-color:#00FF19;--border-radius:0px 0px 0px 0px;--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-249874 .elementor-element.elementor-element-342c88b1:not(.elementor-motion-effects-element-type-background), .elementor-249874 .elementor-element.elementor-element-342c88b1 > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-3c7e790f > .elementor-widget-container{padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-3c7e790f{font-family:\"Roboto\", Sans-serif;font-weight:500;color:#6185C0;}.elementor-249874 .elementor-element.elementor-element-51f00578{width:auto;max-width:auto;z-index:5;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249874 .elementor-element.elementor-element-51f00578 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-51f00578.elementor-element{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group > label, .elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{color:#000000;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field{color:#213864;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:15.5px;font-weight:600;line-height:1.1em;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249874 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249874 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249874 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249874 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-message.elementor-message-success{color:#00FF2700;}@media(max-width:1001px){.elementor-249874 .elementor-element.elementor-element-6ae6ef83{z-index:11;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-size:10px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4{z-index:11;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-size:10px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-177c9b71{z-index:11;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-size:10px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-button{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-51f00578{z-index:11;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-size:10px;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-button{font-size:12px;}}@media(min-width:1001px){.elementor-249874 .elementor-element.elementor-element-6da64a60{--width:500px;}.elementor-249874 .elementor-element.elementor-element-45f807e0{--width:100%;}.elementor-249874 .elementor-element.elementor-element-6c65b106{--width:500px;}.elementor-249874 .elementor-element.elementor-element-75917e71{--width:10px;}.elementor-249874 .elementor-element.elementor-element-5ad25a69{--width:100%;}.elementor-249874 .elementor-element.elementor-element-469b1a7c{--width:500px;}.elementor-249874 .elementor-element.elementor-element-48a37689{--width:22%;}.elementor-249874 .elementor-element.elementor-element-79a46db6{--width:50%;}.elementor-249874 .elementor-element.elementor-element-3aa42503{--width:22%;}.elementor-249874 .elementor-element.elementor-element-78e1d9f5{--width:100%;}.elementor-249874 .elementor-element.elementor-element-cf3602e{--width:103px;}.elementor-249874 .elementor-element.elementor-element-6bf72a5{--width:103px;}.elementor-249874 .elementor-element.elementor-element-34d8bbba{--width:103px;}.elementor-249874 .elementor-element.elementor-element-5a9252c3{--width:103px;}.elementor-249874 .elementor-element.elementor-element-19ecc2b3{--width:103px;}.elementor-249874 .elementor-element.elementor-element-3617569c{--width:103px;}.elementor-249874 .elementor-element.elementor-element-7450a6f8{--width:103px;}.elementor-249874 .elementor-element.elementor-element-8d50d33{--width:100%;}.elementor-249874 .elementor-element.elementor-element-66fd4d36{--width:390px;}.elementor-249874 .elementor-element.elementor-element-17d3ad0c{--width:100%;}.elementor-249874 .elementor-element.elementor-element-5bafe1f3{--width:150%;}.elementor-249874 .elementor-element.elementor-element-62ef38f0{--width:95%;}.elementor-249874 .elementor-element.elementor-element-1c5a5ed5{--width:100%;}.elementor-249874 .elementor-element.elementor-element-4740d3e8{--width:100%;}}@media(max-width:1000px){.elementor-249874 .elementor-element.elementor-element-6da64a60{--width:390px;--margin-top:105px;--margin-bottom:-75px;--margin-left:0px;--margin-right:0px;}.elementor-249874 .elementor-element.elementor-element-45f807e0{--min-height:150px;--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;--margin-top:-47px;--margin-bottom:-32px;--margin-left:0px;--margin-right:0px;--z-index:3;}.elementor-249874 .elementor-element.elementor-element-61dcced4{--width:25%;}.elementor-249874 .elementor-element.elementor-element-6c65b106{--width:100%;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:center;--align-items:center;--flex-wrap:nowrap;--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249874 .elementor-element.elementor-element-6c65b106.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-eb74aa8{--width:75%;--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:center;}.elementor-249874 .elementor-element.elementor-element-eb74aa8.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-1c762c45{--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249874 .elementor-element.elementor-element-6be76773 > .elementor-widget-container{margin:-3px 40px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-5ad25a69{--width:100%;--justify-content:flex-end;--align-items:flex-end;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249874 .elementor-element.elementor-element-52dec736 > .elementor-widget-container{margin:40px 55px -30px 0px;}.elementor-249874 .elementor-element.elementor-element-52dec736{z-index:100;}.elementor-249874 .elementor-element.elementor-element-469b1a7c{--width:78%;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--flex-wrap:nowrap;--margin-top:-103px;--margin-bottom:-7px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-469b1a7c.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-3f5f9124{--justify-content:center;--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249874 .elementor-element.elementor-element-48a37689{--width:25%;--margin-top:2px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-4b68287 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-4b68287{font-size:8px;}.elementor-249874 .elementor-element.elementor-element-79a46db6{--width:46%;--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-249874 .elementor-element.elementor-element-47d25f98 > .elementor-widget-container{margin:0px -20px 0px -20px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-47d25f98{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-3aa42503{--width:25%;--margin-top:4px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-12d5dc39 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-12d5dc39{font-size:7px;}.elementor-249874 .elementor-element.elementor-element-21535e15{--margin-top:-15px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249874 .elementor-element.elementor-element-de420c1{--min-height:15px;--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-249874 .elementor-element.elementor-element-2f60f3f{width:100%;max-width:100%;font-size:10px;}.elementor-249874 .elementor-element.elementor-element-2f60f3f > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-6b485447{width:100%;max-width:100%;font-size:10px;}.elementor-249874 .elementor-element.elementor-element-6b485447 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-78e1d9f5{--width:100%;--gap:6px 4px;--row-gap:6px;--column-gap:4px;--flex-wrap:wrap;--margin-top:-12px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249874 .elementor-element.elementor-element-cf3602e{--width:61px;--min-height:15px;}.elementor-249874 .elementor-element.elementor-element-7a1bb33{font-size:9px;}.elementor-249874 .elementor-element.elementor-element-6bf72a5{--width:61px;--min-height:15px;}.elementor-249874 .elementor-element.elementor-element-1a57dd9{font-size:9px;}.elementor-249874 .elementor-element.elementor-element-34d8bbba{--width:61px;--min-height:15px;}.elementor-249874 .elementor-element.elementor-element-32bd35c6{font-size:9px;}.elementor-249874 .elementor-element.elementor-element-5a9252c3{--width:61px;--min-height:15px;}.elementor-249874 .elementor-element.elementor-element-8722042{font-size:9px;}.elementor-249874 .elementor-element.elementor-element-19ecc2b3{--width:61px;--min-height:15px;}.elementor-249874 .elementor-element.elementor-element-6071d405{font-size:9px;}.elementor-249874 .elementor-element.elementor-element-3617569c{--width:61px;--min-height:15px;}.elementor-249874 .elementor-element.elementor-element-4b013e71{font-size:9px;}.elementor-249874 .elementor-element.elementor-element-7450a6f8{--width:61px;--min-height:15px;}.elementor-249874 .elementor-element.elementor-element-30970f89{font-size:9px;}.elementor-249874 .elementor-element.elementor-element-6aac67a6{--width:96%;--min-height:250px;--margin-top:-56px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-40d299c > .elementor-widget-container{margin:5px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-1fd15d20 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-54e4e530{--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249874 .elementor-element.elementor-element-54e4e530.e-con{--order:-99999 \/* order start hack *\/;}.elementor-249874 .elementor-element.elementor-element-531f3cb1 > .elementor-widget-container{margin:-30px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-3a352c3f > .elementor-widget-container{margin:-181px 0px 1px 0px;}.elementor-249874 .elementor-element.elementor-element-3a352c3f{text-align:center;font-size:10px;line-height:1.2em;}.elementor-249874 .elementor-element.elementor-element-7abb0aba > .elementor-widget-container{margin:-180px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-7abb0aba{text-align:center;font-size:14px;line-height:1.2em;}.elementor-249874 .elementor-element.elementor-element-68e2b2ca > .elementor-widget-container{margin:-110px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-68e2b2ca{font-size:10px;}.elementor-249874 .elementor-element.elementor-element-8d50d33{--width:184px;--margin-top:-156px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249874 .elementor-element.elementor-element-8d50d33.e-con{--align-self:center;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83{width:var( --container-widget-width, 100% );max-width:100%;--container-widget-width:100%;--container-widget-flex-grow:0;z-index:120;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-size:8px;}.elementor-249874 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-size:10.5px;}.elementor-249874 .elementor-element.elementor-element-66fd4d36{--width:85%;--min-height:42px;--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:center;--margin-top:10px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 > .elementor-widget-container{margin:2px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4{z-index:120;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-type-html{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-size:10px;}.elementor-249874 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-size:10.5px;}.elementor-249874 .elementor-element.elementor-element-4a59cf88 > .elementor-widget-container{margin:2px 0px -10px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-4a59cf88{font-size:7.5px;}.elementor-249874 .elementor-element.elementor-element-17d3ad0c{--width:85%;--min-height:42px;--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:center;--margin-top:2px;--margin-bottom:-20px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:251;}.elementor-249874 .elementor-element.elementor-element-177c9b71 > .elementor-widget-container{margin:2px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-177c9b71{z-index:120;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-type-html{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-177c9b71 .elementor-button{font-size:10.5px;}.elementor-249874 .elementor-element.elementor-element-5bafe1f3{--min-height:150px;--margin-top:-149px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249874 .elementor-element.elementor-element-446e8565 > .elementor-widget-container{margin:-133px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-446e8565.elementor-element{--align-self:flex-start;}.elementor-249874 .elementor-element.elementor-element-446e8565{text-align:left;font-size:10px;}.elementor-249874 .elementor-element.elementor-element-f4f51cb > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249874 .elementor-element.elementor-element-f4f51cb.elementor-element{--align-self:flex-start;}.elementor-249874 .elementor-element.elementor-element-f4f51cb{text-align:center;font-size:10px;}.elementor-249874 .elementor-element.elementor-element-f214306 > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249874 .elementor-element.elementor-element-f214306.elementor-element{--align-self:flex-start;}.elementor-249874 .elementor-element.elementor-element-f214306{text-align:center;font-size:10px;}.elementor-249874 .elementor-element.elementor-element-1c5a5ed5{--width:390px;--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-249874 .elementor-element.elementor-element-e964c6b > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249874 .elementor-element.elementor-element-e964c6b.elementor-element{--align-self:flex-start;}.elementor-249874 .elementor-element.elementor-element-e964c6b{text-align:center;font-size:10px;}.elementor-249874 .elementor-element.elementor-element-30eb836c > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-30eb836c{z-index:100;}.elementor-249874 .elementor-element.elementor-element-342c88b1{--min-height:112px;--margin-top:5px;--margin-bottom:5px;--margin-left:5px;--margin-right:5px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249874 .elementor-element.elementor-element-3c7e790f{text-align:center;font-size:15px;}.elementor-249874 .elementor-element.elementor-element-51f00578 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249874 .elementor-element.elementor-element-51f00578{z-index:120;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group > label{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-type-html{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-size:12px;}.elementor-249874 .elementor-element.elementor-element-51f00578 .elementor-button{font-size:10.5px;}}<\/style>\t\t<div data-elementor-type=\"loop-item\" data-elementor-id=\"249874\" class=\"elementor elementor-249874 elementor-bc-flex-widget e-loop-item e-loop-item-38623 post-38623 post type-post status-publish format-standard has-post-thumbnail hentry category-btp category-page-pays-only category-togo category-togo-btp generate-columns tablet-grid-50 mobile-grid-100 grid-parent grid-20\" data-elementor-post-type=\"elementor_library\" data-custom-edit-handle=\"1\">\n\t\t\t<div class=\"elementor-element elementor-element-6da64a60 e-con-full OrdiMobileConteneurClass e-flex e-con e-child\" data-id=\"6da64a60\" data-element_type=\"container\" id=\"testIdTest\">\n\t\t<div class=\"elementor-element elementor-element-45f807e0 e-con-full UploadFileConteneur AdUploadedTitle elementor-hidden-tablet elementor-hidden-mobile elementor-hidden-desktop e-flex e-con e-child\" data-id=\"45f807e0\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-61dcced4 e-con-full e-flex e-con e-child\" data-id=\"61dcced4\" data-element_type=\"container\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6c65b106 e-con-full e-flex e-con e-child\" data-id=\"6c65b106\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-eb74aa8 e-con-full e-flex e-con e-child\" data-id=\"eb74aa8\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1c762c45 e-con-full e-flex e-con e-child\" data-id=\"1c762c45\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5be6a53a e-con-full e-flex e-con e-child\" data-id=\"5be6a53a\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-75917e71 e-con-full e-flex e-con e-child\" data-id=\"75917e71\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6be76773 AnnonceDragIcone elementor-widget elementor-widget-image\" data-id=\"6be76773\" data-element_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\/2025\/05\/arrow-drag-64-bleu.png\" 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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5ad25a69 e-con-full CroixResetAnnonceContainer e-flex e-con e-child\" data-id=\"5ad25a69\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-52dec736 elementor-widget elementor-widget-image\" data-id=\"52dec736\" data-element_type=\"widget\" id=\"CroixResetAnnonce\" 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:\/\/via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-transparent.png\" 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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-469b1a7c e-con-full UploadFileConteneur e-flex e-con e-child\" data-id=\"469b1a7c\" data-element_type=\"container\" id=\"UploadFileConteneur\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-3f5f9124 e-con-full ChoisirEspacePublicitaireDisponibiliteConteneur e-flex e-con e-child\" data-id=\"3f5f9124\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-48a37689 e-con-full e-flex e-con e-child\" data-id=\"48a37689\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b68287 PositionEspacePublicitaire elementor-widget elementor-widget-text-editor\" data-id=\"4b68287\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPosition\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-79a46db6 e-con-full e-flex e-con e-child\" data-id=\"79a46db6\" data-element_type=\"container\" id=\"ChoixEspacePublicitaireTitre\">\n\t\t\t\t<div class=\"elementor-element elementor-element-47d25f98 elementor-widget elementor-widget-text-editor\" data-id=\"47d25f98\" data-element_type=\"widget\" id=\"ChoixEspacePublicitaireTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tChoix d&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-3aa42503 e-con-full e-flex e-con e-child\" data-id=\"3aa42503\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-12d5dc39 ReferenceEspacePublicitaire elementor-widget elementor-widget-text-editor\" data-id=\"12d5dc39\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-21535e15 e-con-full EspPubFormatMainContainer e-flex e-con e-child\" data-id=\"21535e15\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-de420c1 e-con-full e-flex e-con e-child\" data-id=\"de420c1\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2f60f3f elementor-widget-mobile__width-inherit SelectionFormatTitre elementor-widget elementor-widget-text-editor\" data-id=\"2f60f3f\" data-element_type=\"widget\" data-widget_type=\"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 s\u00e9lectionner un format d&rsquo;annonce<\/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-6b485447 elementor-widget-mobile__width-inherit elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile SelectionFormatTitreBlancOLD elementor-widget elementor-widget-text-editor\" data-id=\"6b485447\" data-element_type=\"widget\" data-widget_type=\"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 changer de format d&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-78e1d9f5 e-con-full EspPubFormatListe e-flex e-con e-child\" data-id=\"78e1d9f5\" data-element_type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-cf3602e e-con-full EspPubFormatContainer FormatIdCreation e-flex e-con e-child\" data-id=\"cf3602e\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7a1bb33 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"7a1bb33\" data-element_type=\"widget\" data-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\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-6bf72a5 e-con-full EspPubFormatContainer FormatIdPopUp e-flex e-con e-child\" data-id=\"6bf72a5\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1a57dd9 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"1a57dd9\" data-element_type=\"widget\" data-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-34d8bbba e-con-full EspPubFormatContainer FormatIdBanniere e-flex e-con e-child\" data-id=\"34d8bbba\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-32bd35c6 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"32bd35c6\" data-element_type=\"widget\" data-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-5a9252c3 e-con-full EspPubFormatContainer FormatIdVideo e-flex e-con e-child\" data-id=\"5a9252c3\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8722042 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"8722042\" data-element_type=\"widget\" data-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<a class=\"elementor-element elementor-element-19ecc2b3 e-con-full EspPubFormatContainer FormatIdCommunique e-flex e-con e-child\" data-id=\"19ecc2b3\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6071d405 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"6071d405\" data-element_type=\"widget\" data-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<a class=\"elementor-element elementor-element-3617569c e-con-full EspPubFormatContainer FormatIdInterview e-flex e-con e-child\" data-id=\"3617569c\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b013e71 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"4b013e71\" data-element_type=\"widget\" data-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-7450a6f8 e-con-full EspPubFormatContainer FormatIdParrainage e-flex e-con e-child\" data-id=\"7450a6f8\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-30970f89 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"30970f89\" data-element_type=\"widget\" data-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<div class=\"elementor-element elementor-element-6aac67a6 e-con-full HTMLUploadfileConteneur e-flex e-con e-child\" data-id=\"6aac67a6\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-40d299c elementor-widget__width-inherit HTMLUploadfileClass elementor-widget elementor-widget-html\" data-id=\"40d299c\" data-element_type=\"widget\" id=\"HTMLUploadfile\" 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=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <meta name=\"google\" content=\"notranslate\">\r\n    \r\n    <script data-jetpack-boost=\"ignore\" src=\"https:\/\/code.jquery.com\/jquery-3.6.0.min.js\"><\/script>\r\n    <script data-jetpack-boost=\"ignore\" src=\"https:\/\/code.jquery.com\/ui\/1.12.1\/jquery-ui.min.js\"><\/script>\r\n\r\n<script data-jetpack-boost=\"ignore\">\r\n\/\/ Lazy loading des biblioth\u00e8ques - charg\u00e9es uniquement au besoin\r\nwindow.VIALibraries = {\r\n    mammothLoaded: false,\r\n    pdfLoaded: false,\r\n    \r\n    loadMammoth: function(callback) {\r\n        if (this.mammothLoaded) { callback(); return; }\r\n        var script = document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/mammoth\/1.4.0\/mammoth.browser.min.js';\r\n        script.onload = function() { \r\n            window.VIALibraries.mammothLoaded = true; \r\n            callback(); \r\n        };\r\n        document.head.appendChild(script);\r\n    },\r\n    \r\n    loadPdfJs: function(callback) {\r\n        if (this.pdfLoaded) { callback(); return; }\r\n        var script = document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.11.174\/pdf.min.js';\r\n        script.onload = function() {\r\n            window.VIALibraries.pdfLoaded = true;\r\n            pdfjsLib.GlobalWorkerOptions.workerSrc = '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n            callback();\r\n        };\r\n        document.head.appendChild(script);\r\n    }\r\n};\r\n<\/script>\r\n\r\n<\/head>\r\n<body>\r\n    <div id=\"PopUpMessageAchattest\" class=\"draggable\" draggable=\"true\" style=\"justify-content: center; align-items: flex-start;\">\r\n        <div id=\"drop_file_zone_achat\" class=\"drop_file_zone_achat_class\" ondrop=\"uploadFile_achat(event)\" ondragover=\"return false\">\r\n        <div id=\"drag_upload_file_achat\">\r\n            <p><input class=\"button-2_achat\" type=\"button\" value=\"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\" onclick=\"fileExplorer_achat(event);\" \/><\/p>\r\n                <input type=\"file\" id=\"selectfile_achat\" \/>\r\n        <\/div>\r\n        <\/div>\r\n        <div class=\"img-content\"><\/div>\r\n    <\/div>\r\n<\/body>\r\n<\/html>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1fd15d20 elementor-widget__width-inherit HTMLUploadfileClass elementor-widget elementor-widget-html\" data-id=\"1fd15d20\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script data-jetpack-boost=\"ignore\">\r\nif (!window._espPubScriptLoaded) {\r\nwindow._espPubScriptLoaded = true;\r\n\/**\r\n * Configuration centralis\u00e9e\r\n *\/\r\nconst CONFIG = {\r\n    iframeId: 'yearbook-iframe',\r\n    ajaxUrl: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n    apercuUrl: 'https:\/\/rdc.yearbook-media.com\/apercu',\r\n    \r\n    allowedExtensions: {\r\n        video: ['mp4', 'mov', 'wmv', 'avi', 'flv', 'f4v', 'swf', 'mkv', 'webm', 'mpeg'],\r\n        image: ['jpg', 'jpeg', 'png', 'gif', 'tif', 'svg', 'webp'],\r\n        document: ['doc', 'docx', 'ppt', 'pptx', 'pdf']\r\n    },\r\n    \r\n    mimeTypes: {\r\n        docx: 'application\/vnd.openxmlformats-officedocument.wordprocessingml.document',\r\n        pdf: 'application\/pdf'\r\n    },\r\n    \r\n    dragScroll: {\r\n        threshold: 150,\r\n        maxSpeed: 65,\r\n        throttleDelay: 50\r\n    },\r\n    \r\n    breakpoints: {\r\n        mobile: 1000\r\n    },\r\n    \r\n    keywords: [\r\n        { normal: \"parrainage\", display: \"Parrainage\" },\r\n        { normal: \"communique\", display: \"Communiqu\u00e9\" },\r\n        { normal: \"interview\", display: \"Interview\" }\r\n    ]\r\n};\r\n\r\n\/**\r\n * \u2705 v1.19.1 : Module de positionnement dans l'iframe\r\n * \r\n * PROBL\u00c8ME : L'iframe ne scrolle pas en desktop \u2014 c'est le parent (#PageWebTitrePage) qui scrolle.\r\n * L'iframe est scal\u00e9e \u00e0 0.85 \u2192 les coordonn\u00e9es iframe \u2260 coordonn\u00e9es parent.\r\n * position:fixed dans l'iframe = relatif au CONTENU TOTAL, pas au viewport visible.\r\n * \r\n * SOLUTION : Le parent calcule visibleTopIframe (la position iframe du haut du viewport)\r\n * et l'envoie dans le message 'PageWebTitrePage-scroll'. L'iframe n'a qu'\u00e0 l'utiliser.\r\n * \r\n * Pour scroller, l'iframe envoie 'scrollToIframeY' au parent qui fait la conversion.\r\n *\/\r\nconst ScrollHelper = {\r\n    _visibleTopIframe: 0,\r\n    _iframeScale: 0.85,\r\n\r\n    init() {\r\n        \/\/ \u00c9couter les donn\u00e9es de scroll envoy\u00e9es par le parent\r\n        window.addEventListener('message', (event) => {\r\n            var msg = event.data;\r\n            if (msg && msg.action === 'PageWebTitrePage-scroll') {\r\n                if (typeof msg.visibleTopIframe === 'number') {\r\n                    this._visibleTopIframe = msg.visibleTopIframe;\r\n                }\r\n                if (typeof msg.iframeScale === 'number') {\r\n                    this._iframeScale = msg.iframeScale;\r\n                }\r\n            }\r\n        });\r\n        console.log('\u2705 ScrollHelper initialis\u00e9');\r\n    },\r\n\r\n    \/**\r\n     * Position Y dans le document iframe correspondant au haut du viewport visible\r\n     *\/\r\n    getVisibleTop() {\r\n        if (window === window.top) {\r\n            return window.scrollY || 0;\r\n        }\r\n        return this._visibleTopIframe;\r\n    },\r\n\r\n    \/**\r\n     * Demande au parent de scroller pour positionner `element` \u00e0 `offsetFromTop` px du viewport\r\n     *\/\r\n    scrollElementTo(element, offsetFromTop) {\r\n        if (!element) return;\r\n\r\n        \/\/ getBoundingClientRect().top dans une iframe sans scroll = position absolue Y\r\n        var elementAbsY = element.getBoundingClientRect().top;\r\n\r\n        if (window === window.top) {\r\n            window.scrollTo({ top: elementAbsY - offsetFromTop + (window.scrollY || 0), behavior: 'smooth' });\r\n            return;\r\n        }\r\n\r\n        \/\/ Envoyer au parent \u2014 le parent fait la conversion scale\r\n        window.parent.postMessage({\r\n            type: 'scrollToIframeY',\r\n            iframeId: CONFIG.iframeId,\r\n            iframeY: elementAbsY,\r\n            offsetFromTop: offsetFromTop\r\n        }, '*');\r\n        console.log('\ud83d\udcdc scrollToIframeY:', { iframeY: Math.round(elementAbsY), offsetFromTop });\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'\u00e9tat (SessionStorage)\r\n *\/\r\nconst StateManager = {\r\n    init() {\r\n        if (sessionStorage.getItem(\"AchatEspaceCall\") === 'No') {\r\n            sessionStorage.clear();\r\n        }\r\n        \r\n        this.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        this.set('dragstart_Rank_Emplacement_Page_Web', 'No');\r\n        this.set('dragstart_Commande_Emplacement_Page_Web', 'No');\r\n        \r\n        \/\/ \u2705 v2.1.1 : Popup \u2192 ne jamais pr\u00e9remplir le format\r\n        if (this.get('PopUpChoice') === 'Yes') {\r\n            this.set('Formatchoisi', 'No');\r\n            this.set('FormatSelect', '');\r\n            this.set('Commande_Format_Transmis', '');\r\n        }\r\n    },\r\n    \r\n    get(key) {\r\n        return sessionStorage.getItem(key);\r\n    },\r\n    \r\n    set(key, value) {\r\n        sessionStorage.setItem(key, value);\r\n    },\r\n    \r\n    getMultiple(keys) {\r\n        return keys.reduce((acc, key) => {\r\n            acc[key] = this.get(key);\r\n            return acc;\r\n        }, {});\r\n    },\r\n    \r\n    setMultiple(obj) {\r\n        Object.entries(obj).forEach(([key, value]) => {\r\n            this.set(key, value);\r\n        });\r\n    },\r\n    \r\n    buildEmplacementReference(rank) {\r\n        const codeSite = this.get('codeSite');\r\n        const codePage = this.get('codePage');\r\n        return `${codeSite}${codePage}L${rank.substring(3)}`;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des fichiers\r\n *\/\r\nconst FileManager = {\r\n    getExtension(filename) {\r\n        console.log('filename:', filename);\r\n        const parts = filename.split('.');\r\n        return parts.length > 1 ? parts.pop().toLowerCase() : '';\r\n    },\r\n    \r\n    isAllowedExtension(extension) {\r\n        return Object.values(CONFIG.allowedExtensions)\r\n            .flat()\r\n            .includes(extension);\r\n    },\r\n    \r\n    getFileType(extension) {\r\n        for (const [type, extensions] of Object.entries(CONFIG.allowedExtensions)) {\r\n            if (extensions.includes(extension)) {\r\n                return type;\r\n            }\r\n        }\r\n        return null;\r\n    },\r\n    \r\n    async urlToFile(url, filename) {\r\n        console.log(\"Fetching from URL:\", url);\r\n        \r\n        const mimeType = filename.includes('.docx') \r\n            ? CONFIG.mimeTypes.docx \r\n            : filename.includes('.pdf') \r\n            ? CONFIG.mimeTypes.pdf \r\n            : null;\r\n        \r\n        try {\r\n            const response = await fetch(url);\r\n            \r\n            if (!response.ok) {\r\n                throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`);\r\n            }\r\n            \r\n            const blob = await response.blob();\r\n            return new File([blob], filename, { type: mimeType });\r\n        } catch (error) {\r\n            console.error(\"Error in urlToFile:\", error);\r\n            alert(\"Erreur lors du chargement du fichier. Veuillez r\u00e9essayer.\");\r\n            throw error;\r\n        }\r\n    },\r\n    \r\n    createObjectUrl(file) {\r\n        \/\/ R\u00e9voquer l'ancien URL si existant\r\n        const oldUrl = StateManager.get('objectUrl');\r\n        if (oldUrl && oldUrl.startsWith('blob:')) {\r\n            URL.revokeObjectURL(oldUrl);\r\n            console.log('\ud83d\uddd1\ufe0f Old Object URL revoked');\r\n        }\r\n        \r\n        const url = URL.createObjectURL(file);\r\n        StateManager.set('objectUrl', url);\r\n        return url;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion du Drag & Drop\r\n *\/\r\nconst DragDropManager = {\r\n    state: {\r\n        isFileBeingDragged: false,\r\n        draggedFile: null,\r\n        dragInProgress: false,\r\n        throttleTimeout: null\r\n    },\r\n    \r\n    init() {\r\n        this.attachEventListeners();\r\n    },\r\n    \r\n    attachEventListeners() {\r\n        window.addEventListener('dragstart', (e) => this.handleDragStart(e), true);\r\n        jQuery(document).on('dragover', (e) => this.handleDragOver(e));\r\n        jQuery(document).on('dragleave drop', (e) => this.handleDragEnd(e));\r\n        jQuery(\"#drop_file_zone_achat\").on(\"dragover\", (e) => this.handleDropZoneDragOver(e));\r\n        jQuery(\".draggable\").on(\"dragend\", (e) => this.handleDraggableEnd(e));\r\n    },\r\n    \r\n    handleDragStart(e) {\r\n        console.log('Window-level dragstart', e);\r\n        this.state.dragInProgress = true;\r\n    \r\n        const $target = $(e.target);\r\n        const droppableParent = $target.closest('.droppable');\r\n        const parentId = droppableParent.length ? droppableParent.attr('id') : null;\r\n        \r\n        StateManager.set('dragstart_Rank_Emplacement_Page_Web', parentId);\r\n        console.log('dragstart_Rank_Emplacement_Page_Web', parentId);\r\n        \r\n        \/\/ \u2705 CALCULER IMM\u00c9DIATEMENT dragstart_Commande_Emplacement_Page_Web\r\n        if (parentId) {\r\n            const dragstartRef = StateManager.buildEmplacementReference(parentId);\r\n            StateManager.set('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n            console.log('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n            \/\/ \u2705 v2.4.5 : Capturer l'\u00e9tat checkbox R\u00e9server au moment du dragstart\r\n            \/\/ Si l'utilisateur a explicitement d\u00e9coch\u00e9, forcer \u00e0 No m\u00eame si DOM est coch\u00e9\r\n            var $_dragCb = $('#' + parentId).find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n            var _dragCbChecked = $_dragCb.prop('checked') === true;\r\n            var _expliciteDecocheDrag = StateManager.get('_reserverDecoche_' + parentId) === 'Yes';\r\n            var _reserverDrag = _dragCbChecked && !_expliciteDecocheDrag;\r\n            StateManager.set('dragstart_ReserverChecked', _reserverDrag ? 'Yes' : 'No');\r\n            \/\/ R\u00e9initialiser le flag apr\u00e8s lecture\r\n            StateManager.set('_reserverDecoche_' + parentId, 'No');\r\n            console.log('[dragstart] ReserverChecked dom:', _dragCbChecked, '| d\u00e9coch\u00e9 explicitement:', _expliciteDecocheDrag, '| final:', _reserverDrag);\r\n        }\r\n    \r\n        const dataTransfer = e.dataTransfer || e.originalEvent?.dataTransfer;\r\n        const files = dataTransfer?.files || null;\r\n        \r\n        const imgSrc = $target.closest('.draggable').find('img').attr('src');\r\n        const videoSrc = $target.closest('.draggable').find('video').attr('src') || \r\n                        $target.closest('.draggable').find('video source').attr('src');\r\n        const mediaSrc = imgSrc || videoSrc;\r\n    \r\n        console.log('dragstart target:', e.target);\r\n        console.log('files:', files);\r\n        console.log('mediaSrc:', mediaSrc);\r\n    \r\n        if (!mediaSrc && (!files || files.length === 0)) {\r\n            console.log('No media source or files found, preventing drag');\r\n            e.preventDefault();\r\n            this.state.dragInProgress = false;\r\n            return false;\r\n        }\r\n    \r\n        if (mediaSrc) {\r\n            StateManager.set('objectUrl', mediaSrc);\r\n        }\r\n    \r\n        StateManager.set('Commande_Format_Transmis', '');\r\n        \r\n        if ($target.closest('.droppable').find('.doc-preview-container:visible').length > 0) {\r\n            StateManager.set('Commande_Format_Transmis', 'R\u00e9dactionnel');\r\n            StateManager.set('FullPathAdFile', \r\n                $target.closest('.droppable').find('.doc-preview-FullPathAdFile').text());\r\n        }\r\n    \r\n        if (files && files.length > 0) {\r\n            this.state.isFileBeingDragged = true;\r\n            this.state.draggedFile = files[0];\r\n        }\r\n        \r\n        \/\/ \u2705 TOUJOURS marquer comme \"Moved\" quand on drag depuis un espace existant\r\n        if (parentId && mediaSrc) {\r\n            StateManager.set('FirstUploadFileorMoved', 'Moved');\r\n            console.log('\u2705 Drag depuis espace existant - Moved');\r\n        }\r\n    \r\n        console.log('Drag Started', {\r\n            file: this.state.draggedFile,\r\n            mediaSrc: mediaSrc,\r\n            dragstartRef: StateManager.get('dragstart_Commande_Emplacement_Page_Web')\r\n        });\r\n    },\r\n    \r\n    handleDragOver(e) {\r\n        e.preventDefault();\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            this.handleIframeDragScroll(e);\r\n        } else {\r\n            this.handleDirectPageScroll(e);\r\n        }\r\n    },\r\n    \r\n    handleIframeDragScroll(e) {\r\n        if (!this.state.throttleTimeout) {\r\n            this.state.throttleTimeout = setTimeout(() => {\r\n                MessageManager.sendToParent('dragScroll', { clientY: e.clientY });\r\n                this.state.throttleTimeout = null;\r\n            }, CONFIG.dragScroll.throttleDelay);\r\n        }\r\n    },\r\n    \r\n    handleDirectPageScroll(e) {\r\n        const { threshold, maxSpeed } = CONFIG.dragScroll;\r\n        const windowHeight = window.innerHeight;\r\n        \r\n        if (e.clientY < threshold) {\r\n            const speed = Math.max(1, maxSpeed * (1 - e.clientY \/ threshold));\r\n            window.scrollBy(0, -speed);\r\n        } else if (e.clientY > windowHeight - threshold) {\r\n            const speed = Math.max(1, maxSpeed * (1 - (windowHeight - e.clientY) \/ threshold));\r\n            window.scrollBy(0, speed);\r\n        }\r\n    },\r\n    \r\n    handleDragEnd(e) {\r\n        e.preventDefault();\r\n        MessageManager.sendToParent('dragEnd', {});\r\n        console.log('dragleave drop');\r\n    },\r\n    \r\n    handleDropZoneDragOver(e) {\r\n        e.preventDefault();\r\n        console.log(\"FirstUploadFileorMoved:\", StateManager.get('FirstUploadFileorMoved'));\r\n    },\r\n    \r\n    handleDraggableEnd(e) {\r\n        e.preventDefault();\r\n        this.resetState();\r\n        console.log('dragend');\r\n    },\r\n    \r\n    resetState() {\r\n        this.state.isFileBeingDragged = false;\r\n        this.state.draggedFile = null;\r\n        this.state.dragInProgress = false;\r\n    },\r\n    \r\n    clearDataTransferFiles(e) {\r\n        e.dataTransfer = new DataTransfer();\r\n        console.log('DataTransfer files cleared');\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'interface utilisateur\r\n *\/\r\nconst UIManager = {\r\n    isMobile() {\r\n        return window.outerWidth < CONFIG.breakpoints.mobile;\r\n    },\r\n    \r\n    isDesktop() {\r\n        const userAgent = navigator.userAgent;\r\n        const isWindows = userAgent.indexOf('Windows') > -1;\r\n        const isMac = userAgent.indexOf('Macintosh') > -1;\r\n        const isLinux = userAgent.indexOf('Linux') > -1 && userAgent.indexOf('Android') === -1;\r\n        return isWindows || isMac || isLinux;\r\n    },\r\n    \r\n    initMobileUI() {\r\n        $(document).ready(() => {\r\n            $('label[for=\"form-field-LienAnnonce\"]').each(function() {\r\n                $(this).text('Renseigner le lien hypertexte de l\\'annonce');\r\n            });\r\n            \r\n            $('input[name=\"form_fields[LienAnnonce]\"]').each(function() {\r\n                $(this).attr('placeholder', 'Renseigner le lien hypertexte de l\\'annonce');\r\n            });\r\n        });\r\n        \r\n        jQuery('.MsgDatesText').hide();\r\n        this.attachMobileEventListeners();\r\n    },\r\n    \r\n    attachMobileEventListeners() {\r\n        jQuery('.TransmettreFichierAnnonceContainer').on('click', (e) => {\r\n            this.handleMobileSpaceSelection(e);\r\n        });\r\n        \r\n        jQuery('[id=\"form-field-selected_currency_Mobile\"]').off('change').on('change', (e) => {\r\n            this.handleMobileCurrencyChange(e);\r\n        });\r\n    },\r\n    \r\n    handleMobileSpaceSelection(e) {\r\n        e.preventDefault();\r\n        jQuery('#IndisponibilitesMsg').hide();\r\n        \r\n        jQuery('input[name=\"form_fields[SelectEspacePublicitaireMobile]\"]').prop('checked', false);\r\n        jQuery(e.currentTarget).find('input[name=\"form_fields[SelectEspacePublicitaireMobile]\"]').prop('checked', true);\r\n        \r\n        StateManager.set(\"PageWebDisplayed\", 'Yes');\r\n        \r\n        jQuery('.FormSelectDevisesMobile').hide();\r\n        jQuery(e.target).closest('.EspacePublicitaireMobile').find('.FormSelectDevisesMobile').show();\r\n        \r\n        const $droppable = jQuery(e.currentTarget).closest('.droppable');\r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', rankId);\r\n        StateManager.set('Commande_Emplacement_Page_Web', \r\n            StateManager.buildEmplacementReference(rankId));\r\n        \r\n        this.updateEmplacementDisplay();\r\n        this.handleAvailabilityDisplay(e);\r\n        this.displayUploadedAdIfExists(e);\r\n        this.updateTariffDisplay(e);\r\n    },\r\n    \r\n    updateEmplacementDisplay() {\r\n        const emplacement = StateManager.get('Commande_Emplacement_Page_Web');\r\n        jQuery('#EmplacementAnnonceDataStep3').html(emplacement).css({'color': '#56BE50'});\r\n        console.log(\"Emplacement:\", emplacement);\r\n    },\r\n    \r\n    handleAvailabilityDisplay(e) {\r\n        const $espace = jQuery(e.target).closest('.EspacePublicitaireMobile');\r\n        const dispoText = $espace.find('.ChoisirEspacePublicitaireDisponibilite').text();\r\n        \r\n        if (dispoText.length > 46) {\r\n            const espacePublicitaireDispoFrom = dispoText.slice(-10);\r\n            console.log(\"espacePublicitaireDispoFrom:\", espacePublicitaireDispoFrom);\r\n            console.log(\"Date de debut:\", StateManager.get(\"Debut_de_campagne\"));\r\n        } else {\r\n            jQuery('#form-field-DebutCampagne').val(StateManager.get(\"Debut_de_campagne\"));\r\n        }\r\n    },\r\n    \r\n    displayUploadedAdIfExists(e) {\r\n        if (StateManager.get(\"FileReceived\") === 'Yes') {\r\n            jQuery('.VisualisationAnnonceMobile').hide();\r\n            \r\n            const espaceId = StateManager.get('espaceChoisi');\r\n            const $espace = document.querySelector(`[id=\"${espaceId}\"]`);\r\n            \r\n            jQuery($espace).find('.MessageAnnonceMobileTexte')\r\n                .html('Merci de choisir des dates de campagne<br>afin d\\'obtenir le tarif de cet espace publicitaire');\r\n            jQuery($espace).find('.VisualisationAnnonceMobile').show();\r\n        \r\n            const img = document.createElement('img');\r\n            img.src = StateManager.get('objectUrl');\r\n            img.style.width = 'auto';\r\n            img.style.height = 'auto';\r\n            img.style.maxWidth = '100%';\r\n            img.style.maxHeight = '200px';\r\n            \r\n            jQuery('.VisualisationAnnonceMobile').empty();\r\n            jQuery($espace).find('.VisualisationAnnonceMobile').append(img);\r\n        }\r\n    },\r\n    \r\n    updateTariffDisplay(e) {\r\n        jQuery('.TariftobedisplayedMobile').html('-');\r\n        const newTarif = StateManager.get('NewTarifformatted');\r\n        \r\n        if (newTarif && newTarif !== '-') {\r\n            jQuery(e.target).closest('.EspacePublicitaireMobile')\r\n                .find('.TariftobedisplayedMobile')\r\n                .html(newTarif);\r\n        }\r\n    },\r\n    \r\n    handleMobileCurrencyChange(e) {\r\n        event.preventDefault();\r\n        StateManager.setMultiple({\r\n            \"SelectionCatalogueOuAchat\": 'Catalogue',\r\n            \"selected_currency\": jQuery(e.currentTarget).val()\r\n        });\r\n        \r\n        jQuery('#form-field-selected_currency_2').val(StateManager.get(\"selected_currency\"));\r\n        console.log(\"selected currency:\", StateManager.get(\"selected_currency\"));\r\n        \r\n        setTimeout(() => {\r\n            jQuery(e.target).closest('.EspacePublicitaireMobile')\r\n                .find('.TariftobedisplayedMobile')\r\n                .html(StateManager.get(\"NewTarifformatted\"));\r\n        }, 500);\r\n    },\r\n    \r\n    initDesktopUI() {\r\n        StateManager.setMultiple({\r\n            \"FileReceived\": \"No\",\r\n            \"AdDisplayed\": \"No\"\r\n        });\r\n        jQuery('.MsgAdNotDisplayed').hide();\r\n    },\r\n    \r\n    showUploadProgress($dropZone) {\r\n        \/\/ Cacher les \u00e9l\u00e9ments\r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .TexteMobileAnnonce')\r\n            .hide();\r\n        \r\n        \/\/ Afficher et styler le message de progression\r\n        var _uplMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed')\r\n            .show()\r\n            .html(_uplMsg)\r\n            .css({\r\n                'color': '#00ff19',\r\n                'background-color': 'white',\r\n                'padding': '12px 20px',\r\n                'border-radius': '6px',\r\n                'font-weight': '700',\r\n                'font-size': '18px',\r\n                'line-height': '1.4',\r\n                'display': 'inline-block',\r\n                'margin': '10px auto',\r\n                'text-align': 'center'\r\n            });\r\n        \r\n        \/\/ Cacher les autres \u00e9l\u00e9ments\r\n        $dropZone.closest('.droppable')\r\n            .find('.UploadIci, .EnvoiUlterieurTexte, .EnvoiUlterieurContainer')\r\n            .hide();\r\n            \r\n        $dropZone.closest('.droppable')\r\n            .find('.UploadFileConteneur')\r\n            .css({\r\n                'background-color': 'transparent'\r\n            });\r\n    },\r\n    \r\n    showFormatError($dropZone, message = 'Format de fichier incompatible') {\r\n        \/\/ \u2705 v2.4.6 : M\u00eame rendu overlay que le bloc jpeg \u2014 position absolute sur $dropZone\r\n        var _errId = 'fmt-error-msg-' + Date.now();\r\n        $dropZone.css('position', 'relative');\r\n        var _errHtml = '<div id=\"' + _errId + '\" style=\"'\r\n            + 'position:absolute;top:50px;left:50%;transform:translateX(-50%);width:auto;white-space:nowrap;'\r\n            + 'background:#fff;color:#FB5E2A;font-weight:700;font-size:13px;'\r\n            + 'text-align:center;padding:8px 10px;border-radius:6px;'\r\n            + 'border:2px solid #FB5E2A;box-sizing:border-box;'\r\n            + 'z-index:99999;line-height:1.4;'\r\n            + '\">' + message + '<\/div>';\r\n        $dropZone.append(_errHtml);\r\n        setTimeout(function() { jQuery('#' + _errId).remove(); }, 4000);\r\n    },\r\n    \r\n    updateAfterSuccessfulUpload($dropZone) {\r\n        jQuery('#errorMessageMobileText').hide();\r\n        \r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 Pas de margin-top:150px si d\u00e9p\u00f4t depuis miniature kit (d\u00e9j\u00e0 positionn\u00e9)\r\n        if (!window._dropFromMiniature) {\r\n            $dropZone.closest('.OrdiMobileConteneurClass')\r\n                .css({'margin-top': '150px', 'margin-bottom': '0px'});\r\n        }\r\n    },\r\n    \r\n    finalizeAdDisplay($dropZone) {\r\n        StateManager.setMultiple({\r\n            \"FileReceived\": \"Yes\",\r\n            \"PageWebDisplayed\": \"Yes\"\r\n        });\r\n        \r\n        jQuery('#MsgChoixPageWeb, #MsgInsererAnnonceConteneur').hide();\r\n        jQuery('#ChoixEspacePublicitaire')\r\n            .html('L\\'annonce est plac\u00e9e dans un espace publicitaire')\r\n            .show()\r\n            .css({'color': '#56BE50'});\r\n        \r\n        jQuery('#MsgPlacerAnnoncePosition').hide();\r\n        jQuery('#FonctionMenu4').show();\r\n        jQuery('.AnnonceData').html(\"Transmis\").css({'color': '#56BE50'});\r\n        \r\n        jQuery('#ProcederPaiementConteneur').hide();\r\n        jQuery('#ProcederPaiementTitreIconeUp').hide();\r\n        jQuery('#ProcederPaiementTitreIconeDown').show();\r\n        \r\n        jQuery('#message').remove();\r\n        \r\n        this.styleUploadedAd($dropZone);\r\n        this.adjustLayoutAfterUpload($dropZone);\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox \"R\u00e9server\" apr\u00e8s upload\r\n        FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n    },\r\n    \r\n    styleUploadedAd($dropZone) {\r\n        const $container = $dropZone.closest('.OrdiMobileConteneurClass');\r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \r\n        \/\/ \u2705 v1.19.5 : V\u00e9rifier si c'est une restauration via flag d\u00e9di\u00e9\r\n        const isRestoration = StateManager.get('_isAdRestoration') === 'Yes';\r\n        \r\n        $container\r\n            .find('.PositionReference, .TexteMobile, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        $container\r\n            .find('.AdUploadedTitle, .DimensionsMaximales')\r\n            .show();\r\n        \r\n        \/\/ \u2705 Bug 2 fix : montrer le conteneur parent + la croix (CroixResetAnnonceContainer cach\u00e9 par reset)\r\n        $droppable.find('.CroixResetAnnonceContainer').show();\r\n        $droppable.find('#CroixResetAnnonce').show();\r\n        \r\n        \/\/ \u2705 v2.2 : Marquer le droppable comme occup\u00e9 pour qu'Entete le skip\r\n        $droppable.attr('data-via-ad-loaded', 'true');\r\n        \r\n        \/\/ \u2705 v2.0.11 : AdUploadedTitle ne doit pas bloquer le touch sur doc-preview-readmore (mobile)\r\n        $container.find('.AdUploadedTitle').css('pointer-events', 'none');\r\n        \r\n        \/\/ \u2705 #CroixResetAnnonce au-dessus de tous les conteneurs superpos\u00e9s\r\n        $container.find('#CroixResetAnnonce').css({\r\n            'position': 'relative',\r\n            'z-index': '9999'\r\n        });\r\n        \r\n        \/\/ \u2705 Desktop : les conteneurs superpos\u00e9s bloquent la croix \u2014 les rendre transparents aux clics\r\n        if (!UIManager.isMobile()) {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css('pointer-events', 'none');\r\n            \/\/ R\u00e9activer les \u00e9l\u00e9ments interactifs\r\n            $container.find('#CroixResetAnnonce').css('pointer-events', 'auto');\r\n            $dropZone.closest('#PopUpMessageAchattest').css('pointer-events', 'auto'); \/\/ drag annonce\r\n        }\r\n        \r\n        \/\/ \u2705 v2.4.3 : Sur mobile, masquer titre et logo drag quand annonce d\u00e9pos\u00e9e dans Ele0A\r\n        if (UIManager.isMobile()) {\r\n            if ($droppable.attr('id') === 'Ele0A') {\r\n                $droppable.find('#ChoixEspacePublicitaireTexte').hide();\r\n                $droppable.find('#Ele0ADragHandle').hide();\r\n                \/\/ \u2705 v2.4.12 : UploadFileConteneur a pointer-events:none \u2192 forcer auto sur la croix\r\n                $droppable.find('.CroixResetAnnonceContainer')[0] && $droppable.find('.CroixResetAnnonceContainer')[0].style.setProperty('pointer-events', 'auto', 'important');\r\n                $droppable.find('#CroixResetAnnonce')[0] && $droppable.find('#CroixResetAnnonce')[0].style.setProperty('pointer-events', 'auto', 'important');\r\n            }\r\n        }\r\n        \r\n        jQuery(\".HTMLUploadfileConteneur\").css({\r\n            'border': 'none',\r\n            'background-color': 'transparent'\r\n        });\r\n        \r\n        \/\/ \u2705 v2.4.12 : Retirer le liser\u00e9 envoi diff\u00e9r\u00e9 (#UploadFileConteneur) si pr\u00e9sent\r\n        \/\/ (le d\u00e9p\u00f4t d'une annonce cr\u00e9e son propre liser\u00e9 sur .HTMLUploadfileConteneur)\r\n        var $_ufcEd = $dropZone.closest('.droppable').find('#UploadFileConteneur');\r\n        if ($_ufcEd[0]) {\r\n            $_ufcEd[0].style.removeProperty('box-shadow');\r\n            $_ufcEd[0].style.removeProperty('box-sizing');\r\n            if (UIManager.isMobile()) {\r\n                $_ufcEd[0].style.removeProperty('transform');\r\n                $_ufcEd[0].style.removeProperty('transform-origin');\r\n            }\r\n        }\r\n        \r\n        $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n            'box-shadow': 'inset 0 0 0 2px #00FF19',  \/\/ \u2705 v2.4.5 : inset \u2192 jamais clipp\u00e9 par overflow:hidden\r\n            'background-color': 'white',\r\n            'box-sizing': 'border-box',\r\n            'overflow': 'hidden'\r\n        });\r\n        \r\n        \/\/ \u2705 v2.0.9 : Fix mobile \u2014 r\u00e9duire le scale pour que le liser\u00e9 vert soit visible\r\n        \/\/ \u2705 Pas de scale si annonce d\u00e9pos\u00e9e depuis la miniature kit (d\u00e9j\u00e0 aux bonnes dimensions)\r\n        \/\/ \u2705 v2.4.9 : Pas de scale si AchatEspaceCall=Yes (drop depuis miniature dans iframe)\r\n        \/\/ \u2705 data-kit-drop : marqueur DOM pos\u00e9 par kitAdCreated, r\u00e9siste \u00e0 l'async\r\n        var _fromKitDrop = $droppable[0] ? $droppable[0].getAttribute('data-kit-drop') === 'true' : false;\r\n        if (_fromKitDrop) { window._dropFromMiniature = true; } \/\/ sync le flag window\r\n        var _fromMiniature = window._dropFromMiniature || _fromKitDrop;\r\n        var _fromAchat = StateManager.get('AchatEspaceCall') === 'Yes';\r\n        if (UIManager.isMobile() && !_fromMiniature && !_fromAchat) {\r\n            $dropZone.closest('.UploadFileConteneur').css({\r\n                'transform': 'scale(1.35)',\r\n                'transform-origin': 'top center'\r\n            });\r\n            \/\/ \u2705 v2.4.11 : Corps de page mobile \u2014 le .ToBeHidden clippe le scale(1.35) c\u00f4t\u00e9 droit\r\n            \/\/ \u2192 overflow:visible pour que le liser\u00e9 vert soit visible sur les 4 c\u00f4t\u00e9s\r\n            $dropZone.closest('.ToBeHidden').css('overflow', 'visible');\r\n        }\r\n        \r\n        \/\/ \u2705 v2.2 : Sur restauration, Entete a d\u00e9j\u00e0 positionn\u00e9 le droppable correctement\r\n        \/\/ et est emp\u00each\u00e9 de le retoucher (data-via-ad-loaded). On ne touche pas aux marges.\r\n        \/\/ Sur premier upload, on applique les marges normalement.\r\n        \/\/ \u2705 Pas de marges si d\u00e9p\u00f4t depuis miniature kit (dimensions naturelles conserv\u00e9es)\r\n        if (!isRestoration && !_fromMiniature) {\r\n            if ($container.data('orig-mb') === undefined) {\r\n                $container.data('orig-mb', parseInt($container.css('margin-bottom')) || 0);\r\n            }\r\n            if ($droppable.data('orig-mt') === undefined) {\r\n                $droppable.data('orig-mt', parseInt($droppable.css('margin-top')) || 0);\r\n            }\r\n            var _isDocPreview = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _marginAdd = _isDocPreview ? 60 : 130;\r\n            var _marginReduce = _isDocPreview ? 60 : 130;\r\n            $container.css({\r\n                'margin-bottom': ($container.data('orig-mb') + _marginAdd) + 'px'\r\n            });\r\n            $droppable.css({\r\n                'margin-top': ($droppable.data('orig-mt') - _marginReduce + 75) + 'px'\r\n            });\r\n        } else {\r\n            \/\/ \u2705 Sur restauration, ajouter 50px en dessous pour \u00e9viter que le contenu soit trop coll\u00e9\r\n            var _curMb = parseInt($container.css('margin-bottom')) || 0;\r\n            $container.css('margin-bottom', (_curMb + 50) + 'px');\r\n        }\r\n        \r\n        \/\/ \u2705 Masquer .PositionEspacePublicitaireContainer et l'ancien .ReserverContainer\r\n        $droppable.find('.PositionEspacePublicitaireContainer').hide();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        \/\/ \u2705 Supprimer tout ancien bouton dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 v2.1.2 : Cr\u00e9er le bouton R\u00e9server m\u00eame lors d'une restauration\r\n        if (isRestoration) {\r\n            console.log('\ud83d\udd04 Restauration d\u00e9tect\u00e9e - affichage bouton R\u00e9server + DeplaceAnnonce');\r\n            $droppable.find('.DeplaceAnnonce').show();\r\n            \/\/ S'assurer que FileReceived est d\u00e9fini pour la validation\r\n            StateManager.set('FileReceived', 'Yes');\r\n            \/\/ Cocher automatiquement SEULEMENT si c'est une restauration de commande r\u00e9serv\u00e9e (pas pendingAd)\r\n            var _isPendingAdRestore = sessionStorage.getItem('_pendingAdRestoration') === 'Yes';\r\n            if (!_isPendingAdRestore) {\r\n                var _isReservedRestore = sessionStorage.getItem('_isReservedRestoration') === 'Yes';\r\n                setTimeout(function() {\r\n                    var $checkbox = $droppable.find('.reserver-dynamic-checkbox');\r\n                    if ($checkbox.length && _isReservedRestore) {\r\n                        $checkbox.prop('checked', true);\r\n                        $droppable.find('.reserver-dynamic-label').text('Espace publicitaire r\u00e9serv\u00e9').css('color', 'rgb(62, 170, 19)');\r\n                        console.log('\u2705 R\u00e9server coch\u00e9 automatiquement (restauration commande r\u00e9serv\u00e9e)');\r\n                    }\r\n                    sessionStorage.removeItem('_isReservedRestoration');\r\n                    StateManager.set('_isAdRestoration', 'No');\r\n                    \/\/ \u2705 v2.4.7 : updateReserverCheckboxState APR\u00c8S avoir coch\u00e9 la checkbox\r\n                    \/\/ (l'appel synchrone ligne 614 intervient avant le cocher \u2192 label incorrect)\r\n                    if (typeof FormatUIManager !== 'undefined') {\r\n                        FormatUIManager.updateReserverCheckboxState($droppable);\r\n                    }\r\n                }, 150);\r\n            } else {\r\n                \/\/ pendingAd : ne pas cocher, ne pas envoyer au parent\r\n                console.log('\u2705 pendingAd restaur\u00e9 \u2014 R\u00e9server NON coch\u00e9');\r\n                sessionStorage.removeItem('_pendingAdRestoration');\r\n                StateManager.set('_isAdRestoration', 'No');\r\n            }\r\n        }\r\n        \r\n        \/\/ \u2705 Supprimer tout bouton R\u00e9server existant avant insertion (\u00e9vite doublons sur restauration)\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 Cr\u00e9er le bouton \"R\u00e9server\" dynamique avec id unique pour \u00e9viter conflit label\/for Elementor\r\n        const _rankId = $droppable.attr('id') || ('drop_' + Date.now());\r\n        const _cbId = 'reserver-cb-' + _rankId;\r\n        const reserverHTML = `\r\n            <div class=\"reserver-dynamic-container\">\r\n                <span class=\"reserver-dynamic-option\">\r\n                    <input type=\"checkbox\" id=\"${_cbId}\" value=\"R\u00e9server cet espace publicitaire\" \r\n                           class=\"reserver-dynamic-checkbox\"\r\n                           name=\"form_fields[ReserverEspacePublicitaire]\">\r\n                    <span class=\"reserver-dynamic-label\">R\u00e9server cet espace publicitaire<\/span>\r\n                <\/span>\r\n            <\/div>\r\n        `;\r\n        \r\n        \/\/ \u2705 Ins\u00e9rer juste avant .DeplaceAnnonceText (position stable)\r\n        const $anchor = $droppable.find('.DeplaceAnnonceText');\r\n        if ($anchor.length) {\r\n            $anchor.before(reserverHTML);\r\n            $anchor.prev('.reserver-dynamic-container').css('margin-bottom', '-40px');\r\n            if (!UIManager.isMobile()) {\r\n                $anchor.prev('.reserver-dynamic-container').find('.reserver-dynamic-label').css({'font-size': '20px', 'font-weight': '700'});\r\n            }\r\n        } else {\r\n            $droppable.after(reserverHTML);\r\n            const $btn = $droppable.next('.reserver-dynamic-container');\r\n            $btn.css('margin-top', UIManager.isMobile() ? '-10px' : '-140px');\r\n        }\r\n        \r\n        console.log('\u2705 Bouton \"R\u00e9server\" dynamique cr\u00e9\u00e9');\r\n    },\r\n    \r\n    adjustLayoutAfterUpload($dropZone) {\r\n        console.log('\ud83d\udcf1 adjustLayoutAfterUpload \u2014 isMobile():', this.isMobile(), 'outerWidth:', window.outerWidth);\r\n        if (this.isMobile()) {\r\n            this.adjustMobileLayout($dropZone);\r\n            \r\n            \/\/ Repositionner le bouton R\u00e9server APR\u00c8S les ajustements de layout\r\n            setTimeout(() => {\r\n                const $droppable = $dropZone.closest('.droppable');\r\n                const $btn = $droppable.find('.reserver-dynamic-container').add($droppable.next('.reserver-dynamic-container')).first();\r\n                const $lisere = $droppable.find('.HTMLUploadfileConteneur');\r\n                if ($btn.length && $lisere.length) {\r\n                    const lisereBottom = $lisere[0].getBoundingClientRect().bottom;\r\n                    const btnTop = $btn[0].getBoundingClientRect().top;\r\n                    const offset = lisereBottom - btnTop - 48;\r\n                    \r\n                    \/\/ 15px suppl\u00e9mentaires pour homepage et articles\r\n                    let extraOffset = 0;\r\n                    const isHomepage = window.location.pathname === \"\/\" || window.location.pathname === \"\/en\/\";\r\n                    const isSectorPage = $('body').hasClass('page');\r\n                    if (isHomepage) {\r\n                        extraOffset = 13;\r\n                    }\r\n                    if (!isSectorPage) {\r\n                        extraOffset = 15;\r\n                    }\r\n                    \r\n                    \/\/ \u2705 v2.0.9 : +4px pour documents (communiqu\u00e9\/interview\/PDF) avec pr\u00e9sentation HTML\r\n                    if ($droppable.find('.doc-preview-container:visible').length > 0) {\r\n                        extraOffset += 4;\r\n                    }\r\n                    \r\n                    $btn.css({\r\n                        'margin-top': (offset + extraOffset + 20) + 'px',\r\n                        'margin-bottom': (-(offset + extraOffset) - 100) + 'px'\r\n                    });\r\n                    console.log('\ud83d\udcd0 Repositionnement mobile R\u00e9server:', { lisereBottom, btnTop, offset });\r\n                }\r\n            }, 50);\r\n        } else {\r\n            this.adjustDesktopLayout($dropZone);\r\n        }\r\n    },\r\n    \r\n    adjustMobileLayout($dropZone) {\r\n        console.log('\ud83d\udcf1 adjustMobileLayout START');\r\n        console.log('\ud83d\udcf1 AchatEspaceCall:', StateManager.get(\"AchatEspaceCall\"));\r\n        console.log('\ud83d\udcf1 PageAjoutModifAnnonce:', StateManager.get(\"PageAjoutModifAnnonce\"));\r\n        console.log('\ud83d\udcf1 window===window.top:', window === window.top);\r\n        console.log('\ud83d\udcf1 pathname:', location.pathname);\r\n        \r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \r\n        \/\/ \u2705 v2.4.3 : Masquer les textes position\/label\/r\u00e9f\u00e9rence (comme sur desktop)\r\n        $droppable\r\n            .find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 v2.6 : Renseigner .PositionEspacePublicitaire sur mobile (manquait vs desktop)\r\n        (function() {\r\n            var _rankPosMob = StateManager.get('Rank_Emplacement_Page_Web') || $droppable.attr('id') || '';\r\n            var _posLibMob = PreviewRenderer._getPositionLibelle(_rankPosMob);\r\n            if (_posLibMob) {\r\n                $droppable\r\n                    .find('.PositionEspacePublicitaire')\r\n                    .text(_posLibMob)\r\n                    .each(function() {\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        \/\/ \u2705 Scop\u00e9 au $dropZone courant (\u00e9vite d'affecter les autres espaces pub)\r\n        $dropZone.closest('.droppable').find('#CroixResetAnnonce').css({'zoom': '75%'});\r\n\r\n        \/\/ \u2705 v2.4.3 : Remonter la croix reset sur mobile (override margin-top Elementor)\r\n        \/\/ \u2705 v2.4.5 : Poser aussi margin-right ici (Entete.txt ne l'atteint pas pour Ele0A)\r\n        var _croixContainer = $dropZone.closest('.OrdiMobileConteneurClass').find('.CroixResetAnnonceContainer')[0];\r\n        if (_croixContainer) {\r\n            var _isEle0ACroix = ($dropZone.closest('.droppable').attr('id') === 'Ele0A');\r\n            var _mtCroix = StateManager.get(\"PageAjoutModifAnnonce\") === 'Yes' ? '-88px' : '24px';\r\n            \/\/ Ele0A : +40px vers le bas, +15px vers la gauche (margin-right) par rapport \u00e0 Ele1A\r\n            \/\/ Ele0A : margin-top identique aux autres espaces (pas de d\u00e9calage suppl\u00e9mentaire)\r\n            _croixContainer.style.setProperty('margin-top', _mtCroix, 'important');\r\n            _croixContainer.style.setProperty('margin-right', _isEle0ACroix ? '17px' : '12px', 'important');\r\n        }\r\n        \r\n        var _isMiniatureAdj = window._dropFromMiniature;\r\n        window._dropFromMiniature = false;\r\n\r\n        if (_isMiniatureAdj && window.outerWidth <= 1000) {\r\n            \/\/ \u2705 Miniature doc-preview MOBILE : ajuster HTMLUploadfileConteneur \u00e0 la hauteur du contenu\r\n            \/\/ et neutraliser tous les margins Elementor qui d\u00e9calent le $dropZone hors du parent\r\n            var _isDocPreviewMob = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _docH = _isDocPreviewMob ? 144 : 115;\r\n            $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                'height':     _docH + 'px',\r\n                'min-height': _docH + 'px',\r\n                'max-height': _docH + 'px',\r\n                'margin-top': '-55px',\r\n                'margin-bottom': '0px',\r\n                'overflow': 'hidden'\r\n            });\r\n            $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px', 'height': (_docH - 6) + 'px'});\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '65px', 'margin-bottom': '-10px'});\r\n            \/\/ \u2705 v2.4.9 : Doc-preview \u2014 overflow:visible pour que le liser\u00e9 du haut ne soit pas clipp\u00e9\r\n            if (_isDocPreviewMob) {\r\n                $dropZone.closest('.OrdiMobileConteneurClass').css('overflow', 'visible');\r\n                $dropZone.closest('.OrdiMobileConteneurClass').parent().css('overflow', 'visible');\r\n            }\r\n            \/\/ \u2705 v2.4.9 : Ele0A popup mobile \u2014 neutraliser translateY(-32px) pos\u00e9 par Entete sur EnvoiUlterieurTexte\r\n            var _isEle0AMob = ($dropZone.closest('.droppable').attr('id') === 'Ele0A');\r\n            if (_isEle0AMob) {\r\n                var $_euTxt = $dropZone.closest('.droppable').find('.EnvoiUlterieurTexte');\r\n                if ($_euTxt[0]) {\r\n                    $_euTxt[0].style.setProperty('transform', 'translateY(0px)', 'important');\r\n                    $_euTxt[0].style.setProperty('margin-top', '0px', 'important');\r\n                }\r\n            }\r\n            \/\/ \u2705 v2.4.12 : AchatEspaceCall=Yes \u2192 override margins (m\u00eame correction que pour upload direct)\r\n            if (StateManager.get('AchatEspaceCall') === 'Yes') {\r\n                $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px'});\r\n                var _docHAchatMini = _isDocPreviewMob ? 150 : 112;\r\n                $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                    'margin-top': '70px',\r\n                    'margin-bottom': '35px',\r\n                    'min-height': _docHAchatMini + 'px',\r\n                    'height': _isDocPreviewMob ? _docHAchatMini + 'px' : '',\r\n                    'max-height': _isDocPreviewMob ? _docHAchatMini + 'px' : ''\r\n                });\r\n                console.log('\ud83d\udcf1 [miniature] AchatEspaceCall=Yes OVERRIDE: mt=70px | docPreview:', _isDocPreviewMob);\r\n            }\r\n            return;\r\n        }\r\n        \/\/ \u2705 v2.4.10 : Miniature DESKTOP \u2192 layout normal appliqu\u00e9 ci-dessous\r\n        if (_isMiniatureAdj) {\r\n            \/\/ Pas de overflow:hidden \u2014 le liser\u00e9 box-shadow inset doit rester visible\r\n        }\r\n\r\n        $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n            'min-height': '112px',\r\n            'margin-top': '-85px',\r\n            \/\/ \u2705 v2.4.10 : Miniature desktop \u2014 pas de margin-bottom excessif qui fait grandir le droppable\r\n            'margin-bottom': _isMiniatureAdj ? '0px' : '20px' \/\/ \u2705 v2.6 : 195px \u2192 59px \u2192 20px (\u00f73) espace sous checkbox R\u00e9server\r\n        });\r\n        console.log('\ud83d\udcf1 HTMLUploadfileConteneur margins set: mt=-85px mb=20px, el found:', $dropZone.closest('.HTMLUploadfileConteneur').length);\r\n        \r\n        $dropZone.css({\r\n            'margin-top': '-50px',\r\n            'margin-bottom': '-140px'\r\n        });\r\n        \r\n        $dropZone.closest('.OrdiMobileConteneurClass').css({\r\n            'margin-top': '65px',\r\n            'margin-bottom': '-10px'\r\n        });\r\n        console.log('\ud83d\udcf1 OrdiMobile margins set: mt=65px mb=-10px');\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            \/\/ \u2705 v2.4.12 : Reset $dropZone margins (les -50px\/-140px tirent le contenu vers le haut dans l'iframe)\r\n            \/\/ Pour doc-preview (Communiqu\u00e9\/Interview), la hauteur est plus grande \u2192 ajuster min-height\r\n            var _isDocPreviewAchat = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _docHAchat = _isDocPreviewAchat ? 150 : 112;\r\n            $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px'});\r\n            $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                \/\/ \u2705 v2.4.13 : Miniature desktop \u2192 +40px suppl\u00e9mentaires pour compenser le d\u00e9calage\r\n                'margin-top': _isMiniatureAdj ? '110px' : '70px',\r\n                'margin-bottom': '35px',\r\n                'min-height': _docHAchat + 'px',\r\n                'height': _isDocPreviewAchat ? _docHAchat + 'px' : '',\r\n                'max-height': _isDocPreviewAchat ? _docHAchat + 'px' : ''\r\n            });\r\n            console.log('\ud83d\udcf1 AchatEspaceCall=Yes OVERRIDE: mt=' + (_isMiniatureAdj ? '110px' : '70px') + ' | docPreview:', _isDocPreviewAchat, '| h:', _docHAchat);\r\n        }\r\n        \r\n        if (location.pathname === '\/annonce' || location.pathname === '\/annonce\/') {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '70px'});\r\n        }\r\n        \r\n        if (window === window.top) {\r\n            console.log('\ud83d\udcf1 window===window.top OVERRIDE droppable margins');\r\n            $dropZone.closest('.droppable').css({\r\n                'margin-top': '-100px',\r\n                'margin-bottom': '-100px'\r\n            });\r\n            $dropZone.closest('#UploadFileConteneur').css({'width': '80%'});\r\n        }        \r\n    },\r\n    \r\n    adjustDesktopLayout($dropZone) {\r\n        const emplacement = StateManager.get('Commande_Emplacement_Page_Web');\r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \/\/ \u2705 v2.4.13 : Lire et resetter _dropFromMiniature ici aussi (desktop)\r\n        var _fromMiniatureDesktop = window._dropFromMiniature || ($droppable[0] ? $droppable[0].getAttribute('data-kit-drop') === 'true' : false);\r\n        window._dropFromMiniature = false;\r\n        \/\/ \u2705 Nettoyer data-kit-drop apr\u00e8s lecture\r\n        if ($droppable[0]) { $droppable[0].removeAttribute('data-kit-drop'); }\r\n        \r\n        \/\/ \u2705 Masquer les textes enfants (position, label, r\u00e9f\u00e9rence) sans toucher au conteneur\r\n        $droppable\r\n            .find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur > div > .elementor-widget-text-editor')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 +15px sur .droppable \u2014 sauf si drop depuis miniature (dimensions naturelles)\r\n        if (!_fromMiniatureDesktop) {\r\n            const currentMt = parseInt($droppable.css('margin-top')) || 0;\r\n            $droppable.css('margin-top', (currentMt + 15) + 'px');\r\n        } else {\r\n            \/\/ \u2705 v2.4.13 : Drop depuis miniature Kit \u2014 d\u00e9caler de 30px vers le bas\r\n            const currentMt = parseInt($droppable.css('margin-top')) || 0;\r\n            \/\/ \u2705 Homepage : -20px (annonce trop basse sur r\u00e9gie) \u2014 autres pages : +70px\r\n            var _mtOffsetMini = (window.location.pathname === '\/' || window.location.pathname === '\/en\/' || window.location.pathname === '\/fr\/') ? -20 : 70;\r\n            $droppable.css('margin-top', (currentMt + _mtOffsetMini) + 'px');\r\n        }\r\n        \r\n        $dropZone.closest('.OrdiMobileConteneurClass')\r\n            .find('.RefEspacePublicitaire')\r\n            .html(emplacement)\r\n            .attr('id', 'RefEspacePublicitaire')\r\n            .each(function() {\r\n                \/\/ \u2705 Forcer aussi le parent .DeplaceAnnonce visible (display:none !important inline)\r\n                var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                this.style.setProperty('display', 'block', 'important');\r\n            });\r\n        \/\/ \u2705 v2.4.5 : Renseigner et afficher .PositionEspacePublicitaire\r\n        (function() {\r\n            var _rankPos = StateManager.get('Rank_Emplacement_Page_Web') || $droppable.attr('id') || '';\r\n            var _posLib = PreviewRenderer._getPositionLibelle(_rankPos);\r\n            if (_posLib) {\r\n                $dropZone.closest('.OrdiMobileConteneurClass')\r\n                    .find('.PositionEspacePublicitaireDeplacer')\r\n                    .text(_posLib)\r\n                    .each(function() {\r\n                        var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                        if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        if (window.location.pathname === \"\/\" || window.location.pathname === \"\/en\/\") {\r\n            \/\/ \u2705 v2.4.10 : top selon contexte \u2014 espaces hors .remainingContent d\u00e9calent de 60px, ceux dedans de 20px\r\n            var _inRemainingContent = $dropZone.closest('.remainingContent').length > 0;\r\n            var _topOffsetHP = _inRemainingContent ? '20px' : '100px';\r\n            $dropZone.closest('.ToBeHidden')\r\n                .css('top', _topOffsetHP)\r\n                .css('min-height', '300px');\r\n            \/\/ NB : pas de overflow:hidden ici \u2014 le liser\u00e9 vert (box-shadow inset sur HTMLUploadfileConteneur)\r\n            \/\/ doit rester visible sur les 4 c\u00f4t\u00e9s\r\n        }\r\n        \r\n        \/\/ \u2705 Toutes pages desktop : rendre le parent du droppable non-clippant\r\n        \/\/ Le bouton R\u00e9server est ins\u00e9r\u00e9 apr\u00e8s .droppable avec margin-top n\u00e9gatif \u2014\r\n        \/\/ overflow:hidden sur le parent Elementor le masque sinon.\r\n        $droppable.parent().css('overflow', 'visible');\r\n        \r\n        if (location.pathname === '\/annonce' || location.pathname === '\/annonce\/') {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '0px'});\r\n        }\r\n    }\r\n};\r\n\r\n\/**\r\n * \u2705 Module de gestion des formats et du titre .SelectionFormatTitre\r\n *\/\r\nconst FormatUIManager = {\r\n    \r\n    \/**\r\n     * V\u00e9rifie si un format est s\u00e9lectionn\u00e9 dans un espace publicitaire\r\n     * V\u00e9rifie le background-color OU le sessionStorage (format venant de l'accord\u00e9on)\r\n     *\/\r\n    hasSelectedFormat($element) {\r\n        const $droppable = $element.closest('.droppable');\r\n        const isEle0A = $droppable.attr('id') === 'Ele0A';\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            if (isEle0A) {\r\n                \/\/ \u2705 v2.3.4 : Ele0A popup \u2014 vrai seulement si un format sous-jacent (hors FormatIdPopUp) est s\u00e9lectionn\u00e9\r\n                var _hasDomFmt = $droppable.find('.EspPubFormatContainer').not('.FormatIdPopUp').toArray().some(el => {\r\n                    return $(el).css('background-color') === 'rgb(255, 255, 255)';\r\n                });\r\n                if (_hasDomFmt) return true;\r\n                \/\/ \u2705 v2.4.5 : Fallback sessionStorage \u2014 DOM pas encore mis \u00e0 jour (timing MutationObserver)\r\n                return !!sessionStorage.getItem('FormatSelect');\r\n            }\r\n            \/\/ Autres espaces en mode popup \u2192 toujours vrai\r\n            return true;\r\n        }\r\n        const hasWhiteBg = $droppable.find('.EspPubFormatContainer').toArray().some(el => {\r\n            return $(el).css('background-color') === 'rgb(255, 255, 255)';\r\n        });\r\n        if (hasWhiteBg) return true;\r\n        \/\/ \u2705 v1.16.0 : Fallback sessionStorage Formatchoisi\r\n        if (sessionStorage.getItem('Formatchoisi') === 'Yes') return true;\r\n        \/\/ \u2705 v2.4.5 : Fallback FormatSelect \u2014 cas du chargement initial avec format d\u00e9j\u00e0 s\u00e9lectionn\u00e9\r\n        \/\/ (Formatchoisi peut \u00eatre remis \u00e0 No au chargement, mais FormatSelect persiste)\r\n        if (sessionStorage.getItem('FormatSelect')) return true;\r\n        \/\/ \u2705 v2.4.9 : Fallback _FormatSelectApplied \u2014 survit au clear de yearbook-media.js init\r\n        return !!sessionStorage.getItem('_FormatSelectApplied');\r\n    },\r\n    \r\n    \/**\r\n     * Met \u00e0 jour la couleur du titre .SelectionFormatTitre\r\n     * Blanc si un format est s\u00e9lectionn\u00e9, rouge #FB5E2A sinon\r\n     *\/\r\n    updateTitleColor($droppable) {\r\n        \/\/ \u2705 v2.4.5 : Ele0A \u2014 ne jamais afficher SelectionFormatTitre\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes' && $droppable.attr('id') === 'Ele0A') {\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n            return;\r\n        }\r\n\r\n        if (this.hasSelectedFormat($droppable)) {\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n            console.log('\u2705 SelectionFormatTitreBlanc affich\u00e9 (format s\u00e9lectionn\u00e9)');\r\n        } else {\r\n            $droppable.find('.SelectionFormatTitre').show();\r\n            $droppable.find('.SelectionFormatTitreBlanc').hide();\r\n            console.log('\u26a0\ufe0f SelectionFormatTitre affich\u00e9 (aucun format s\u00e9lectionn\u00e9)');\r\n        }\r\n    },\r\n    \r\n    \/**\r\n     * Flash visuel sur le titre pour indiquer qu'un format est requis\r\n     *\/\r\n    flashTitle($element) {\r\n        const $droppable = $element.closest('.droppable');\r\n        const $titre = $droppable.find('.SelectionFormatTitre');\r\n        if (!$titre.length) return;\r\n        \r\n        \/\/ Flash rouge rapide 3 fois\r\n        let count = 0;\r\n        const originalColor = $titre.css('color');\r\n        \r\n        const flash = setInterval(() => {\r\n            $titre.css('color', count % 2 === 0 ? '#FF0000' : '#FB5E2A');\r\n            count++;\r\n            if (count >= 6) {\r\n                clearInterval(flash);\r\n                $titre.css('color', '#FB5E2A');\r\n            }\r\n        }, 250);\r\n        \r\n        console.log('\u26a0\ufe0f Flash titre format - action bloqu\u00e9e (aucun format s\u00e9lectionn\u00e9)');\r\n    },\r\n    \r\n    \/**\r\n     * Met \u00e0 jour l'\u00e9tat de la checkbox \"R\u00e9server cet espace publicitaire\"\r\n     * La checkbox est activable si : format s\u00e9lectionn\u00e9 ET (fichier d\u00e9pos\u00e9 OU envoi diff\u00e9r\u00e9)\r\n     *\/\r\n    updateReserverCheckboxState($droppable) {\r\n        \/\/ \u2705 Chercher le label : dynamique ou Elementor statique\r\n        let $label = null;\r\n        let $container = null;\r\n        \r\n        \/\/ 1. Bouton dynamique dans le droppable\r\n        $container = $droppable.find('.reserver-dynamic-container');\r\n        if (!$container.length) {\r\n            $container = $droppable.next('.reserver-dynamic-container');\r\n        }\r\n        if (!$container.length) {\r\n            \/\/ Mobile : checkbox attach\u00e9e au body avec data-droppable-id\r\n            $container = $('body > .reserver-dynamic-container[data-droppable-id=\"' + $droppable.attr('id') + '\"]');\r\n        }\r\n        if (!$container.length) {\r\n            $container = $('body > .reserver-dynamic-container');\r\n        }\r\n        \r\n        if ($container.length) {\r\n            $label = $container.find('.reserver-dynamic-label');\r\n            $container.find('.reserver-dynamic-option, .elementor-field-option').css('opacity', '1');\r\n        }\r\n        \r\n        \/\/ 2. Bouton Elementor statique - chercher dans le droppable puis globalement\r\n        let $reserverStatique = $droppable.find('.elementor-field-group-ReserverEspacePublicitaire label');\r\n        if (!$reserverStatique.length) {\r\n            $reserverStatique = $droppable.find('label[for^=\"form-field-ReserverEspacePublicitaire\"]');\r\n        }\r\n        if (!$reserverStatique.length) {\r\n            \/\/ Fallback global : le formulaire peut \u00eatre en dehors du droppable\r\n            $reserverStatique = $('.elementor-field-group-ReserverEspacePublicitaire .elementor-field-option label');\r\n        }\r\n        \r\n        const hasFormat = this.hasSelectedFormat($droppable);\r\n        const hasFile = StateManager.get('FileReceived') === 'Yes';\r\n        const hasEnvoiDiffere = $droppable.find('input[name*=\"EnvoiUlterieur\"]:checked').length > 0;\r\n        \r\n        const canReserve = hasFormat && (hasFile || hasEnvoiDiffere);\r\n        \r\n        \/\/ \u2705 Si la checkbox R\u00e9server est coch\u00e9e \u2192 label vert \"Espace publicitaire r\u00e9serv\u00e9\"\r\n        const isChecked = $droppable.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked') ||\r\n                          ($container.length && $container.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked'));\r\n        \/\/ \u2705 v2.4.7 : Signal de restauration r\u00e9serv\u00e9e \u2014 checkbox pas encore coch\u00e9e (setTimeout 150ms)\r\n        \/\/             mais on sait d\u00e9j\u00e0 que l'espace est r\u00e9serv\u00e9 \u2192 traiter comme coch\u00e9\r\n        const _isReservedRestoration = sessionStorage.getItem('_isReservedRestoration') === 'Yes';\r\n        const isCheckedOrReservedRestore = isChecked || _isReservedRestoration;\r\n        \r\n        if ($label && $label.length) {\r\n            if (isCheckedOrReservedRestore) {\r\n                $label.text('Espace publicitaire r\u00e9serv\u00e9').css('color', 'rgb(62, 170, 19)');\r\n            } else {\r\n                $label.text('R\u00e9server cet espace publicitaire').css('color', canReserve ? '#FB5E2A' : '');\r\n            }\r\n        }\r\n        if ($reserverStatique.length) {\r\n            if (isCheckedOrReservedRestore) {\r\n                $reserverStatique.attr('style', 'color: rgb(62, 170, 19) !important;');\r\n            } else if (canReserve) {\r\n                $reserverStatique.attr('style', 'color: #FB5E2A !important;');\r\n            } else {\r\n                $reserverStatique.removeAttr('style');\r\n            }\r\n        }\r\n        \r\n        console.log('\ud83d\udd04 updateReserverCheckboxState:', { hasFormat, hasFile, hasEnvoiDiffere, canReserve, dynamicLabel: !!($label && $label.length), staticLabel: $reserverStatique.length });\r\n    },\r\n    \r\n    \/**\r\n     * Initialise les listeners pour le changement de format et la checkbox R\u00e9server\r\n     *\/\r\n    init() {\r\n        \/\/ \u2705 \u00c9couter les clics sur les conteneurs de format et leurs parents\r\n        jQuery(document).on('click', '.EspPubFormatContainer, .EspPubFormatListe, .EspPubFormatMainContainer', (e) => {\r\n            const $droppable = jQuery(e.target).closest('.droppable');\r\n            if (!$droppable.length) return;\r\n            \r\n            \/\/ Multiples d\u00e9lais pour couvrir les traitements asynchrones\r\n            [50, 200, 500].forEach(delay => {\r\n                setTimeout(() => {\r\n                    this.updateTitleColor($droppable);\r\n                    this.updateReserverCheckboxState($droppable);\r\n                }, delay);\r\n            });\r\n\r\n            \/\/ \u2705 v2.2.0 : Si un format (non Cr\u00e9ation) est cliqu\u00e9, notifier le parent pour mettre \u00e0 jour le Kit\r\n            const $btn = jQuery(e.target).closest('.EspPubFormatContainer');\r\n            if ($btn.length && !$btn.hasClass('FormatIdCreation') && !$btn.hasClass('FormatIdPopUp')) {\r\n                \/\/ \u2705 v2.3.4 : FormatIdPopUp g\u00e9r\u00e9 par clickFormatFromIframe (Entete.txt) \u2014 ne pas doubler\r\n                var classes = $btn.attr('class') || '';\r\n                var match = classes.match(\/FormatId(\\w+)\/);\r\n                if (match && match[1]) {\r\n                    var _rankEP = $droppable.attr('id') || '';\r\n                    setTimeout(function() {\r\n                        MessageManager.sendToParent('formatChangedInIframe', { formatSelect: match[1], rank: _rankEP });\r\n                        console.log('\ud83d\udd04 formatChangedInIframe envoy\u00e9:', match[1], '| rank:', _rankEP);\r\n                    }, 100);\r\n                }\r\n            }\r\n        });\r\n        \r\n        \/\/ \u2705 MutationObserver sur les conteneurs de format pour d\u00e9tecter les changements de style\r\n        setTimeout(() => {\r\n            this.observeFormatChanges();\r\n            \r\n            \/\/ Initialiser les couleurs des titres au chargement\r\n            jQuery('.droppable').each((i, el) => {\r\n                this.updateTitleColor(jQuery(el));\r\n            });\r\n            \r\n            \/\/ \u2705 v2.3.4 : Popup \u2192 restaurer FormatIdPopUp + format sous-jacent (sans \u00e9craser applyFormatState)\r\n            if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n                jQuery('.FormatIdPopUp').css({'background-color': '#ffffff'});\r\n                jQuery('.FormatIdPopUp').find('.EspPubFormat').css({'color': '#37D900'});\r\n                \/\/ Restaurer aussi le format sous-jacent dans Ele0A\r\n                var _fmtSS = sessionStorage.getItem('FormatSelect') || '';\r\n                if (_fmtSS) {\r\n                    var _fmtSSNorm = _fmtSS.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                    jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdCreation').each(function() {\r\n                        var _cls = this.className.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                        if (_cls.includes(_fmtSSNorm)) {\r\n                            jQuery(this).css({'background-color': '#ffffff'});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        }\r\n                    });\r\n                }\r\n                jQuery('.droppable').each((i, el) => {\r\n                    this.updateTitleColor(jQuery(el));\r\n                });\r\n            }\r\n        }, 500);\r\n        \r\n        \/\/ \u2705 v1.16.0 : Re-v\u00e9rifier apr\u00e8s un d\u00e9lai plus long (format venant de l'accord\u00e9on via postMessage)\r\n        [1500, 3000].forEach(delay => {\r\n            setTimeout(() => {\r\n                \/\/ \u2705 v2.3.4 : Popup \u2192 restaurer FormatIdPopUp + format sous-jacent\r\n                if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n                    jQuery('.FormatIdPopUp').css({'background-color': '#ffffff'});\r\n                    jQuery('.FormatIdPopUp').find('.EspPubFormat').css({'color': '#37D900'});\r\n                    var _fmtSSR = sessionStorage.getItem('FormatSelect') || '';\r\n                    if (_fmtSSR) {\r\n                        var _fmtSSRNorm = _fmtSSR.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                        jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdCreation').each(function() {\r\n                            var _cls = this.className.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                            if (_cls.includes(_fmtSSRNorm)) {\r\n                                jQuery(this).css({'background-color': '#ffffff'});\r\n                                jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                            }\r\n                        });\r\n                    }\r\n                    jQuery('.droppable').each((i, el) => {\r\n                        this.updateTitleColor(jQuery(el));\r\n                    });\r\n                    return;\r\n                }\r\n                if (sessionStorage.getItem('Formatchoisi') === 'Yes') {\r\n                    jQuery('.droppable').each((i, el) => {\r\n                        this.updateTitleColor(jQuery(el));\r\n                    });\r\n                }\r\n            }, delay);\r\n        });\r\n    },\r\n    \r\n    \/**\r\n     * Attache un MutationObserver sur chaque .EspPubFormatContainer\r\n     * pour d\u00e9tecter tout changement de style (background-color) \r\n     * quel que soit le script qui le d\u00e9clenche\r\n     *\/\r\n    observeFormatChanges() {\r\n        \/\/ \u2705 Guard global anti-boucle \u2014 un seul verrou pour tous les observers\r\n        window._formatObserverLocked = false;\r\n        \r\n        jQuery('.EspPubFormatContainer').each((i, el) => {\r\n            const observer = new MutationObserver(() => {\r\n                if (window._formatObserverLocked) return;\r\n                window._formatObserverLocked = true;\r\n                \/\/ \u2705 v2.4.12 : Debounce 150ms \u2014 applyFormatState manipule plusieurs containers\r\n                \/\/ en s\u00e9quence rapide, le MutationObserver peut firer sur un \u00e9tat interm\u00e9diaire\r\n                clearTimeout(window._formatObserverTimer);\r\n                window._formatObserverTimer = setTimeout(() => {\r\n                    const $droppable = jQuery(el).closest('.droppable');\r\n                    this.updateTitleColor($droppable);\r\n                    this.updateReserverCheckboxState($droppable);\r\n                    window._formatObserverLocked = false;\r\n                }, 150);\r\n            });\r\n            observer.observe(el, { \r\n                attributes: true, \r\n                attributeFilter: ['style', 'class'] \r\n            });\r\n        });\r\n        console.log('\u2705 MutationObserver attach\u00e9 aux conteneurs de format');\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de communication avec la page parente\r\n *\/\r\nconst MessageManager = {\r\n    sendToParent(type, data = {}) {\r\n        try {\r\n            window.parent.postMessage({\r\n                type: type,\r\n                iframeId: CONFIG.iframeId,\r\n                data: data\r\n            }, '*');\r\n        } catch (error) {\r\n            console.error('Error sending message to parent:', error);\r\n            window.parent.postMessage({\r\n                type: 'error',\r\n                error: error.message,\r\n                iframeId: CONFIG.iframeId\r\n            }, '*');\r\n        }\r\n    },\r\n    \r\n    sendDataToParent(data) {\r\n        this.sendToParent('dataFromIframeEspacePub', data);\r\n    },\r\n    \r\n    sendDelAdToParent(data) {\r\n        this.sendToParent('dataDelAd', data);\r\n    },\r\n    \r\n    prepareUploadData() {\r\n        const keys = [\r\n            'AddNewRefInVosCampagnes',\r\n            'FirstUploadFileorMoved',\r\n            'LoadedPageUrl',\r\n            'codePage',\r\n            'Rank_Emplacement_Page_Web',\r\n            'Commande_Emplacement_Page_Web',\r\n            'dragstart_Commande_Emplacement_Page_Web',\r\n            'dragstart_Rank_Emplacement_Page_Web',  \r\n            'FullPathAdFile',\r\n            'Upload_File_Name',\r\n            'FileReceived',\r\n            'PageWebDisplayed',\r\n            'Commande_Format_Transmis',\r\n            'EspPubLienAnnonce',\r\n            'EnvoiUlterieur',\r\n            'Formatchoisi'\r\n        ];\r\n        \r\n        const data = StateManager.getMultiple(keys);\r\n        \r\n        \/\/ \u2705 v2.3.4 : Popup (Ele0A) \u2014 lire le format sous-jacent depuis le DOM\r\n        \/\/ StateManager contient 'PopUp' (virtuel), mais le vrai format est visuellement s\u00e9lectionn\u00e9 dans #Ele0A\r\n        if (data.Rank_Emplacement_Page_Web === 'Ele0A' || sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            var _ele0AFormatDOM = '';\r\n            jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdPopUp').each(function() {\r\n                if (jQuery(this).css('background-color') === 'rgb(255, 255, 255)') {\r\n                    var _cls = this.className || '';\r\n                    var _match = _cls.match(\/FormatId(\\S+)\/);\r\n                    if (_match) { _ele0AFormatDOM = _match[1]; return false; }\r\n                }\r\n            });\r\n            if (_ele0AFormatDOM) {\r\n                data.Commande_Format_Transmis = _ele0AFormatDOM;\r\n            }\r\n        }\r\n        \r\n        console.log('\ud83d\udce4 prepareUploadData:', {\r\n            FirstUploadFileorMoved: data.FirstUploadFileorMoved,\r\n            dragstart_Commande_Emplacement_Page_Web: data.dragstart_Commande_Emplacement_Page_Web,\r\n            Commande_Emplacement_Page_Web: data.Commande_Emplacement_Page_Web\r\n        });\r\n    \r\n        return data;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de rendu des aper\u00e7us de fichiers\r\n *\/\r\nconst PreviewRenderer = {\r\n    _getPositionLibelle(rankId) {\r\n        if (!rankId) return '';\r\n        var match = rankId.match(\/Ele(\\d+)[A-Z]\/);\r\n        if (!match) return '';\r\n        var rang = parseInt(match[1]);\r\n        if (rang === 0) return 'Pop-up';\r\n        if (rang === 1 || rang === 2) return 'Haut de page';\r\n        return 'Corps de page';\r\n    },\r\n    renderVideo(objectUrl, fileName, $dropZone) {\r\n        const videoElement = jQuery('<video controls autoplay muted>').attr({\r\n            'src': objectUrl,\r\n            'width': 'auto',\r\n            'height': 'auto',\r\n            'id': fileName\r\n        }).css({\r\n            'max-width': '100%',\r\n            'max-height': '100%'\r\n        });\r\n        \r\n        if (UIManager.isDesktop()) {\r\n            $dropZone.empty().append(videoElement.clone());\r\n            jQuery('#ApercuMobile').css({\r\n                'display': 'flex',\r\n                'justify-content': 'center',\r\n                'align-items': 'center'\r\n            }).append(videoElement);\r\n        } else {\r\n            const img = document.createElement('img');\r\n            img.src = objectUrl;\r\n            img.style.width = 'auto';\r\n            img.style.height = 'auto';\r\n            img.style.maxWidth = 'calc(100% - 4px)';  \/\/ \u2705 v2.4.5 : 2px retrait inset box-shadow\r\n            img.style.maxHeight = '115px';\r\n            \r\n            const container = $dropZone[0];\r\n            while (container.firstChild) {\r\n                container.removeChild(container.firstChild);\r\n            }\r\n            container.appendChild(img);\r\n        }\r\n        \r\n        StateManager.setMultiple({\r\n            'Commande_Format': 'Vid\u00e9o',\r\n            'Commande_Format_Transmis': 'Vid\u00e9o',\r\n            'videoSrc': objectUrl,\r\n            'FormatAnnonceSelection': 'Yes',\r\n            'PositionAnnonceSelection': 'Yes'\r\n        });\r\n        \r\n        jQuery('#FormatDataStep3').html('Vid\u00e9o').css({'color': '#56BE50'});\r\n        jQuery('#TarifDataStep3').css({'color': '#96894D'});\r\n    },\r\n    \r\n    renderImage(objectUrl, $dropZone) {\r\n        const maxHeight = UIManager.isMobile() ? 105 : $dropZone.closest('.HTMLUploadfileConteneur').height();\r\n    \r\n        $dropZone.css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center',\r\n            'width': '100%',\r\n            'height': maxHeight + 'px',\r\n            'overflow': 'hidden',\r\n            'position': UIManager.isMobile() ? 'relative' : '',\r\n            'top': UIManager.isMobile() ? '45px' : '',\r\n            'padding': UIManager.isMobile() ? '0 2px' : ''  \/\/ \u2705 v2.4.5 : 2px retrait inset box-shadow mobile\r\n        });\r\n    \r\n        \/\/ \u2705 v1.19.2 : Image charg\u00e9e en arri\u00e8re-plan, remplace le message d'attente au onload\r\n        \/\/ \u2705 v2.4.5 : max-width calc(100%-4px) sur mobile pour ne pas recouvrir le box-shadow inset 2px\r\n        var _mxw = UIManager.isMobile() ? 'calc(100% - 4px)' : '100%';\r\n        var img = new Image();\r\n        img.style.cssText = 'max-width:' + _mxw + '; max-height:' + maxHeight + 'px; width:auto; height:auto; object-fit:contain;';\r\n        img.onload = function() {\r\n            $dropZone.empty().append(img);\r\n        };\r\n        img.onerror = function() {\r\n            $dropZone.html('<img decoding=\"async\" src=\"' + objectUrl + '\" style=\"max-width:' + _mxw + '; max-height:' + maxHeight + 'px; width:auto; height:auto; object-fit:contain;\">');\r\n        };\r\n        img.src = objectUrl;\r\n    \r\n        StateManager.setMultiple({\r\n            'Commande_Format_Transmis': 'Image',\r\n            'FormatAnnonceSelection': 'Yes',\r\n            'PositionAnnonceSelection': 'Yes'\r\n        });\r\n    \r\n        console.log('Image ajout\u00e9e avec succ\u00e8s');\r\n    },\r\n    \r\n    async renderWord(fileObj, $dropZone) {\r\n        return new Promise((resolve, reject) => {\r\n            const reader = new FileReader();\r\n            \r\n            reader.onload = async (e) => {\r\n                try {\r\n                    const arrayBuffer = e.target.result;\r\n                    const result = await mammoth.convertToHtml({arrayBuffer: arrayBuffer});\r\n                    \r\n                    const htmlContent = result.value;\r\n                    const tempContainer = document.createElement('div');\r\n                    tempContainer.innerHTML = htmlContent;\r\n                    \r\n                    const textContent = tempContainer.textContent || \"\";\r\n                    const normalizedText = this.normalizeText(textContent);\r\n                    const firstImage = tempContainer.querySelector('img');\r\n                    \r\n                    const titleText = this.findDocumentTitle(normalizedText);\r\n                    \r\n                    if (firstImage) {\r\n                        this.renderDocumentPreview(\r\n                            $dropZone,\r\n                            firstImage.src,\r\n                            titleText,\r\n                            textContent,\r\n                            htmlContent\r\n                        );\r\n                    } else {\r\n                        \/\/ \u2705 v1.19.0 : Accepter les documents sans image\r\n                        this.renderDocumentPreview(\r\n                            $dropZone,\r\n                            null,\r\n                            titleText,\r\n                            textContent,\r\n                            htmlContent\r\n                        );\r\n                        console.log('\u2139\ufe0f Document Word sans image \u2014 aper\u00e7u texte seul');\r\n                    }\r\n                    resolve();\r\n                } catch (error) {\r\n                    $dropZone.html(`<p style=\"color: #FB5E2A; font-weight: 600; font-family: Roboto, Arial, sans-serif; font-size: 12px; text-align: center; padding: 15px;\">Erreur lors de la lecture du document<\/p>`);\r\n                    reject(error);\r\n                }\r\n            };\r\n            \r\n            reader.readAsArrayBuffer(fileObj);\r\n        });\r\n        \r\n        this.finalizeRedactionnelUpload();\r\n    },\r\n    \r\n    renderDocumentPreview($dropZone, imageSrc, title, text, htmlContent = null) {\r\n        \/\/ \u2705 v1.19.0 : Deux layouts \u2014 avec image ou texte seul\r\n        let previewHtml;\r\n\r\n        if (imageSrc) {\r\n            \/\/ Layout avec miniature image\r\n            previewHtml = `\r\n                <div class=\"doc-preview-container\">\r\n                    <div class=\"doc-preview-thumbnail\">\r\n                        <img decoding=\"async\" src=\"${imageSrc}\" alt=\"Document image\">\r\n                    <\/div>\r\n                    <div class=\"doc-preview-info\">\r\n                        <div class=\"doc-preview-title\" id=\"AdTitle\">${title}<\/div>\r\n                        <div class=\"doc-preview-description\" id=\"AdText\">${this.getTextPreview(text, 13)}<\/div>\r\n                        <div class=\"doc-preview-readmore\" id=\"AdLirelasuite\">Ouvrir et visualiser<\/div>\r\n                        <div class=\"doc-preview-FullPathAdFile\" id=\"AdFullPathAdFile\">${StateManager.get(\"FullPathAdFile\")}<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            `;\r\n        } else {\r\n            \/\/ Layout texte seul (sans image)\r\n            previewHtml = `\r\n                <div class=\"doc-preview-container doc-preview-noimage\">\r\n                    <div class=\"doc-preview-icon\">\r\n                        <svg width=\"36\" height=\"36\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#213864\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n                            <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\/><polyline points=\"14 2 14 8 20 8\"\/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"\/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"\/><polyline points=\"10 9 9 9 8 9\"\/>\r\n                        <\/svg>\r\n                    <\/div>\r\n                    <div class=\"doc-preview-info doc-preview-info-full\">\r\n                        <div class=\"doc-preview-title\" id=\"AdTitle\">${title}<\/div>\r\n                        <div class=\"doc-preview-description\" id=\"AdText\">${this.getTextPreview(text, 25)}<\/div>\r\n                        <div class=\"doc-preview-readmore\" id=\"AdLirelasuite\">Ouvrir et visualiser<\/div>\r\n                        <div class=\"doc-preview-FullPathAdFile\" id=\"AdFullPathAdFile\">${StateManager.get(\"FullPathAdFile\")}<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            `;\r\n        }\r\n        \r\n        $dropZone.html(previewHtml + this.getPreviewStyles());\r\n        \r\n        if (htmlContent) {\r\n            this.attachWordPreviewHandler($dropZone, title, htmlContent);\r\n        }\r\n    },\r\n    \r\n    attachWordPreviewHandler($dropZone, titleText, htmlContent) {\r\n        var $droppable = $dropZone.closest('.droppable');\r\n\r\n        \/\/ \u2705 Adapter le libell\u00e9 selon le type de document\r\n        var isInterview = (titleText || '').toLowerCase().indexOf('interview') !== -1;\r\n        var formatLabel = isInterview ? 'l\\'interview' : 'le communiqu\u00e9';\r\n        $droppable.find('.doc-preview-readmore').text('Ouvrir et visualiser ' + formatLabel);\r\n\r\n        \/\/ \u2705 v2.0.11 : D\u00e9l\u00e9gation d'\u00e9v\u00e9nement \u2014 plus robuste sur mobile (survit aux manipulations DOM)\r\n        $droppable.off('click.docpreview').on('click.docpreview', '.doc-preview-readmore', (event) => {\r\n            event.preventDefault();\r\n            event.stopPropagation();\r\n            \r\n            if (htmlContent) {\r\n                var popupTitle = isInterview ? 'Interview' : 'Communiqu\u00e9';\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    htmlContent: htmlContent\r\n                });\r\n            } else {\r\n                console.warn('Le document est encore en cours de traitement.');\r\n            }\r\n        });\r\n    },\r\n    \r\n    normalizeText(text) {\r\n        return text\r\n            .toLowerCase()\r\n            .normalize(\"NFD\")\r\n            .replace(\/[\\u0300-\\u036f]\/g, \"\");\r\n    },\r\n    \r\n    findDocumentTitle(normalizedText) {\r\n        const foundKeyword = CONFIG.keywords.find(keyword => \r\n            normalizedText.includes(keyword.normal)\r\n        );\r\n        if (foundKeyword) return foundKeyword.display;\r\n        \r\n        \/\/ \u2705 v1.19.1 : Fallback \u2014 utiliser le format s\u00e9lectionn\u00e9 (FormatSelect)\r\n        var formatSelect = (sessionStorage.getItem('FormatSelect') || '').toLowerCase();\r\n        if (formatSelect.indexOf('interview') !== -1) return 'Interview';\r\n        if (formatSelect.indexOf('communiq') !== -1) return 'Communiqu\u00e9';\r\n        \r\n        return \"Document\";\r\n    },\r\n    \r\n    getTextPreview(text, maxWords) {\r\n        const words = text.split(' ');\r\n        if (words.length > maxWords) {\r\n            return words.slice(0, maxWords).join(' ') + ' ...';\r\n        }\r\n        return text;\r\n    },\r\n    \r\n    getPreviewStyles() {\r\n        return `\r\n            <style>\r\n                @import url('https:\/\/fonts.googleapis.com\/css2?family=Roboto:wght@400;600&display=swap');\r\n                \r\n                .doc-preview-container {\r\n                    margin: 0px 0;\r\n                    display: flex;\r\n                    width: 100%;\r\n                    max-height: 140px;\r\n                    overflow: hidden;\r\n                    box-sizing: border-box;  \/* \u2705 v2.4.5 *\/\r\n                    background: white;\r\n                    background-color: #f8f8f8;\r\n                }\r\n                .doc-preview-thumbnail {\r\n                    width: 50%; \r\n                    height: 130px;\r\n                    overflow: hidden;\r\n                    display: flex;\r\n                    align-items: center;\r\n                    justify-content: center;\r\n                    margin-top: 0px;\r\n                }\r\n                .doc-preview-thumbnail img {\r\n                    max-width: 75%;\r\n                    max-height: 75%;\r\n                    object-position: center;\r\n                    object-fit: fill;\r\n                }\r\n                .doc-preview-info {\r\n                    width: 50%;\r\n                    height: 130px; \r\n                    flex: 1;\r\n                    padding: 10px;\r\n                    display: flex;\r\n                    flex-direction: column; \r\n                }\r\n                .doc-preview-title {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #213864;\r\n                    font-size: 14px;\r\n                    font-weight: 600;\r\n                    text-align: left;\r\n                    margin-bottom: 5px;\r\n                }\r\n                .doc-preview-description {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #213864;\r\n                    font-size: 11px;\r\n                    font-weight: 400;\r\n                    text-align: left;\r\n                    overflow: hidden;\r\n                    margin-bottom: 5px;\r\n                    flex: 1;\r\n                }\r\n                .doc-preview-readmore {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #958848;\r\n                    font-size: 13px;\r\n                    font-weight: 600;\r\n                    text-align: left;\r\n                    cursor: pointer;\r\n                    padding: 4px 0;\r\n                    -webkit-tap-highlight-color: rgba(149,136,72,0.2);\r\n                }\r\n                @media (max-width: 999px) {\r\n                    .doc-preview-readmore { font-size: 12px; }\r\n                    \/* \u2705 Laisser 3px tout autour pour que le liser\u00e9 vert (box-shadow\/outline sur parent) soit visible *\/\r\n                    .doc-preview-container {\r\n                        width: calc(100% - 16px) !important;\r\n                        max-height: 109px !important;\r\n                        margin: 3px !important;\r\n                        margin-top: 23px !important;\r\n                        box-sizing: border-box !important;\r\n                    }\r\n                }\r\n                .doc-preview-FullPathAdFile {\r\n                    display: none;\r\n                }\r\n                \/* \u2705 v1.19.0 : Layout sans image *\/\r\n                .doc-preview-noimage {\r\n                    flex-direction: row;\r\n                    align-items: flex-start;\r\n                    gap: 10px;\r\n                    padding: 8px 10px;\r\n                }\r\n                .doc-preview-icon {\r\n                    flex-shrink: 0;\r\n                    display: flex;\r\n                    align-items: center;\r\n                    justify-content: center;\r\n                    width: 44px;\r\n                    height: 44px;\r\n                    background: #eef2f7;\r\n                    border-radius: 6px;\r\n                    margin-top: 4px;\r\n                }\r\n                .doc-preview-info-full {\r\n                    width: 100%;\r\n                    height: auto;\r\n                    max-height: 130px;\r\n                }\r\n                .doc-preview-noimage .doc-preview-description {\r\n                    font-size: 11px;\r\n                    line-height: 1.35;\r\n                    max-height: 60px;\r\n                    overflow: hidden;\r\n                }\r\n            <\/style>\r\n        `;\r\n    },\r\n    \r\n    finalizeRedactionnelUpload() {\r\n        \/\/ \u2705 v1.19.5 : D\u00e9terminer le format r\u00e9dactionnel correct\r\n        \/\/ Si le format s\u00e9lectionn\u00e9 est \"Interview\", on garde \"Interview\"\r\n        \/\/ Sinon on met \"Communiqu\u00e9\" par d\u00e9faut (au lieu de \"R\u00e9dactionnel\" qui n'est pas un format tarifaire valide)\r\n        var formatSelect = sessionStorage.getItem('FormatSelect') || '';\r\n        var formatTransmis = 'Communiqu\u00e9'; \/\/ Par d\u00e9faut\r\n        \r\n        if (formatSelect.toLowerCase().indexOf('interview') !== -1) {\r\n            formatTransmis = 'Interview';\r\n        } else if (formatSelect.toLowerCase().indexOf('communiq') !== -1) {\r\n            formatTransmis = 'Communiqu\u00e9';\r\n        }\r\n        \r\n        StateManager.set('Commande_Format_Transmis', formatTransmis);\r\n        console.log('\u2705 Format r\u00e9dactionnel d\u00e9termin\u00e9:', formatTransmis, '(FormatSelect:', formatSelect, ')');\r\n        \r\n        if (StateManager.get(\"TarifDirectSelectionne\") === 'Yes') {\r\n            const formatText = jQuery('#FormatDataStep3').text();\r\n            if (formatText !== 'Vid\u00e9o' && formatText !== 'Banni\u00e8re') {\r\n                jQuery('#form-field-RedactionnelSelection')\r\n                    .val(formatText)\r\n                    .css({'color': '#56BE50'});\r\n            }\r\n        }\r\n        \r\n        RedactionnelDepose();\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'upload\r\n *\/\r\nconst UploadManager = {\r\n    isRunning: false,\r\n    \r\n    \/\/ \u2705 Reset manuel espace publicitaire\r\n    resetEspaceManuel: function($droppable) {\r\n        console.log('\ud83d\udd27 Reset manuel espace publicitaire');\r\n        \r\n        var $dropZone = $droppable.find('#drop_file_zone_achat');\r\n        var $uploadContainer = $droppable.find('.HTMLUploadfileConteneur');\r\n        var $container = $droppable.find('.OrdiMobileConteneurClass');\r\n        \r\n        \/\/ 1. Vider la zone de drop et restaurer le HTML par d\u00e9faut\r\n        $dropZone.empty().html(\r\n            '<div id=\"drag_upload_file_achat\">' +\r\n                '<p class=\"UploadIci\" style=\"color: #FB5E2A; font-weight: 600;\">Ici glisser \u2013 d\u00e9poser ou<br>t\u00e9l\u00e9charger une annonce<\/p>' +\r\n            '<\/div>'\r\n        );\r\n        \r\n        \/\/ 2. Afficher les \u00e9l\u00e9ments cach\u00e9s lors de l'upload\r\n        $droppable.find('.UploadIci').show();\r\n        $droppable.find('.EnvoiUlterieurTexte').show();\r\n        $droppable.find('.EnvoiUlterieurContainer').show();\r\n        $droppable.find('.EspPubFormatMainContainer').show();\r\n        $droppable.find('.EspPubFormatListe').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireClass').show();\r\n        $droppable.find('.GlisserDeposerConteneur').show();\r\n        $droppable.find('.OUClass').show();\r\n        $droppable.find('.TexteMobileAnnonce').show();\r\n        $droppable.find('.PositionReference').show();\r\n        $droppable.find('.ClassHdpCdp').show();\r\n        $droppable.find('.ClassRefEsp').show();\r\n        \r\n        \/\/ 3. Cacher les \u00e9l\u00e9ments d'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle').hide();\r\n        $droppable.find('#CroixResetAnnonce').hide();\r\n        $droppable.find('.CroixResetAnnonceContainer').hide();\r\n        $droppable.find('.DeplaceAnnonce').hide();\r\n        $droppable.find('.RefEspacePublicitaire').hide();\r\n        $droppable.find('.AdDroppedTextNotDisplayed').hide();\r\n        \r\n        \/\/ 4. Reset des styles\r\n        $uploadContainer.css({\r\n            'border': 'none',\r\n            'background-color': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': ''\r\n        });\r\n        \r\n        $container.css({\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'top': '',\r\n            'height': ''\r\n        });\r\n        \r\n        \/\/ \u2705 Reset des positionnements desktop appliqu\u00e9s par adjustDesktopLayout\r\n        $droppable.closest('.ToBeHidden').css({'top': '', 'min-height': ''});\r\n        $droppable.parent().css('overflow', '');\r\n        \/\/ \u2705 v2.0.11 : Cleanup event namespace docpreview\r\n        $droppable.off('click.docpreview');\r\n        \r\n        \/\/ 5. Reset des formats s\u00e9lectionn\u00e9s\r\n        $droppable.find('.EspPubFormatContainer').css({\r\n            'background-color': '',\r\n            'border': ''\r\n        });\r\n        \r\n        \/\/ 6. Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ 7. Restaurer .PositionEspacePublicitaireContainer et .ReserverContainer\r\n        $droppable.find('.PositionEspacePublicitaireContainer').show();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        console.log('\u2705 Reset manuel termin\u00e9');\r\n    },\r\n    \r\n    async handleFileUpload(fileObj, $dropZone) {\r\n        console.log('fileObj:', fileObj);\r\n        \r\n        \/\/ \u2705 v2.4.6 : Contr\u00f4les d'extension EN PREMIER \u2014 avant tout affichage\r\n        const extension = FileManager.getExtension(fileObj.name);\r\n        StateManager.set('FileExtension', extension);\r\n        console.log('FileExtension:', extension);\r\n        \r\n        \/\/ \u2705 v2.6 : jpg\/jpeg accept\u00e9s sur desktop et mobile\r\n        \r\n        if (!FileManager.isAllowedExtension(extension)) {\r\n            UIManager.showFormatError($dropZone);\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.5 : Afficher le message d'attente seulement si le format est valide\r\n        var _waitMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.html('<div class=\"ad-loading-msg\" style=\"color:#00ff19; background:white; padding:12px 20px; border-radius:6px; font-weight:700; text-align:center; font-size:18px; line-height:1.4;\">' + _waitMsg + '<\/div>');\r\n        \r\n        this.prepareUIForUpload($dropZone);\r\n        \r\n        const formData = new FormData();\r\n        formData.append('file', fileObj);\r\n        formData.append('action', 'upload_annonce_file_v3');\r\n        \r\n        UIManager.showUploadProgress($dropZone);\r\n        \r\n        try {\r\n            const response = await this.sendUploadRequest(formData);\r\n            await this.handleUploadResponse(response, fileObj, $dropZone, extension);\r\n        } catch (error) {\r\n            console.error('Upload error:', error);\r\n        }\r\n    },\r\n    \r\n    prepareUIForUpload($dropZone) {\r\n        if (!UIManager.isMobile()) {\r\n            jQuery('.ChoisirEspacePublicitaireClass').show();\r\n            jQuery('.ChoisirEspacePublicitaire2ndLigne').show();\r\n            jQuery('.GlisserDeposerConteneur').show();\r\n            jQuery('.OUClass').show();\r\n            \/\/ \u2705 Cibler uniquement le droppable courant \u2014 ne pas r\u00e9afficher sur les espaces d\u00e9j\u00e0 upload\u00e9s\r\n            $dropZone.closest('.droppable').find('.UploadIci').show();\r\n        }\r\n        \r\n        if (StateManager.get(\"PopUpChoice\") === 'Yes') {\r\n            \/\/ \u2705 Ne masquer DeplaceAnnonce QUE sur Ele0A \u2014 pas sur Ele1A qui a deja une annonce chargee\r\n            $dropZone.closest('.OrdiMobileConteneurClass').find('.DeplaceAnnonce').each(function() {\r\n                var _d = jQuery(this).closest('.droppable')[0];\r\n                if (_d && _d.getAttribute('data-via-ad-loaded') === 'true') { return; }\r\n                jQuery(this).hide();\r\n            });\r\n            $('.AnnonceDragIcone').show().find('img').attr('alt', '');\r\n        } else {\r\n            $('.AnnonceDragIcone').hide();\r\n        }\r\n        \r\n        if (StateManager.get(\"Commande_Page\") === 'Home Page') {\r\n            jQuery('#HPTarifConteneur').css({'background-color': '#B5FFB1'});\r\n        }\r\n        \r\n        jQuery('.ChoisirEspacePublicitaireClass').css({'color': '#ffffff'});\r\n        jQuery('.InterfaceTitreDore').not('#PageWebTitreDore')\r\n            .html(\"Merci de choisir les \u00e9l\u00e9ments de votre campagne publicitaire\");\r\n        jQuery('#ProcessCommande').show();\r\n    },\r\n    \r\n    sendUploadRequest(formData) {\r\n        \/\/ \u2705 v2.6 : dataType 'text' pour eviter parsererror si texte parasite apres le JSON\r\n        return jQuery.ajax({\r\n            url: CONFIG.ajaxUrl,\r\n            type: 'POST',\r\n            data: formData,\r\n            cache: false,\r\n            contentType: false,\r\n            processData: false,\r\n            dataType: 'text'\r\n        }).then(function(text) {\r\n            \/\/ Extraire le JSON meme si du texte parasite suit\r\n            var _json = null;\r\n            try {\r\n                var _match = text.match(\/(\\{[\\s\\S]*?\\})(?:[^{]|$)\/);\r\n                _json = JSON.parse(_match ? _match[1] : text);\r\n            } catch(_e) {\r\n                return jQuery.Deferred().reject({ responseText: text }).promise();\r\n            }\r\n            \/\/ Normaliser le format vers {success, data} attendu par handleUploadResponse\r\n            if (_json.status === 'success') {\r\n                var _fp = _json.file_path || '';\r\n                var _baseUrl = CONFIG.ajaxUrl.replace('\/wp-admin\/admin-ajax.php', '\/wp-content\/');\r\n                return {\r\n                    success: true,\r\n                    data: {\r\n                        file_url:  _baseUrl + _fp,\r\n                        file_name: _fp.replace(\/^.*\\\/\/, ''),\r\n                        file_path: _fp\r\n                    }\r\n                };\r\n            }\r\n            \/\/ Format WordPress standard {success, data} - retourner tel quel\r\n            return _json;\r\n        });\r\n    },\r\n    \r\n    async handleUploadResponse(response, fileObj, $dropZone, extension) {\r\n        console.log('\u2705 R\u00e9ponse re\u00e7ue');\r\n        \r\n        if (response.responseJSON) {\r\n            response = response.responseJSON;\r\n        }\r\n        \r\n        console.log('\u2705 Response pars\u00e9e:', response);\r\n        \r\n        if (!response.success || !response.data) {\r\n            \/\/ \u2705 v2.1.2 : Si c'est une restauration (_isAdRestoration = 'Yes'),\r\n            \/\/ le fichier existe d\u00e9j\u00e0 sur le serveur \u2192 afficher l'image depuis le fileObj local\r\n            if (StateManager.get('_isAdRestoration') === 'Yes' && fileObj) {\r\n                console.log('\ud83d\udd04 Restauration: upload \u00e9chou\u00e9 (fichier existant) \u2192 rendu local');\r\n                \r\n                FileManager.createObjectUrl(fileObj);\r\n                StateManager.set('FileReceived', 'Yes');\r\n                \r\n                \/\/ \u2705 v2.1.2 : Restaurer l'\u00e9tat EnvoiUlterieur depuis le sessionStorage parent\r\n                var _restoredEnvoi = sessionStorage.getItem('_restoredEnvoiUlterieur');\r\n                if (_restoredEnvoi === 'true') {\r\n                    StateManager.set('EnvoiUlterieur', 'true');\r\n                    StateManager.set('FileReceived', 'No');\r\n                    StateManager.set('FullPathAdFile', '');\r\n                    console.log('\ud83d\udce4 Restauration EnvoiUlterieur = true');\r\n                }\r\n                \r\n                var _objUrl = StateManager.get('objectUrl');\r\n                var _fileType = FileManager.getFileType(extension);\r\n                \r\n                StateManager.set('FormatReconnu', 'No');\r\n                \r\n                switch (_fileType) {\r\n                    case 'video':\r\n                        PreviewRenderer.renderVideo(_objUrl, fileObj.name, $dropZone);\r\n                        StateManager.set('FormatReconnu', 'Yes');\r\n                        break;\r\n                    case 'image':\r\n                        PreviewRenderer.renderImage(_objUrl, $dropZone);\r\n                        StateManager.set('FormatReconnu', 'Yes');\r\n                        break;\r\n                    case 'document':\r\n                        \/\/ \u2705 v2.1.2 : Documents Word\/PDF aussi en restauration\r\n                        await this.handleDocumentUpload(extension, fileObj, $dropZone);\r\n                        break;\r\n                }\r\n                \r\n                UIManager.updateAfterSuccessfulUpload($dropZone);\r\n                \r\n                if (StateManager.get('FormatReconnu') === 'Yes') {\r\n                    this.finalizeUpload($dropZone);\r\n                    $('#MsgSelectEspace').hide();\r\n                }\r\n                \r\n                FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n                console.log('\u2705 Restauration visuelle termin\u00e9e (upload bypass)');\r\n                StateManager.set('_isAdRestoration', 'No');\r\n            }\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 SAUVEGARDER les infos de d\u00e9placement AVANT updateStateAfterUpload\r\n        const isMoved = StateManager.get('FirstUploadFileorMoved') === 'Moved';\r\n        const dragstartRankId = StateManager.get('dragstart_Rank_Emplacement_Page_Web');\r\n        const currentRankId = StateManager.get('Rank_Emplacement_Page_Web');\r\n        const shouldResetOldSpace = isMoved && dragstartRankId && dragstartRankId !== currentRankId;\r\n        \r\n        console.log('\ud83d\udd0d D\u00e9placement?', { isMoved, dragstartRankId, currentRankId, shouldResetOldSpace });\r\n        \r\n        this.updateStateAfterUploadWithoutReset(response, fileObj);\r\n        \r\n        const fileType = FileManager.getFileType(extension);\r\n        \r\n        StateManager.set('FormatReconnu', 'No');\r\n        \r\n        \/\/ \u2705 v1.19.2 : Message d'attente IMM\u00c9DIAT avant le rendu de l'annonce\r\n        var _waitMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.html('<div class=\"ad-loading-msg\" style=\"color:#00ff19; background:white; padding:12px 20px; border-radius:6px; font-weight:700; text-align:center; font-size:18px; line-height:1.4;\">' + _waitMsg + '<\/div>');\r\n        \r\n        switch (fileType) {\r\n            case 'video':\r\n                PreviewRenderer.renderVideo(StateManager.get('objectUrl'), fileObj.name, $dropZone);\r\n                StateManager.set('FormatReconnu', 'Yes');\r\n                break;\r\n                \r\n            case 'image':\r\n                PreviewRenderer.renderImage(StateManager.get('objectUrl'), $dropZone);\r\n                StateManager.set('FormatReconnu', 'Yes');\r\n                break;\r\n                \r\n            case 'document':\r\n                await this.handleDocumentUpload(extension, fileObj, $dropZone);\r\n                break;\r\n        }\r\n        \r\n        UIManager.updateAfterSuccessfulUpload($dropZone);\r\n        \r\n        if (StateManager.get('FormatReconnu') === 'Yes') {\r\n            this.finalizeUpload($dropZone);\r\n            $('#MsgSelectEspace').hide();\r\n        }\r\n        \r\n        \/\/ \u2705 RESET L'ANCIEN ESPACE ICI - APR\u00c8S avoir affich\u00e9 la nouvelle image\r\n        \/\/ \u2705 v2.4.5 : Toujours initialiser \u00e0 false avant le bloc (\u00e9vite la valeur r\u00e9siduelle)\r\n        var _sourceWasReserved = false;\r\n        StateManager.set('_sourceWasReserved', 'No');\r\n        \r\n        if (shouldResetOldSpace) {\r\n            console.log('\ud83d\udd04 Reset ancien espace:', dragstartRankId);\r\n            \r\n            var $oldDroppable = $('#' + dragstartRankId);\r\n            \r\n            if ($oldDroppable.length) {\r\n                var $container = $oldDroppable.find('.OrdiMobileConteneurClass').first();\r\n                \r\n                \/\/ \u2705 v2.4.5 : Utiliser l'\u00e9tat captur\u00e9 au dragstart (fiable vs re-check async)\r\n                if ($container.length) {\r\n                    _sourceWasReserved = StateManager.get('dragstart_ReserverChecked') === 'Yes';\r\n                    console.log('[d\u00e9placement] ReserverChecked au dragstart:', _sourceWasReserved, '| rank:', dragstartRankId);\r\n                    StateManager.set('_sourceWasReserved', _sourceWasReserved ? 'Yes' : 'No');\r\n                    RestoreadSpaceTemplateLocal($container[0]);\r\n                }\r\n            }\r\n        }\r\n        StateManager.set(\"EnvoiUlterieur\", 'false');\r\n        \r\n        \/\/ \u2705 v1.19.1 : Positionner l'espace \u00e0 10px du haut du viewport apr\u00e8s upload\r\n        setTimeout(function() {\r\n            var el = $dropZone.closest('.droppable').find('.HTMLUploadfileConteneur')[0]\r\n                     || $dropZone.closest('.droppable')[0];\r\n            if (el) {\r\n                ScrollHelper.scrollElementTo(el, 10);\r\n            }\r\n        }, 400);\r\n        \r\n        \/\/ \u2705 NE PLUS envoyer automatiquement - c'est la checkbox \"R\u00e9server\" qui d\u00e9clenche\r\n        \/\/ On met \u00e0 jour l'\u00e9tat de la checkbox pour qu'elle devienne activable\r\n        FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n        \r\n        \/\/ \u2705 v2.4.5 : Si l'espace source \u00e9tait r\u00e9serv\u00e9, cocher la checkbox de l'espace cible\r\n        if (StateManager.get('_sourceWasReserved') === 'Yes') {\r\n            var $targetCb = $dropZone.closest('.droppable').find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n            if ($targetCb.length && !$targetCb.prop('checked')) {\r\n                $targetCb.prop('checked', true).trigger('change');\r\n                console.log('\u2705 [d\u00e9placement] Checkbox R\u00e9server coch\u00e9e sur espace cible');\r\n            }\r\n            StateManager.set('_sourceWasReserved', 'No');\r\n        }\r\n        \r\n        console.log('\ud83d\udccb Upload termin\u00e9 - en attente de validation via checkbox \"R\u00e9server\"');\r\n    },\r\n    \r\n    updateStateAfterUploadWithoutReset(response, fileObj) {\r\n        StateManager.setMultiple({\r\n            \"PageWhithADType\": StateManager.get('SelectedPageType'),\r\n            \"PageWhithADSecteur\": StateManager.get('SelectedPageSecteur')\r\n        });\r\n        \r\n        $('#BackPageWebWithADCroix').hide();\r\n        jQuery('#ApercuMobile').empty().css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center'\r\n        });\r\n        \r\n        const firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n        \r\n        if (firstUploadOrMoved === 'FirstUpload') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": response.data.file_url,\r\n                \"fileObj\": fileObj,\r\n                \"Upload_File_Name\": fileObj.name\r\n            });\r\n            \r\n            FileManager.createObjectUrl(fileObj);\r\n            \r\n            console.log('\ud83d\udcc1 Fichier upload\u00e9:', {\r\n                fullUrl: response.data.file_url,\r\n                fileName: response.data.file_name,\r\n                filePath: response.data.file_path\r\n            });\r\n        }\r\n    },\r\n    \r\n    updateStateAfterUpload(response, fileObj) {\r\n        StateManager.setMultiple({\r\n            \"PageWhithADType\": StateManager.get('SelectedPageType'),\r\n            \"PageWhithADSecteur\": StateManager.get('SelectedPageSecteur')\r\n        });\r\n        \r\n        $('#BackPageWebWithADCroix').hide();\r\n        jQuery('#ApercuMobile').empty().css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center'\r\n        });\r\n        \r\n        const firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n        console.log('\ud83d\udd0d FirstUploadFileorMoved:', firstUploadOrMoved);\r\n        \r\n        if (firstUploadOrMoved === 'FirstUpload') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": response.data.file_url,\r\n                \"fileObj\": fileObj,\r\n                \"Upload_File_Name\": fileObj.name\r\n            });\r\n            \r\n            FileManager.createObjectUrl(fileObj);\r\n            \r\n            console.log('\ud83d\udcc1 Fichier upload\u00e9:', {\r\n                fullUrl: response.data.file_url,\r\n                fileName: response.data.file_name,\r\n                filePath: response.data.file_path\r\n            });\r\n        } else if (firstUploadOrMoved === 'Moved') {\r\n            const dragstartRankId = StateManager.get('dragstart_Rank_Emplacement_Page_Web');\r\n            const currentRankId = StateManager.get('Rank_Emplacement_Page_Web');\r\n            \r\n            console.log('\ud83d\udd04 D\u00c9PLACEMENT D\u00c9TECT\u00c9');\r\n            console.log('   Ancien espace (dragstart):', dragstartRankId);\r\n            console.log('   Nouvel espace (current):', currentRankId);\r\n            \r\n            if (dragstartRankId && dragstartRankId !== currentRankId) {\r\n                const $oldDroppable = $('#' + dragstartRankId);\r\n                \r\n                console.log('   $oldDroppable trouv\u00e9:', $oldDroppable.length > 0);\r\n                \r\n                if ($oldDroppable.length) {\r\n                    const $container = $oldDroppable.find('.OrdiMobileConteneurClass');\r\n                    \r\n                    console.log('   $container trouv\u00e9:', $container.length > 0);\r\n                    \r\n                    if ($container.length) {\r\n                        console.log('\ud83d\udd27 Appel RestoreadSpaceTemplate sur:', $container[0]);\r\n                        \r\n                        if (typeof window.RestoreadSpaceTemplate === 'function') {\r\n                            window.RestoreadSpaceTemplate($container[0]);\r\n                            console.log('\u2705 RestoreadSpaceTemplate ex\u00e9cut\u00e9');\r\n                        }\r\n                    } else {\r\n                        console.warn('\u26a0\ufe0f .OrdiMobileConteneurClass non trouv\u00e9 dans', dragstartRankId);\r\n                    }\r\n                }\r\n            } else {\r\n                console.log('\u23ed\ufe0f M\u00eame espace ou dragstartRankId invalide, pas de reset');\r\n            }\r\n        }\r\n    },\r\n        \r\n    async handleDocumentUpload(extension, fileObj, $dropZone) {\r\n        StateManager.set('FormatReconnu', 'Yes');\r\n        \r\n        \/\/ \u2705 Cacher le File r\u00e9dactionnel pour r\u00e9utilisation lors des d\u00e9placements (\u00e9vite CORS)\r\n        window._lastRedactionnelFile = fileObj;\r\n        \r\n        if (extension === 'doc' || extension === 'docx') {\r\n            await new Promise(resolve => window.VIALibraries.loadMammoth(resolve));\r\n            await PreviewRenderer.renderWord(fileObj, $dropZone);\r\n        } else if (extension === 'ppt' || extension === 'pptx') {\r\n            this.renderPowerPoint($dropZone);\r\n            PreviewRenderer.finalizeRedactionnelUpload();\r\n        } else if (extension === 'pdf') {\r\n            await new Promise(resolve => window.VIALibraries.loadPdfJs(resolve));\r\n            await PDFHandler.renderPDF(fileObj, $dropZone);\r\n            PreviewRenderer.finalizeRedactionnelUpload();\r\n        }\r\n    },\r\n    \r\n    renderPowerPoint($dropZone) {\r\n        const img = jQuery('<img \/>', {\r\n            src: '\/wp-content\/uploads\/2024\/06\/microsoft-powerpoint.png',\r\n            css: {\r\n                'width': 'auto',\r\n                'height': 'auto',\r\n                'margin-bottom': '20px',\r\n                'max-width': '150px',\r\n                'max-height': '160px'\r\n            }\r\n        });\r\n        $dropZone.empty().append(img.clone());\r\n        jQuery('#ApercuMobile').append(img);\r\n    },\r\n    \r\n    finalizeUpload($dropZone) {\r\n        \/\/ \u2705 Reset sendDataToParentFlag : nouvel upload = pas encore r\u00e9serv\u00e9\r\n        StateManager.set('sendDataToParentFlag', 'No');\r\n        \r\n        StateManager.setMultiple({\r\n            \"PageAnnonceSelection\": 'Yes',\r\n            \"FormatReconnu\": 'Yes'\r\n        });\r\n        \r\n        jQuery('#MsgChoixPageWeb, #MsgInsererAnnonceConteneur').hide();\r\n        \r\n        if (StateManager.get(\"Commande_Format\") === 'R\u00e9dactionnel') {\r\n            StateManager.set('Commande_Format', '\u00e0 choisir');\r\n            RedactionnelDepose();\r\n        }\r\n        \r\n        if (StateManager.get(\"Commande_Page\") === ' ') {\r\n            jQuery('#HPTarifConteneur').css({'background-color': '#BCFFAD'});\r\n            jQuery('#EmplacementDataStep3').html(\"Home Page\");\r\n            StateManager.setMultiple({\r\n                \"Commande_Page\": 'Home Page',\r\n                \"PageAnnonceSelection\": 'Yes'\r\n            });\r\n        }\r\n        \r\n        $('#PageWeb').css('zoom', '70%');\r\n        $('#PageWebTitreDore').css({'font-size': '14px'});\r\n        \r\n        if (!UIManager.isMobile()) {\r\n            $('#PageWebTitreDore').css({'color': '#213864'});\r\n        }\r\n        \r\n        StateManager.set(\"Page_Web_with_AD_URL\", StateManager.get(\"Page_Web_URL\"));\r\n        \r\n        UIManager.finalizeAdDisplay($dropZone);\r\n        \r\n        \/\/ \u2705 Notifier le parent de l'annonce d\u00e9pos\u00e9e non r\u00e9serv\u00e9e \u2014 pour restauration au retour sur la page\r\n        var _fileRcv = StateManager.get('FileReceived');\r\n        var _isRestoring = StateManager.get('_isAdRestoration') === 'Yes';\r\n        console.log('\ud83d\udfe1 [finalizeUpload] FileReceived:', _fileRcv, '| _isAdRestoration:', _isRestoring);\r\n        if (_fileRcv === 'Yes' && !_isRestoring) {\r\n            var _pendingRank = StateManager.get('Rank_Emplacement_Page_Web') || $dropZone.closest('.droppable').attr('id') || '';\r\n            console.log('\ud83d\udfe1 [finalizeUpload] pendingRank:', _pendingRank, '| FullPathAdFile:', StateManager.get('FullPathAdFile'));\r\n            if (_pendingRank) {\r\n                console.log('\ud83d\udce4 [finalizeUpload] annonceDeposeeSansReservation \u2192 parent rank:', _pendingRank);\r\n                \/\/ \u2705 D\u00e9terminer le vrai format commercial selon le type de fichier d\u00e9pos\u00e9 + format s\u00e9lectionn\u00e9\r\n                var _formatSelect = sessionStorage.getItem('FormatSelect') || StateManager.get('Commande_Format_Transmis') || '';\r\n                var _uploadedExt = (StateManager.get('Upload_File_Name') || '').split('.').pop().toLowerCase();\r\n                var _fileKind = CONFIG.allowedExtensions.video.indexOf(_uploadedExt) !== -1 ? 'video'\r\n                              : CONFIG.allowedExtensions.image.indexOf(_uploadedExt) !== -1 ? 'image'\r\n                              : CONFIG.allowedExtensions.document.indexOf(_uploadedExt) !== -1 ? 'document'\r\n                              : '';\r\n                var _formatPending;\r\n                if (_fileKind === 'video') {\r\n                    \/\/ Vid\u00e9o \u2192 toujours Vid\u00e9o\r\n                    _formatPending = 'Vid\u00e9o';\r\n                } else if (_fileKind === 'image') {\r\n                    \/\/ Image \u2192 Banni\u00e8re ou Parrainage si s\u00e9lectionn\u00e9, sinon Banni\u00e8re par d\u00e9faut\r\n                    var _imgFormats = ['Banni\u00e8re', 'Banniere', 'Parrainage'];\r\n                    _formatPending = (_imgFormats.indexOf(_formatSelect) !== -1) ? _formatSelect : 'Banni\u00e8re';\r\n                } else if (_fileKind === 'document') {\r\n                    \/\/ Document \u2192 Communiqu\u00e9 ou Interview si s\u00e9lectionn\u00e9, sinon Communiqu\u00e9 par d\u00e9faut\r\n                    var _docFormats = ['Communiqu\u00e9', 'Communique', 'Interview'];\r\n                    _formatPending = (_docFormats.indexOf(_formatSelect) !== -1) ? _formatSelect : 'Communiqu\u00e9';\r\n                } else {\r\n                    \/\/ Fallback\r\n                    _formatPending = _formatSelect || StateManager.get('Commande_Format_Transmis') || '';\r\n                }\r\n                \/\/ \u2705 v2.4.9 : Si le format d\u00e9duit diff\u00e8re du format s\u00e9lectionn\u00e9 \u2192 mettre \u00e0 jour vignette + sessionStorage\r\n                if (_formatPending && _formatPending !== _formatSelect) {\r\n                    StateManager.set('FormatSelect', _formatPending);\r\n                    StateManager.set('Commande_Format_Transmis', _formatPending);\r\n                    StateManager.set('Formatchoisi', 'Yes');\r\n                    \/\/ Mettre \u00e0 jour visuellement la vignette dans le droppable courant\r\n                    var _fmtNorm = _formatPending.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    var $_drp = $dropZone.closest('.droppable');\r\n                    $_drp.find('.EspPubFormatContainer').each(function() {\r\n                        var _cls = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                        if (_cls.includes(_fmtNorm)) {\r\n                            jQuery(this).css({'background-color': '#ffffff'});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        } else if (!jQuery(this).hasClass('FormatIdPopUp')) {\r\n                            jQuery(this).css({'background-color': ''});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': ''});\r\n                        }\r\n                    });\r\n                    \/\/ Mettre \u00e0 jour aussi le bandeau parent via postMessage\r\n                    MessageManager.sendToParent('formatChangedInIframe', { formatSelect: _formatPending, rank: _pendingRank });\r\n                    console.log('\ud83d\udd04 [finalizeUpload] Format corrig\u00e9:', _formatSelect, '\u2192', _formatPending);\r\n                }\r\n                var _firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n                var _isMoved = _firstUploadOrMoved === 'Moved';\r\n                var _oldRankMoved = _isMoved ? (StateManager.get('dragstart_Rank_Emplacement_Page_Web') || '') : '';\r\n                MessageManager.sendToParent('annonceDeposeeSansReservation', {\r\n                    Rank_Emplacement_Page_Web: _pendingRank,\r\n                    FullPathAdFile: StateManager.get('FullPathAdFile') || '',\r\n                    Upload_File_Name: StateManager.get('Upload_File_Name') || '',\r\n                    LoadedPageUrl: window.location.href,\r\n                    FileReceived: 'Yes',\r\n                    \/\/ \u2705 Lire EnvoiUlterieur depuis la checkbox du droppable courant (pas le StateManager global)\r\n                    \/\/ StateManager.get('EnvoiUlterieur') est global \u2192 peut valoir 'true' si un autre espace a sa checkbox coch\u00e9e\r\n                    EnvoiUlterieur: ($dropZone.closest('.droppable').find('input[name*=\"EnvoiUlterieur\"]').prop('checked') ? 'true' : 'false'),\r\n                    Commande_Format_Transmis: _formatPending,\r\n                    codeSite: StateManager.get('codeSite') || '',\r\n                    codePage: StateManager.get('codePage') || '',\r\n                    Commande_Emplacement_Page_Web: StateManager.buildEmplacementReference(_pendingRank),\r\n                    isMoved: _isMoved,\r\n                    oldRank: _oldRankMoved\r\n                });\r\n            }\r\n        }\r\n    },\r\n    \r\n    activateSendDataToParent($dropZone) {\r\n        if (StateManager.get(\"sendDataToParentFlag\") !== 'Yes') {\r\n            return;\r\n        }\r\n        \r\n        if (StateManager.get(\"FirstUploadFileorMoved\") === 'Moved') {\r\n            const dragstartRef = StateManager.buildEmplacementReference(\r\n                StateManager.get(\"dragstart_Rank_Emplacement_Page_Web\")\r\n            );\r\n            StateManager.set('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n        }\r\n        \r\n        console.log('Esp Pub Ref FirstUploadFileorMoved:', StateManager.get(\"FirstUploadFileorMoved\"));\r\n        console.log('Esp Pub dragstart_Commande:', StateManager.get(\"dragstart_Commande_Emplacement_Page_Web\"));\r\n        \r\n        if (StateManager.get(\"PageAjoutModifAnnonce\") === 'Yes') {\r\n            this.handlePageModification($dropZone);\r\n        } else {\r\n            this.handleNormalUpload();\r\n        }\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        setTimeout(() => {\r\n            StateManager.set(\"AddNewRefInVosCampagnes\", 'Yes');\r\n        }, 4000);\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            StateManager.set('Commande_Format_Transmis', '');\r\n        }\r\n    },\r\n    \r\n    handlePageModification($dropZone) {\r\n        $('#CroixResetAnnonce, .DeplaceAnnonce').hide();\r\n        $('.PageAjoutModifAnnonceCroixResetAnnonce').show();\r\n        \r\n        const emplacementRef = $dropZone.closest('.CampagnesTemplateClass')\r\n            .find('.ReferenceEspace').text();\r\n        \r\n        console.log('Commande_Emplacement_Page_Web:', emplacementRef);\r\n        \r\n        jQuery.ajax({\r\n            type: \"POST\",\r\n            url: CONFIG.ajaxUrl,\r\n            data: {\r\n                action: 'via_update_fichier_annonce',\r\n                commande_ref_url: StateManager.get(\"commande_ref_url\"),\r\n                emplacement_page_web: emplacementRef,\r\n                chemin_fichier: StateManager.get(\"FullPathAdFile\")\r\n            },\r\n            xhrFields: { withCredentials: true },\r\n            success: (response) => {\r\n                if (response.success) {\r\n                    console.log('\u2705 Fichier annonce mis \u00e0 jour:', response.data.message);\r\n                    location.reload();\r\n                } else {\r\n                    console.error('\u274c Erreur:', response.data.message);\r\n                }\r\n            },\r\n            error: (xhr, status, error) => {\r\n                console.error('\u274c Erreur AJAX:', error);\r\n            }\r\n        });\r\n    },\r\n    \r\n    handleNormalUpload() {\r\n        if (StateManager.get(\"EnvoiUlterieur\") === 'true') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": '',\r\n                \"Upload_File_Name\": ''\r\n            });\r\n        }\r\n        \r\n        StateManager.set(\"LoadedPageUrl\", window.location.href);\r\n        \r\n        console.log('EnvoiUlterieur:', StateManager.get(\"EnvoiUlterieur\"));\r\n        console.log('LoadedPageUrl:', StateManager.get(\"LoadedPageUrl\"));\r\n        console.log('FileReceived:', StateManager.get(\"FileReceived\"));\r\n        \r\n        const data = MessageManager.prepareUploadData();\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            MessageManager.sendDataToParent(data);\r\n        } else {\r\n            const formatChoisi = StateManager.get(\"Formatchoisi\") === 'Yes';\r\n            const fichierDepose = StateManager.get(\"FileReceived\") === 'Yes';\r\n            const envoiDiffere = StateManager.get(\"EnvoiUlterieur\") === 'true';\r\n            \r\n            console.log('\ud83d\udd0d handleNormalUpload - Conditions:', { formatChoisi, fichierDepose, envoiDiffere });\r\n            \r\n            if (formatChoisi && (fichierDepose || envoiDiffere)) {\r\n                if (typeof window.handleEspacePubData === 'function') {\r\n                    window.handleEspacePubData(data);\r\n                } else {\r\n                    console.warn('\u26a0\ufe0f handleEspacePubData non disponible, fallback direct');\r\n                    if (typeof window.executeWithProcessLoaded === 'function') {\r\n                        window.executeWithProcessLoaded(function() {\r\n                            jQuery('#PopupProcessCommandeContainer').show();\r\n                        });\r\n                    } else {\r\n                        jQuery('#PopupProcessCommandeContainer').show();\r\n                    }\r\n                }\r\n            } else if (formatChoisi) {\r\n                console.log('\ud83d\udcdd Mise \u00e0 jour format uniquement');\r\n                \r\n                const borderStyle = {'box-shadow': 'inset 0 0 0 2px #00FF19', 'box-sizing': 'border-box'};  \/\/ \u2705 v2.4.5\r\n                \r\n                jQuery(\".FormatClassique, .FormatPopup\").css({'border': 'none'});\r\n                \r\n                jQuery('.FormatClassique, .FormatPopup').each(function() {\r\n                    \/\/ \u2705 v2.1.1 : NFD normalize both sides\r\n                    var _cn = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    var _cf = (data.Commande_Format_Transmis || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    if (_cn.includes(_cf) && _cf) {\r\n                        jQuery(this).css(borderStyle);\r\n                    }\r\n                });\r\n            }\r\n        }\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        setTimeout(() => {\r\n            StateManager.set(\"AddNewRefInVosCampagnes\", 'Yes');\r\n        }, 4000);\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            StateManager.set('Commande_Format_Transmis', '');\r\n        }\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des fichiers PDF (s\u00e9par\u00e9 pour \u00e9viter la complexit\u00e9)\r\n *\/\r\nconst PDFHandler = {\r\n    pdfData: null,\r\n    pdfDataForViewer: null,\r\n    \r\n    async renderPDF(fileObj, $dropZone) {\r\n        return new Promise((resolve, reject) => {\r\n            const reader = new FileReader();\r\n            \r\n            reader.onload = async (e) => {\r\n                try {\r\n                    const arrayBuffer = e.target.result;\r\n                    this.pdfData = new Uint8Array(arrayBuffer);\r\n                    this.pdfDataForViewer = arrayBuffer;\r\n                    \r\n                    console.log(\"Initial PDF load, size:\", this.pdfData.byteLength);\r\n                    \r\n                    const pdfjsLib = window['pdfjs-dist\/build\/pdf'];\r\n                    pdfjsLib.GlobalWorkerOptions.workerSrc = \r\n                        '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n                    \r\n                    const pdf = await pdfjsLib.getDocument({ data: new Uint8Array(this.pdfData) }).promise;\r\n                    const page = await pdf.getPage(1);\r\n                    \r\n                    const { titleText, pageText } = await this.extractTextFromPage(page);\r\n                    const imageData = await this.extractImageFromPage(page, pdfjsLib);\r\n                    \r\n                    if (imageData) {\r\n                        PreviewRenderer.renderDocumentPreview(\r\n                            $dropZone,\r\n                            imageData.dataUrl,\r\n                            titleText,\r\n                            pageText\r\n                        );\r\n                    } else {\r\n                        \/\/ \u2705 v1.19.0 : Accepter les PDF sans image\r\n                        PreviewRenderer.renderDocumentPreview(\r\n                            $dropZone,\r\n                            null,\r\n                            titleText,\r\n                            pageText\r\n                        );\r\n                        console.log('\u2139\ufe0f PDF sans image \u2014 aper\u00e7u texte seul');\r\n                    }\r\n                    \r\n                    this.attachPDFPreviewHandler($dropZone, titleText);\r\n                    resolve();\r\n                } catch (error) {\r\n                    console.error('Error extracting from PDF:', error);\r\n                    \/\/ \u2705 v1.19.0 : Message d'erreur en fran\u00e7ais\r\n                    $dropZone.html(`\r\n                        <div style=\"padding: 15px; background-color: #f8f8f8; border-radius: 4px; text-align: center;\">\r\n                            <p style=\"color: #FB5E2A; font-weight: 600; font-family: Roboto, Arial, sans-serif; font-size: 12px;\">\r\n                                Erreur lors de la lecture du document\r\n                            <\/p>\r\n                        <\/div>\r\n                    `);\r\n                    reject(error);\r\n                }\r\n            };\r\n            \r\n            reader.readAsArrayBuffer(fileObj);\r\n        });\r\n    },\r\n    \r\n    async extractTextFromPage(page) {\r\n        const textContent = await page.getTextContent();\r\n        \r\n        let text = '';\r\n        let lastX = -1;\r\n        let lastY = -1;\r\n        \r\n        for (const item of textContent.items) {\r\n            if (lastY !== -1 && (Math.abs(lastY - item.transform[5]) > 5)) {\r\n                text += '\\n';\r\n            } else if (lastX !== -1 && (item.transform[4] - lastX > 10)) {\r\n                text += ' ';\r\n            }\r\n            \r\n            text += item.str;\r\n            \r\n            lastX = item.transform[4] + (item.width || 0);\r\n            lastY = item.transform[5];\r\n        }\r\n        \r\n        text = text\r\n            .replace(\/(\\w) (\\w)\/g, (match, p1, p2) => {\r\n                if (\/[\u00e9\u00e8\u00ea\u00eb\u00e0\u00e2\u00e4\u00f4\u00f6\u00fb\u00fc\u00ef\u00ee\u00e7]\/i.test(p2)) {\r\n                    return p1 + p2;\r\n                }\r\n                return match;\r\n            })\r\n            .replace(\/ ([.,;:!?])\/g, '$1');\r\n        \r\n        const normalizedText = PreviewRenderer.normalizeText(text);\r\n        const titleText = PreviewRenderer.findDocumentTitle(normalizedText);\r\n        \r\n        return { titleText, pageText: text };\r\n    },\r\n    \r\n    async extractImageFromPage(page, pdfjsLib) {\r\n        const opList = await page.getOperatorList();\r\n        const imageInfo = [];\r\n        let currentTransform = null;\r\n        \r\n        for (let i = 0; i < opList.fnArray.length; i++) {\r\n            const operator = opList.fnArray[i];\r\n            const args = opList.argsArray[i];\r\n            \r\n            if (operator === pdfjsLib.OPS.transform) {\r\n                currentTransform = args;\r\n            } else if (operator === pdfjsLib.OPS.paintImageXObject) {\r\n                const imageName = args[0];\r\n                \r\n                if (!imageInfo.some(info => info.name === imageName)) {\r\n                    const position = currentTransform ? {\r\n                        x: currentTransform[4] || 0,\r\n                        y: currentTransform[5] || 0\r\n                    } : { x: 0, y: 0 };\r\n                    \r\n                    imageInfo.push({ name: imageName, position: position });\r\n                }\r\n            }\r\n        }\r\n        \r\n        if (imageInfo.length === 0) {\r\n            return null;\r\n        }\r\n        \r\n        imageInfo.sort((a, b) => b.position.y - a.position.y);\r\n        \r\n        const targetImageName = imageInfo[0].name;\r\n        const imageObj = page.objs.get(targetImageName);\r\n        \r\n        if (!imageObj) {\r\n            const img = await page.objs.get(targetImageName, true);\r\n            return this.processImageObject(img);\r\n        }\r\n        \r\n        return this.processImageObject(imageObj);\r\n    },\r\n    \r\n    processImageObject(imageObj) {\r\n        if (!imageObj) {\r\n            throw new Error('Image object is null');\r\n        }\r\n        \r\n        if (imageObj.bitmap instanceof ImageBitmap) {\r\n            const width = imageObj.bitmap.width || imageObj.width || imageObj.w;\r\n            const height = imageObj.bitmap.height || imageObj.height || imageObj.h;\r\n            \r\n            const canvas = document.createElement('canvas');\r\n            canvas.width = width;\r\n            canvas.height = height;\r\n            const ctx = canvas.getContext('2d');\r\n            \r\n            ctx.drawImage(imageObj.bitmap, 0, 0);\r\n            \r\n            return {\r\n                canvas: canvas,\r\n                width: width,\r\n                height: height,\r\n                dataUrl: canvas.toDataURL('image\/jpeg', 0.92)\r\n            };\r\n        }\r\n        \r\n        const width = imageObj.width || imageObj.w;\r\n        const height = imageObj.height || imageObj.h;\r\n        \r\n        if (!width || !height) {\r\n            throw new Error('Could not determine image dimensions');\r\n        }\r\n        \r\n        let imgData = imageObj.data || imageObj.bitmap;\r\n        \r\n        if (!imgData) {\r\n            throw new Error('No valid image data found');\r\n        }\r\n        \r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = width;\r\n        canvas.height = height;\r\n        const ctx = canvas.getContext('2d');\r\n        \r\n        ctx.fillStyle = 'white';\r\n        ctx.fillRect(0, 0, width, height);\r\n        \r\n        const imageData = ctx.createImageData(width, height);\r\n        \r\n        this.fillImageData(imageData, imgData, imageObj.kind, width, height);\r\n        \r\n        ctx.putImageData(imageData, 0, 0);\r\n        \r\n        return {\r\n            canvas: canvas,\r\n            width: width,\r\n            height: height,\r\n            dataUrl: canvas.toDataURL('image\/jpeg', 0.92)\r\n        };\r\n    },\r\n    \r\n    fillImageData(imageData, imgData, kind, width, height) {\r\n        if (kind === 'GRAY') {\r\n            for (let i = 0, j = 0; i < imgData.length; i++, j += 4) {\r\n                const value = imgData[i];\r\n                imageData.data[j] = value;\r\n                imageData.data[j + 1] = value;\r\n                imageData.data[j + 2] = value;\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (kind === 'CMYK') {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 4, j += 4) {\r\n                const c = imgData[i] \/ 255;\r\n                const m = imgData[i + 1] \/ 255;\r\n                const y = imgData[i + 2] \/ 255;\r\n                const k = imgData[i + 3] \/ 255;\r\n                \r\n                imageData.data[j] = 255 * (1 - c) * (1 - k);\r\n                imageData.data[j + 1] = 255 * (1 - m) * (1 - k);\r\n                imageData.data[j + 2] = 255 * (1 - y) * (1 - k);\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (kind === 'RGB24') {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 3, j += 4) {\r\n                imageData.data[j] = imgData[i];\r\n                imageData.data[j + 1] = imgData[i + 1];\r\n                imageData.data[j + 2] = imgData[i + 2];\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (imgData.length === width * height * 3) {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 3, j += 4) {\r\n                imageData.data[j] = imgData[i];\r\n                imageData.data[j + 1] = imgData[i + 1];\r\n                imageData.data[j + 2] = imgData[i + 2];\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else {\r\n            const tempArray = new Uint8ClampedArray(imgData.length);\r\n            for (let i = 0; i < imgData.length; i++) {\r\n                tempArray[i] = imgData[i];\r\n            }\r\n            \r\n            if (tempArray.length === imageData.data.length \/ 4 * 3) {\r\n                for (let i = 0, j = 0; i < tempArray.length; i += 3, j += 4) {\r\n                    imageData.data[j] = tempArray[i];\r\n                    imageData.data[j + 1] = tempArray[i + 1];\r\n                    imageData.data[j + 2] = tempArray[i + 2];\r\n                    imageData.data[j + 3] = 255;\r\n                }\r\n            } else if (tempArray.length === imageData.data.length) {\r\n                imageData.data.set(tempArray);\r\n            } else {\r\n                console.warn('Unknown image format - creating placeholder');\r\n                for (let i = 0; i < imageData.data.length; i += 4) {\r\n                    const x = (i\/4) % width;\r\n                    const y = Math.floor((i\/4) \/ width);\r\n                    imageData.data[i] = x % 256;\r\n                    imageData.data[i + 1] = y % 256;\r\n                    imageData.data[i + 2] = 100;\r\n                    imageData.data[i + 3] = 255;\r\n                }\r\n            }\r\n        }\r\n    },\r\n    \r\n    attachPDFPreviewHandler($dropZone, titleText) {\r\n        var $droppable = $dropZone.closest('.droppable');\r\n        var self = this;\r\n\r\n        \/\/ \u2705 Adapter le libell\u00e9 selon le format (communiqu\u00e9 \/ interview)\r\n        var kitFormat = $droppable.data('kitFormatSelect') || '';\r\n        var isInterview = (kitFormat || titleText || '').toLowerCase().indexOf('interview') !== -1;\r\n        var formatLabel = isInterview ? 'l\\'interview' : 'le communiqu\u00e9';\r\n        $droppable.find('.doc-preview-readmore').text('Ouvrir et visualiser ' + formatLabel);\r\n\r\n        \/\/ \u2705 v2.0.11 : D\u00e9l\u00e9gation d'\u00e9v\u00e9nement \u2014 plus robuste sur mobile\r\n        $droppable.off('click.docpreview').on('click.docpreview', '.doc-preview-readmore', (event) => {\r\n            event.preventDefault();\r\n            event.stopPropagation();\r\n            var popupTitle = isInterview ? 'Interview' : 'Communiqu\u00e9';\r\n\r\n            \/\/ \u2705 Priorit\u00e9 1 : pdfImageDataURL dispo (Kit)\r\n            var kitPdfImage = $droppable.data('kitPdfImageDataURL');\r\n            if (kitPdfImage) {\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    pdfDataURL: kitPdfImage\r\n                });\r\n                return;\r\n            }\r\n\r\n            \/\/ \u2705 Priorit\u00e9 2 : PDF upload\u00e9 manuellement \u2192 popup inline aussi\r\n            if (self.pdfDataForViewer && self.pdfDataForViewer.byteLength > 0) {\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    pdfArrayBuffer: self.pdfDataForViewer\r\n                });\r\n                return;\r\n            }\r\n\r\n            console.error('PDF data is not available');\r\n        });\r\n    },\r\n\r\n    \/\/ \u2705 v1.19.1 : Popup inline document \u2014 position:absolute + ScrollHelper.getVisibleTop()\r\n    \/\/ Le parent envoie visibleTopIframe dans le message scroll \u2192 positionnement fiable.\r\n    showInlineDocPopup($dropZone, options) {\r\n        var existing = document.getElementById('via-pdf-inline-popup');\r\n        if (existing) existing.remove();\r\n\r\n        var $droppable = $dropZone.closest('.droppable');\r\n        var droppableW = $droppable.outerWidth() || 300;\r\n        var popupW = Math.round(droppableW * 1.15);\r\n        \/\/ \u2705 v2.0.11 : Contraindre la largeur au viewport sur mobile (\u00e9vite troncature gauche\/droite)\r\n        var viewportW = document.documentElement.clientWidth || window.innerWidth;\r\n        if (UIManager.isMobile()) {\r\n            popupW = Math.min(popupW, viewportW - 8);\r\n        }\r\n        var popupH = Math.round(popupW * 2.5 * 0.51);\r\n\r\n        \/\/ \u2500\u2500 Position visible r\u00e9elle \u2500\u2500\r\n        var visibleTop = ScrollHelper.getVisibleTop();\r\n        var popupTop = Math.round(visibleTop + 284);\r\n\r\n        \/\/ \u2500\u2500 Popup position:absolute (positionn\u00e9 dans le document iframe) \u2500\u2500\r\n        var popup = document.createElement('div');\r\n        popup.id = 'via-pdf-inline-popup';\r\n        popup.style.cssText =\r\n            'position:absolute;z-index:99999;top:' + popupTop + 'px;' +\r\n            'width:' + popupW + 'px;height:' + popupH + 'px;' +\r\n            'background:#fff;border-radius:8px 8px 0 0;padding:0;' +\r\n            'box-shadow:0 8px 32px rgba(0,0,0,0.35);display:flex;flex-direction:column;' +\r\n            'min-width:200px;min-height:150px;touch-action:none;';\r\n\r\n        \/\/ Centrer horizontalement sur le droppable (coordonn\u00e9es absolues)\r\n        var droppableRect = $droppable[0].getBoundingClientRect();\r\n        var scrollX = window.scrollX || 0;\r\n        var initLeft = Math.round(droppableRect.left + scrollX + (droppableRect.width - popupW) \/ 2);\r\n        initLeft = Math.max(4, initLeft);\r\n        \/\/ \u2705 v2.0.11 : Contraindre \u00e0 droite aussi sur mobile\r\n        if (UIManager.isMobile()) {\r\n            initLeft = Math.min(initLeft, viewportW - popupW - 4);\r\n            initLeft = Math.max(4, initLeft);\r\n        }\r\n        popup.style.left = initLeft + 'px';\r\n\r\n        \/\/ \u2500\u2500 Header \u2500\u2500\r\n        var header = document.createElement('div');\r\n        header.style.cssText =\r\n            'display:flex;align-items:center;justify-content:center;position:relative;' +\r\n            'padding:10px 14px;background:#f0f0f0;color:#494949;flex-shrink:0;' +\r\n            'cursor:grab;user-select:none;border-radius:8px 8px 0 0;';\r\n        var titleEl = document.createElement('span');\r\n        titleEl.style.cssText = 'font-family:Roboto,Arial,sans-serif;font-size:15px;font-weight:600;';\r\n        titleEl.textContent = options.formatTitle || 'Document';\r\n        header.appendChild(titleEl);\r\n\r\n        var closeBtn = document.createElement('button');\r\n        closeBtn.textContent = '\u00d7';\r\n        closeBtn.style.cssText =\r\n            'position:absolute;right:10px;top:50%;transform:translateY(-50%);' +\r\n            'background:transparent;border:none;color:#494949;font-size:20px;' +\r\n            'cursor:pointer;line-height:1;padding:0 4px;';\r\n        closeBtn.addEventListener('click', cleanup);\r\n        header.appendChild(closeBtn);\r\n        popup.appendChild(header);\r\n\r\n        \/\/ \u2500\u2500 Zone scrollable \u2014 pleine largeur \u2500\u2500\r\n        var scrollZone = document.createElement('div');\r\n        scrollZone.style.cssText =\r\n            'flex:1;overflow-y:auto;overflow-x:hidden;padding:0;margin:0;touch-action:pan-y;';\r\n        popup.appendChild(scrollZone);\r\n\r\n        var loader = document.createElement('div');\r\n        loader.style.cssText =\r\n            'text-align:center;padding:30px;font-family:Roboto,Arial,sans-serif;font-size:12px;color:#666;';\r\n        loader.textContent = 'Chargement du document\u2026';\r\n        scrollZone.appendChild(loader);\r\n\r\n        \/\/ \u2500\u2500 8 poign\u00e9es de redimensionnement \u2500\u2500\r\n        var handles = [\r\n            { cursor:'nw-resize', pos:'top:-4px;left:-4px;',       dx:-1, dy:-1 },\r\n            { cursor:'n-resize',  pos:'top:-4px;left:50%;',        dx:0,  dy:-1 },\r\n            { cursor:'ne-resize', pos:'top:-4px;right:-4px;',      dx:1,  dy:-1 },\r\n            { cursor:'w-resize',  pos:'top:50%;left:-4px;',        dx:-1, dy:0  },\r\n            { cursor:'e-resize',  pos:'top:50%;right:-4px;',       dx:1,  dy:0  },\r\n            { cursor:'sw-resize', pos:'bottom:-4px;left:-4px;',    dx:-1, dy:1  },\r\n            { cursor:'s-resize',  pos:'bottom:-4px;left:50%;',     dx:0,  dy:1  },\r\n            { cursor:'se-resize', pos:'bottom:-4px;right:-4px;',   dx:1,  dy:1  }\r\n        ];\r\n        handles.forEach(function(h) {\r\n            var handle = document.createElement('div');\r\n            var isCorner = (h.dx !== 0 && h.dy !== 0);\r\n            handle.style.cssText =\r\n                'position:absolute;touch-action:none;' + h.pos +\r\n                'width:' + (isCorner ? '12px' : (h.dy === 0 ? '8px' : '30px')) + ';' +\r\n                'height:' + (isCorner ? '12px' : (h.dy === 0 ? '30px' : '8px')) + ';' +\r\n                'cursor:' + h.cursor + ';z-index:10;';\r\n            (function(hInfo) {\r\n                handle.addEventListener('pointerdown', function(e) {\r\n                    e.preventDefault(); e.stopPropagation();\r\n                    handle.setPointerCapture(e.pointerId);\r\n                    var startX = e.clientX, startY = e.clientY;\r\n                    var rect0 = popup.getBoundingClientRect();\r\n                    var sY = window.scrollY || 0, sX = window.scrollX || 0;\r\n                    var startW = rect0.width, startH = rect0.height;\r\n                    var startL = rect0.left + sX, startT = rect0.top + sY;\r\n                    function onResize(ev) {\r\n                        ev.preventDefault();\r\n                        var ddx = ev.clientX - startX, ddy = ev.clientY - startY;\r\n                        var newW = startW, newH = startH, newL = startL, newT = startT;\r\n                        if (hInfo.dx === 1)  newW = Math.max(200, startW + ddx);\r\n                        if (hInfo.dx === -1) { newW = Math.max(200, startW - ddx); newL = startL + ddx; }\r\n                        if (hInfo.dy === 1)  newH = Math.max(150, startH + ddy);\r\n                        if (hInfo.dy === -1) { newH = Math.max(150, startH - ddy); newT = startT + ddy; }\r\n                        popup.style.width  = newW + 'px';\r\n                        popup.style.height = newH + 'px';\r\n                        popup.style.left   = newL + 'px';\r\n                        popup.style.top    = newT + 'px';\r\n                    }\r\n                    function onResizeEnd(ev) {\r\n                        handle.releasePointerCapture(ev.pointerId);\r\n                        handle.removeEventListener('pointermove', onResize);\r\n                        handle.removeEventListener('pointerup', onResizeEnd);\r\n                    }\r\n                    handle.addEventListener('pointermove', onResize);\r\n                    handle.addEventListener('pointerup', onResizeEnd);\r\n                });\r\n            })(h);\r\n            popup.appendChild(handle);\r\n        });\r\n\r\n        \/\/ \u2500\u2500 Drag via header \u2500\u2500\r\n        header.style.touchAction = 'none';\r\n        header.addEventListener('pointerdown', function(e) {\r\n            if (e.target === closeBtn) return;\r\n            e.preventDefault();\r\n            header.setPointerCapture(e.pointerId);\r\n            var mx = e.clientX, my = e.clientY;\r\n            var popupRect = popup.getBoundingClientRect();\r\n            var scrollY = window.scrollY || 0;\r\n            var scrollX = window.scrollX || 0;\r\n            var curLeft = popupRect.left + scrollX;\r\n            var curTop  = popupRect.top  + scrollY;\r\n            header.style.cursor = 'grabbing';\r\n            function onMove(ev) {\r\n                ev.preventDefault();\r\n                var dx = ev.clientX - mx;\r\n                var dy = ev.clientY - my;\r\n                curLeft += dx;\r\n                curTop  += dy;\r\n                popup.style.left = curLeft + 'px';\r\n                popup.style.top  = curTop  + 'px';\r\n                mx = ev.clientX;\r\n                my = ev.clientY;\r\n            }\r\n            function onUp(ev) {\r\n                header.releasePointerCapture(ev.pointerId);\r\n                header.style.cursor = 'grab';\r\n                header.removeEventListener('pointermove', onMove);\r\n                header.removeEventListener('pointerup', onUp);\r\n            }\r\n            header.addEventListener('pointermove', onMove);\r\n            header.addEventListener('pointerup', onUp);\r\n        });\r\n\r\n        \/\/ \u2500\u2500 Cleanup \u2500\u2500\r\n        function cleanup() {\r\n            popup.remove();\r\n            document.removeEventListener('keydown', escHandler);\r\n        }\r\n        var escHandler = function(e) { if (e.key === 'Escape') cleanup(); };\r\n        document.addEventListener('keydown', escHandler);\r\n\r\n        document.body.appendChild(popup);\r\n\r\n        \/\/ \u2500\u2500 Rendre le contenu \u2500\u2500\r\n        if (options.pdfDataURL)          this.renderPdfInPopup(scrollZone, options.pdfDataURL, popupW, 'dataurl');\r\n        else if (options.pdfArrayBuffer) this.renderPdfInPopup(scrollZone, options.pdfArrayBuffer, popupW, 'arraybuffer');\r\n        else if (options.htmlContent)    this.renderHtmlInPopup(scrollZone, options.htmlContent);\r\n    },\r\n\r\n    \/\/ Alias pour compatibilit\u00e9\r\n    showInlinePdfPopup($dropZone, pdfImageDataURL, formatTitle) {\r\n        this.showInlineDocPopup($dropZone, { formatTitle: formatTitle, pdfDataURL: pdfImageDataURL });\r\n    },\r\n\r\n    \/\/ \u2705 Rendu PDF dans popup (dataurl ou arraybuffer) \u2014 avec crop des marges blanches\r\n    async renderPdfInPopup(container, pdfData, popupWidth, mode) {\r\n        try {\r\n            var u8;\r\n            if (mode === 'dataurl') {\r\n                var b64 = pdfData.split(',')[1];\r\n                var bstr = atob(b64);\r\n                u8 = new Uint8Array(bstr.length);\r\n                for (var i = 0; i < bstr.length; i++) { u8[i] = bstr.charCodeAt(i); }\r\n            } else {\r\n                u8 = new Uint8Array(pdfData);\r\n            }\r\n\r\n            var pdfjsLib = window['pdfjs-dist\/build\/pdf'];\r\n            if (!pdfjsLib) {\r\n                container.innerHTML = '<div style=\"padding:20px;text-align:center;color:#c00;\">pdf.js non charg\u00e9<\/div>';\r\n                return;\r\n            }\r\n            pdfjsLib.GlobalWorkerOptions.workerSrc =\r\n                '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n\r\n            var pdf = await pdfjsLib.getDocument({ data: u8 }).promise;\r\n            console.log('\ud83d\udcc4 PDF popup :', pdf.numPages, 'pages');\r\n            container.innerHTML = '';\r\n\r\n            var firstPage = await pdf.getPage(1);\r\n            var vpNative = firstPage.getViewport({ scale: 1 });\r\n            var scale = popupWidth \/ vpNative.width;\r\n\r\n            \/\/ \u2705 R\u00e9f\u00e9rence au popup pour ajuster sa hauteur apr\u00e8s rendu\r\n            var _popup = container.closest('#via-pdf-inline-popup');\r\n            var _headerH = _popup ? (_popup.querySelector('div[style*=\"grab\"]') || {offsetHeight: 44}).offsetHeight : 44;\r\n\r\n            \/\/ \u2705 D\u00e9tecte les marges blanches haut\/bas d'un canvas rendu et retourne {top, bottom}\r\n            function detectWhiteMargins(canvas) {\r\n                var ctx = canvas.getContext('2d');\r\n                var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\r\n                var W = canvas.width, H = canvas.height;\r\n                var topRow = 0, bottomRow = H - 1;\r\n                \/\/ Chercher la premi\u00e8re ligne non-blanche (tol\u00e9rance 252 pour les artefacts anti-aliasing)\r\n                outer: for (var y = 0; y < H; y++) {\r\n                    for (var x = 0; x < W; x++) {\r\n                        var i = (y * W + x) * 4;\r\n                        if (data[i] < 252 || data[i+1] < 252 || data[i+2] < 252) { topRow = y; break outer; }\r\n                    }\r\n                }\r\n                outer2: for (var y2 = H - 1; y2 >= topRow; y2--) {\r\n                    for (var x2 = 0; x2 < W; x2++) {\r\n                        var i2 = (y2 * W + x2) * 4;\r\n                        if (data[i2] < 252 || data[i2+1] < 252 || data[i2+2] < 252) { bottomRow = y2; break outer2; }\r\n                    }\r\n                }\r\n                return { top: topRow, bottom: bottomRow };\r\n            }\r\n\r\n            for (var pageNum = 1; pageNum <= pdf.numPages; pageNum++) {\r\n                var page = await pdf.getPage(pageNum);\r\n                var vp = page.getViewport({ scale: scale });\r\n                \/\/ Rendre dans un canvas temporaire\r\n                var tmpCanvas = document.createElement('canvas');\r\n                tmpCanvas.width = vp.width;\r\n                tmpCanvas.height = vp.height;\r\n                await page.render({ canvasContext: tmpCanvas.getContext('2d'), viewport: vp }).promise;\r\n\r\n                \/\/ \u2705 Crop marges blanches\r\n                var margins = detectWhiteMargins(tmpCanvas);\r\n                var cropTop = Math.max(0, margins.top - 4);\r\n                var cropBottom = Math.min(tmpCanvas.height - 1, margins.bottom + 4);\r\n                var croppedH = cropBottom - cropTop + 1;\r\n\r\n                \/\/ Canvas final crop\u00e9\r\n                var canvas = document.createElement('canvas');\r\n                canvas.width = tmpCanvas.width;\r\n                canvas.height = croppedH;\r\n                canvas.getContext('2d').drawImage(tmpCanvas, 0, cropTop, tmpCanvas.width, croppedH, 0, 0, tmpCanvas.width, croppedH);\r\n                canvas.style.cssText = 'display:block;width:100%;height:auto;margin:0;padding:0;';\r\n                container.appendChild(canvas);\r\n                console.log('\ud83d\udcc4 Page', pageNum, '- crop:', cropTop, '\u2192', cropBottom, '(', Math.round(cropTop\/vp.height*100), '% top trimmed)');\r\n            }\r\n\r\n            \/\/ \u2705 Ajuster la hauteur du popup \u00e0 la hauteur r\u00e9elle du contenu rendu\r\n            \/\/ (popup \u00e9tait calcul\u00e9 sur popupW*2.5*0.51 qui peut \u00eatre trop grand ou trop petit)\r\n            if (_popup) {\r\n                var _totalH = 0;\r\n                container.querySelectorAll('canvas').forEach(function(c) { _totalH += c.height * (popupWidth \/ c.width); });\r\n                var _viewportH = window.innerHeight || document.documentElement.clientHeight || 600;\r\n                var _maxPopupH = Math.round(_viewportH * 0.88);\r\n                var _idealH = Math.min(_totalH + _headerH + 8, _maxPopupH);\r\n                _popup.style.height = _idealH + 'px';\r\n                console.log('\ud83d\udcd0 Popup redimensionn\u00e9:', Math.round(_idealH), 'px (contenu:', Math.round(_totalH), ')');\r\n            }\r\n        } catch (err) {\r\n            console.error('\u274c Erreur rendu PDF popup:', err);\r\n            container.innerHTML =\r\n                '<div style=\"padding:20px;text-align:center;color:#c00;font-size:12px;\">Erreur lors du chargement du document<\/div>';\r\n        }\r\n    },\r\n\r\n    \/\/ \u2705 Rendu HTML (Word) dans popup \u2014 avec CSS complet pour mammoth\r\n    renderHtmlInPopup(container, htmlContent) {\r\n        container.innerHTML = '';\r\n        \/\/ \u2705 Nettoyer les <p> vides en d\u00e9but\/fin produits par mammoth (marges parasites)\r\n        htmlContent = htmlContent\r\n            .replace(\/^(\\s*<p[^>]*>\\s*(<br\\s*\\\/?>\\s*)*<\\\/p>\\s*)+\/i, '')\r\n            .replace(\/(\\s*<p[^>]*>\\s*(<br\\s*\\\/?>\\s*)*<\\\/p>\\s*)+$\/i, '');\r\n        \/\/ \u2500\u2500 Styles pour le HTML g\u00e9n\u00e9r\u00e9 par mammoth (titres, paragraphes, listes, images) \u2500\u2500\r\n        var style = document.createElement('style');\r\n        style.textContent = [\r\n            '.via-html-popup-body { padding:20px 24px; background:#fff; color:#222; font-family:Georgia,\"Times New Roman\",serif; font-size:15px; line-height:1.7; }',\r\n            '.via-html-popup-body h1 { font-size:22px; font-weight:700; margin:0 0 12px; line-height:1.3; }',\r\n            '.via-html-popup-body h2 { font-size:18px; font-weight:700; margin:18px 0 8px; line-height:1.3; }',\r\n            '.via-html-popup-body h3 { font-size:15px; font-weight:700; margin:14px 0 6px; }',\r\n            '.via-html-popup-body p  { margin:0 0 10px; }',\r\n            '.via-html-popup-body p:first-child { margin-top:0; }',\r\n            '.via-html-popup-body strong, .via-html-popup-body b { font-weight:700; }',\r\n            '.via-html-popup-body em, .via-html-popup-body i { font-style:italic; }',\r\n            '.via-html-popup-body ul, .via-html-popup-body ol { margin:6px 0 10px 22px; padding:0; }',\r\n            '.via-html-popup-body li { margin-bottom:4px; }',\r\n            '.via-html-popup-body img { max-width:100%; height:auto; display:block; margin:10px auto; border-radius:4px; }',\r\n            '.via-html-popup-body table { width:100%; border-collapse:collapse; margin:10px 0; font-size:13px; }',\r\n            '.via-html-popup-body td, .via-html-popup-body th { border:1px solid #ddd; padding:6px 8px; vertical-align:top; }',\r\n            '.via-html-popup-body th { background:#f0f4f8; font-weight:700; }',\r\n            '.via-html-popup-body a { color:#225da9; text-decoration:underline; }'\r\n        ].join('');\r\n        container.appendChild(style);\r\n        var wrapper = document.createElement('div');\r\n        wrapper.className = 'via-html-popup-body';\r\n        wrapper.innerHTML = htmlContent;\r\n        container.appendChild(wrapper);\r\n    },\r\n    \r\n    async renderPDFInWindow(childWindow, container) {\r\n        container.innerHTML = '';\r\n        \r\n        const script = childWindow.document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.4.120\/pdf.min.js';\r\n        childWindow.document.head.appendChild(script);\r\n        \r\n        script.onload = async () => {\r\n            const pdfjsLib = childWindow.pdfjsLib;\r\n            const viewerContainer = childWindow.document.createElement('div');\r\n            viewerContainer.style.width = '100%';\r\n            viewerContainer.style.backgroundColor = 'white';\r\n            viewerContainer.style.position = 'relative';\r\n            container.appendChild(viewerContainer);\r\n            \r\n            const loadingTask = pdfjsLib.getDocument({data: window.pdfDataToTransfer});\r\n            const pdf = await loadingTask.promise;\r\n            \r\n            const firstPage = await pdf.getPage(1);\r\n            const viewport = firstPage.getViewport({scale: 1.5});\r\n            const pageHeight = viewport.height;\r\n            \r\n            const spacing = -15;\r\n            const totalHeight = (pageHeight * pdf.numPages) + (spacing * (pdf.numPages - 1));\r\n            viewerContainer.style.height = `${totalHeight}px`;\r\n            \r\n            for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {\r\n                const page = await pdf.getPage(pageNum);\r\n                const canvas = childWindow.document.createElement('canvas');\r\n                const context = canvas.getContext('2d');\r\n                \r\n                canvas.width = viewport.width;\r\n                canvas.height = viewport.height;\r\n                \r\n                canvas.style.position = 'absolute';\r\n                canvas.style.left = '50%';\r\n                canvas.style.transform = 'translateX(-50%)';\r\n                canvas.style.top = `${(pageNum - 1) * (pageHeight + spacing)}px`;\r\n                \r\n                await page.render({\r\n                    canvasContext: context,\r\n                    viewport: viewport\r\n                }).promise;\r\n                \r\n                viewerContainer.appendChild(canvas);\r\n            }\r\n        };\r\n    },\r\n    \r\n    arrayBufferToBase64(buffer) {\r\n        let binary = '';\r\n        const bytes = new Uint8Array(buffer);\r\n        const len = bytes.byteLength;\r\n        for (let i = 0; i < len; i++) {\r\n            binary += String.fromCharCode(bytes[i]);\r\n        }\r\n        return window.btoa(binary);\r\n    },\r\n    \r\n    base64ToArrayBuffer(base64) {\r\n        const binaryString = window.atob(base64);\r\n        const len = binaryString.length;\r\n        const bytes = new Uint8Array(len);\r\n        for (let i = 0; i < len; i++) {\r\n            bytes[i] = binaryString.charCodeAt(i);\r\n        }\r\n        return bytes.buffer;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des \u00e9v\u00e9nements de drop et d'upload\r\n *\/\r\nconst DropHandler = {\r\n    async handleDrop(e) {\r\n        e.preventDefault();\r\n        \r\n        const $currentTarget = this.findDropTarget(e);\r\n        \r\n        if (!$currentTarget) {\r\n            console.log('No valid drop target found');\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 V\u00c9RIFIER SI C'EST UN D\u00c9PLACEMENT (pas besoin de v\u00e9rifier le format)\r\n        const isMoved = StateManager.get('FirstUploadFileorMoved') === 'Moved';\r\n        const dragstartRef = StateManager.get('dragstart_Commande_Emplacement_Page_Web');\r\n        let hasDragstartRef = false;\r\n        \r\n        if (dragstartRef) {\r\n            if (dragstartRef !== 'No') {\r\n                hasDragstartRef = true;\r\n            }\r\n        }\r\n        \r\n        let isDeplacementAnnonce = false;\r\n        if (isMoved) {\r\n            if (hasDragstartRef) {\r\n                isDeplacementAnnonce = true;\r\n            }\r\n        }\r\n        \r\n        if (isDeplacementAnnonce) {\r\n            console.log('\ud83d\udd04 D\u00e9placement d\u00e9tect\u00e9 - contr\u00f4le format ignor\u00e9');\r\n        } else {\r\n            \/\/ \u2705 CONTR\u00d4LE FORMAT SEULEMENT POUR NOUVEAU D\u00c9P\u00d4T\r\n            \/\/ Utilise FormatUIManager au lieu de showFormatWarning\r\n            if (StateManager.get('Formatchoisi') === 'No') {\r\n                FormatUIManager.flashTitle($currentTarget);\r\n                return;\r\n            }\r\n            \r\n            if (!FormatUIManager.hasSelectedFormat($currentTarget)) {\r\n                FormatUIManager.flashTitle($currentTarget);\r\n                return;\r\n            }\r\n        }\r\n    \r\n        console.log(\"Drop at:\", $currentTarget);\r\n        \r\n        this.updateEmplacementState($currentTarget);\r\n        \r\n        const shouldProcess = this.shouldProcessDrop(e, $currentTarget);\r\n        \r\n        if (shouldProcess) {\r\n            await this.processFileDrop(e, $currentTarget);\r\n        } else {\r\n            this.processVideoDrop($currentTarget);\r\n        }\r\n        \r\n        DragDropManager.clearDataTransferFiles(e);\r\n    },\r\n    \r\n    findDropTarget(e) {\r\n        \/\/ \u2705 v2.4.3 : Si Ele0A est actif et le drop arrive sur Ele1A \u2192 rediriger vers Ele0A\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            var _ele0ADrop = document.querySelector('#Ele0A #drop_file_zone_achat');\r\n            if (_ele0ADrop) {\r\n                console.log('\ud83c\udfaf findDropTarget \u2014 PopUpChoice=Yes \u2192 cible forc\u00e9e: Ele0A');\r\n                return jQuery(_ele0ADrop);\r\n            }\r\n        }\r\n\r\n        let target = e.target.closest('#drop_file_zone_achat');\r\n        \r\n        if (!target) {\r\n            target = e.currentTarget.closest('#drop_file_zone_achat');\r\n            console.log('Drop target found 1');\r\n        }\r\n        \r\n        if (!target) {\r\n            target = jQuery(e.target).closest('#drop_file_zone_achat')[0];\r\n            console.log('Drop target found 2');\r\n        }\r\n        \r\n        return target ? jQuery(target) : null;\r\n    },\r\n    \r\n    updateEmplacementState($target) {\r\n        const espaceId = $target.closest('.droppable').attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', espaceId);\r\n        StateManager.set('Commande_Emplacement_Page_Web',\r\n            StateManager.buildEmplacementReference(espaceId));\r\n        \r\n        UIManager.updateEmplacementDisplay();\r\n        \r\n        console.log(\"Rank_Emplacement_Page_Web:\", StateManager.get('Rank_Emplacement_Page_Web'));\r\n        console.log(\"Droppable at:\", StateManager.get('Commande_Emplacement_Page_Web'));\r\n    },\r\n    \r\n    shouldProcessDrop(e, $target) {\r\n        const hasFiles = e.dataTransfer.files.length > 0;\r\n        const isRedactionnel = StateManager.get('Commande_Format_Transmis') === 'R\u00e9dactionnel';\r\n        const isValidBackground = window.getComputedStyle(\r\n            $target.closest('#UploadFileConteneur')[0]\r\n        ).backgroundColor !== 'rgba(0, 0, 0, 0)';\r\n        \r\n        return (hasFiles || isRedactionnel) && isValidBackground;\r\n    },\r\n    \r\n    async processFileDrop(e, $target) {\r\n        jQuery('.MsgAdNotDisplayed').hide();\r\n        StateManager.setMultiple({\r\n            \"AdDisplayed\": 'Yes',\r\n            \/\/ \u2705 NE PLUS mettre sendDataToParentFlag ici - c'est la checkbox \"R\u00e9server\" qui le fera\r\n            \/\/ \"sendDataToParentFlag\": 'Yes'\r\n        });\r\n        \r\n        console.log('ajaxFileUpload_achat launched');\r\n        console.log(\"FirstUploadFileorMoved:\", StateManager.get('FirstUploadFileorMoved'));\r\n        \r\n        if (UIManager.isMobile()) {\r\n            $target = jQuery('#Ele1A').find('#drop_file_zone_achat');\r\n        }\r\n        \r\n        if (StateManager.get('Commande_Format_Transmis') === 'R\u00e9dactionnel') {\r\n            const fileURL = StateManager.get('FullPathAdFile');\r\n            const filename = fileURL.substring(fileURL.indexOf('_') + 1);\r\n            \r\n            try {\r\n                \/\/ \u2705 R\u00e9utiliser le File cach\u00e9 (\u00e9vite CORS cross-domain)\r\n                let file;\r\n                if (window._lastRedactionnelFile) {\r\n                    file = window._lastRedactionnelFile;\r\n                    console.log('\u267b\ufe0f R\u00e9utilisation du File cach\u00e9:', file.name, Math.round(file.size \/ 1024) + 'KB');\r\n                } else {\r\n                    file = await FileManager.urlToFile(fileURL, filename);\r\n                }\r\n                await UploadManager.handleFileUpload(file, $target);\r\n            } catch (error) {\r\n                console.error('Error:', error);\r\n            }\r\n        } else {\r\n            await UploadManager.handleFileUpload(e.dataTransfer.files[0], $target);\r\n        }\r\n    },\r\n    \r\n    processVideoDrop($target) {\r\n        const isValidBackground = window.getComputedStyle(\r\n            $target.closest('#UploadFileConteneur')[0]\r\n        ).backgroundColor !== 'rgba(0, 0, 0, 0)';\r\n        \r\n        if (!isValidBackground) {\r\n            jQuery('.MsgAdNotDisplayed').show();\r\n            StateManager.set(\"AdDisplayed\", 'No');\r\n            return;\r\n        }\r\n        \r\n        StateManager.set(\"AdDisplayed\", 'Yes');\r\n        \r\n        const objectUrl = StateManager.get('videoSrc');\r\n        const $previousDropZone = $('.drop_file_zone_achat_class').has(`video[src=\"${objectUrl}\"]`);\r\n        window.RestoreadSpaceTemplate($previousDropZone);\r\n        \r\n        const videoElement = jQuery('<video controls autoplay muted>').attr({\r\n            'src': objectUrl,\r\n            'max-width': '100%',\r\n            'max-height': '100%',\r\n            'draggable': 'true'\r\n        }).css({\r\n            'max-width': '100%',\r\n            'max-height': '100%'\r\n        });\r\n        \r\n        $target.empty().append(videoElement);\r\n        \r\n        $target.closest('#UploadFileConteneur').css({'background-color': '#FFFFFF00'});\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass')\r\n            .find('.RefEspacePublicitaire')\r\n            .html('R\u00e9f\u00e9rence de l\\'espace : ' + StateManager.get('Commande_Emplacement_Page_Web'))\r\n            .attr('id', 'RefEspacePublicitaire')\r\n            .each(function() {\r\n                var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                this.style.setProperty('display', 'block', 'important');\r\n            });\r\n        \/\/ \u2705 v2.4.5 : Renseigner et afficher .PositionEspacePublicitaire\r\n        (function() {\r\n            var _rankPosV = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            var _posLibV = PreviewRenderer._getPositionLibelle(_rankPosV);\r\n            if (_posLibV) {\r\n                $target.closest('.OrdiMobileConteneurClass')\r\n                    .find('.PositionEspacePublicitaireDeplacer')\r\n                    .text(_posLibV)\r\n                    .each(function() {\r\n                        var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                        if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass').find('.AdUploadedTitle').show();\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass')\r\n            .css({'top': '60px', 'margin-bottom': '80px'});\r\n        \r\n        $target.closest('.HTMLUploadfileConteneur')\r\n            .not('.AdUploadedTitle')\r\n            .css({\r\n                'top': '0px',\r\n                'margin-bottom': '0px',\r\n                'box-shadow': 'inset 0 0 0 2px #00FF19',  \/\/ \u2705 v2.4.5\r\n                'background-color': 'white'\r\n            });\r\n        \r\n        $target.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, .ChoisirEspacePublicitaire2ndLigne, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        jQuery('#MsgElementsCommandeValides, #MessageOptionsacompleterConteneur').hide();\r\n        \r\n        StateManager.set(\"FirstUploadFileorMoved\", 'Moved');\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server (au lieu d'envoyer automatiquement)\r\n        FormatUIManager.updateReserverCheckboxState($target.closest('.droppable'));\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'explorateur de fichiers\r\n *\/\r\nconst FileExplorer = {\r\n    isRunning: false,\r\n\r\n    open(e) {\r\n        if (this.isRunning) {\r\n            return;\r\n        }\r\n        \r\n        const $element = jQuery(e.target).closest('.droppable');\r\n        \r\n        \/\/ \u2705 V\u00e9rifier si un format est s\u00e9lectionn\u00e9 (utilise FormatUIManager)\r\n        if (!FormatUIManager.hasSelectedFormat($element)) {\r\n            FormatUIManager.flashTitle($element);\r\n            return;\r\n        }\r\n        \r\n        this.isRunning = true;\r\n        \r\n        const rankId = $element.attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', rankId);\r\n        StateManager.set('Commande_Emplacement_Page_Web',\r\n            StateManager.buildEmplacementReference(rankId));\r\n        \r\n        UIManager.updateEmplacementDisplay();\r\n        \r\n        console.log(\"Drop at:\", StateManager.get('Commande_Emplacement_Page_Web'));\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        \r\n        const $currentTarget = jQuery(e.target).closest('#drop_file_zone_achat');\r\n        const $fileInput = jQuery('#selectfile_achat');\r\n        \r\n        console.log(\"currentTarget\", $currentTarget);\r\n        \r\n        $fileInput.off('change');\r\n        $fileInput.off('click');\r\n        \r\n        const onChange = (event) => {\r\n            this.isRunning = false;\r\n            $fileInput.off('change', onChange);\r\n            \r\n            \/\/ \u2705 NE PLUS mettre sendDataToParentFlag ici\r\n            \/\/ StateManager.set(\"sendDataToParentFlag\", 'Yes');\r\n            \r\n            if ($fileInput[0].files.length > 0) {\r\n                UploadManager.handleFileUpload($fileInput[0].files[0], $currentTarget);\r\n            }\r\n        };\r\n        \r\n        const onClick = () => {\r\n            $fileInput.off('click', onClick);\r\n            $fileInput.on('focus', function onFocus() {\r\n                setTimeout(() => {\r\n                    if (!$fileInput.val()) {\r\n                        FileExplorer.isRunning = false;\r\n                    }\r\n                }, 200);\r\n                $fileInput.off('focus', onFocus);\r\n            });\r\n        };\r\n        \r\n        $fileInput.on('change', onChange);\r\n        $fileInput.on('click', onClick);\r\n        \r\n        $fileInput.click();\r\n        \r\n        setTimeout(() => {\r\n            this.isRunning = false;\r\n        }, 300);\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion du reset d'annonce\r\n *\/\r\nconst AdResetHandler = {\r\n    handle(e) {\r\n        e.preventDefault();\r\n        console.log(\"CroixResetAnnonce click\");\r\n        \r\n        \/\/ Reset l'\u00e9tat EnvoiUlterieur\r\n        StateManager.set('EnvoiUlterieur', 'false');\r\n        \r\n        \/\/ \u2705 v1.19.6 : Reset FileReceived mais garder le format s\u00e9lectionn\u00e9\r\n        StateManager.set('FileReceived', 'No');\r\n        \r\n        const $element = jQuery(e.currentTarget);\r\n        const $droppable = $element.closest('.droppable');\r\n        const resetRef = StateManager.buildEmplacementReference($droppable.attr('id'));\r\n        \r\n        console.log(\"Reset_Commande_Emplacement_Page_Web:\", resetRef);\r\n        \r\n        \/\/ \u2705 Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        var _rankForDel = $droppable.attr('id') || StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            MessageManager.sendDelAdToParent({\r\n                Commande_Emplacement_Page_Web: resetRef,\r\n                Rank_Emplacement_Page_Web: _rankForDel,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n        } else {\r\n            window.processdataDelAd({\r\n                Commande_Emplacement_Page_Web: resetRef,\r\n                Rank_Emplacement_Page_Web: _rankForDel,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n        }\r\n        \r\n        \/\/ \u2705 v1.16.0 : Appeler RestoreadSpaceTemplateLocal directement (accessible dans ce scope)\r\n        RestoreadSpaceTemplateLocal(e.currentTarget);\r\n        \r\n        window.FonctionCroixResetAnnonce(e.currentTarget);\r\n        \r\n        \/\/ \u2705 v2.1.1 : Sauf popup\r\n        var formatWasSelected = sessionStorage.getItem('FormatSelect') \r\n            || sessionStorage.getItem('Commande_Format_Transmis')\r\n            || $droppable.data('kitFormatSelect');\r\n        \r\n        if (sessionStorage.getItem('PopUpChoice') !== 'Yes' && (formatWasSelected || sessionStorage.getItem('Formatchoisi') === 'Yes')) {\r\n            sessionStorage.setItem('Formatchoisi', 'Yes');\r\n            console.log('\u2705 Formatchoisi forc\u00e9 \u00e0 Yes apr\u00e8s reset');\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.6 : Remettre \u00e0 jour le titre format et r\u00e9afficher la checkbox R\u00e9server\r\n        setTimeout(() => {\r\n            FormatUIManager.updateTitleColor($droppable);\r\n            FormatUIManager.updateReserverCheckboxState($droppable);\r\n            \r\n            \/\/ \u2705 R\u00e9afficher le .ReserverContainer statique\r\n            $droppable.find('.ReserverContainer').show();\r\n        }, 150);\r\n    }\r\n};\r\n\r\n\/**\r\n * \u2705 Template pour r\u00e9initialisation des espaces publicitaires (IFRAME)\r\n *\/\r\nvar adSpaceTemplatesLocal = {};\r\n\r\nfunction saveAdSpaceTemplateLocal() {\r\n    var saved = 0;\r\n    jQuery('.droppable').each(function() {\r\n        var droppableId = jQuery(this).attr('id');\r\n        if (!droppableId) return;\r\n        \r\n        \/\/ \u2705 Ne jamais sauvegarder Ele0A (clone temporaire popup, pas un template d'origine)\r\n        if (droppableId === 'Ele0A') return;\r\n        \r\n        \/\/ \u2705 Ne pas r\u00e9-\u00e9craser un template d\u00e9j\u00e0 sauvegard\u00e9\r\n        if (adSpaceTemplatesLocal[droppableId]) return;\r\n        \r\n        \/\/ \u2705 v2.3.4 : Ne pas sauvegarder si template d\u00e9j\u00e0 connu (\u00e9tat propre sauvegard\u00e9)\r\n        \/\/ Le guard hasAd est supprim\u00e9 \u2014 on veut capturer le template le plus t\u00f4t possible\r\n        \/\/ Si le template existe d\u00e9j\u00e0, on ne le r\u00e9\u00e9crase pas\r\n        \/\/ (le guard anti-\u00e9crasement if (adSpaceTemplatesLocal[droppableId]) return; suffit)\r\n        \r\n        var $content = jQuery(this).find('.OrdiMobileConteneurClass').first();\r\n        if ($content.length > 0) {\r\n            adSpaceTemplatesLocal[droppableId] = $content.clone(true, true);\r\n            saved++;\r\n        }\r\n    });\r\n    if (saved > 0) {\r\n        console.log('\u2705 Templates espaces pub sauvegard\u00e9s:', saved, 'espaces -', Object.keys(adSpaceTemplatesLocal));\r\n        return true;\r\n    }\r\n    return false;\r\n}\r\n\r\nfunction RestoreadSpaceTemplateLocal(element) {\r\n    console.log('\ud83d\udd04 RestoreadSpaceTemplateLocal', element);\r\n    \r\n    var $element = jQuery(element);\r\n    var $droppable = $element.closest('.droppable');\r\n    var droppableId = $droppable.attr('id');\r\n    \r\n    \/\/ \u2705 FIX Ele0A : pas de template sauvegard\u00e9 (clone temporaire popup)\r\n    \/\/ \u2192 pas de remplacement DOM, reset visuel direct sur le contenu existant\r\n    var _isEle0A = (droppableId === 'Ele0A');\r\n\r\n    \/\/ \u2705 v1.19.3 : Chercher le template sp\u00e9cifique \u00e0 CET espace (sauf Ele0A)\r\n    if (!_isEle0A) {\r\n        if (!droppableId || !adSpaceTemplatesLocal[droppableId]) {\r\n            if (!saveAdSpaceTemplateLocal()) {\r\n                console.error('\u274c Template non disponible');\r\n                return false;\r\n            }\r\n            if (!adSpaceTemplatesLocal[droppableId]) {\r\n                console.error('\u274c Template non trouv\u00e9 pour', droppableId);\r\n                return false;\r\n            }\r\n        }\r\n    }\r\n    \r\n    var adSpaceElement = $droppable.find('.OrdiMobileConteneurClass').first();\r\n    \r\n    if (!adSpaceElement || !adSpaceElement.length) {\r\n        console.error('\u274c OrdiMobileConteneurClass non trouv\u00e9');\r\n        return false;\r\n    }\r\n    \r\n    var newElement;\r\n    if (_isEle0A) {\r\n        \/\/ Ele0A : pas de clone \u2014 on remet en \u00e9tat le contenu existant directement\r\n        newElement = adSpaceElement;\r\n        console.log('\u2705 [Ele0A] reset visuel direct (pas de template clone)');\r\n        \/\/ \u2705 Vider le contenu du dropzone et restaurer le HTML par d\u00e9faut\r\n        \/\/ (le replaceWith n'ayant pas lieu, l'image d\u00e9pos\u00e9e et le fond blanc restent sinon)\r\n        var $dz0A = $droppable.find('#drop_file_zone_achat');\r\n        $dz0A.empty().html(\r\n            '<div id=\"drag_upload_file_achat\">' +\r\n                '<p class=\"UploadIci\" style=\"color:#FB5E2A;font-weight:600;\">Ici glisser \u2013 d\u00e9poser ou<br>t\u00e9l\u00e9charger une annonce<\/p>' +\r\n            '<\/div>'\r\n        );\r\n        \/\/ Restaurer le fond bleu #9FC5F3 et retirer les styles d'annonce upload\u00e9e\r\n        $droppable.find('#UploadFileConteneur').css({\r\n            'background-color': '#9FC5F3',\r\n            'border': '',\r\n            'box-sizing': ''\r\n        });\r\n        $droppable.find('.HTMLUploadfileConteneur').css({\r\n            'box-shadow': '',\r\n            'background-color': '',\r\n            'border': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': '',\r\n            'overflow': '',\r\n            'height': '',\r\n            'max-height': ''\r\n        });\r\n        \/\/ Masquer la croix et le titre d'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle, #CroixResetAnnonce, .CroixResetAnnonceContainer, .DeplaceAnnonce').hide();\r\n        $droppable.removeAttr('data-via-ad-loaded').removeAttr('data-from-miniature');\r\n        console.log('\u2705 [Ele0A] dropzone vid\u00e9 + fond restaur\u00e9');\r\n    } else {\r\n        \/\/ \u2705 v1.19.3 : Cloner le template SP\u00c9CIFIQUE \u00e0 cet espace (pas le premier)\r\n        newElement = adSpaceTemplatesLocal[droppableId].clone(true, true);\r\n        console.log('\u2705 Template utilis\u00e9 pour', droppableId);\r\n        adSpaceElement.replaceWith(newElement);\r\n        \/\/ \u2705 v2.4.12 : Effacer data-via-ad-loaded (sinon selectEspaceActif masque .ReserverContainer)\r\n        $droppable.removeAttr('data-via-ad-loaded').removeAttr('data-from-miniature');\r\n        if (window.outerWidth < 1000) {\r\n            newElement.css({'margin-top': '-25px', 'bottom': '0px'});\r\n        }\r\n    }\r\n    \r\n    \/\/ D\u00e9cocher la case Envoi diff\u00e9r\u00e9 si elle existe\r\n    newElement.find('input[name*=\"EnvoiUlterieur\"]').prop('checked', false);\r\n    \r\n    \/\/ \u2705 D\u00e9cocher la checkbox \"R\u00e9server\"\r\n    newElement.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked', false);\r\n    \r\n    \/\/ Reset l'\u00e9tat EnvoiUlterieur\r\n    StateManager.set('EnvoiUlterieur', 'false');\r\n    \r\n    \/\/ \u2705 v1.19.3 : R\u00e9initialiser TOUS les styles inline des conteneurs parents modifi\u00e9s pendant le d\u00e9p\u00f4t\r\n    if ($droppable.length) {\r\n        \/\/ \u2705 v2.0.9 : Restaurer les marges de l'algorithme de positionnement (sauvegard\u00e9es par styleUploadedAd)\r\n        var origMt = $droppable.data('orig-mt');\r\n        $droppable.css({\r\n            'margin-top': (origMt !== undefined) ? origMt + 'px' : '',\r\n            'margin-bottom': '',\r\n            'margin-left': '',\r\n            'margin-right': ''\r\n        });\r\n        \/\/ \u2705 v2.0.11 : Cleanup event namespace docpreview\r\n        $droppable.off('click.docpreview');\r\n        \r\n        \/\/ Reset .OrdiMobileConteneurClass margins\r\n        var $container = $droppable.find('.OrdiMobileConteneurClass');\r\n        var origMb = $container.data('orig-mb');\r\n        $container.css({\r\n            'margin-top': '',\r\n            'margin-bottom': (origMb !== undefined) ? origMb + 'px' : ''\r\n        });\r\n        \r\n        \/\/ Reset .HTMLUploadfileConteneur (set by styleUploadedAd: box-shadow inset, background-color:white)\r\n        $droppable.find('.HTMLUploadfileConteneur').css({\r\n            'border': '',\r\n            'box-shadow': '',\r\n            'outline': '',\r\n            'outline-offset': '',\r\n            'background-color': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': '',\r\n            'overflow': '',\r\n            'padding': '',\r\n            'position': ''\r\n        });\r\n        $droppable.find('.via-green-border-overlay').remove();\r\n        \r\n        \/\/ \u2705 Restaurer pointer-events sur OrdiMobileConteneurClass et ses enfants\r\n        $droppable.find('.OrdiMobileConteneurClass').css('pointer-events', '');\r\n        $droppable.find('#CroixResetAnnonce').css({'pointer-events': '', 'position': '', 'z-index': ''});\r\n        \/\/ \u2705 v2.4.5 : Reset margin-right Ele0A (pos\u00e9 par adjustMobileLayout)\r\n        var _croixContReset = $droppable.find('.CroixResetAnnonceContainer')[0];\r\n        if (_croixContReset) { _croixContReset.style.removeProperty('margin-right'); _croixContReset.style.removeProperty('margin-top'); }\r\n        $droppable.find('#PopUpMessageAchattest').css('pointer-events', '');\r\n        \r\n        \/\/ \u2705 v2.0.9 : Restaurer le scale(1.4) sur .UploadFileConteneur (r\u00e9duit \u00e0 scale(1) par styleUploadedAd sur mobile)\r\n        $droppable.find('.UploadFileConteneur').css({\r\n            'transform': '',\r\n            'transform-origin': ''\r\n        });\r\n        \r\n        \/\/ Reset #UploadFileConteneur - Restaurer le fond bleu #9FC5F3 + retirer liser\u00e9 envoi diff\u00e9r\u00e9\r\n        $droppable.find('#UploadFileConteneur').css({\r\n            'width': '',\r\n            'background-color': '#9FC5F3',\r\n            'border': '',\r\n            'box-sizing': ''\r\n        });\r\n        \r\n        \/\/ Reset .ToBeHidden (set by adjustDesktopLayout: top:105px, min-height:300px + overflow mobile)\r\n        $droppable.closest('.ToBeHidden').css({\r\n            'top': '',\r\n            'min-height': '',\r\n            'overflow': ''\r\n        });\r\n        \r\n        \/\/ Reset overflow sur le parent du droppable (set by adjustDesktopLayout)\r\n        $droppable.parent().css('overflow', '');\r\n        \r\n        \/\/ \u2705 v1.19.5 : Gestion device-specific pour les textes\r\n        var isDesktop = window.outerWidth >= 1000;\r\n        \r\n        if (isDesktop) {\r\n            \/\/ Desktop : cacher les textes mobiles, afficher UploadIci\r\n            $droppable.find('.TexteMobile').hide();\r\n            $droppable.find('.TexteMobileAnnonce').hide();\r\n            $droppable.find('.TexteMobileAjoutAnnonce').hide();\r\n            $droppable.find('.UploadIci').show();\r\n        } else {\r\n            \/\/ Mobile : afficher TexteMobileAnnonce\r\n            $droppable.find('.TexteMobileAnnonce').show();\r\n        }\r\n        \r\n        \/\/ R\u00e9-afficher les \u00e9l\u00e9ments masqu\u00e9s pendant l'upload\r\n        $droppable.find('.PositionEspacePublicitaireContainer').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireDisponibiliteConteneur').show();\r\n        $droppable.find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur > div > .elementor-widget-text-editor').show();\r\n        $droppable.find('.AdDroppedTextNotDisplayed').hide();\r\n        \/\/ \u2705 v2.4.5 : Ele0A + PopUpChoice=Yes \u2192 ne pas r\u00e9-afficher le titre si format d\u00e9j\u00e0 s\u00e9lectionn\u00e9\r\n        var _skipTitre = (sessionStorage.getItem('PopUpChoice') === 'Yes' && $droppable.attr('id') === 'Ele0A');\r\n        $droppable.find('.SelectionFormatTitreBlanc').hide();\r\n        if (!_skipTitre) {\r\n            $droppable.find('.SelectionFormatTitre').show();\r\n        }\r\n        $droppable.find('span.ClassHdpCdp, .ClassRefEsp').show();\r\n        $droppable.find('.EspPubFormatMainContainer').show();\r\n        $droppable.find('.EspPubFormatListe').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireClass').show();\r\n        $droppable.find('.GlisserDeposerConteneur').show();\r\n        $droppable.find('.OUClass').show();\r\n        $droppable.find('.PositionReference').show();\r\n        $droppable.find('.ClassHdpCdp').show();\r\n        $droppable.find('.ClassRefEsp').show();\r\n        $droppable.find('.EnvoiUlterieurTexte').show();\r\n        $droppable.find('.EnvoiUlterieurContainer').show();\r\n        \r\n        \/\/ \u2705 v1.19.5 : R\u00e9afficher le .ReserverContainer (bouton Elementor statique)\r\n        $droppable.find('.ReserverContainer').show();\r\n        newElement.find('.ReserverContainer').show();\r\n        \r\n        \/\/ Masquer les \u00e9l\u00e9ments sp\u00e9cifiques \u00e0 l'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle, #CroixResetAnnonce, .CroixResetAnnonceContainer, .DeplaceAnnonce').hide();\r\n        $droppable.find('#CroixResetAnnonce').css({'position': '', 'z-index': ''});\r\n        $droppable.find('.RefEspacePublicitaire').hide();\r\n        \r\n        \/\/ Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 v1.19.6 : Restaurer le format s\u00e9lectionn\u00e9 visuellement\r\n        \/\/ Chercher le format dans plusieurs sources possibles\r\n        var formatSelect = sessionStorage.getItem('FormatSelect') \r\n            || sessionStorage.getItem('Commande_Format_Transmis')\r\n            || $droppable.data('kitFormatSelect')\r\n            || '';\r\n        \r\n        var formatchoisi = sessionStorage.getItem('Formatchoisi');\r\n        console.log('\ud83d\udcd0 Format \u00e0 restaurer:', formatSelect, '| Formatchoisi:', formatchoisi);\r\n        \r\n        \/\/ D'abord reset tous les formats visuellement (sur newElement ET $droppable)\r\n        var $allFormats = newElement.find('.EspPubFormatContainer').add($droppable.find('.EspPubFormatContainer'));\r\n        $allFormats.css({\r\n            'background-color': '',\r\n            'border': ''\r\n        });\r\n        newElement.find('.EspPubFormat').add($droppable.find('.EspPubFormat')).css({\r\n            'color': ''\r\n        });\r\n        \r\n        \/\/ Si un format \u00e9tait s\u00e9lectionn\u00e9 (via sessionStorage OU visuellement avant)\r\n        \/\/ \u2705 v2.1.1 : Sauf popup\r\n        if ((formatSelect || formatchoisi === 'Yes') && sessionStorage.getItem('PopUpChoice') !== 'Yes') {\r\n            var formatFound = false;\r\n            \r\n            if (formatSelect) {\r\n                \/\/ \u2705 v2.1.1 : Normaliser via NFD (plus fiable que les replace manuels)\r\n                var formatLower = formatSelect.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase().replace(\/ \/g, '');\r\n                \r\n                \/\/ Appliquer sur newElement ET $droppable pour \u00eatre s\u00fbr\r\n                var $allContainers = newElement.find('.EspPubFormatContainer').add($droppable.find('.EspPubFormatContainer'));\r\n                \r\n                $allContainers.each(function() {\r\n                    var className = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    \r\n                    if (className.includes(formatLower)) {\r\n                        jQuery(this).css({'background-color': '#ffffff'});\r\n                        jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        formatFound = true;\r\n                        \/\/ \u2705 v2.4.12 : M\u00e9moriser le format restaur\u00e9 (lu par selectEspaceActif pour re-surligner apr\u00e8s reset global)\r\n                        $droppable.attr('data-restored-format', formatSelect);\r\n                        console.log('\u2705 Format restaur\u00e9 visuellement:', formatSelect, '- classe:', this.className);\r\n                    }\r\n                });\r\n            }\r\n            \r\n            \/\/ \u2705 IMPORTANT : Pr\u00e9server Formatchoisi = Yes pour permettre l'upload\r\n            sessionStorage.setItem('Formatchoisi', 'Yes');\r\n            console.log('\u2705 Formatchoisi maintenu \u00e0 Yes');\r\n            \r\n            \/\/ Basculer les titres format (sur newElement ET $droppable)\r\n            newElement.find('.SelectionFormatTitre').hide();\r\n            newElement.find('.SelectionFormatTitreBlanc').show();\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n        }\r\n    }\r\n    \r\n    \/\/ \u2705 v1.19.2 : Relancer InitLoadedPage pour recalculer positions et tailles\r\n    setTimeout(function() {\r\n        if (typeof window.InitLoadedPage === 'function') {\r\n            window.InitLoadedPage();\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.6 : R\u00e9attacher les MutationObservers sur les formats\r\n        if (typeof FormatUIManager !== 'undefined' && FormatUIManager.observeFormatChanges) {\r\n            FormatUIManager.observeFormatChanges();\r\n        }\r\n    }, 100);\r\n    \r\n    console.log('\u2705 Espace publicitaire r\u00e9initialis\u00e9');\r\n    return true;\r\n}\r\n\r\n\/\/ \u2705 Exposer pour appel depuis yearbook-media.js (suppression popup mode=popup)\r\nwindow.RestoreadSpaceTemplateLocal = RestoreadSpaceTemplateLocal;\r\n\r\nwindow.verifierAffichageMsgSelectEspaceLocal = function() {\r\n    const formatChoisi = StateManager.get('Formatchoisi') === 'Yes';\r\n    const fileReceived = StateManager.get('FileReceived');\r\n    const envoiUlterieur = StateManager.get('EnvoiUlterieur');\r\n    \r\n    var dateDebut, dateFin, pays;\r\n    try {\r\n        dateDebut = window.parent.$('#form-field-DebutCampagne').val();\r\n        dateFin = window.parent.$('#form-field-FinCampagne').val();\r\n        pays = window.parent.$('#form-field-Nationalite_Societe').val();\r\n    } catch(e) {\r\n        jQuery('#MsgSelectEspace').hide();\r\n        return;\r\n    }\r\n    \r\n    if (!dateDebut || !dateFin || !pays || !formatChoisi) {\r\n        jQuery('#MsgSelectEspace').hide();\r\n        return;\r\n    }\r\n    \r\n    if (fileReceived !== 'Yes') {\r\n        if (envoiUlterieur !== 'true') {\r\n            jQuery('#MsgSelectEspace').show();\r\n        } else {\r\n            jQuery('#MsgSelectEspace').hide();\r\n        }\r\n    } else {\r\n        jQuery('#MsgSelectEspace').hide();\r\n    }\r\n};\r\n\r\n\/\/ Sauvegarder les templates au chargement (apr\u00e8s rendu complet Elementor)\r\njQuery(document).ready(function() {\r\n    \/\/ \u2705 v1.19.3 : D\u00e9lai augment\u00e9 + double sauvegarde pour garantir les bonnes dimensions\r\n    setTimeout(saveAdSpaceTemplateLocal, 3000);\r\n    setTimeout(saveAdSpaceTemplateLocal, 6000);\r\n    \/\/ \u2705 v2.3.4 : Sauvegarde imm\u00e9diate d\u00e8s que la page est pr\u00eate dans l'iframe\r\n    \/\/ (avant toute interaction utilisateur)\r\n    setTimeout(saveAdSpaceTemplateLocal, 100);\r\n    setTimeout(saveAdSpaceTemplateLocal, 500);\r\n});\r\n\r\n\/\/ \u2705 v2.3.4 : Forcer sauvegarde \u00e0 la r\u00e9ception de elementsRemoved (espaces visibles + vierges)\r\nwindow.addEventListener('message', function(e) {\r\n    if (e.data && e.data.type === 'elementsRemoved') {\r\n        \/\/ Les espaces sont vierges \u00e0 ce stade \u2192 sauvegarder imm\u00e9diatement\r\n        setTimeout(saveAdSpaceTemplateLocal, 50);\r\n        setTimeout(saveAdSpaceTemplateLocal, 300);\r\n    }\r\n});\r\n\r\n\/**\r\n * Fonction helper pour le d\u00e9p\u00f4t r\u00e9dactionnel\r\n *\/\r\nfunction RedactionnelDepose() {\r\n    jQuery('#Tariftobedisplayed').html('-');\r\n    jQuery('#TarifDataStep3').html('\u00e0 choisir').css({'color': '#FB5E2A'});\r\n    jQuery('#FormatDataStep3').html('\u00e0 choisir').css({'color': '#FB5E2A'});\r\n    jQuery('#ListePaysDirect, #ListeThemeDirect, .ListeArticles, #PageAfficheeMessage').hide();\r\n    StateManager.set(\"PositionAnnonceSelection\", 'Yes');\r\n}\r\n\r\n\/**\r\n * Exposition des fonctions globales n\u00e9cessaires\r\n *\/\r\nwindow.uploadFile_achat = (e) => DropHandler.handleDrop(e);\r\nwindow.fileExplorer_achat = (e) => FileExplorer.open(e);\r\nwindow.ajaxFileUpload_achat = (fileObj, dropZone) => UploadManager.handleFileUpload(fileObj, dropZone);\r\nwindow.ActivatesendDataToParent = (dropZone) => UploadManager.activateSendDataToParent(dropZone);\r\n\/\/ \u2705 v2.3.4 : Exposer FormatUIManager pour appel depuis Entete.txt (selectEspaceActif)\r\nwindow.FormatUIManagerRef = FormatUIManager;\r\n\r\n\/**\r\n * Initialisation de l'application\r\n *\/\r\njQuery(document).ready(() => {\r\n    StateManager.init();\r\n    ScrollHelper.init();\r\n    DragDropManager.init();\r\n    FormatUIManager.init();\r\n    \r\n    if (UIManager.isMobile()) {\r\n        UIManager.initMobileUI();\r\n    } else {\r\n        UIManager.initDesktopUI();\r\n    }\r\n    \r\n    jQuery(document).on('click', '#CroixResetAnnonce', (e) => AdResetHandler.handle(e));\r\n    \r\n    \/\/ \u2705 Clic sur le texte du label \u2192 toggle manuel de la checkbox du m\u00eame conteneur\r\n    jQuery(document).on('click', '.reserver-dynamic-label', function(e) {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        const $cb = $(this).closest('.reserver-dynamic-option, .reserver-dynamic-container').find('.reserver-dynamic-checkbox');\r\n        if ($cb.length) {\r\n            $cb.prop('checked', !$cb.prop('checked')).trigger('change');\r\n        }\r\n    });\r\n\r\n    \/\/ \u2705 CHECKBOX \"R\u00e9server cet espace publicitaire\" \u2014 VALIDATION ET ENVOI DES DONN\u00c9ES\r\n    \/\/ \u2705 v2.4.13 : iOS touchend\r\n    \/\/ \u2705 v2.4.13 : Mobile \u2014 \u00e9couter touchend sur input ET click\/touchend sur label\r\n    jQuery(document).on('touchend', 'input[name=\"form_fields[ReserverEspacePublicitaire]\"]', function() {\r\n        if (this._viaResTouch) { return; }\r\n        this._viaResTouch = true;\r\n        var _self = this;\r\n        setTimeout(function() { _self._viaResTouch = false; }, 500);\r\n        setTimeout(function() { jQuery(_self).trigger('change'); }, 100);\r\n    });\r\n    jQuery(document).on('touchend click', '.elementor-field-group-ReserverEspacePublicitaire label, .reserver-dynamic-label, .reserver-dynamic-option label', function(e) {\r\n        \/\/ Trouver l'input associ\u00e9\r\n        var $input = jQuery(this).closest('.elementor-field-option, .reserver-dynamic-option').find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n        if (!$input.length) { $input = jQuery(this).siblings('input[name=\"form_fields[ReserverEspacePublicitaire]\"]'); }\r\n        if (!$input.length) { $input = jQuery('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').first(); }\r\n        if ($input.length) {\r\n            if (e.type === 'touchend') { e.preventDefault(); }\r\n            var _wasChecked = $input.prop('checked');\r\n            $input.prop('checked', !_wasChecked);\r\n            setTimeout(function() {\r\n                $input.trigger('change');\r\n            }, 50);\r\n        }\r\n    });\r\n    jQuery(document).on('change', 'input[name=\"form_fields[ReserverEspacePublicitaire]\"]', function(e) {\r\n        const $checkbox = $(this);\r\n        let $droppable = $checkbox.closest('.droppable');\r\n        if (!$droppable.length) {\r\n            $droppable = $checkbox.closest('.reserver-dynamic-container').prev('.droppable');\r\n        }\r\n        \/\/ \u2705 v2.4.13 : Fallback mobile \u2014 checkbox dans body > .reserver-dynamic-container[data-droppable-id]\r\n        if (!$droppable.length) {\r\n            const $dynContainer = $checkbox.closest('.reserver-dynamic-container');\r\n            const _droppableId = $dynContainer.attr('data-droppable-id') || '';\r\n            if (_droppableId) {\r\n                $droppable = $('#' + _droppableId);\r\n            }\r\n        }\r\n        \/\/ Dernier recours : utiliser le rank en sessionStorage\r\n        if (!$droppable.length) {\r\n            const _rankFallback = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            if (_rankFallback) { $droppable = $('#' + _rankFallback); }\r\n        }\r\n        \r\n        \/\/ Si on d\u00e9coche\r\n        if (!$checkbox.is(':checked')) {\r\n            console.log('\u2610 Checkbox \"R\u00e9server\" d\u00e9coch\u00e9e');\r\n            \/\/ \u2705 Mettre \u00e0 jour le label\r\n            const $lbl = $checkbox.closest('.reserver-dynamic-option, .elementor-field-option').find('.reserver-dynamic-label, label').not('input');\r\n            $lbl.text('R\u00e9server cet espace publicitaire').css('color', '');\r\n            \/\/ \u2705 Notifier le parent pour d\u00e9-r\u00e9server l'item dans le r\u00e9cap\r\n            const _rankDecoche = $droppable.attr('id') || StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            const _emplacementDecoche = StateManager.buildEmplacementReference(_rankDecoche);\r\n            MessageManager.sendToParent('annulationReservation', {\r\n                Rank_Emplacement_Page_Web: _rankDecoche,\r\n                Commande_Emplacement_Page_Web: _emplacementDecoche,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n            \/\/ \u2705 v2.4.5 : M\u00e9moriser que ce rank a \u00e9t\u00e9 explicitement d\u00e9coch\u00e9\r\n            StateManager.set('_reserverDecoche_' + _rankDecoche, 'Yes');\r\n            console.log('\ud83d\udce4 annulationReservation envoy\u00e9 \u2192 parent | rank:', _rankDecoche, '| emplacement:', _emplacementDecoche);\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 V\u00e9rifier les conditions : format s\u00e9lectionn\u00e9 ET (fichier d\u00e9pos\u00e9 OU envoi diff\u00e9r\u00e9)\r\n        const hasFormat = FormatUIManager.hasSelectedFormat($droppable);\r\n        const hasFile = StateManager.get('FileReceived') === 'Yes';\r\n        const hasEnvoiDiffere = $droppable.find('input[name*=\"EnvoiUlterieur\"]:checked').length > 0;\r\n        \r\n        console.log('\ud83d\udd0d Checkbox \"R\u00e9server\" - Validation:', { hasFormat, hasFile, hasEnvoiDiffere });\r\n        \r\n        if (!hasFormat) {\r\n            \/\/ \u2705 Si un fichier est d\u00e9j\u00e0 d\u00e9pos\u00e9 \u2192 d\u00e9duire le format depuis l'extension (ne pas bloquer)\r\n            if (hasFile) {\r\n                const _uploadedName = StateManager.get('Upload_File_Name') || '';\r\n                const _ext = _uploadedName.split('.').pop().toLowerCase();\r\n                const _fileType = FileManager.getFileType(_ext);\r\n                let _deducedFormat = '';\r\n                if (_fileType === 'video') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Video' : 'Vid\u00e9o';\r\n                } else if (_fileType === 'image') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Banner' : 'Banni\u00e8re';\r\n                } else if (_fileType === 'document') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Press release' : 'Communiqu\u00e9';\r\n                }\r\n                if (_deducedFormat) {\r\n                    StateManager.set('Commande_Format_Transmis', _deducedFormat);\r\n                    StateManager.set('FormatSelect', _deducedFormat);\r\n                    StateManager.set('Formatchoisi', 'Yes');\r\n                    console.log('\u2705 Format d\u00e9duit depuis extension (' + _ext + '):', _deducedFormat);\r\n                    \/\/ Continuer vers l'envoi (pas de return false)\r\n                } else {\r\n                    e.preventDefault();\r\n                    $checkbox.prop('checked', false);\r\n                    FormatUIManager.flashTitle($droppable);\r\n                    console.log('\u274c R\u00e9servation bloqu\u00e9e : format non d\u00e9ductible depuis extension:', _ext);\r\n                    return false;\r\n                }\r\n            } else {\r\n                e.preventDefault();\r\n                $checkbox.prop('checked', false);\r\n                FormatUIManager.flashTitle($droppable);\r\n                console.log('\u274c R\u00e9servation bloqu\u00e9e : aucun format s\u00e9lectionn\u00e9');\r\n                return false;\r\n            }\r\n        }\r\n        \r\n        if (!hasFile && !hasEnvoiDiffere) {\r\n            e.preventDefault();\r\n            $checkbox.prop('checked', false);\r\n            console.log('\u274c R\u00e9servation bloqu\u00e9e : ni annonce d\u00e9pos\u00e9e ni envoi diff\u00e9r\u00e9');\r\n            return false;\r\n        }\r\n        \r\n        \/\/ \u2705 Conditions remplies \u2014 Pr\u00e9parer et envoyer les donn\u00e9es\r\n        console.log('\u2705 Checkbox \"R\u00e9server\" valid\u00e9e \u2014 envoi des donn\u00e9es');\r\n        \r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.setMultiple({\r\n            \"sendDataToParentFlag\": \"Yes\",\r\n            \"Formatchoisi\": \"Yes\",\r\n            \"Rank_Emplacement_Page_Web\": rankId,\r\n            \"Commande_Emplacement_Page_Web\": StateManager.buildEmplacementReference(rankId),\r\n            \"LoadedPageUrl\": window.location.href,\r\n            \/\/ \u2705 v2.3.0 : Forcer avant l'envoi \u2014 le setTimeout(4000) dans activateSendDataToParent\r\n            \/\/ arrive trop tard sur le 1er clic \u2192 AddNewRefInVosCampagnes restait null\r\n            \"AddNewRefInVosCampagnes\": \"Yes\"\r\n        });\r\n        \r\n        \/\/ \u2705 D\u00e9clencher l'envoi des donn\u00e9es via activateSendDataToParent\r\n        const $dropZone = $droppable.find('#drop_file_zone_achat');\r\n        UploadManager.activateSendDataToParent($dropZone);\r\n    });\r\n    \r\n    \/\/ G\u00c9RER \"Envoi diff\u00e9r\u00e9\" \u2014 marquer l'\u00e9tat sans envoyer (c'est \"R\u00e9server\" qui envoie)\r\n    \/\/ \u2705 v2.4.13 : iOS touchend\r\n    jQuery(document).on('touchend', 'input[name*=\"EnvoiUlterieur\"]', function() {\r\n        if (this._viaTouch) { return; }\r\n        this._viaTouch = true;\r\n        var _self = this;\r\n        setTimeout(function() { _self._viaTouch = false; }, 500);\r\n        setTimeout(function() { jQuery(_self).trigger('change'); }, 100);\r\n    });\r\n    jQuery(document).on('change', 'input[name*=\"EnvoiUlterieur\"]', function(e) {\r\n        const $checkbox = $(this);\r\n        let $droppable = $checkbox.closest('.droppable');\r\n        \/\/ \u2705 v2.4.13 : Fallback mobile\r\n        if (!$droppable.length) {\r\n            const $dynContainer = $checkbox.closest('.reserver-dynamic-container');\r\n            const _droppableId = $dynContainer.attr('data-droppable-id') || '';\r\n            if (_droppableId) { $droppable = $('#' + _droppableId); }\r\n        }\r\n        if (!$droppable.length) {\r\n            const _rankFallback = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            if (_rankFallback) { $droppable = $('#' + _rankFallback); }\r\n        }\r\n  \r\n        \/\/ Si on d\u00e9coche\r\n        if (!$checkbox.is(':checked')) {\r\n            StateManager.set('EnvoiUlterieur', 'false');\r\n            \r\n            if (typeof window.verifierAffichageMsgSelectEspaceLocal === 'function') {\r\n                window.verifierAffichageMsgSelectEspaceLocal();\r\n            }\r\n            \r\n            \/\/ Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server\r\n            FormatUIManager.updateReserverCheckboxState($droppable);\r\n            return;\r\n        }\r\n        \r\n        \/\/ Si on coche, masquer le message\r\n        jQuery('#MsgSelectEspace').hide();\r\n    \r\n        \/\/ V\u00e9rifier si un format est s\u00e9lectionn\u00e9\r\n        const hasSelectedFormat = FormatUIManager.hasSelectedFormat($droppable);\r\n        \r\n        if (!hasSelectedFormat) {\r\n            e.preventDefault();\r\n            $checkbox.prop('checked', false);\r\n            FormatUIManager.flashTitle($droppable);\r\n            return false;\r\n        }\r\n        \r\n        \/\/ \u2705 FORMAT OK \u2014 Marquer l'\u00e9tat envoi diff\u00e9r\u00e9 (sans envoyer les donn\u00e9es)\r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.setMultiple({\r\n            \"EnvoiUlterieur\": 'true',\r\n            \"Rank_Emplacement_Page_Web\": rankId,\r\n            \"Commande_Emplacement_Page_Web\": StateManager.buildEmplacementReference(rankId),\r\n            \"LoadedPageUrl\": window.location.href,\r\n            \"FileReceived\": \"No\",\r\n            \"FullPathAdFile\": '',\r\n            \"Upload_File_Name\": '',\r\n            \"Formatchoisi\": 'Yes'\r\n        });\r\n        \r\n        console.log('\ud83d\udcdd Envoi diff\u00e9r\u00e9 coch\u00e9 \u2014 en attente de validation via checkbox \"R\u00e9server\"');\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server (maintenant activable)\r\n        FormatUIManager.updateReserverCheckboxState($droppable);\r\n    });\r\n\r\n    \/\/ \u2705 v2.2.0 : Bouton \"Cr\u00e9ation\" dans espace publicitaire \u2192 Kit Ad Creator dans le parent\r\n    jQuery(document).on('click', '.FormatIdCreation', function(e) {\r\n        e.preventDefault();\r\n        var $btn = jQuery(this);\r\n        var isActive = $btn.data('creationActive') === true;\r\n\r\n        if (isActive) {\r\n            \/\/ D\u00e9sactiver\r\n            $btn.data('creationActive', false);\r\n            $btn.find('.EspPubFormat').css({'color': '#ffffff'});\r\n            $btn.css({'background-color': 'transparent'});\r\n            MessageManager.sendToParent('closeAdCreatorFromIframe', {});\r\n            console.log('\ud83c\udfa8 Cr\u00e9ation iframe \u2192 toggle OFF, fermeture popup parent');\r\n        } else {\r\n            \/\/ Activer : texte vert sur fond blanc\r\n            $btn.data('creationActive', true);\r\n            $btn.find('.EspPubFormat').css({'color': '#37D900'});\r\n            $btn.css({'background-color': '#ffffff'});\r\n            var formatSelect = sessionStorage.getItem('FormatSelect') || '';\r\n            var formatTransmis = sessionStorage.getItem('Commande_Format_Transmis') || '';\r\n            \/\/ \u2705 v2.2.1 : Envoyer aussi Commande_Format_Transmis (format cliqu\u00e9 dans l'iframe, sans accent)\r\n            var _rankKit = $btn.closest('.droppable').attr('id') || sessionStorage.getItem('Rank_Emplacement_Page_Web') || '';\r\n            var _cSite = sessionStorage.getItem('codeSite') || '';\r\n            var _cPage = sessionStorage.getItem('codePage') || '';\r\n            var _sfxKit = _rankKit.replace('Ele', '');\r\n            var _emplKit = (_cSite && _cPage && _sfxKit) ? (_cSite + _cPage + 'L' + _sfxKit) : (sessionStorage.getItem('Commande_Emplacement_Page_Web') || '');\r\n            MessageManager.sendToParent('openAdCreatorFromIframe', { formatSelect: formatSelect, formatTransmis: formatTransmis, rankId: _rankKit, emplacement: _emplKit });\r\n            console.log('\ud83c\udfa8 Cr\u00e9ation iframe \u2192 toggle ON (FormatSelect:', formatSelect, '| Commande_Format_Transmis:', formatTransmis, ')');\r\n        }\r\n    });\r\n\r\n    \/\/ \u2705 v2.2.0 : Messages depuis le parent concernant le bouton Cr\u00e9ation\r\n    window.addEventListener('message', function(event) {\r\n        var msg = event.data;\r\n        if (!msg) return;\r\n\r\n        \/\/ \u2705 v2.2.1 : Fournir la position du titre R\u00e9server pour positionner la miniature\r\n        if (msg.type === 'getReserverLabelRect') {\r\n            var $label = jQuery('.reserver-dynamic-label').first();\r\n            if ($label.length) {\r\n                var r = $label[0].getBoundingClientRect();\r\n                var iframeScale = (window.outerWidth > 1000) ? 0.75 : 0.80; \/\/ \u2705 v2.4.12 : 0.85 \u2192 0.75 (scale r\u00e9el du parent)\r\n                event.source.postMessage({\r\n                    type: 'reserVeurLabelRectResult',\r\n                    \/\/ Retourner bottom en coordonn\u00e9es iframe internes (non scal\u00e9es)\r\n                    bottom: r.bottom,\r\n                    left: r.left,\r\n                    right: r.right,\r\n                    iframeScale: iframeScale\r\n                }, '*');\r\n            } else {\r\n                event.source.postMessage({ type: 'reserVeurLabelRectResult', bottom: null }, '*');\r\n            }\r\n        }\r\n\r\n        \/\/ Fermeture du popup \u2192 d\u00e9s\u00e9lectionner le bouton Cr\u00e9ation\r\n        if (msg.type === 'adCreatorClosedFromParent') {\r\n            jQuery('.FormatIdCreation').each(function() {\r\n                jQuery(this).data('creationActive', false);\r\n                jQuery(this).find('.EspPubFormat').css({'color': '#ffffff'});\r\n                jQuery(this).css({'background-color': 'transparent'});\r\n            });\r\n            console.log('\ud83c\udfa8 adCreatorClosedFromParent re\u00e7u \u2192 bouton Cr\u00e9ation d\u00e9s\u00e9lectionn\u00e9');\r\n        }\r\n\r\n        \/\/ Restaurer le style du bouton Cr\u00e9ation apr\u00e8s un reset de removeElements\r\n        if (msg.type === 'restoreCreationButton') {\r\n            jQuery('.FormatIdCreation').each(function() {\r\n                if (jQuery(this).data('creationActive') === true) {\r\n                    jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                    jQuery(this).css({'background-color': '#ffffff'});\r\n                }\r\n            });\r\n            console.log('\ud83c\udfa8 restoreCreationButton re\u00e7u \u2192 style Cr\u00e9ation restaur\u00e9');\r\n        }\r\n    });\r\n\r\n});\r\n\r\n\/\/ =========================================================================\r\n\/\/ \u2705 Listener kitAdCreated \u2014 annonce cr\u00e9\u00e9e par le Kit overlay (mode=kit)\r\n\/\/ Injecte directement dans l'espace pub identifi\u00e9 par rankId\r\nwindow.addEventListener('message', function(event) {\r\n    var msg = event.data;\r\n    if (!msg || msg.action !== 'kitAdCreated') return;\r\n\r\n    var _rankId = msg.rankId || '';\r\n    var _emplacement = msg.emplacement || '';\r\n    console.log('\ud83c\udfa8 [espace_pub] kitAdCreated re\u00e7u | rankId:', _rankId, '| emplacement:', _emplacement);\r\n\r\n    if (!_rankId) { console.warn('\u26a0\ufe0f [kitAdCreated] rankId manquant'); return; }\r\n\r\n    var $droppable = jQuery('#' + _rankId);\r\n    if (!$droppable.length) { console.warn('\u26a0\ufe0f [kitAdCreated] droppable non trouv\u00e9:', _rankId); return; }\r\n    var $dropZone = $droppable.find('.drop_file_zone_achat_class').first();\r\n    if (!$dropZone.length) { $dropZone = $droppable.find('#drop_file_zone_achat').first(); }\r\n    if (!$dropZone.length) { console.warn('\u26a0\ufe0f [kitAdCreated] dropZone non trouv\u00e9e dans', _rankId); return; }\r\n\r\n    var _dataURL = msg.fullResDataURL || msg.pdfDataURL || null;\r\n    var _filename = msg.filename || 'annonce.png';\r\n    var _isPDF = msg.isPDF || false;\r\n    if (!_dataURL) { console.warn('\u26a0\ufe0f [kitAdCreated] aucune donn\u00e9e image'); return; }\r\n\r\n    var _parts = _dataURL.split(',');\r\n    var _mime = (_parts[0].match(\/:(.*?);\/) || [])[1] || (_isPDF ? 'application\/pdf' : 'image\/png');\r\n    var _bStr = atob(_parts[1]);\r\n    var _bytes = new Uint8Array(_bStr.length);\r\n    for (var _i = 0; _i < _bStr.length; _i++) { _bytes[_i] = _bStr.charCodeAt(_i); }\r\n    var _blob = new Blob([_bytes], { type: _mime });\r\n    \/\/ \u2705 Ajouter extension si absente\r\n    var _MIME_EXT = {'image\/png':'.png','image\/jpeg':'.jpg','image\/jpg':'.jpg','image\/webp':'.webp','application\/pdf':'.pdf'};\r\n    if (_filename.indexOf('.') === -1) { _filename = _filename + (_MIME_EXT[_mime] || (_isPDF ? '.pdf' : '.png')); }\r\n    var _file = new File([_blob], _filename, { type: _mime });\r\n\r\n    \/\/ \u2705 Pr\u00e9parer StateManager\r\n    StateManager.set('Rank_Emplacement_Page_Web', _rankId);\r\n    StateManager.set('Commande_Emplacement_Page_Web', _emplacement);\r\n    StateManager.set('Formatchoisi', 'Yes');\r\n    \/\/ \u2705 Marquer le droppable directement en DOM \u2014 r\u00e9siste \u00e0 l'async, lu par styleUploadedAd\r\n    $droppable[0].setAttribute('data-kit-drop', 'true');\r\n    window._dropFromMiniature = true;\r\n\r\n    console.log('\u2705 [kitAdCreated] \u2192 UploadManager.handleFileUpload | rankId:', _rankId);\r\n    UploadManager.handleFileUpload(_file, $dropZone).then(function() {\r\n        console.log('\u2705 [kitAdCreated] handleFileUpload termin\u00e9');\r\n    }).catch(function(err) {\r\n        window._dropFromMiniature = false;\r\n        $droppable[0].removeAttribute('data-kit-drop');\r\n        console.error('\u274c [kitAdCreated] handleFileUpload erreur:', err);\r\n    });\r\n});\r\n\r\n\/\/ \u2705 v1.17.0 : Listener \"thumbnailDropped\" \u2014 d\u00e9p\u00f4t de l'annonce depuis la miniature\r\n\/\/ =========================================================================\r\n\/**\r\n * Re\u00e7oit le drop de l'image-annonce depuis la miniature dans la page parente.\r\n * Identifie l'espace publicitaire sous le curseur, s\u00e9lectionne cet espace,\r\n * et d\u00e9clenche le flux dataFromIframeEspacePub en mode \"envoi diff\u00e9r\u00e9\"\r\n * (l'utilisateur uploadera le vrai fichier depuis le formulaire de commande).\r\n *\r\n * Coordonn\u00e9es re\u00e7ues : viewport de l'iframe (clientX\/clientY relatifs \u00e0 l'iframe)\r\n *\/\r\nwindow.addEventListener('message', function(event) {\r\n    var msg = event.data;\r\n    if (!msg || msg.action !== 'thumbnailDropped') return;\r\n\r\n    console.log('\ud83d\udce8 thumbnailDropped re\u00e7u \u2014 coords iframe:', msg.xRel, msg.yRel);\r\n\r\n    \/\/ \u2705 v1.19.3 : Corriger les coordonn\u00e9es pour le facteur de scale de l'iframe\r\n    \/\/ \u2705 v2.4.10 : 0.75 = scale appliqu\u00e9 par le PARENT sur l'\u00e9l\u00e9ment iframe (et non 0.85 qui est le scale interne OrdiMobileConteneurClass)\r\n    \/\/ Les coords xRel\/yRel viennent de getBoundingClientRect() sur l'iframe scal\u00e9 \u00e0 0.75 dans le parent \u2192 diviser par 0.75\r\n    var iframeScale = (window.outerWidth > 1000) ? 0.75 : 0.80;\r\n    \/\/ \u2705 v2.4.3 : Si Entete a intercept\u00e9 et pos\u00e9 un redirect vers Ele0A, utiliser ces coords\r\n    var _redirect = window._thumbnailDropRedirect || null;\r\n    window._thumbnailDropRedirect = null;\r\n    \/\/ \u2705 v2.4.4 : Les coords de redirect viennent de getBoundingClientRect() dans l'iframe (espace logique)\r\n    \/\/            \u2192 ne pas re-diviser par iframeScale (d\u00e9j\u00e0 en coords iframe-logiques)\r\n    var xAdjusted = _redirect ? _redirect.xRel : (msg.xRel \/ iframeScale);\r\n    var yAdjusted = _redirect ? _redirect.yRel : (msg.yRel \/ iframeScale);\r\n    if (_redirect) { console.log('\ud83d\udd00 [thumbnailDropped] coords redirig\u00e9es vers Ele0A:', Math.round(xAdjusted), Math.round(yAdjusted)); }\r\n    else { console.log('\ud83d\udcd0 Coords ajust\u00e9es (scale', iframeScale, '):', Math.round(xAdjusted), Math.round(yAdjusted)); }\r\n\r\n    \/\/ 1. Identifier l'espace publicitaire le plus proche du point de drop\r\n    \/\/    \u2705 v1.18.1 : Recherche par distance \u2014 coords \u00e9ventuellement redirig\u00e9es par Entete.txt\r\n    var allDroppables = document.querySelectorAll('.droppable');\r\n    var droppableEl = null;\r\n    var closestDist = Infinity;\r\n\r\n    \/\/ \u2705 v2.4.4 : Guard rect Ele0A \u2014 si PopUpChoice=Yes ET curseur dans le rect d'Ele0A \u2192 forcer\r\n    \/\/            (Ele0A est un popup flottant : son centre peut \u00eatre loin du curseur \u2192 algo distance l'ignore)\r\n    \/\/            Ne force PAS si le drop est hors d'Ele0A \u2192 les autres espaces restent accessibles\r\n    if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n        var _ele0ACheck = document.getElementById('Ele0A');\r\n        if (_ele0ACheck) {\r\n            var _r0A = _ele0ACheck.getBoundingClientRect();\r\n            var _margin = 30;\r\n            var _inR0A = (xAdjusted >= _r0A.left - _margin);\r\n            if (_inR0A) { _inR0A = (xAdjusted <= _r0A.right + _margin); }\r\n            if (_inR0A) { _inR0A = (yAdjusted >= _r0A.top - _margin); }\r\n            if (_inR0A) { _inR0A = (yAdjusted <= _r0A.bottom + _margin); }\r\n            if (_inR0A) {\r\n                droppableEl = _ele0ACheck;\r\n                closestDist = 0;\r\n                console.log('\ud83c\udfaf [thumbnailDropped] Ele0A forc\u00e9 (curseur dans rect Ele0A +30px)');\r\n            }\r\n        }\r\n    }\r\n\r\n    if (!droppableEl) {\r\n        allDroppables.forEach(function(d) {\r\n            var r = d.getBoundingClientRect();\r\n            var dCenterX = r.left + r.width  \/ 2;\r\n            var dCenterY = r.top  + r.height \/ 2;\r\n            var dist = Math.abs(dCenterX - xAdjusted) + Math.abs(dCenterY - yAdjusted);\r\n            if (dist < closestDist) { closestDist = dist; droppableEl = d; }\r\n        });\r\n        \/\/ \u2705 v2.4.3 : Si Entete a d\u00e9tect\u00e9 un drop sur Ele0A \u2192 forcer directement\r\n        if (_redirect) { if (_redirect.forceEle0A) {\r\n            var _ele0AForced = document.getElementById('Ele0A');\r\n            if (_ele0AForced) { droppableEl = _ele0AForced; console.log('\ud83c\udfaf [thumbnailDropped] Ele0A forc\u00e9 (redirect Entete)'); }\r\n        } }\r\n    }\r\n\r\n    if (!droppableEl || closestDist > 800) {\r\n        console.warn('thumbnailDropped \u2014 aucun droppable proche (dist min:', closestDist, ')');\r\n        return;\r\n    }\r\n    console.log('\ud83d\udccd Droppable trouv\u00e9:', droppableEl.id, '(dist:', Math.round(closestDist), ')');\r\n\r\n    var $droppable = jQuery(droppableEl);\r\n    var rankId = $droppable.attr('id');\r\n    if (!rankId) { console.warn('thumbnailDropped \u2014 .droppable sans id'); return; }\r\n\r\n    var $dropZone = $droppable.find('#drop_file_zone_achat').first();\r\n    if (!$dropZone.length) { console.warn('thumbnailDropped \u2014 #drop_file_zone_achat introuvable dans', rankId); return; }\r\n\r\n    var emplacementRef = StateManager.buildEmplacementReference(rankId);\r\n    console.log('\u2705 thumbnailDropped \u2014 espace pub:', rankId, '\u2192', emplacementRef);\r\n\r\n    \/\/ 2. Pr\u00e9parer l'\u00e9tat SessionStorage (comme un vrai drop de fichier)\r\n    StateManager.setMultiple({\r\n        'Rank_Emplacement_Page_Web':     rankId,\r\n        'Commande_Emplacement_Page_Web': emplacementRef,\r\n        'FirstUploadFileorMoved':        'FirstUpload',\r\n        'Formatchoisi':                  'Yes',\r\n        'Commande_Format_Transmis':      'Image',\r\n        'EnvoiUlterieur':                'false',\r\n        'FileReceived':                  'No',\r\n        'AdDisplayed':                   'Yes'\r\n    });\r\n\r\n    UIManager.updateEmplacementDisplay();\r\n\r\n    \/\/ 3. Construire le File \u00e0 partir du PDF (communiqu\u00e9\/interview) ou de l'image PNG (autres formats)\r\n    \/\/    puis appeler handleFileUpload \u2192 m\u00eame flux qu'un vrai drag&drop : liser\u00e9 vert, aper\u00e7u, R\u00e9server\r\n    var dataURL, mime, ext;\r\n\r\n    \/\/ \u2705 Stocker le PDF image et le format sur le droppable pour le popup de visualisation inline\r\n    if (msg.pdfImageDataURL) {\r\n        $droppable.data('kitPdfImageDataURL', msg.pdfImageDataURL);\r\n        $droppable.data('kitFormatSelect', msg.FormatSelect || '');\r\n        console.log('\ud83d\udcce pdfImageDataURL stock\u00e9 sur', rankId, '| format:', msg.FormatSelect);\r\n    } else {\r\n        $droppable.removeData('kitPdfImageDataURL');\r\n        $droppable.removeData('kitFormatSelect');\r\n    }\r\n\r\n    if (msg.isPDF && msg.pdfDataURL) {\r\n        \/\/ \u2500\u2500 Format PDF (communiqu\u00e9 \/ interview) \u2500\u2500\u2500\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        dataURL = msg.pdfDataURL;                         \/\/ \"data:application\/pdf;base64,\u2026\"\r\n        mime    = 'application\/pdf';\r\n        ext     = '.pdf';\r\n    } else if (msg.imageDataURL) {\r\n        \/\/ \u2500\u2500 Format image (banni\u00e8re \/ parrainage) \u2500\u2500\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        dataURL = msg.imageDataURL;\r\n        var mimeMatch = dataURL.match(\/^data:([^;]+);base64,\/);\r\n        mime    = mimeMatch ? mimeMatch[1] : 'image\/png';\r\n        ext     = mime === 'image\/jpeg' ? '.jpg' : '.png';\r\n    } else {\r\n        console.warn('thumbnailDropped \u2014 aucune donn\u00e9e image\/pdf disponible');\r\n        return;\r\n    }\r\n\r\n    var baseName = msg.filename ? msg.filename.replace(\/\\.[^.]+$\/, '') : 'annonce-kit';\r\n    var fileName = baseName + ext;\r\n\r\n    \/\/ dataURL \u2192 Uint8Array \u2192 Blob \u2192 File\r\n    var b64  = dataURL.split(',')[1];\r\n    var bstr = atob(b64);\r\n    var u8   = new Uint8Array(bstr.length);\r\n    for (var i = 0; i < bstr.length; i++) { u8[i] = bstr.charCodeAt(i); }\r\n    var blob    = new Blob([u8], { type: mime });\r\n    var fileObj = new File([blob], fileName, { type: mime });\r\n\r\n    console.log('thumbnailDropped \u2192 handleFileUpload:', fileName, Math.round(fileObj.size \/ 1024) + 'KB');\r\n\r\n    \/\/ \u2705 Cacher le File pour r\u00e9utilisation lors des d\u00e9placements (\u00e9vite CORS)\r\n    window._lastRedactionnelFile = fileObj;\r\n\r\n    \/\/ \u2705 v2.4.10 : Signaler \u00e0 adjustDesktopLayout que c'est un drop depuis la miniature\r\n    \/\/ \u2192 applique max-height sur HTMLUploadfileConteneur pour \u00e9viter le d\u00e9bordement vertical (homepage corps de page)\r\n    window._dropFromMiniature = true;\r\n    UploadManager.handleFileUpload(fileObj, $dropZone);\r\n\r\n    \/\/ \u2705 v1.19.1 : Positionner l'espace \u00e0 10px du haut du viewport (tous formats)\r\n    \/\/ \u2705 v2.4.13 : Skip si drop depuis miniature \u2014 selectEspaceActif g\u00e8re d\u00e9j\u00e0 le scroll\r\n    if (!window._dropFromMiniature) {\r\n        setTimeout(function() {\r\n            var el = $droppable.find('.HTMLUploadfileConteneur')[0] || $droppable[0];\r\n            if (el) {\r\n                ScrollHelper.scrollElementTo(el, 10);\r\n            }\r\n        }, 400);\r\n    }\r\n});\r\n\r\nconsole.log('This is a ' + (UIManager.isDesktop() ? 'desktop' : 'non-desktop') + ' device.');\r\n\r\n} \/\/ end _espPubScriptLoaded guard\r\n<\/script>\r\n\r\n<style>\r\n\/* Les styles CSS restent inchang\u00e9s *\/\r\n#drop_file_zone_achat {\r\n    background-color: #FFFFFF00;\r\n    color: #225DA9;\r\n    font-weight: 500;\r\n    text-align: center;\r\n    border: #999 0px dashed;\r\n    width: 100%;\r\n    height: 180px;\r\n    font-size: 11.5px;\r\n    display: flex;\r\n    justify-content: center; \r\n    align-items: center; \r\n    flex-wrap: wrap;\r\n}\r\n\r\n#drag_upload_file_achat {\r\n    margin: 0 auto;\r\n    width: 90%;\r\n    height: 60px;\r\n}\r\n\r\n#drag_upload_file_achat p {\r\n    text-align: center;\r\n}\r\n\r\n\/* \u2705 v1.16.0 : Liser\u00e9 noir fin autour du texte \"Ici glisser \u2013 d\u00e9poser\" *\/\r\n.GlisserDeposerConteneur .elementor-widget-container p {\r\n    border: 1px solid #000000;\r\n    border-radius: 4px;\r\n    padding: 4px 10px;\r\n    display: inline-block;\r\n}\r\n\r\n#selectfile_achat {\r\n    display: none;\r\n}\r\n\r\n.button-2_achat, .button-2_achat-after-reset {\r\n    background-color: #ffffff00!important;\r\n    border: 1px solid white!important;\r\n    border-radius: 8px;\r\n    color: #225DA9!important;\r\n    cursor: pointer;\r\n    display: inline-block;\r\n    font-size: 11px;\r\n    font-weight: 500;\r\n    list-style: none;\r\n    width: 390px;\r\n    height: 62px;\r\n    top: 0px!important; \r\n    margin-top: 0px!important; \r\n    padding-left: 5px!important;\r\n    padding-right: 5px!important;\r\n    margin-bottom: 70px!important;\r\n    margin: 0;\r\n    text-align: center;\r\n    transition: all 200ms;\r\n    vertical-align: baseline;\r\n    white-space: wrap!important;\r\n}\r\n\r\n@media only screen and (max-width: 1000px) {\r\n    .button-2_achat, .button-2_achat-after-reset {\r\n        width: 95%;\r\n        height: 50px;\r\n    }\r\n}\r\n\r\n.newMessageClass {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #56BE50;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 45px;\r\n    bottom: 0px;\r\n    right: 0px;\r\n    left: 0px;\r\n    display: flex;\r\n    justify-content: center;\r\n    align-items: center;\r\n    text-align: center;\r\n}\r\n\r\n.MessageClassFormatnonReconnuTitre {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #FB5E2A;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    margin-top: -300px;\r\n    right: 0px;\r\n    text-align: center;\r\n    line-height: 15px;\r\n}\r\n\r\n.MessageClassFormatnonReconnu {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #ffffff;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    margin-top: -280px;\r\n    right: 0px;\r\n    text-align: center;\r\n    line-height: 15px;\r\n}\r\n\r\n.newButtonClass {\r\n    font-size: 12px; \r\n    font-weight: 500;\r\n    background-color: #ffffff00;\r\n    color: #717171;\r\n    height: 10px;\r\n    width: 100%; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 45px;\r\n    bottom: 0px;\r\n    text-align: center;\r\n    right:  50px;\r\n    line-height: 10px;\r\n    border-radius: 3px;\r\n    border: 0px solid #E8ECF1;\r\n}\r\n\r\n.linkClass {\r\n    width: 15px; \r\n    height: 15px;\r\n    margin-top: -310px;\r\n    margin-bottom: -25px;\r\n    margin-right: -50px;\r\n    position: relative;\r\n    top: 0; \r\n    z-index: 99;\r\n    display: block;\r\n    background-image: url('https:\/\/rdc.via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-blanc.jpg');\r\n    background-size: cover;\r\n}\r\n\r\n.newButtonClassVideo {\r\n    font-size: 12px; \r\n    font-weight: 500;\r\n    background-color: #ffffff00;\r\n    color: #717171;\r\n    height: 10px;\r\n    width: 100%; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 0px;\r\n    bottom: 0px;\r\n    right: 10px;\r\n    text-align: center;\r\n    line-height: 10px;\r\n    border-radius: 3px;\r\n    border: 0px solid #E8ECF1;\r\n}\r\n\r\n.linkClassVideo {\r\n    width: 15px; \r\n    height: 15px;\r\n    margin-top: -438px;\r\n    margin-bottom: -25px;\r\n    margin-right: -15px;\r\n    position: relative;\r\n    top: 0; \r\n    z-index: 99;\r\n    display: block;\r\n    background-image: url('https:\/\/rdc.via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-blanc.jpg');\r\n    background-size: cover;\r\n}\r\n\r\n.FinCampagneMobileClass .elementor-button,\r\n.DebutCampagneMobileClass .elementor-button,\r\n.FormSelectDevisesMobile .elementor-button,\r\n.HideFormButton .elementor-button {\r\n    display: none !important;\r\n}\r\n\r\n#drag_upload_file_achat {\r\n    margin: 0;\r\n    padding: 0;\r\n    position: relative;\r\n}\r\n\r\n.dot-container {\r\n    display: inline-block;\r\n}\r\n\r\n.dot {\r\n    opacity: 0;\r\n    transition: opacity 0.3s ease;\r\n}\r\n\r\n@keyframes firstDot {\r\n    0%, 100% { opacity: 0; }\r\n    10%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n@keyframes secondDot {\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 thirdDot {\r\n    0%, 40%, 100% { opacity: 0; }\r\n    50%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n.dot:nth-child(1) {\r\n    animation: firstDot 3s infinite;\r\n}\r\n\r\n.dot:nth-child(2) {\r\n    animation: secondDot 3s infinite;\r\n}\r\n\r\n.dot:nth-child(3) {\r\n    animation: thirdDot 3s infinite;\r\n}\r\n\r\n.droppable .elementor-field-type-checkbox .elementor-field-option {\r\n    display: flex;\r\n    flex-direction: row-reverse;\r\n    align-items: center;\r\n    gap: 8px;\r\n}\r\n\r\n.droppable .elementor-field-type-checkbox .elementor-field-option input[type=\"checkbox\"] {\r\n    width: 12px;\r\n    height: 12px;\r\n    min-width: 12px;\r\n    min-height: 12px;\r\n}\r\n\r\n\/* \u2705 Bouton \"R\u00e9server\" dynamique *\/\r\n.reserver-dynamic-container {\r\n    text-align: center;\r\n    margin-top: -7px;\r\n    margin-bottom: 15px;\r\n    padding: 5px 0;\r\n    transform: scale(1.4);\r\n    transform-origin: center top;\r\n    position: relative;\r\n    z-index: 200;\r\n}\r\n\r\n@media only screen and (min-width: 1001px) {\r\n    .reserver-dynamic-container {\r\n        transform: scale(1);\r\n        margin-top: -200px;\r\n        margin-bottom: 0;\r\n    }\r\n}\r\n\r\n.reserver-dynamic-option {\r\n    display: inline-flex;\r\n    flex-direction: row-reverse;\r\n    align-items: center;\r\n    gap: 8px;\r\n    cursor: pointer;\r\n    color: #213864;\r\n    background-color: #ffffff;\r\n    padding: 2px 4px;\r\n    border-radius: 6px;\r\n}\r\n\r\n.reserver-dynamic-checkbox {\r\n    width: 16px;\r\n    height: 16px;\r\n    min-width: 16px;\r\n    min-height: 16px;\r\n    cursor: pointer;\r\n    pointer-events: auto;\r\n}\r\n\r\n.reserver-dynamic-label {\r\n    cursor: pointer;\r\n    color: #213864;\r\n    font-size: 16px;\r\n    font-weight: 600;\r\n    user-select: none;\r\n}\r\n\r\n@media only screen and (max-width: 1000px) {\r\n    .reserver-dynamic-container {\r\n        transform: scale(0.98);\r\n        margin-bottom: 20px;\r\n        white-space: nowrap;\r\n        z-index: 300;\r\n        pointer-events: auto;\r\n    }\r\n    .reserver-dynamic-option {\r\n        padding-top: 0px;\r\n        padding-bottom: 0px;\r\n    }\r\n}\r\n\r\n\/* \u2705 v2.1.3 : DeplaceAnnonceText \/ DeplaceAnnonce \u2014 desktop uniquement *\/\r\n@media only screen and (min-width: 1001px) {\r\n    .DeplaceAnnonceText {\r\n        margin-top: -5px;\r\n        position: relative;\r\n        z-index: 201;\r\n    }\r\n    .DeplaceAnnonce {\r\n        margin-bottom: -150px;\r\n    }\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<div class=\"elementor-element elementor-element-54e4e530 e-con-full MsgFormatIncorrectConteneur elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"54e4e530\" data-element_type=\"container\" id=\"NotusedAnymore\">\n\t\t\t\t<div class=\"elementor-element elementor-element-531f3cb1 MsgFormatIncorrect elementor-widget__width-inherit elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"531f3cb1\" data-element_type=\"widget\" data-widget_type=\"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 format du fichier n&rsquo;est pas reconnu<\/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-3a352c3f elementor-hidden-desktop TexteMobile TexteMobileAnnonce elementor-widget elementor-widget-text-editor\" data-id=\"3a352c3f\" data-element_type=\"widget\" data-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 ou cliquer ici<br>pour t\u00e9l\u00e9charger une 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-7abb0aba elementor-hidden-desktop TexteMobileAjoutAnnonce elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"7abb0aba\" data-element_type=\"widget\" data-widget_type=\"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;\">Cliquer ici pour t\u00e9l\u00e9charger une annonce<\/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-68e2b2ca UploadIci elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"68e2b2ca\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ici glisser-d\u00e9poser ou t\u00e9l\u00e9charger une annonce<\/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-8d50d33 e-con-full e-flex e-con e-child\" data-id=\"8d50d33\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6ae6ef83 elementor-button-align-center elementor-widget__width-initial HideFormButton EspPubLienAnnonce elementor-widget-mobile__width-initial elementor-widget elementor-widget-form\" data-id=\"6ae6ef83\" data-element_type=\"widget\" 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_URL_annonce\" aria-label=\"Formulaire_URL_annonce\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249874\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"6ae6ef83\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-LienAnnonce elementor-col-100 elementor-sm-100 elementor-field-required\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-LienAnnonce\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tIci renseigner si n\u00e9cessaire le lien hypertexte de l\u2019annonce\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[LienAnnonce]\" id=\"form-field-LienAnnonce\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Ici renseigner si n\u00e9cessaire le lien hypertexte de l\u2019annonce\" 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-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=\"ButtonValidURLAnnonce\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-66fd4d36 e-con-full EnvoiUlterieurContainer e-flex e-con e-child\" data-id=\"66fd4d36\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4ea8e2b4 elementor-button-align-center elementor-widget__width-auto HideFormButton EnvoiUlterieur elementor-widget elementor-widget-form\" data-id=\"4ea8e2b4\" data-element_type=\"widget\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249874\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"4ea8e2b4\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-EnvoiUlterieur elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-EnvoiUlterieur\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tEnvoi diff\u00e9r\u00e9 de l'annonce\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=\"Envoi diff\u00e9r\u00e9 de l&#039;annonce\" id=\"form-field-EnvoiUlterieur-0\" name=\"form_fields[EnvoiUlterieur]\"> <label for=\"form-field-EnvoiUlterieur-0\">Envoi diff\u00e9r\u00e9 de l'annonce<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-4a59cf88 EnvoiUlterieurTexte elementor-widget elementor-widget-text-editor\" data-id=\"4a59cf88\" data-element_type=\"widget\" data-widget_type=\"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;\">Envoyer l\u2019annonce jusqu\u2019\u00e0 8 jours apr\u00e8s paiement<br>\nUn lien vous sera adress\u00e9 par <span style=\"color: #ffffff;\"><a style=\"color: #ffffff;\" 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<div class=\"elementor-element elementor-element-17d3ad0c e-con-full ReserverContainer e-flex e-con e-child\" data-id=\"17d3ad0c\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-177c9b71 elementor-button-align-center elementor-widget__width-auto HideFormButton ReserverBouton elementor-widget elementor-widget-form\" data-id=\"177c9b71\" data-element_type=\"widget\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249874\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"177c9b71\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-ReserverEspacePublicitaire elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-ReserverEspacePublicitaire\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tR\u00e9server cet espace publicitaire\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=\"R\u00e9server cet espace publicitaire\" id=\"form-field-ReserverEspacePublicitaire-0\" name=\"form_fields[ReserverEspacePublicitaire]\"> <label for=\"form-field-ReserverEspacePublicitaire-0\">R\u00e9server cet espace publicitaire<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-5bafe1f3 e-con-full AdUploadedTitle DeplaceAnnonce elementor-hidden-tablet elementor-hidden-mobile elementor-hidden-desktop e-flex e-con e-child\" data-id=\"5bafe1f3\" data-element_type=\"container\" id=\"DeplaceAnnonceId\">\n\t\t<div class=\"elementor-element elementor-element-432cc2a1 e-con-full DeplaceAnnonceSubContainer e-flex e-con e-child\" data-id=\"432cc2a1\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-446e8565 elementor-hidden-tablet elementor-hidden-mobile EspaceReserve elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"446e8565\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Espace r\u00e9serv\u00e9<br \/>Annonce transmise<\/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-60df49d0 elementor-hidden-tablet elementor-hidden-mobile DeplaceAnnonceText elementor-widget elementor-widget-text-editor\" data-id=\"60df49d0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tSi vous souhaitez un autre emplacement, vous pouvez d\u00e9placer cette annonce\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-62ef38f0 e-con-full e-flex e-con e-child\" data-id=\"62ef38f0\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f4f51cb elementor-hidden-tablet elementor-hidden-mobile PositionEspacePublicitaireDeplacer elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"f4f51cb\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Position<\/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-f214306 elementor-hidden-tablet elementor-hidden-mobile RefEspacePublicitaire elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"f214306\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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>\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-1c5a5ed5 e-con-full AdUploadedOverlay elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"1c5a5ed5\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4740d3e8 e-con-full OverlayHeader e-flex e-con e-child\" data-id=\"4740d3e8\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e964c6b elementor-hidden-tablet elementor-hidden-mobile OverlayRefEspace elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"e964c6b\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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-30eb836c OverlayCroixReset elementor-widget elementor-widget-image\" data-id=\"30eb836c\" data-element_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:\/\/via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-transparent.png\" 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-342c88b1 e-con-full OverlayPreviewZone e-flex e-con e-child\" data-id=\"342c88b1\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3c7e790f OverlayDeplaceTexte elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"3c7e790f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Si vous souhaitez un autre emplacement, vous pouvez d\u00e9placer cette annonce<\/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-51f00578 elementor-button-align-center elementor-widget__width-auto HideFormButton OverlayReserverForm elementor-widget elementor-widget-form\" data-id=\"51f00578\" data-element_type=\"widget\" id=\"Formulaire_Reserver_Overlay\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249874\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"51f00578\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-ReserverEspacePublicitaire elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-ReserverEspacePublicitaire\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tR\u00e9server cet espace publicitaire\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=\"R\u00e9server cet espace publicitaire\" id=\"form-field-ReserverEspacePublicitaire-0\" name=\"form_fields[ReserverEspacePublicitaire]\"> <label for=\"form-field-ReserverEspacePublicitaire-0\">R\u00e9server cet espace publicitaire<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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<\/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<\/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<div class=\"elementor-element elementor-element-0b2c677 e-flex e-con-boxed e-con e-parent\" data-id=\"0b2c677\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-12cab97 e-transform elementor-widget elementor-widget-text-editor\" data-id=\"12cab97\" data-element_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);\">Les 30 km en cours de r\u00e9habilitation entre les villes d\u2019Av\u00e9pozo et d\u2019An\u00e9ho et la protection c\u00f4ti\u00e8re avec la construction de 31 \u00e9pis font partie d\u2019un grand projet financ\u00e9 par la Banque Africaine de D\u00e9veloppement (BAD), l\u2019Union Europ\u00e9enne (UE), la Banque Ouest Africaine de D\u00e9veloppement (BOAD), la Banque Islamique de D\u00e9veloppement (BID) et d\u2019autres bailleurs de fonds. Sur les dix premiers kilom\u00e8tres au Togo (Av\u00e9pozo-Togokom\u00e9), les travaux routiers y compris le contr\u00f4le et la surveillance desdits travaux, estim\u00e9s \u00e0 15,3 milliards de Franc CFA TTC, sont r\u00e9alis\u00e9s par une entreprise chinoise (CRBC). Pour la r\u00e9habilitation des 20 kilom\u00e8tres suivants (Togokom\u00e9-An\u00e9ho), dont le co\u00fbt est estim\u00e9 \u00e0 36,16 milliards de Franc CFA y compris le contr\u00f4le et la surveillance des travaux y aff\u00e9rents, c\u2019est la Tunisienne Soci\u00e9t\u00e9 des routes et des b\u00e2timents (SOROUBAT) qui est attributaire des travaux.<\/span><\/p>\n<p>La RN1 qui relie Lom\u00e9 et Cinkass\u00e9 au nord (\u00e0 la fronti\u00e8re du Burkina Faso), soit 700 km, est en projet de d\u00e9doublement et d\u2019une profonde modernisation en 2 \u00d7 2 voies.\u00a0<\/p>\n<p>L\u2019Association Internationale de D\u00e9veloppement (IDA, institution de la Banque mondiale) a annonc\u00e9 en juillet 2021 qu\u2019elle allait d\u00e9bloquer une enveloppe de 470 millions de dollars dans le cadre du Projet de corridor \u00e9conomique Lom\u00e9-Ouagadougou-Niamey pour aider le Togo, le Burkina Faso et le Niger \u00e0 am\u00e9liorer la connectivit\u00e9 r\u00e9gionale sur cet axe qui relie les trois capitales. Le processus est en cours avec l\u2019\u00e9volution du projet de r\u00e9habilitation du tron\u00e7on de route Aouda-Kara (115 km) sur la RN1.<\/p>\n<p>Le troisi\u00e8me grand chantier routier concerne la RN 5 sur le tron\u00e7on Lom\u00e9-Kpalim\u00e9 (kpalim\u00e9, ville situ\u00e9e \u00e0 120 km au nord-ouest de Lom\u00e9), soit 120 km de chauss\u00e9e qui est en cours de r\u00e9habilitation et d\u2019\u00e9largissement.<\/p>\n<p>Les travaux ont d\u00e9marr\u00e9 en juin 2020 pour une dur\u00e9e pr\u00e9vue de trente-six mois et un co\u00fbt global estim\u00e9 \u00e0 195 milliards de F CFA, int\u00e9grant des bassins \u00e0 Lom\u00e9 et l\u2019am\u00e9nagement de voiries dans la ville de Kpalim\u00e9.<\/p>\n<p><!-- \/wp:paragraph --><\/p>\n<p><!-- wp:paragraph --><\/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<div class=\"elementor-element elementor-element-320bb41 ToBeHidden e-flex e-con-boxed e-con e-child\" data-id=\"320bb41\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-7f22429 e-con-full droppable e-flex e-con e-child\" data-id=\"7f22429\" data-element_type=\"container\" id=\"Ele4A\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4a7f340 elementor-widget__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"4a7f340\" data-element_type=\"widget\" data-widget_type=\"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=\"page\" data-elementor-id=\"83347\" class=\"elementor elementor-83347\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6442de91 e-con-full OrdiMobileConteneurClass e-flex e-con e-child\" data-id=\"6442de91\" data-element_type=\"container\" id=\"testIdTest\">\n\t\t\t\t<div class=\"elementor-element elementor-element-57de103 elementor-widget elementor-widget-text-editor\" data-id=\"57de103\" data-element_type=\"widget\" data-widget_type=\"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-249875 .elementor-element.elementor-element-6da64a60{--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;--justify-content:space-around;--align-items:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:50px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-6da64a60.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-45f807e0{--display:flex;--min-height:0px;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-100px;--margin-bottom:62px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:3;}.elementor-249875 .elementor-element.elementor-element-45f807e0.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-61dcced4{--display:flex;--margin-top:0px;--margin-bottom:-11px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-6c65b106{--display:flex;--margin-top:0px;--margin-bottom:-30px;--margin-left:-25px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-eb74aa8{--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-249875 .elementor-element.elementor-element-eb74aa8:not(.elementor-motion-effects-element-type-background), .elementor-249875 .elementor-element.elementor-element-eb74aa8 > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-1c762c45{--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;--flex-wrap:nowrap;--margin-top:-3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-5be6a53a{--display:flex;--align-items:flex-start;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249875 .elementor-element.elementor-element-5be6a53a.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-75917e71{--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-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-249875 .elementor-element.elementor-element-6be76773 > .elementor-widget-container{margin:38px 5px -38px -40px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-6be76773.elementor-element{--align-self:flex-start;}.elementor-249875 .elementor-element.elementor-element-6be76773{text-align:right;}.elementor-249875 .elementor-element.elementor-element-6be76773 img{width:17px;}.elementor-249875 .elementor-element.elementor-element-5ad25a69{--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-249875 .elementor-element.elementor-element-5ad25a69.e-con{--align-self:flex-end;}.elementor-249875 .elementor-element.elementor-element-52dec736 > .elementor-widget-container{margin:45px -18px -55px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-52dec736{z-index:101;text-align:right;}.elementor-249875 .elementor-element.elementor-element-469b1a7c{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-25px;--margin-bottom:90px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-469b1a7c:not(.elementor-motion-effects-element-type-background), .elementor-249875 .elementor-element.elementor-element-469b1a7c > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#9FC5F3;}.elementor-249875 .elementor-element.elementor-element-3f5f9124{--display:flex;--min-height:30px;--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;--justify-content:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:1px;--margin-bottom:-6px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:99;}.elementor-249875 .elementor-element.elementor-element-3f5f9124.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-48a37689{--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;--justify-content:flex-start;--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--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-249875 .elementor-element.elementor-element-4b68287 > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249875 .elementor-element.elementor-element-4b68287.elementor-element{--align-self:flex-start;}.elementor-249875 .elementor-element.elementor-element-4b68287{text-align:start;font-family:\"Roboto\", Sans-serif;font-size:12px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-79a46db6{--display:flex;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249875 .elementor-element.elementor-element-47d25f98 > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-47d25f98{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:18px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-3aa42503{--display:flex;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:flex-end;--align-items:flex-end;--margin-top:4px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-12d5dc39 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-12d5dc39.elementor-element{--align-self:flex-start;}.elementor-249875 .elementor-element.elementor-element-12d5dc39{text-align:end;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-21535e15{--display:flex;--justify-content:flex-start;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--flex-wrap:wrap;--margin-top:-2px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-21535e15.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-de420c1{--display:flex;--min-height:30px;--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-249875 .elementor-element.elementor-element-2f60f3f > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-2f60f3f.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-2f60f3f{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:500;line-height:1.1em;color:#FB5E2A;}.elementor-249875 .elementor-element.elementor-element-6b485447 > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-6b485447.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-6b485447{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-78e1d9f5{--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;--justify-content:center;--gap:010px 9px;--row-gap:010px;--column-gap:9px;--flex-wrap:wrap;--margin-top:-14px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:100;}.elementor-249875 .elementor-element.elementor-element-78e1d9f5.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-cf3602e{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-7a1bb33 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-7a1bb33.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-7a1bb33{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-6bf72a5{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-1a57dd9 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-1a57dd9.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-1a57dd9{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-34d8bbba{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-32bd35c6 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-32bd35c6.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-32bd35c6{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-5a9252c3{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-8722042 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-8722042.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-8722042{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-19ecc2b3{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-6071d405 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-6071d405.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-6071d405{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-3617569c{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-4b013e71 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-4b013e71.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-4b013e71{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-7450a6f8{--display:flex;--min-height:20px;--justify-content:center;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:4px 4px 4px 4px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-30970f89 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-30970f89.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-30970f89{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:500;line-height:1.1em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-6aac67a6{--display:flex;--margin-top:-46px;--margin-bottom:-20px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:2;}.elementor-249875 .elementor-element.elementor-element-40d299c{width:100%;max-width:100%;}.elementor-249875 .elementor-element.elementor-element-40d299c.elementor-element{--align-self:flex-end;}.elementor-249875 .elementor-element.elementor-element-1fd15d20{width:100%;max-width:100%;}.elementor-249875 .elementor-element.elementor-element-1fd15d20.elementor-element{--align-self:flex-end;}.elementor-249875 .elementor-element.elementor-element-54e4e530{--display:flex;--justify-content:center;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249875 .elementor-element.elementor-element-531f3cb1{width:100%;max-width:100%;font-family:\"Roboto\", Sans-serif;font-size:10px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249875 .elementor-element.elementor-element-531f3cb1 > .elementor-widget-container{margin:-37px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-531f3cb1.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-3a352c3f > .elementor-widget-container{margin:7px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-3a352c3f.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-3a352c3f{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249875 .elementor-element.elementor-element-7abb0aba > .elementor-widget-container{margin:7px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-7abb0aba.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-7abb0aba{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249875 .elementor-element.elementor-element-68e2b2ca > .elementor-widget-container{margin:-110px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-68e2b2ca.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-68e2b2ca{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:18px;font-weight:600;line-height:1.1em;color:#FB5E2A;}.elementor-249875 .elementor-element.elementor-element-8d50d33{--display:flex;--margin-top:-85px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-8d50d33.e-con{--align-self:center;}.elementor-widget-form .elementor-field-group > label, .elementor-widget-form .elementor-field-subgroup label{color:var( --e-global-color-text );}.elementor-widget-form .elementor-field-group > label{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .elementor-field-type-html{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-widget-form .elementor-field-group .elementor-field{color:var( --e-global-color-text );}.elementor-widget-form .elementor-field-group .elementor-field, .elementor-widget-form .elementor-field-subgroup label{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .elementor-button{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-widget-form .e-form__buttons__wrapper__button-next{background-color:var( --e-global-color-accent );}.elementor-widget-form .elementor-button[type=\"submit\"]{background-color:var( --e-global-color-accent );}.elementor-widget-form .e-form__buttons__wrapper__button-previous{background-color:var( --e-global-color-accent );}.elementor-widget-form .elementor-message{font-family:var( --e-global-typography-text-font-family ), Sans-serif;font-weight:var( --e-global-typography-text-font-weight );}.elementor-widget-form .e-form__indicators__indicator, .elementor-widget-form .e-form__indicators__indicator__label{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-widget-form{--e-form-steps-indicator-inactive-primary-color:var( --e-global-color-text );--e-form-steps-indicator-active-primary-color:var( --e-global-color-accent );--e-form-steps-indicator-completed-primary-color:var( --e-global-color-accent );--e-form-steps-indicator-progress-color:var( --e-global-color-accent );--e-form-steps-indicator-progress-background-color:var( --e-global-color-text );--e-form-steps-indicator-progress-meter-color:var( --e-global-color-text );}.elementor-widget-form .e-form__indicators__indicator__progress__meter{font-family:var( --e-global-typography-accent-font-family ), Sans-serif;font-weight:var( --e-global-typography-accent-font-weight );}.elementor-249875 .elementor-element.elementor-element-6ae6ef83{width:var( --container-widget-width, 75% );max-width:75%;--container-widget-width:75%;--container-widget-flex-grow:0;z-index:120;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group{padding-right:calc( 10px\/2 );padding-left:calc( 10px\/2 );margin-bottom:6px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-form-fields-wrapper{margin-left:calc( -10px\/2 );margin-right:calc( -10px\/2 );margin-bottom:-6px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label, .elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{color:#7B88A3;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-type-html{padding-bottom:0px;color:#7A7A7A;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field{color:#484848;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:01px 01px 01px 01px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:01px 01px 01px 01px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249875 .elementor-element.elementor-element-66fd4d36{--display:flex;--min-height:58px;--gap:0px 0px;--row-gap:0px;--column-gap:0px;border-style:solid;--border-style:solid;border-width:1px 1px 1px 1px;--border-top-width:1px;--border-right-width:1px;--border-bottom-width:1px;--border-left-width:1px;border-color:#FFFFFF;--border-color:#FFFFFF;--border-radius:8px 8px 8px 8px;--margin-top:12px;--margin-bottom:10px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249875 .elementor-element.elementor-element-66fd4d36.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4{width:auto;max-width:auto;z-index:120;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 > .elementor-widget-container{margin:2px 0px 2px 1px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label, .elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field{color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:14px;font-weight:600;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249875 .elementor-element.elementor-element-4a59cf88 > .elementor-widget-container{margin:-3px 0px -24px 0px;}.elementor-249875 .elementor-element.elementor-element-4a59cf88.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-4a59cf88{text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.2em;color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-17d3ad0c{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;border-style:none;--border-style:none;--border-radius:8px 8px 8px 8px;--margin-top:-4px;--margin-bottom:05px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249875 .elementor-element.elementor-element-17d3ad0c.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-177c9b71{width:auto;max-width:auto;z-index:5;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 > .elementor-widget-container{margin:2px 0px 2px 1px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-177c9b71.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label, .elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{color:#000000;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field{color:#000000;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:16px;font-weight:600;line-height:1.1em;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-message.elementor-message-success{color:#00FF2700;}.elementor-249875 .elementor-element.elementor-element-5bafe1f3{--display:flex;--min-height:0px;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--gap:0px 0px;--row-gap:0px;--column-gap:0px;--overlay-opacity:1;--margin-top:230px;--margin-bottom:-220px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:10;}.elementor-249875 .elementor-element.elementor-element-5bafe1f3::before, .elementor-249875 .elementor-element.elementor-element-5bafe1f3 > .elementor-background-video-container::before, .elementor-249875 .elementor-element.elementor-element-5bafe1f3 > .e-con-inner > .elementor-background-video-container::before, .elementor-249875 .elementor-element.elementor-element-5bafe1f3 > .elementor-background-slideshow::before, .elementor-249875 .elementor-element.elementor-element-5bafe1f3 > .e-con-inner > .elementor-background-slideshow::before, .elementor-249875 .elementor-element.elementor-element-5bafe1f3 > .elementor-motion-effects-container > .elementor-motion-effects-layer::before{--background-overlay:'';background-size:cover;}.elementor-249875 .elementor-element.elementor-element-5bafe1f3.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-432cc2a1{--display:flex;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--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-249875 .elementor-element.elementor-element-446e8565 > .elementor-widget-container{margin:0px 3px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-446e8565.elementor-element{--align-self:flex-end;}.elementor-249875 .elementor-element.elementor-element-446e8565{z-index:5;text-align:center;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249875 .elementor-element.elementor-element-60df49d0 > .elementor-widget-container{margin:35px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-60df49d0.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-60df49d0{z-index:5;text-align:center;font-family:\"Roboto\", Sans-serif;font-size:15px;font-weight:500;line-height:1.1em;color:#6185C0;}.elementor-249875 .elementor-element.elementor-element-62ef38f0{--display:flex;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:space-between;--align-items:flex-start;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--margin-top:-287px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-f4f51cb > .elementor-widget-container{margin:0px 3px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-f4f51cb.elementor-element{--align-self:flex-end;}.elementor-249875 .elementor-element.elementor-element-f4f51cb{z-index:5;text-align:left;font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249875 .elementor-element.elementor-element-f214306 > .elementor-widget-container{margin:0px 0px 0px 3px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-f214306.elementor-element{--align-self:flex-end;}.elementor-249875 .elementor-element.elementor-element-f214306{z-index:5;text-align:start;font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249875 .elementor-element.elementor-element-1c5a5ed5{--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;--justify-content:flex-start;--align-items:center;--gap:0px 0px;--row-gap:0px;--column-gap:0px;--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-249875 .elementor-element.elementor-element-1c5a5ed5.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-4740d3e8{--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;--justify-content:space-between;--margin-top:5px;--margin-bottom:5px;--margin-left:010px;--margin-right:10px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-e964c6b > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-e964c6b.elementor-element{--align-self:flex-end;}.elementor-249875 .elementor-element.elementor-element-e964c6b{z-index:5;text-align:left;font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:600;line-height:1.1em;color:#213864;}.elementor-249875 .elementor-element.elementor-element-30eb836c > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-30eb836c{z-index:101;text-align:right;}.elementor-249875 .elementor-element.elementor-element-342c88b1{--display:flex;--min-height:180px;--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;--justify-content:center;--align-items:center;--overflow:hidden;border-style:solid;--border-style:solid;border-width:4px 4px 4px 4px;--border-top-width:4px;--border-right-width:4px;--border-bottom-width:4px;--border-left-width:4px;border-color:#00FF19;--border-color:#00FF19;--border-radius:0px 0px 0px 0px;--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-249875 .elementor-element.elementor-element-342c88b1:not(.elementor-motion-effects-element-type-background), .elementor-249875 .elementor-element.elementor-element-342c88b1 > .elementor-motion-effects-container > .elementor-motion-effects-layer{background-color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-3c7e790f > .elementor-widget-container{padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-3c7e790f{font-family:\"Roboto\", Sans-serif;font-weight:500;color:#6185C0;}.elementor-249875 .elementor-element.elementor-element-51f00578{width:auto;max-width:auto;z-index:5;--e-form-steps-indicators-spacing:20px;--e-form-steps-indicator-padding:30px;--e-form-steps-indicator-inactive-secondary-color:#ffffff;--e-form-steps-indicator-active-secondary-color:#ffffff;--e-form-steps-divider-width:1px;--e-form-steps-divider-gap:10px;}.elementor-249875 .elementor-element.elementor-element-51f00578 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-51f00578.elementor-element{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group{padding-right:calc( 0px\/2 );padding-left:calc( 0px\/2 );margin-bottom:0px;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-form-fields-wrapper{margin-left:calc( -0px\/2 );margin-right:calc( -0px\/2 );margin-bottom:-0px;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group.recaptcha_v3-bottomleft, .elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group.recaptcha_v3-bottomright{margin-bottom:0;}body.rtl .elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-labels-inline .elementor-field-group > label{padding-left:0px;}body:not(.rtl) .elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-labels-inline .elementor-field-group > label{padding-right:0px;}body .elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-labels-above .elementor-field-group > label{padding-bottom:0px;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group > label, .elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{color:#000000;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group > label{font-family:\"Roboto\", Sans-serif;font-size:17px;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-type-html{padding-bottom:0px;color:#FFFFFF;font-family:\"Roboto\", Sans-serif;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field{color:#213864;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-family:\"Roboto\", Sans-serif;font-size:15.5px;font-weight:600;line-height:1.1em;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field:not(.elementor-select-wrapper){background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-select-wrapper select{background-color:#FFFFFF;border-color:#E8ECF1;border-width:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-select-wrapper::before{color:#E8ECF1;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-button{font-family:\"Roboto\", Sans-serif;font-size:1px;font-weight:100;border-radius:6px 6px 6px 6px;}.elementor-249875 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-next{background-color:#10274200;color:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]{background-color:#10274200;color:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"] svg *{fill:#FFFFFF00;}.elementor-249875 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-previous{color:#ffffff;}.elementor-249875 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-next:hover{color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]:hover{color:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-button[type=\"submit\"]:hover svg *{fill:#FFFFFF;}.elementor-249875 .elementor-element.elementor-element-51f00578 .e-form__buttons__wrapper__button-previous:hover{color:#ffffff;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-message{font-family:\"Roboto\", Sans-serif;font-size:13px;font-weight:400;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-message.elementor-message-success{color:#00FF2700;}@media(max-width:1001px){.elementor-249875 .elementor-element.elementor-element-6ae6ef83{z-index:11;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-size:10px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4{z-index:11;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-size:10px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-177c9b71{z-index:11;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-size:10px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-button{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-51f00578{z-index:11;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-size:10px;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-button{font-size:12px;}}@media(min-width:1001px){.elementor-249875 .elementor-element.elementor-element-6da64a60{--width:500px;}.elementor-249875 .elementor-element.elementor-element-45f807e0{--width:100%;}.elementor-249875 .elementor-element.elementor-element-6c65b106{--width:500px;}.elementor-249875 .elementor-element.elementor-element-75917e71{--width:10px;}.elementor-249875 .elementor-element.elementor-element-5ad25a69{--width:100%;}.elementor-249875 .elementor-element.elementor-element-469b1a7c{--width:500px;}.elementor-249875 .elementor-element.elementor-element-48a37689{--width:22%;}.elementor-249875 .elementor-element.elementor-element-79a46db6{--width:50%;}.elementor-249875 .elementor-element.elementor-element-3aa42503{--width:22%;}.elementor-249875 .elementor-element.elementor-element-78e1d9f5{--width:100%;}.elementor-249875 .elementor-element.elementor-element-cf3602e{--width:103px;}.elementor-249875 .elementor-element.elementor-element-6bf72a5{--width:103px;}.elementor-249875 .elementor-element.elementor-element-34d8bbba{--width:103px;}.elementor-249875 .elementor-element.elementor-element-5a9252c3{--width:103px;}.elementor-249875 .elementor-element.elementor-element-19ecc2b3{--width:103px;}.elementor-249875 .elementor-element.elementor-element-3617569c{--width:103px;}.elementor-249875 .elementor-element.elementor-element-7450a6f8{--width:103px;}.elementor-249875 .elementor-element.elementor-element-8d50d33{--width:100%;}.elementor-249875 .elementor-element.elementor-element-66fd4d36{--width:390px;}.elementor-249875 .elementor-element.elementor-element-17d3ad0c{--width:100%;}.elementor-249875 .elementor-element.elementor-element-5bafe1f3{--width:150%;}.elementor-249875 .elementor-element.elementor-element-62ef38f0{--width:95%;}.elementor-249875 .elementor-element.elementor-element-1c5a5ed5{--width:100%;}.elementor-249875 .elementor-element.elementor-element-4740d3e8{--width:100%;}}@media(max-width:1000px){.elementor-249875 .elementor-element.elementor-element-6da64a60{--width:390px;--margin-top:105px;--margin-bottom:-75px;--margin-left:0px;--margin-right:0px;}.elementor-249875 .elementor-element.elementor-element-45f807e0{--min-height:150px;--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;--margin-top:-47px;--margin-bottom:-32px;--margin-left:0px;--margin-right:0px;--z-index:3;}.elementor-249875 .elementor-element.elementor-element-61dcced4{--width:25%;}.elementor-249875 .elementor-element.elementor-element-6c65b106{--width:100%;--flex-direction:row;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--container-widget-height:100%;--container-widget-flex-grow:1;--container-widget-align-self:stretch;--flex-wrap-mobile:wrap;--justify-content:center;--align-items:center;--flex-wrap:nowrap;--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249875 .elementor-element.elementor-element-6c65b106.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-eb74aa8{--width:75%;--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:center;}.elementor-249875 .elementor-element.elementor-element-eb74aa8.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-1c762c45{--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249875 .elementor-element.elementor-element-6be76773 > .elementor-widget-container{margin:-3px 40px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-5ad25a69{--width:100%;--justify-content:flex-end;--align-items:flex-end;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--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-249875 .elementor-element.elementor-element-52dec736 > .elementor-widget-container{margin:40px 55px -30px 0px;}.elementor-249875 .elementor-element.elementor-element-52dec736{z-index:100;}.elementor-249875 .elementor-element.elementor-element-469b1a7c{--width:78%;--align-items:center;--container-widget-width:calc( ( 1 - var( --container-widget-flex-grow ) ) * 100% );--flex-wrap:nowrap;--margin-top:-103px;--margin-bottom:-7px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-469b1a7c.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-3f5f9124{--justify-content:center;--margin-top:0px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249875 .elementor-element.elementor-element-48a37689{--width:25%;--margin-top:2px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-4b68287 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-4b68287{font-size:8px;}.elementor-249875 .elementor-element.elementor-element-79a46db6{--width:46%;--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-249875 .elementor-element.elementor-element-47d25f98 > .elementor-widget-container{margin:0px -20px 0px -20px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-47d25f98{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-3aa42503{--width:25%;--margin-top:4px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-12d5dc39 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-12d5dc39{font-size:7px;}.elementor-249875 .elementor-element.elementor-element-21535e15{--margin-top:-15px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249875 .elementor-element.elementor-element-de420c1{--min-height:15px;--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-249875 .elementor-element.elementor-element-2f60f3f{width:100%;max-width:100%;font-size:10px;}.elementor-249875 .elementor-element.elementor-element-2f60f3f > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-6b485447{width:100%;max-width:100%;font-size:10px;}.elementor-249875 .elementor-element.elementor-element-6b485447 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-78e1d9f5{--width:100%;--gap:6px 4px;--row-gap:6px;--column-gap:4px;--flex-wrap:wrap;--margin-top:-12px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249875 .elementor-element.elementor-element-cf3602e{--width:61px;--min-height:15px;}.elementor-249875 .elementor-element.elementor-element-7a1bb33{font-size:9px;}.elementor-249875 .elementor-element.elementor-element-6bf72a5{--width:61px;--min-height:15px;}.elementor-249875 .elementor-element.elementor-element-1a57dd9{font-size:9px;}.elementor-249875 .elementor-element.elementor-element-34d8bbba{--width:61px;--min-height:15px;}.elementor-249875 .elementor-element.elementor-element-32bd35c6{font-size:9px;}.elementor-249875 .elementor-element.elementor-element-5a9252c3{--width:61px;--min-height:15px;}.elementor-249875 .elementor-element.elementor-element-8722042{font-size:9px;}.elementor-249875 .elementor-element.elementor-element-19ecc2b3{--width:61px;--min-height:15px;}.elementor-249875 .elementor-element.elementor-element-6071d405{font-size:9px;}.elementor-249875 .elementor-element.elementor-element-3617569c{--width:61px;--min-height:15px;}.elementor-249875 .elementor-element.elementor-element-4b013e71{font-size:9px;}.elementor-249875 .elementor-element.elementor-element-7450a6f8{--width:61px;--min-height:15px;}.elementor-249875 .elementor-element.elementor-element-30970f89{font-size:9px;}.elementor-249875 .elementor-element.elementor-element-6aac67a6{--width:96%;--min-height:250px;--margin-top:-56px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-40d299c > .elementor-widget-container{margin:5px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-1fd15d20 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-54e4e530{--margin-top:3px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249875 .elementor-element.elementor-element-54e4e530.e-con{--order:-99999 \/* order start hack *\/;}.elementor-249875 .elementor-element.elementor-element-531f3cb1 > .elementor-widget-container{margin:-30px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-3a352c3f > .elementor-widget-container{margin:-181px 0px 1px 0px;}.elementor-249875 .elementor-element.elementor-element-3a352c3f{text-align:center;font-size:10px;line-height:1.2em;}.elementor-249875 .elementor-element.elementor-element-7abb0aba > .elementor-widget-container{margin:-180px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-7abb0aba{text-align:center;font-size:14px;line-height:1.2em;}.elementor-249875 .elementor-element.elementor-element-68e2b2ca > .elementor-widget-container{margin:-110px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-68e2b2ca{font-size:10px;}.elementor-249875 .elementor-element.elementor-element-8d50d33{--width:184px;--margin-top:-156px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249875 .elementor-element.elementor-element-8d50d33.e-con{--align-self:center;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83{width:var( --container-widget-width, 100% );max-width:100%;--container-widget-width:100%;--container-widget-flex-grow:0;z-index:120;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group > label{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-field-subgroup label{font-size:8px;}.elementor-249875 .elementor-element.elementor-element-6ae6ef83 .elementor-button{font-size:10.5px;}.elementor-249875 .elementor-element.elementor-element-66fd4d36{--width:85%;--min-height:42px;--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:center;--margin-top:10px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:151;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 > .elementor-widget-container{margin:2px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4{z-index:120;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group > label{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-type-html{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-field-subgroup label{font-size:10px;}.elementor-249875 .elementor-element.elementor-element-4ea8e2b4 .elementor-button{font-size:10.5px;}.elementor-249875 .elementor-element.elementor-element-4a59cf88 > .elementor-widget-container{margin:2px 0px -10px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-4a59cf88{font-size:7.5px;}.elementor-249875 .elementor-element.elementor-element-17d3ad0c{--width:85%;--min-height:42px;--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:center;--margin-top:2px;--margin-bottom:-20px;--margin-left:0px;--margin-right:0px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;--z-index:251;}.elementor-249875 .elementor-element.elementor-element-177c9b71 > .elementor-widget-container{margin:2px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-177c9b71{z-index:120;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group > label{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-type-html{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-field-subgroup label{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-177c9b71 .elementor-button{font-size:10.5px;}.elementor-249875 .elementor-element.elementor-element-5bafe1f3{--min-height:150px;--margin-top:-149px;--margin-bottom:0px;--margin-left:0px;--margin-right:0px;}.elementor-249875 .elementor-element.elementor-element-446e8565 > .elementor-widget-container{margin:-133px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-446e8565.elementor-element{--align-self:flex-start;}.elementor-249875 .elementor-element.elementor-element-446e8565{text-align:left;font-size:10px;}.elementor-249875 .elementor-element.elementor-element-f4f51cb > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249875 .elementor-element.elementor-element-f4f51cb.elementor-element{--align-self:flex-start;}.elementor-249875 .elementor-element.elementor-element-f4f51cb{text-align:center;font-size:10px;}.elementor-249875 .elementor-element.elementor-element-f214306 > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249875 .elementor-element.elementor-element-f214306.elementor-element{--align-self:flex-start;}.elementor-249875 .elementor-element.elementor-element-f214306{text-align:center;font-size:10px;}.elementor-249875 .elementor-element.elementor-element-1c5a5ed5{--width:390px;--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-249875 .elementor-element.elementor-element-e964c6b > .elementor-widget-container{margin:0px 0px 0px 10px;}.elementor-249875 .elementor-element.elementor-element-e964c6b.elementor-element{--align-self:flex-start;}.elementor-249875 .elementor-element.elementor-element-e964c6b{text-align:center;font-size:10px;}.elementor-249875 .elementor-element.elementor-element-30eb836c > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-30eb836c{z-index:100;}.elementor-249875 .elementor-element.elementor-element-342c88b1{--min-height:112px;--margin-top:5px;--margin-bottom:5px;--margin-left:5px;--margin-right:5px;--padding-top:0px;--padding-bottom:0px;--padding-left:0px;--padding-right:0px;}.elementor-249875 .elementor-element.elementor-element-3c7e790f{text-align:center;font-size:15px;}.elementor-249875 .elementor-element.elementor-element-51f00578 > .elementor-widget-container{margin:0px 0px 0px 0px;padding:0px 0px 0px 0px;}.elementor-249875 .elementor-element.elementor-element-51f00578{z-index:120;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group > label{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-type-html{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-group .elementor-field, .elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-field-subgroup label{font-size:12px;}.elementor-249875 .elementor-element.elementor-element-51f00578 .elementor-button{font-size:10.5px;}}<\/style>\t\t<div data-elementor-type=\"loop-item\" data-elementor-id=\"249875\" class=\"elementor elementor-249875 elementor-bc-flex-widget e-loop-item e-loop-item-38623 post-38623 post type-post status-publish format-standard has-post-thumbnail hentry category-btp category-page-pays-only category-togo category-togo-btp generate-columns tablet-grid-50 mobile-grid-100 grid-parent grid-20\" data-elementor-post-type=\"elementor_library\" data-custom-edit-handle=\"1\">\n\t\t\t<div class=\"elementor-element elementor-element-6da64a60 e-con-full OrdiMobileConteneurClass e-flex e-con e-child\" data-id=\"6da64a60\" data-element_type=\"container\" id=\"testIdTest\">\n\t\t<div class=\"elementor-element elementor-element-45f807e0 e-con-full UploadFileConteneur AdUploadedTitle elementor-hidden-tablet elementor-hidden-mobile elementor-hidden-desktop e-flex e-con e-child\" data-id=\"45f807e0\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-61dcced4 e-con-full e-flex e-con e-child\" data-id=\"61dcced4\" data-element_type=\"container\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6c65b106 e-con-full e-flex e-con e-child\" data-id=\"6c65b106\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-eb74aa8 e-con-full e-flex e-con e-child\" data-id=\"eb74aa8\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1c762c45 e-con-full e-flex e-con e-child\" data-id=\"1c762c45\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-5be6a53a e-con-full e-flex e-con e-child\" data-id=\"5be6a53a\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-75917e71 e-con-full e-flex e-con e-child\" data-id=\"75917e71\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6be76773 AnnonceDragIcone elementor-widget elementor-widget-image\" data-id=\"6be76773\" data-element_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\/2025\/05\/arrow-drag-64-bleu.png\" 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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5ad25a69 e-con-full CroixResetAnnonceContainer e-flex e-con e-child\" data-id=\"5ad25a69\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-52dec736 elementor-widget elementor-widget-image\" data-id=\"52dec736\" data-element_type=\"widget\" id=\"CroixResetAnnonce\" 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:\/\/via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-transparent.png\" 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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-469b1a7c e-con-full UploadFileConteneur e-flex e-con e-child\" data-id=\"469b1a7c\" data-element_type=\"container\" id=\"UploadFileConteneur\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-3f5f9124 e-con-full ChoisirEspacePublicitaireDisponibiliteConteneur e-flex e-con e-child\" data-id=\"3f5f9124\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-48a37689 e-con-full e-flex e-con e-child\" data-id=\"48a37689\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b68287 PositionEspacePublicitaire elementor-widget elementor-widget-text-editor\" data-id=\"4b68287\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tPosition\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-79a46db6 e-con-full e-flex e-con e-child\" data-id=\"79a46db6\" data-element_type=\"container\" id=\"ChoixEspacePublicitaireTitre\">\n\t\t\t\t<div class=\"elementor-element elementor-element-47d25f98 elementor-widget elementor-widget-text-editor\" data-id=\"47d25f98\" data-element_type=\"widget\" id=\"ChoixEspacePublicitaireTexte\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tChoix d&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-3aa42503 e-con-full e-flex e-con e-child\" data-id=\"3aa42503\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-12d5dc39 ReferenceEspacePublicitaire elementor-widget elementor-widget-text-editor\" data-id=\"12d5dc39\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-21535e15 e-con-full EspPubFormatMainContainer e-flex e-con e-child\" data-id=\"21535e15\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-de420c1 e-con-full e-flex e-con e-child\" data-id=\"de420c1\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2f60f3f elementor-widget-mobile__width-inherit SelectionFormatTitre elementor-widget elementor-widget-text-editor\" data-id=\"2f60f3f\" data-element_type=\"widget\" data-widget_type=\"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 s\u00e9lectionner un format d&rsquo;annonce<\/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-6b485447 elementor-widget-mobile__width-inherit elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile SelectionFormatTitreBlancOLD elementor-widget elementor-widget-text-editor\" data-id=\"6b485447\" data-element_type=\"widget\" data-widget_type=\"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 changer de format d&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-78e1d9f5 e-con-full EspPubFormatListe e-flex e-con e-child\" data-id=\"78e1d9f5\" data-element_type=\"container\">\n\t\t<a class=\"elementor-element elementor-element-cf3602e e-con-full EspPubFormatContainer FormatIdCreation e-flex e-con e-child\" data-id=\"cf3602e\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7a1bb33 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"7a1bb33\" data-element_type=\"widget\" data-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\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-6bf72a5 e-con-full EspPubFormatContainer FormatIdPopUp e-flex e-con e-child\" data-id=\"6bf72a5\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1a57dd9 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"1a57dd9\" data-element_type=\"widget\" data-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-34d8bbba e-con-full EspPubFormatContainer FormatIdBanniere e-flex e-con e-child\" data-id=\"34d8bbba\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-32bd35c6 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"32bd35c6\" data-element_type=\"widget\" data-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-5a9252c3 e-con-full EspPubFormatContainer FormatIdVideo e-flex e-con e-child\" data-id=\"5a9252c3\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8722042 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"8722042\" data-element_type=\"widget\" data-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<a class=\"elementor-element elementor-element-19ecc2b3 e-con-full EspPubFormatContainer FormatIdCommunique e-flex e-con e-child\" data-id=\"19ecc2b3\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6071d405 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"6071d405\" data-element_type=\"widget\" data-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<a class=\"elementor-element elementor-element-3617569c e-con-full EspPubFormatContainer FormatIdInterview e-flex e-con e-child\" data-id=\"3617569c\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4b013e71 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"4b013e71\" data-element_type=\"widget\" data-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-7450a6f8 e-con-full EspPubFormatContainer FormatIdParrainage e-flex e-con e-child\" data-id=\"7450a6f8\" data-element_type=\"container\" href=\"#\">\n\t\t\t\t<div class=\"elementor-element elementor-element-30970f89 EspPubFormat elementor-widget elementor-widget-text-editor\" data-id=\"30970f89\" data-element_type=\"widget\" data-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<div class=\"elementor-element elementor-element-6aac67a6 e-con-full HTMLUploadfileConteneur e-flex e-con e-child\" data-id=\"6aac67a6\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-40d299c elementor-widget__width-inherit HTMLUploadfileClass elementor-widget elementor-widget-html\" data-id=\"40d299c\" data-element_type=\"widget\" id=\"HTMLUploadfile\" 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=\"en\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <meta name=\"google\" content=\"notranslate\">\r\n    \r\n    <script data-jetpack-boost=\"ignore\" src=\"https:\/\/code.jquery.com\/jquery-3.6.0.min.js\"><\/script>\r\n    <script data-jetpack-boost=\"ignore\" src=\"https:\/\/code.jquery.com\/ui\/1.12.1\/jquery-ui.min.js\"><\/script>\r\n\r\n<script data-jetpack-boost=\"ignore\">\r\n\/\/ Lazy loading des biblioth\u00e8ques - charg\u00e9es uniquement au besoin\r\nwindow.VIALibraries = {\r\n    mammothLoaded: false,\r\n    pdfLoaded: false,\r\n    \r\n    loadMammoth: function(callback) {\r\n        if (this.mammothLoaded) { callback(); return; }\r\n        var script = document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/mammoth\/1.4.0\/mammoth.browser.min.js';\r\n        script.onload = function() { \r\n            window.VIALibraries.mammothLoaded = true; \r\n            callback(); \r\n        };\r\n        document.head.appendChild(script);\r\n    },\r\n    \r\n    loadPdfJs: function(callback) {\r\n        if (this.pdfLoaded) { callback(); return; }\r\n        var script = document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.11.174\/pdf.min.js';\r\n        script.onload = function() {\r\n            window.VIALibraries.pdfLoaded = true;\r\n            pdfjsLib.GlobalWorkerOptions.workerSrc = '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n            callback();\r\n        };\r\n        document.head.appendChild(script);\r\n    }\r\n};\r\n<\/script>\r\n\r\n<\/head>\r\n<body>\r\n    <div id=\"PopUpMessageAchattest\" class=\"draggable\" draggable=\"true\" style=\"justify-content: center; align-items: flex-start;\">\r\n        <div id=\"drop_file_zone_achat\" class=\"drop_file_zone_achat_class\" ondrop=\"uploadFile_achat(event)\" ondragover=\"return false\">\r\n        <div id=\"drag_upload_file_achat\">\r\n            <p><input class=\"button-2_achat\" type=\"button\" value=\"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\" onclick=\"fileExplorer_achat(event);\" \/><\/p>\r\n                <input type=\"file\" id=\"selectfile_achat\" \/>\r\n        <\/div>\r\n        <\/div>\r\n        <div class=\"img-content\"><\/div>\r\n    <\/div>\r\n<\/body>\r\n<\/html>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1fd15d20 elementor-widget__width-inherit HTMLUploadfileClass elementor-widget elementor-widget-html\" data-id=\"1fd15d20\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script data-jetpack-boost=\"ignore\">\r\nif (!window._espPubScriptLoaded) {\r\nwindow._espPubScriptLoaded = true;\r\n\/**\r\n * Configuration centralis\u00e9e\r\n *\/\r\nconst CONFIG = {\r\n    iframeId: 'yearbook-iframe',\r\n    ajaxUrl: 'https:\/\/via-agency.media\/wp-admin\/admin-ajax.php',\r\n    apercuUrl: 'https:\/\/rdc.yearbook-media.com\/apercu',\r\n    \r\n    allowedExtensions: {\r\n        video: ['mp4', 'mov', 'wmv', 'avi', 'flv', 'f4v', 'swf', 'mkv', 'webm', 'mpeg'],\r\n        image: ['jpg', 'jpeg', 'png', 'gif', 'tif', 'svg', 'webp'],\r\n        document: ['doc', 'docx', 'ppt', 'pptx', 'pdf']\r\n    },\r\n    \r\n    mimeTypes: {\r\n        docx: 'application\/vnd.openxmlformats-officedocument.wordprocessingml.document',\r\n        pdf: 'application\/pdf'\r\n    },\r\n    \r\n    dragScroll: {\r\n        threshold: 150,\r\n        maxSpeed: 65,\r\n        throttleDelay: 50\r\n    },\r\n    \r\n    breakpoints: {\r\n        mobile: 1000\r\n    },\r\n    \r\n    keywords: [\r\n        { normal: \"parrainage\", display: \"Parrainage\" },\r\n        { normal: \"communique\", display: \"Communiqu\u00e9\" },\r\n        { normal: \"interview\", display: \"Interview\" }\r\n    ]\r\n};\r\n\r\n\/**\r\n * \u2705 v1.19.1 : Module de positionnement dans l'iframe\r\n * \r\n * PROBL\u00c8ME : L'iframe ne scrolle pas en desktop \u2014 c'est le parent (#PageWebTitrePage) qui scrolle.\r\n * L'iframe est scal\u00e9e \u00e0 0.85 \u2192 les coordonn\u00e9es iframe \u2260 coordonn\u00e9es parent.\r\n * position:fixed dans l'iframe = relatif au CONTENU TOTAL, pas au viewport visible.\r\n * \r\n * SOLUTION : Le parent calcule visibleTopIframe (la position iframe du haut du viewport)\r\n * et l'envoie dans le message 'PageWebTitrePage-scroll'. L'iframe n'a qu'\u00e0 l'utiliser.\r\n * \r\n * Pour scroller, l'iframe envoie 'scrollToIframeY' au parent qui fait la conversion.\r\n *\/\r\nconst ScrollHelper = {\r\n    _visibleTopIframe: 0,\r\n    _iframeScale: 0.85,\r\n\r\n    init() {\r\n        \/\/ \u00c9couter les donn\u00e9es de scroll envoy\u00e9es par le parent\r\n        window.addEventListener('message', (event) => {\r\n            var msg = event.data;\r\n            if (msg && msg.action === 'PageWebTitrePage-scroll') {\r\n                if (typeof msg.visibleTopIframe === 'number') {\r\n                    this._visibleTopIframe = msg.visibleTopIframe;\r\n                }\r\n                if (typeof msg.iframeScale === 'number') {\r\n                    this._iframeScale = msg.iframeScale;\r\n                }\r\n            }\r\n        });\r\n        console.log('\u2705 ScrollHelper initialis\u00e9');\r\n    },\r\n\r\n    \/**\r\n     * Position Y dans le document iframe correspondant au haut du viewport visible\r\n     *\/\r\n    getVisibleTop() {\r\n        if (window === window.top) {\r\n            return window.scrollY || 0;\r\n        }\r\n        return this._visibleTopIframe;\r\n    },\r\n\r\n    \/**\r\n     * Demande au parent de scroller pour positionner `element` \u00e0 `offsetFromTop` px du viewport\r\n     *\/\r\n    scrollElementTo(element, offsetFromTop) {\r\n        if (!element) return;\r\n\r\n        \/\/ getBoundingClientRect().top dans une iframe sans scroll = position absolue Y\r\n        var elementAbsY = element.getBoundingClientRect().top;\r\n\r\n        if (window === window.top) {\r\n            window.scrollTo({ top: elementAbsY - offsetFromTop + (window.scrollY || 0), behavior: 'smooth' });\r\n            return;\r\n        }\r\n\r\n        \/\/ Envoyer au parent \u2014 le parent fait la conversion scale\r\n        window.parent.postMessage({\r\n            type: 'scrollToIframeY',\r\n            iframeId: CONFIG.iframeId,\r\n            iframeY: elementAbsY,\r\n            offsetFromTop: offsetFromTop\r\n        }, '*');\r\n        console.log('\ud83d\udcdc scrollToIframeY:', { iframeY: Math.round(elementAbsY), offsetFromTop });\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'\u00e9tat (SessionStorage)\r\n *\/\r\nconst StateManager = {\r\n    init() {\r\n        if (sessionStorage.getItem(\"AchatEspaceCall\") === 'No') {\r\n            sessionStorage.clear();\r\n        }\r\n        \r\n        this.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        this.set('dragstart_Rank_Emplacement_Page_Web', 'No');\r\n        this.set('dragstart_Commande_Emplacement_Page_Web', 'No');\r\n        \r\n        \/\/ \u2705 v2.1.1 : Popup \u2192 ne jamais pr\u00e9remplir le format\r\n        if (this.get('PopUpChoice') === 'Yes') {\r\n            this.set('Formatchoisi', 'No');\r\n            this.set('FormatSelect', '');\r\n            this.set('Commande_Format_Transmis', '');\r\n        }\r\n    },\r\n    \r\n    get(key) {\r\n        return sessionStorage.getItem(key);\r\n    },\r\n    \r\n    set(key, value) {\r\n        sessionStorage.setItem(key, value);\r\n    },\r\n    \r\n    getMultiple(keys) {\r\n        return keys.reduce((acc, key) => {\r\n            acc[key] = this.get(key);\r\n            return acc;\r\n        }, {});\r\n    },\r\n    \r\n    setMultiple(obj) {\r\n        Object.entries(obj).forEach(([key, value]) => {\r\n            this.set(key, value);\r\n        });\r\n    },\r\n    \r\n    buildEmplacementReference(rank) {\r\n        const codeSite = this.get('codeSite');\r\n        const codePage = this.get('codePage');\r\n        return `${codeSite}${codePage}L${rank.substring(3)}`;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des fichiers\r\n *\/\r\nconst FileManager = {\r\n    getExtension(filename) {\r\n        console.log('filename:', filename);\r\n        const parts = filename.split('.');\r\n        return parts.length > 1 ? parts.pop().toLowerCase() : '';\r\n    },\r\n    \r\n    isAllowedExtension(extension) {\r\n        return Object.values(CONFIG.allowedExtensions)\r\n            .flat()\r\n            .includes(extension);\r\n    },\r\n    \r\n    getFileType(extension) {\r\n        for (const [type, extensions] of Object.entries(CONFIG.allowedExtensions)) {\r\n            if (extensions.includes(extension)) {\r\n                return type;\r\n            }\r\n        }\r\n        return null;\r\n    },\r\n    \r\n    async urlToFile(url, filename) {\r\n        console.log(\"Fetching from URL:\", url);\r\n        \r\n        const mimeType = filename.includes('.docx') \r\n            ? CONFIG.mimeTypes.docx \r\n            : filename.includes('.pdf') \r\n            ? CONFIG.mimeTypes.pdf \r\n            : null;\r\n        \r\n        try {\r\n            const response = await fetch(url);\r\n            \r\n            if (!response.ok) {\r\n                throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`);\r\n            }\r\n            \r\n            const blob = await response.blob();\r\n            return new File([blob], filename, { type: mimeType });\r\n        } catch (error) {\r\n            console.error(\"Error in urlToFile:\", error);\r\n            alert(\"Erreur lors du chargement du fichier. Veuillez r\u00e9essayer.\");\r\n            throw error;\r\n        }\r\n    },\r\n    \r\n    createObjectUrl(file) {\r\n        \/\/ R\u00e9voquer l'ancien URL si existant\r\n        const oldUrl = StateManager.get('objectUrl');\r\n        if (oldUrl && oldUrl.startsWith('blob:')) {\r\n            URL.revokeObjectURL(oldUrl);\r\n            console.log('\ud83d\uddd1\ufe0f Old Object URL revoked');\r\n        }\r\n        \r\n        const url = URL.createObjectURL(file);\r\n        StateManager.set('objectUrl', url);\r\n        return url;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion du Drag & Drop\r\n *\/\r\nconst DragDropManager = {\r\n    state: {\r\n        isFileBeingDragged: false,\r\n        draggedFile: null,\r\n        dragInProgress: false,\r\n        throttleTimeout: null\r\n    },\r\n    \r\n    init() {\r\n        this.attachEventListeners();\r\n    },\r\n    \r\n    attachEventListeners() {\r\n        window.addEventListener('dragstart', (e) => this.handleDragStart(e), true);\r\n        jQuery(document).on('dragover', (e) => this.handleDragOver(e));\r\n        jQuery(document).on('dragleave drop', (e) => this.handleDragEnd(e));\r\n        jQuery(\"#drop_file_zone_achat\").on(\"dragover\", (e) => this.handleDropZoneDragOver(e));\r\n        jQuery(\".draggable\").on(\"dragend\", (e) => this.handleDraggableEnd(e));\r\n    },\r\n    \r\n    handleDragStart(e) {\r\n        console.log('Window-level dragstart', e);\r\n        this.state.dragInProgress = true;\r\n    \r\n        const $target = $(e.target);\r\n        const droppableParent = $target.closest('.droppable');\r\n        const parentId = droppableParent.length ? droppableParent.attr('id') : null;\r\n        \r\n        StateManager.set('dragstart_Rank_Emplacement_Page_Web', parentId);\r\n        console.log('dragstart_Rank_Emplacement_Page_Web', parentId);\r\n        \r\n        \/\/ \u2705 CALCULER IMM\u00c9DIATEMENT dragstart_Commande_Emplacement_Page_Web\r\n        if (parentId) {\r\n            const dragstartRef = StateManager.buildEmplacementReference(parentId);\r\n            StateManager.set('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n            console.log('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n            \/\/ \u2705 v2.4.5 : Capturer l'\u00e9tat checkbox R\u00e9server au moment du dragstart\r\n            \/\/ Si l'utilisateur a explicitement d\u00e9coch\u00e9, forcer \u00e0 No m\u00eame si DOM est coch\u00e9\r\n            var $_dragCb = $('#' + parentId).find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n            var _dragCbChecked = $_dragCb.prop('checked') === true;\r\n            var _expliciteDecocheDrag = StateManager.get('_reserverDecoche_' + parentId) === 'Yes';\r\n            var _reserverDrag = _dragCbChecked && !_expliciteDecocheDrag;\r\n            StateManager.set('dragstart_ReserverChecked', _reserverDrag ? 'Yes' : 'No');\r\n            \/\/ R\u00e9initialiser le flag apr\u00e8s lecture\r\n            StateManager.set('_reserverDecoche_' + parentId, 'No');\r\n            console.log('[dragstart] ReserverChecked dom:', _dragCbChecked, '| d\u00e9coch\u00e9 explicitement:', _expliciteDecocheDrag, '| final:', _reserverDrag);\r\n        }\r\n    \r\n        const dataTransfer = e.dataTransfer || e.originalEvent?.dataTransfer;\r\n        const files = dataTransfer?.files || null;\r\n        \r\n        const imgSrc = $target.closest('.draggable').find('img').attr('src');\r\n        const videoSrc = $target.closest('.draggable').find('video').attr('src') || \r\n                        $target.closest('.draggable').find('video source').attr('src');\r\n        const mediaSrc = imgSrc || videoSrc;\r\n    \r\n        console.log('dragstart target:', e.target);\r\n        console.log('files:', files);\r\n        console.log('mediaSrc:', mediaSrc);\r\n    \r\n        if (!mediaSrc && (!files || files.length === 0)) {\r\n            console.log('No media source or files found, preventing drag');\r\n            e.preventDefault();\r\n            this.state.dragInProgress = false;\r\n            return false;\r\n        }\r\n    \r\n        if (mediaSrc) {\r\n            StateManager.set('objectUrl', mediaSrc);\r\n        }\r\n    \r\n        StateManager.set('Commande_Format_Transmis', '');\r\n        \r\n        if ($target.closest('.droppable').find('.doc-preview-container:visible').length > 0) {\r\n            StateManager.set('Commande_Format_Transmis', 'R\u00e9dactionnel');\r\n            StateManager.set('FullPathAdFile', \r\n                $target.closest('.droppable').find('.doc-preview-FullPathAdFile').text());\r\n        }\r\n    \r\n        if (files && files.length > 0) {\r\n            this.state.isFileBeingDragged = true;\r\n            this.state.draggedFile = files[0];\r\n        }\r\n        \r\n        \/\/ \u2705 TOUJOURS marquer comme \"Moved\" quand on drag depuis un espace existant\r\n        if (parentId && mediaSrc) {\r\n            StateManager.set('FirstUploadFileorMoved', 'Moved');\r\n            console.log('\u2705 Drag depuis espace existant - Moved');\r\n        }\r\n    \r\n        console.log('Drag Started', {\r\n            file: this.state.draggedFile,\r\n            mediaSrc: mediaSrc,\r\n            dragstartRef: StateManager.get('dragstart_Commande_Emplacement_Page_Web')\r\n        });\r\n    },\r\n    \r\n    handleDragOver(e) {\r\n        e.preventDefault();\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            this.handleIframeDragScroll(e);\r\n        } else {\r\n            this.handleDirectPageScroll(e);\r\n        }\r\n    },\r\n    \r\n    handleIframeDragScroll(e) {\r\n        if (!this.state.throttleTimeout) {\r\n            this.state.throttleTimeout = setTimeout(() => {\r\n                MessageManager.sendToParent('dragScroll', { clientY: e.clientY });\r\n                this.state.throttleTimeout = null;\r\n            }, CONFIG.dragScroll.throttleDelay);\r\n        }\r\n    },\r\n    \r\n    handleDirectPageScroll(e) {\r\n        const { threshold, maxSpeed } = CONFIG.dragScroll;\r\n        const windowHeight = window.innerHeight;\r\n        \r\n        if (e.clientY < threshold) {\r\n            const speed = Math.max(1, maxSpeed * (1 - e.clientY \/ threshold));\r\n            window.scrollBy(0, -speed);\r\n        } else if (e.clientY > windowHeight - threshold) {\r\n            const speed = Math.max(1, maxSpeed * (1 - (windowHeight - e.clientY) \/ threshold));\r\n            window.scrollBy(0, speed);\r\n        }\r\n    },\r\n    \r\n    handleDragEnd(e) {\r\n        e.preventDefault();\r\n        MessageManager.sendToParent('dragEnd', {});\r\n        console.log('dragleave drop');\r\n    },\r\n    \r\n    handleDropZoneDragOver(e) {\r\n        e.preventDefault();\r\n        console.log(\"FirstUploadFileorMoved:\", StateManager.get('FirstUploadFileorMoved'));\r\n    },\r\n    \r\n    handleDraggableEnd(e) {\r\n        e.preventDefault();\r\n        this.resetState();\r\n        console.log('dragend');\r\n    },\r\n    \r\n    resetState() {\r\n        this.state.isFileBeingDragged = false;\r\n        this.state.draggedFile = null;\r\n        this.state.dragInProgress = false;\r\n    },\r\n    \r\n    clearDataTransferFiles(e) {\r\n        e.dataTransfer = new DataTransfer();\r\n        console.log('DataTransfer files cleared');\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'interface utilisateur\r\n *\/\r\nconst UIManager = {\r\n    isMobile() {\r\n        return window.outerWidth < CONFIG.breakpoints.mobile;\r\n    },\r\n    \r\n    isDesktop() {\r\n        const userAgent = navigator.userAgent;\r\n        const isWindows = userAgent.indexOf('Windows') > -1;\r\n        const isMac = userAgent.indexOf('Macintosh') > -1;\r\n        const isLinux = userAgent.indexOf('Linux') > -1 && userAgent.indexOf('Android') === -1;\r\n        return isWindows || isMac || isLinux;\r\n    },\r\n    \r\n    initMobileUI() {\r\n        $(document).ready(() => {\r\n            $('label[for=\"form-field-LienAnnonce\"]').each(function() {\r\n                $(this).text('Renseigner le lien hypertexte de l\\'annonce');\r\n            });\r\n            \r\n            $('input[name=\"form_fields[LienAnnonce]\"]').each(function() {\r\n                $(this).attr('placeholder', 'Renseigner le lien hypertexte de l\\'annonce');\r\n            });\r\n        });\r\n        \r\n        jQuery('.MsgDatesText').hide();\r\n        this.attachMobileEventListeners();\r\n    },\r\n    \r\n    attachMobileEventListeners() {\r\n        jQuery('.TransmettreFichierAnnonceContainer').on('click', (e) => {\r\n            this.handleMobileSpaceSelection(e);\r\n        });\r\n        \r\n        jQuery('[id=\"form-field-selected_currency_Mobile\"]').off('change').on('change', (e) => {\r\n            this.handleMobileCurrencyChange(e);\r\n        });\r\n    },\r\n    \r\n    handleMobileSpaceSelection(e) {\r\n        e.preventDefault();\r\n        jQuery('#IndisponibilitesMsg').hide();\r\n        \r\n        jQuery('input[name=\"form_fields[SelectEspacePublicitaireMobile]\"]').prop('checked', false);\r\n        jQuery(e.currentTarget).find('input[name=\"form_fields[SelectEspacePublicitaireMobile]\"]').prop('checked', true);\r\n        \r\n        StateManager.set(\"PageWebDisplayed\", 'Yes');\r\n        \r\n        jQuery('.FormSelectDevisesMobile').hide();\r\n        jQuery(e.target).closest('.EspacePublicitaireMobile').find('.FormSelectDevisesMobile').show();\r\n        \r\n        const $droppable = jQuery(e.currentTarget).closest('.droppable');\r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', rankId);\r\n        StateManager.set('Commande_Emplacement_Page_Web', \r\n            StateManager.buildEmplacementReference(rankId));\r\n        \r\n        this.updateEmplacementDisplay();\r\n        this.handleAvailabilityDisplay(e);\r\n        this.displayUploadedAdIfExists(e);\r\n        this.updateTariffDisplay(e);\r\n    },\r\n    \r\n    updateEmplacementDisplay() {\r\n        const emplacement = StateManager.get('Commande_Emplacement_Page_Web');\r\n        jQuery('#EmplacementAnnonceDataStep3').html(emplacement).css({'color': '#56BE50'});\r\n        console.log(\"Emplacement:\", emplacement);\r\n    },\r\n    \r\n    handleAvailabilityDisplay(e) {\r\n        const $espace = jQuery(e.target).closest('.EspacePublicitaireMobile');\r\n        const dispoText = $espace.find('.ChoisirEspacePublicitaireDisponibilite').text();\r\n        \r\n        if (dispoText.length > 46) {\r\n            const espacePublicitaireDispoFrom = dispoText.slice(-10);\r\n            console.log(\"espacePublicitaireDispoFrom:\", espacePublicitaireDispoFrom);\r\n            console.log(\"Date de debut:\", StateManager.get(\"Debut_de_campagne\"));\r\n        } else {\r\n            jQuery('#form-field-DebutCampagne').val(StateManager.get(\"Debut_de_campagne\"));\r\n        }\r\n    },\r\n    \r\n    displayUploadedAdIfExists(e) {\r\n        if (StateManager.get(\"FileReceived\") === 'Yes') {\r\n            jQuery('.VisualisationAnnonceMobile').hide();\r\n            \r\n            const espaceId = StateManager.get('espaceChoisi');\r\n            const $espace = document.querySelector(`[id=\"${espaceId}\"]`);\r\n            \r\n            jQuery($espace).find('.MessageAnnonceMobileTexte')\r\n                .html('Merci de choisir des dates de campagne<br>afin d\\'obtenir le tarif de cet espace publicitaire');\r\n            jQuery($espace).find('.VisualisationAnnonceMobile').show();\r\n        \r\n            const img = document.createElement('img');\r\n            img.src = StateManager.get('objectUrl');\r\n            img.style.width = 'auto';\r\n            img.style.height = 'auto';\r\n            img.style.maxWidth = '100%';\r\n            img.style.maxHeight = '200px';\r\n            \r\n            jQuery('.VisualisationAnnonceMobile').empty();\r\n            jQuery($espace).find('.VisualisationAnnonceMobile').append(img);\r\n        }\r\n    },\r\n    \r\n    updateTariffDisplay(e) {\r\n        jQuery('.TariftobedisplayedMobile').html('-');\r\n        const newTarif = StateManager.get('NewTarifformatted');\r\n        \r\n        if (newTarif && newTarif !== '-') {\r\n            jQuery(e.target).closest('.EspacePublicitaireMobile')\r\n                .find('.TariftobedisplayedMobile')\r\n                .html(newTarif);\r\n        }\r\n    },\r\n    \r\n    handleMobileCurrencyChange(e) {\r\n        event.preventDefault();\r\n        StateManager.setMultiple({\r\n            \"SelectionCatalogueOuAchat\": 'Catalogue',\r\n            \"selected_currency\": jQuery(e.currentTarget).val()\r\n        });\r\n        \r\n        jQuery('#form-field-selected_currency_2').val(StateManager.get(\"selected_currency\"));\r\n        console.log(\"selected currency:\", StateManager.get(\"selected_currency\"));\r\n        \r\n        setTimeout(() => {\r\n            jQuery(e.target).closest('.EspacePublicitaireMobile')\r\n                .find('.TariftobedisplayedMobile')\r\n                .html(StateManager.get(\"NewTarifformatted\"));\r\n        }, 500);\r\n    },\r\n    \r\n    initDesktopUI() {\r\n        StateManager.setMultiple({\r\n            \"FileReceived\": \"No\",\r\n            \"AdDisplayed\": \"No\"\r\n        });\r\n        jQuery('.MsgAdNotDisplayed').hide();\r\n    },\r\n    \r\n    showUploadProgress($dropZone) {\r\n        \/\/ Cacher les \u00e9l\u00e9ments\r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .TexteMobileAnnonce')\r\n            .hide();\r\n        \r\n        \/\/ Afficher et styler le message de progression\r\n        var _uplMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed')\r\n            .show()\r\n            .html(_uplMsg)\r\n            .css({\r\n                'color': '#00ff19',\r\n                'background-color': 'white',\r\n                'padding': '12px 20px',\r\n                'border-radius': '6px',\r\n                'font-weight': '700',\r\n                'font-size': '18px',\r\n                'line-height': '1.4',\r\n                'display': 'inline-block',\r\n                'margin': '10px auto',\r\n                'text-align': 'center'\r\n            });\r\n        \r\n        \/\/ Cacher les autres \u00e9l\u00e9ments\r\n        $dropZone.closest('.droppable')\r\n            .find('.UploadIci, .EnvoiUlterieurTexte, .EnvoiUlterieurContainer')\r\n            .hide();\r\n            \r\n        $dropZone.closest('.droppable')\r\n            .find('.UploadFileConteneur')\r\n            .css({\r\n                'background-color': 'transparent'\r\n            });\r\n    },\r\n    \r\n    showFormatError($dropZone, message = 'Format de fichier incompatible') {\r\n        \/\/ \u2705 v2.4.6 : M\u00eame rendu overlay que le bloc jpeg \u2014 position absolute sur $dropZone\r\n        var _errId = 'fmt-error-msg-' + Date.now();\r\n        $dropZone.css('position', 'relative');\r\n        var _errHtml = '<div id=\"' + _errId + '\" style=\"'\r\n            + 'position:absolute;top:50px;left:50%;transform:translateX(-50%);width:auto;white-space:nowrap;'\r\n            + 'background:#fff;color:#FB5E2A;font-weight:700;font-size:13px;'\r\n            + 'text-align:center;padding:8px 10px;border-radius:6px;'\r\n            + 'border:2px solid #FB5E2A;box-sizing:border-box;'\r\n            + 'z-index:99999;line-height:1.4;'\r\n            + '\">' + message + '<\/div>';\r\n        $dropZone.append(_errHtml);\r\n        setTimeout(function() { jQuery('#' + _errId).remove(); }, 4000);\r\n    },\r\n    \r\n    updateAfterSuccessfulUpload($dropZone) {\r\n        jQuery('#errorMessageMobileText').hide();\r\n        \r\n        $dropZone.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 Pas de margin-top:150px si d\u00e9p\u00f4t depuis miniature kit (d\u00e9j\u00e0 positionn\u00e9)\r\n        if (!window._dropFromMiniature) {\r\n            $dropZone.closest('.OrdiMobileConteneurClass')\r\n                .css({'margin-top': '150px', 'margin-bottom': '0px'});\r\n        }\r\n    },\r\n    \r\n    finalizeAdDisplay($dropZone) {\r\n        StateManager.setMultiple({\r\n            \"FileReceived\": \"Yes\",\r\n            \"PageWebDisplayed\": \"Yes\"\r\n        });\r\n        \r\n        jQuery('#MsgChoixPageWeb, #MsgInsererAnnonceConteneur').hide();\r\n        jQuery('#ChoixEspacePublicitaire')\r\n            .html('L\\'annonce est plac\u00e9e dans un espace publicitaire')\r\n            .show()\r\n            .css({'color': '#56BE50'});\r\n        \r\n        jQuery('#MsgPlacerAnnoncePosition').hide();\r\n        jQuery('#FonctionMenu4').show();\r\n        jQuery('.AnnonceData').html(\"Transmis\").css({'color': '#56BE50'});\r\n        \r\n        jQuery('#ProcederPaiementConteneur').hide();\r\n        jQuery('#ProcederPaiementTitreIconeUp').hide();\r\n        jQuery('#ProcederPaiementTitreIconeDown').show();\r\n        \r\n        jQuery('#message').remove();\r\n        \r\n        this.styleUploadedAd($dropZone);\r\n        this.adjustLayoutAfterUpload($dropZone);\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox \"R\u00e9server\" apr\u00e8s upload\r\n        FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n    },\r\n    \r\n    styleUploadedAd($dropZone) {\r\n        const $container = $dropZone.closest('.OrdiMobileConteneurClass');\r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \r\n        \/\/ \u2705 v1.19.5 : V\u00e9rifier si c'est une restauration via flag d\u00e9di\u00e9\r\n        const isRestoration = StateManager.get('_isAdRestoration') === 'Yes';\r\n        \r\n        $container\r\n            .find('.PositionReference, .TexteMobile, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        $container\r\n            .find('.AdUploadedTitle, .DimensionsMaximales')\r\n            .show();\r\n        \r\n        \/\/ \u2705 Bug 2 fix : montrer le conteneur parent + la croix (CroixResetAnnonceContainer cach\u00e9 par reset)\r\n        $droppable.find('.CroixResetAnnonceContainer').show();\r\n        $droppable.find('#CroixResetAnnonce').show();\r\n        \r\n        \/\/ \u2705 v2.2 : Marquer le droppable comme occup\u00e9 pour qu'Entete le skip\r\n        $droppable.attr('data-via-ad-loaded', 'true');\r\n        \r\n        \/\/ \u2705 v2.0.11 : AdUploadedTitle ne doit pas bloquer le touch sur doc-preview-readmore (mobile)\r\n        $container.find('.AdUploadedTitle').css('pointer-events', 'none');\r\n        \r\n        \/\/ \u2705 #CroixResetAnnonce au-dessus de tous les conteneurs superpos\u00e9s\r\n        $container.find('#CroixResetAnnonce').css({\r\n            'position': 'relative',\r\n            'z-index': '9999'\r\n        });\r\n        \r\n        \/\/ \u2705 Desktop : les conteneurs superpos\u00e9s bloquent la croix \u2014 les rendre transparents aux clics\r\n        if (!UIManager.isMobile()) {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css('pointer-events', 'none');\r\n            \/\/ R\u00e9activer les \u00e9l\u00e9ments interactifs\r\n            $container.find('#CroixResetAnnonce').css('pointer-events', 'auto');\r\n            $dropZone.closest('#PopUpMessageAchattest').css('pointer-events', 'auto'); \/\/ drag annonce\r\n        }\r\n        \r\n        \/\/ \u2705 v2.4.3 : Sur mobile, masquer titre et logo drag quand annonce d\u00e9pos\u00e9e dans Ele0A\r\n        if (UIManager.isMobile()) {\r\n            if ($droppable.attr('id') === 'Ele0A') {\r\n                $droppable.find('#ChoixEspacePublicitaireTexte').hide();\r\n                $droppable.find('#Ele0ADragHandle').hide();\r\n                \/\/ \u2705 v2.4.12 : UploadFileConteneur a pointer-events:none \u2192 forcer auto sur la croix\r\n                $droppable.find('.CroixResetAnnonceContainer')[0] && $droppable.find('.CroixResetAnnonceContainer')[0].style.setProperty('pointer-events', 'auto', 'important');\r\n                $droppable.find('#CroixResetAnnonce')[0] && $droppable.find('#CroixResetAnnonce')[0].style.setProperty('pointer-events', 'auto', 'important');\r\n            }\r\n        }\r\n        \r\n        jQuery(\".HTMLUploadfileConteneur\").css({\r\n            'border': 'none',\r\n            'background-color': 'transparent'\r\n        });\r\n        \r\n        \/\/ \u2705 v2.4.12 : Retirer le liser\u00e9 envoi diff\u00e9r\u00e9 (#UploadFileConteneur) si pr\u00e9sent\r\n        \/\/ (le d\u00e9p\u00f4t d'une annonce cr\u00e9e son propre liser\u00e9 sur .HTMLUploadfileConteneur)\r\n        var $_ufcEd = $dropZone.closest('.droppable').find('#UploadFileConteneur');\r\n        if ($_ufcEd[0]) {\r\n            $_ufcEd[0].style.removeProperty('box-shadow');\r\n            $_ufcEd[0].style.removeProperty('box-sizing');\r\n            if (UIManager.isMobile()) {\r\n                $_ufcEd[0].style.removeProperty('transform');\r\n                $_ufcEd[0].style.removeProperty('transform-origin');\r\n            }\r\n        }\r\n        \r\n        $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n            'box-shadow': 'inset 0 0 0 2px #00FF19',  \/\/ \u2705 v2.4.5 : inset \u2192 jamais clipp\u00e9 par overflow:hidden\r\n            'background-color': 'white',\r\n            'box-sizing': 'border-box',\r\n            'overflow': 'hidden'\r\n        });\r\n        \r\n        \/\/ \u2705 v2.0.9 : Fix mobile \u2014 r\u00e9duire le scale pour que le liser\u00e9 vert soit visible\r\n        \/\/ \u2705 Pas de scale si annonce d\u00e9pos\u00e9e depuis la miniature kit (d\u00e9j\u00e0 aux bonnes dimensions)\r\n        \/\/ \u2705 v2.4.9 : Pas de scale si AchatEspaceCall=Yes (drop depuis miniature dans iframe)\r\n        \/\/ \u2705 data-kit-drop : marqueur DOM pos\u00e9 par kitAdCreated, r\u00e9siste \u00e0 l'async\r\n        var _fromKitDrop = $droppable[0] ? $droppable[0].getAttribute('data-kit-drop') === 'true' : false;\r\n        if (_fromKitDrop) { window._dropFromMiniature = true; } \/\/ sync le flag window\r\n        var _fromMiniature = window._dropFromMiniature || _fromKitDrop;\r\n        var _fromAchat = StateManager.get('AchatEspaceCall') === 'Yes';\r\n        if (UIManager.isMobile() && !_fromMiniature && !_fromAchat) {\r\n            $dropZone.closest('.UploadFileConteneur').css({\r\n                'transform': 'scale(1.35)',\r\n                'transform-origin': 'top center'\r\n            });\r\n            \/\/ \u2705 v2.4.11 : Corps de page mobile \u2014 le .ToBeHidden clippe le scale(1.35) c\u00f4t\u00e9 droit\r\n            \/\/ \u2192 overflow:visible pour que le liser\u00e9 vert soit visible sur les 4 c\u00f4t\u00e9s\r\n            $dropZone.closest('.ToBeHidden').css('overflow', 'visible');\r\n        }\r\n        \r\n        \/\/ \u2705 v2.2 : Sur restauration, Entete a d\u00e9j\u00e0 positionn\u00e9 le droppable correctement\r\n        \/\/ et est emp\u00each\u00e9 de le retoucher (data-via-ad-loaded). On ne touche pas aux marges.\r\n        \/\/ Sur premier upload, on applique les marges normalement.\r\n        \/\/ \u2705 Pas de marges si d\u00e9p\u00f4t depuis miniature kit (dimensions naturelles conserv\u00e9es)\r\n        if (!isRestoration && !_fromMiniature) {\r\n            if ($container.data('orig-mb') === undefined) {\r\n                $container.data('orig-mb', parseInt($container.css('margin-bottom')) || 0);\r\n            }\r\n            if ($droppable.data('orig-mt') === undefined) {\r\n                $droppable.data('orig-mt', parseInt($droppable.css('margin-top')) || 0);\r\n            }\r\n            var _isDocPreview = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _marginAdd = _isDocPreview ? 60 : 130;\r\n            var _marginReduce = _isDocPreview ? 60 : 130;\r\n            $container.css({\r\n                'margin-bottom': ($container.data('orig-mb') + _marginAdd) + 'px'\r\n            });\r\n            $droppable.css({\r\n                'margin-top': ($droppable.data('orig-mt') - _marginReduce + 75) + 'px'\r\n            });\r\n        } else {\r\n            \/\/ \u2705 Sur restauration, ajouter 50px en dessous pour \u00e9viter que le contenu soit trop coll\u00e9\r\n            var _curMb = parseInt($container.css('margin-bottom')) || 0;\r\n            $container.css('margin-bottom', (_curMb + 50) + 'px');\r\n        }\r\n        \r\n        \/\/ \u2705 Masquer .PositionEspacePublicitaireContainer et l'ancien .ReserverContainer\r\n        $droppable.find('.PositionEspacePublicitaireContainer').hide();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        \/\/ \u2705 Supprimer tout ancien bouton dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 v2.1.2 : Cr\u00e9er le bouton R\u00e9server m\u00eame lors d'une restauration\r\n        if (isRestoration) {\r\n            console.log('\ud83d\udd04 Restauration d\u00e9tect\u00e9e - affichage bouton R\u00e9server + DeplaceAnnonce');\r\n            $droppable.find('.DeplaceAnnonce').show();\r\n            \/\/ S'assurer que FileReceived est d\u00e9fini pour la validation\r\n            StateManager.set('FileReceived', 'Yes');\r\n            \/\/ Cocher automatiquement SEULEMENT si c'est une restauration de commande r\u00e9serv\u00e9e (pas pendingAd)\r\n            var _isPendingAdRestore = sessionStorage.getItem('_pendingAdRestoration') === 'Yes';\r\n            if (!_isPendingAdRestore) {\r\n                var _isReservedRestore = sessionStorage.getItem('_isReservedRestoration') === 'Yes';\r\n                setTimeout(function() {\r\n                    var $checkbox = $droppable.find('.reserver-dynamic-checkbox');\r\n                    if ($checkbox.length && _isReservedRestore) {\r\n                        $checkbox.prop('checked', true);\r\n                        $droppable.find('.reserver-dynamic-label').text('Espace publicitaire r\u00e9serv\u00e9').css('color', 'rgb(62, 170, 19)');\r\n                        console.log('\u2705 R\u00e9server coch\u00e9 automatiquement (restauration commande r\u00e9serv\u00e9e)');\r\n                    }\r\n                    sessionStorage.removeItem('_isReservedRestoration');\r\n                    StateManager.set('_isAdRestoration', 'No');\r\n                    \/\/ \u2705 v2.4.7 : updateReserverCheckboxState APR\u00c8S avoir coch\u00e9 la checkbox\r\n                    \/\/ (l'appel synchrone ligne 614 intervient avant le cocher \u2192 label incorrect)\r\n                    if (typeof FormatUIManager !== 'undefined') {\r\n                        FormatUIManager.updateReserverCheckboxState($droppable);\r\n                    }\r\n                }, 150);\r\n            } else {\r\n                \/\/ pendingAd : ne pas cocher, ne pas envoyer au parent\r\n                console.log('\u2705 pendingAd restaur\u00e9 \u2014 R\u00e9server NON coch\u00e9');\r\n                sessionStorage.removeItem('_pendingAdRestoration');\r\n                StateManager.set('_isAdRestoration', 'No');\r\n            }\r\n        }\r\n        \r\n        \/\/ \u2705 Supprimer tout bouton R\u00e9server existant avant insertion (\u00e9vite doublons sur restauration)\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 Cr\u00e9er le bouton \"R\u00e9server\" dynamique avec id unique pour \u00e9viter conflit label\/for Elementor\r\n        const _rankId = $droppable.attr('id') || ('drop_' + Date.now());\r\n        const _cbId = 'reserver-cb-' + _rankId;\r\n        const reserverHTML = `\r\n            <div class=\"reserver-dynamic-container\">\r\n                <span class=\"reserver-dynamic-option\">\r\n                    <input type=\"checkbox\" id=\"${_cbId}\" value=\"R\u00e9server cet espace publicitaire\" \r\n                           class=\"reserver-dynamic-checkbox\"\r\n                           name=\"form_fields[ReserverEspacePublicitaire]\">\r\n                    <span class=\"reserver-dynamic-label\">R\u00e9server cet espace publicitaire<\/span>\r\n                <\/span>\r\n            <\/div>\r\n        `;\r\n        \r\n        \/\/ \u2705 Ins\u00e9rer juste avant .DeplaceAnnonceText (position stable)\r\n        const $anchor = $droppable.find('.DeplaceAnnonceText');\r\n        if ($anchor.length) {\r\n            $anchor.before(reserverHTML);\r\n            $anchor.prev('.reserver-dynamic-container').css('margin-bottom', '-40px');\r\n            if (!UIManager.isMobile()) {\r\n                $anchor.prev('.reserver-dynamic-container').find('.reserver-dynamic-label').css({'font-size': '20px', 'font-weight': '700'});\r\n            }\r\n        } else {\r\n            $droppable.after(reserverHTML);\r\n            const $btn = $droppable.next('.reserver-dynamic-container');\r\n            $btn.css('margin-top', UIManager.isMobile() ? '-10px' : '-140px');\r\n        }\r\n        \r\n        console.log('\u2705 Bouton \"R\u00e9server\" dynamique cr\u00e9\u00e9');\r\n    },\r\n    \r\n    adjustLayoutAfterUpload($dropZone) {\r\n        console.log('\ud83d\udcf1 adjustLayoutAfterUpload \u2014 isMobile():', this.isMobile(), 'outerWidth:', window.outerWidth);\r\n        if (this.isMobile()) {\r\n            this.adjustMobileLayout($dropZone);\r\n            \r\n            \/\/ Repositionner le bouton R\u00e9server APR\u00c8S les ajustements de layout\r\n            setTimeout(() => {\r\n                const $droppable = $dropZone.closest('.droppable');\r\n                const $btn = $droppable.find('.reserver-dynamic-container').add($droppable.next('.reserver-dynamic-container')).first();\r\n                const $lisere = $droppable.find('.HTMLUploadfileConteneur');\r\n                if ($btn.length && $lisere.length) {\r\n                    const lisereBottom = $lisere[0].getBoundingClientRect().bottom;\r\n                    const btnTop = $btn[0].getBoundingClientRect().top;\r\n                    const offset = lisereBottom - btnTop - 48;\r\n                    \r\n                    \/\/ 15px suppl\u00e9mentaires pour homepage et articles\r\n                    let extraOffset = 0;\r\n                    const isHomepage = window.location.pathname === \"\/\" || window.location.pathname === \"\/en\/\";\r\n                    const isSectorPage = $('body').hasClass('page');\r\n                    if (isHomepage) {\r\n                        extraOffset = 13;\r\n                    }\r\n                    if (!isSectorPage) {\r\n                        extraOffset = 15;\r\n                    }\r\n                    \r\n                    \/\/ \u2705 v2.0.9 : +4px pour documents (communiqu\u00e9\/interview\/PDF) avec pr\u00e9sentation HTML\r\n                    if ($droppable.find('.doc-preview-container:visible').length > 0) {\r\n                        extraOffset += 4;\r\n                    }\r\n                    \r\n                    $btn.css({\r\n                        'margin-top': (offset + extraOffset + 20) + 'px',\r\n                        'margin-bottom': (-(offset + extraOffset) - 100) + 'px'\r\n                    });\r\n                    console.log('\ud83d\udcd0 Repositionnement mobile R\u00e9server:', { lisereBottom, btnTop, offset });\r\n                }\r\n            }, 50);\r\n        } else {\r\n            this.adjustDesktopLayout($dropZone);\r\n        }\r\n    },\r\n    \r\n    adjustMobileLayout($dropZone) {\r\n        console.log('\ud83d\udcf1 adjustMobileLayout START');\r\n        console.log('\ud83d\udcf1 AchatEspaceCall:', StateManager.get(\"AchatEspaceCall\"));\r\n        console.log('\ud83d\udcf1 PageAjoutModifAnnonce:', StateManager.get(\"PageAjoutModifAnnonce\"));\r\n        console.log('\ud83d\udcf1 window===window.top:', window === window.top);\r\n        console.log('\ud83d\udcf1 pathname:', location.pathname);\r\n        \r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \r\n        \/\/ \u2705 v2.4.3 : Masquer les textes position\/label\/r\u00e9f\u00e9rence (comme sur desktop)\r\n        $droppable\r\n            .find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 v2.6 : Renseigner .PositionEspacePublicitaire sur mobile (manquait vs desktop)\r\n        (function() {\r\n            var _rankPosMob = StateManager.get('Rank_Emplacement_Page_Web') || $droppable.attr('id') || '';\r\n            var _posLibMob = PreviewRenderer._getPositionLibelle(_rankPosMob);\r\n            if (_posLibMob) {\r\n                $droppable\r\n                    .find('.PositionEspacePublicitaire')\r\n                    .text(_posLibMob)\r\n                    .each(function() {\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        \/\/ \u2705 Scop\u00e9 au $dropZone courant (\u00e9vite d'affecter les autres espaces pub)\r\n        $dropZone.closest('.droppable').find('#CroixResetAnnonce').css({'zoom': '75%'});\r\n\r\n        \/\/ \u2705 v2.4.3 : Remonter la croix reset sur mobile (override margin-top Elementor)\r\n        \/\/ \u2705 v2.4.5 : Poser aussi margin-right ici (Entete.txt ne l'atteint pas pour Ele0A)\r\n        var _croixContainer = $dropZone.closest('.OrdiMobileConteneurClass').find('.CroixResetAnnonceContainer')[0];\r\n        if (_croixContainer) {\r\n            var _isEle0ACroix = ($dropZone.closest('.droppable').attr('id') === 'Ele0A');\r\n            var _mtCroix = StateManager.get(\"PageAjoutModifAnnonce\") === 'Yes' ? '-88px' : '24px';\r\n            \/\/ Ele0A : +40px vers le bas, +15px vers la gauche (margin-right) par rapport \u00e0 Ele1A\r\n            \/\/ Ele0A : margin-top identique aux autres espaces (pas de d\u00e9calage suppl\u00e9mentaire)\r\n            _croixContainer.style.setProperty('margin-top', _mtCroix, 'important');\r\n            _croixContainer.style.setProperty('margin-right', _isEle0ACroix ? '17px' : '12px', 'important');\r\n        }\r\n        \r\n        var _isMiniatureAdj = window._dropFromMiniature;\r\n        window._dropFromMiniature = false;\r\n\r\n        if (_isMiniatureAdj && window.outerWidth <= 1000) {\r\n            \/\/ \u2705 Miniature doc-preview MOBILE : ajuster HTMLUploadfileConteneur \u00e0 la hauteur du contenu\r\n            \/\/ et neutraliser tous les margins Elementor qui d\u00e9calent le $dropZone hors du parent\r\n            var _isDocPreviewMob = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _docH = _isDocPreviewMob ? 144 : 115;\r\n            $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                'height':     _docH + 'px',\r\n                'min-height': _docH + 'px',\r\n                'max-height': _docH + 'px',\r\n                'margin-top': '-55px',\r\n                'margin-bottom': '0px',\r\n                'overflow': 'hidden'\r\n            });\r\n            $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px', 'height': (_docH - 6) + 'px'});\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '65px', 'margin-bottom': '-10px'});\r\n            \/\/ \u2705 v2.4.9 : Doc-preview \u2014 overflow:visible pour que le liser\u00e9 du haut ne soit pas clipp\u00e9\r\n            if (_isDocPreviewMob) {\r\n                $dropZone.closest('.OrdiMobileConteneurClass').css('overflow', 'visible');\r\n                $dropZone.closest('.OrdiMobileConteneurClass').parent().css('overflow', 'visible');\r\n            }\r\n            \/\/ \u2705 v2.4.9 : Ele0A popup mobile \u2014 neutraliser translateY(-32px) pos\u00e9 par Entete sur EnvoiUlterieurTexte\r\n            var _isEle0AMob = ($dropZone.closest('.droppable').attr('id') === 'Ele0A');\r\n            if (_isEle0AMob) {\r\n                var $_euTxt = $dropZone.closest('.droppable').find('.EnvoiUlterieurTexte');\r\n                if ($_euTxt[0]) {\r\n                    $_euTxt[0].style.setProperty('transform', 'translateY(0px)', 'important');\r\n                    $_euTxt[0].style.setProperty('margin-top', '0px', 'important');\r\n                }\r\n            }\r\n            \/\/ \u2705 v2.4.12 : AchatEspaceCall=Yes \u2192 override margins (m\u00eame correction que pour upload direct)\r\n            if (StateManager.get('AchatEspaceCall') === 'Yes') {\r\n                $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px'});\r\n                var _docHAchatMini = _isDocPreviewMob ? 150 : 112;\r\n                $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                    'margin-top': '70px',\r\n                    'margin-bottom': '35px',\r\n                    'min-height': _docHAchatMini + 'px',\r\n                    'height': _isDocPreviewMob ? _docHAchatMini + 'px' : '',\r\n                    'max-height': _isDocPreviewMob ? _docHAchatMini + 'px' : ''\r\n                });\r\n                console.log('\ud83d\udcf1 [miniature] AchatEspaceCall=Yes OVERRIDE: mt=70px | docPreview:', _isDocPreviewMob);\r\n            }\r\n            return;\r\n        }\r\n        \/\/ \u2705 v2.4.10 : Miniature DESKTOP \u2192 layout normal appliqu\u00e9 ci-dessous\r\n        if (_isMiniatureAdj) {\r\n            \/\/ Pas de overflow:hidden \u2014 le liser\u00e9 box-shadow inset doit rester visible\r\n        }\r\n\r\n        $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n            'min-height': '112px',\r\n            'margin-top': '-85px',\r\n            \/\/ \u2705 v2.4.10 : Miniature desktop \u2014 pas de margin-bottom excessif qui fait grandir le droppable\r\n            'margin-bottom': _isMiniatureAdj ? '0px' : '20px' \/\/ \u2705 v2.6 : 195px \u2192 59px \u2192 20px (\u00f73) espace sous checkbox R\u00e9server\r\n        });\r\n        console.log('\ud83d\udcf1 HTMLUploadfileConteneur margins set: mt=-85px mb=20px, el found:', $dropZone.closest('.HTMLUploadfileConteneur').length);\r\n        \r\n        $dropZone.css({\r\n            'margin-top': '-50px',\r\n            'margin-bottom': '-140px'\r\n        });\r\n        \r\n        $dropZone.closest('.OrdiMobileConteneurClass').css({\r\n            'margin-top': '65px',\r\n            'margin-bottom': '-10px'\r\n        });\r\n        console.log('\ud83d\udcf1 OrdiMobile margins set: mt=65px mb=-10px');\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            \/\/ \u2705 v2.4.12 : Reset $dropZone margins (les -50px\/-140px tirent le contenu vers le haut dans l'iframe)\r\n            \/\/ Pour doc-preview (Communiqu\u00e9\/Interview), la hauteur est plus grande \u2192 ajuster min-height\r\n            var _isDocPreviewAchat = $dropZone.find('.doc-preview-container').length > 0;\r\n            var _docHAchat = _isDocPreviewAchat ? 150 : 112;\r\n            $dropZone.css({'margin-top': '0px', 'margin-bottom': '0px', 'top': '0px'});\r\n            $dropZone.closest('.HTMLUploadfileConteneur').css({\r\n                \/\/ \u2705 v2.4.13 : Miniature desktop \u2192 +40px suppl\u00e9mentaires pour compenser le d\u00e9calage\r\n                'margin-top': _isMiniatureAdj ? '110px' : '70px',\r\n                'margin-bottom': '35px',\r\n                'min-height': _docHAchat + 'px',\r\n                'height': _isDocPreviewAchat ? _docHAchat + 'px' : '',\r\n                'max-height': _isDocPreviewAchat ? _docHAchat + 'px' : ''\r\n            });\r\n            console.log('\ud83d\udcf1 AchatEspaceCall=Yes OVERRIDE: mt=' + (_isMiniatureAdj ? '110px' : '70px') + ' | docPreview:', _isDocPreviewAchat, '| h:', _docHAchat);\r\n        }\r\n        \r\n        if (location.pathname === '\/annonce' || location.pathname === '\/annonce\/') {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '70px'});\r\n        }\r\n        \r\n        if (window === window.top) {\r\n            console.log('\ud83d\udcf1 window===window.top OVERRIDE droppable margins');\r\n            $dropZone.closest('.droppable').css({\r\n                'margin-top': '-100px',\r\n                'margin-bottom': '-100px'\r\n            });\r\n            $dropZone.closest('#UploadFileConteneur').css({'width': '80%'});\r\n        }        \r\n    },\r\n    \r\n    adjustDesktopLayout($dropZone) {\r\n        const emplacement = StateManager.get('Commande_Emplacement_Page_Web');\r\n        const $droppable = $dropZone.closest('.droppable');\r\n        \/\/ \u2705 v2.4.13 : Lire et resetter _dropFromMiniature ici aussi (desktop)\r\n        var _fromMiniatureDesktop = window._dropFromMiniature || ($droppable[0] ? $droppable[0].getAttribute('data-kit-drop') === 'true' : false);\r\n        window._dropFromMiniature = false;\r\n        \/\/ \u2705 Nettoyer data-kit-drop apr\u00e8s lecture\r\n        if ($droppable[0]) { $droppable[0].removeAttribute('data-kit-drop'); }\r\n        \r\n        \/\/ \u2705 Masquer les textes enfants (position, label, r\u00e9f\u00e9rence) sans toucher au conteneur\r\n        $droppable\r\n            .find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur > div > .elementor-widget-text-editor')\r\n            .hide();\r\n        \r\n        \/\/ \u2705 +15px sur .droppable \u2014 sauf si drop depuis miniature (dimensions naturelles)\r\n        if (!_fromMiniatureDesktop) {\r\n            const currentMt = parseInt($droppable.css('margin-top')) || 0;\r\n            $droppable.css('margin-top', (currentMt + 15) + 'px');\r\n        } else {\r\n            \/\/ \u2705 v2.4.13 : Drop depuis miniature Kit \u2014 d\u00e9caler de 30px vers le bas\r\n            const currentMt = parseInt($droppable.css('margin-top')) || 0;\r\n            \/\/ \u2705 Homepage : -20px (annonce trop basse sur r\u00e9gie) \u2014 autres pages : +70px\r\n            var _mtOffsetMini = (window.location.pathname === '\/' || window.location.pathname === '\/en\/' || window.location.pathname === '\/fr\/') ? -20 : 70;\r\n            $droppable.css('margin-top', (currentMt + _mtOffsetMini) + 'px');\r\n        }\r\n        \r\n        $dropZone.closest('.OrdiMobileConteneurClass')\r\n            .find('.RefEspacePublicitaire')\r\n            .html(emplacement)\r\n            .attr('id', 'RefEspacePublicitaire')\r\n            .each(function() {\r\n                \/\/ \u2705 Forcer aussi le parent .DeplaceAnnonce visible (display:none !important inline)\r\n                var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                this.style.setProperty('display', 'block', 'important');\r\n            });\r\n        \/\/ \u2705 v2.4.5 : Renseigner et afficher .PositionEspacePublicitaire\r\n        (function() {\r\n            var _rankPos = StateManager.get('Rank_Emplacement_Page_Web') || $droppable.attr('id') || '';\r\n            var _posLib = PreviewRenderer._getPositionLibelle(_rankPos);\r\n            if (_posLib) {\r\n                $dropZone.closest('.OrdiMobileConteneurClass')\r\n                    .find('.PositionEspacePublicitaireDeplacer')\r\n                    .text(_posLib)\r\n                    .each(function() {\r\n                        var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                        if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        if (window.location.pathname === \"\/\" || window.location.pathname === \"\/en\/\") {\r\n            \/\/ \u2705 v2.4.10 : top selon contexte \u2014 espaces hors .remainingContent d\u00e9calent de 60px, ceux dedans de 20px\r\n            var _inRemainingContent = $dropZone.closest('.remainingContent').length > 0;\r\n            var _topOffsetHP = _inRemainingContent ? '20px' : '100px';\r\n            $dropZone.closest('.ToBeHidden')\r\n                .css('top', _topOffsetHP)\r\n                .css('min-height', '300px');\r\n            \/\/ NB : pas de overflow:hidden ici \u2014 le liser\u00e9 vert (box-shadow inset sur HTMLUploadfileConteneur)\r\n            \/\/ doit rester visible sur les 4 c\u00f4t\u00e9s\r\n        }\r\n        \r\n        \/\/ \u2705 Toutes pages desktop : rendre le parent du droppable non-clippant\r\n        \/\/ Le bouton R\u00e9server est ins\u00e9r\u00e9 apr\u00e8s .droppable avec margin-top n\u00e9gatif \u2014\r\n        \/\/ overflow:hidden sur le parent Elementor le masque sinon.\r\n        $droppable.parent().css('overflow', 'visible');\r\n        \r\n        if (location.pathname === '\/annonce' || location.pathname === '\/annonce\/') {\r\n            $dropZone.closest('.OrdiMobileConteneurClass').css({'margin-top': '0px'});\r\n        }\r\n    }\r\n};\r\n\r\n\/**\r\n * \u2705 Module de gestion des formats et du titre .SelectionFormatTitre\r\n *\/\r\nconst FormatUIManager = {\r\n    \r\n    \/**\r\n     * V\u00e9rifie si un format est s\u00e9lectionn\u00e9 dans un espace publicitaire\r\n     * V\u00e9rifie le background-color OU le sessionStorage (format venant de l'accord\u00e9on)\r\n     *\/\r\n    hasSelectedFormat($element) {\r\n        const $droppable = $element.closest('.droppable');\r\n        const isEle0A = $droppable.attr('id') === 'Ele0A';\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            if (isEle0A) {\r\n                \/\/ \u2705 v2.3.4 : Ele0A popup \u2014 vrai seulement si un format sous-jacent (hors FormatIdPopUp) est s\u00e9lectionn\u00e9\r\n                var _hasDomFmt = $droppable.find('.EspPubFormatContainer').not('.FormatIdPopUp').toArray().some(el => {\r\n                    return $(el).css('background-color') === 'rgb(255, 255, 255)';\r\n                });\r\n                if (_hasDomFmt) return true;\r\n                \/\/ \u2705 v2.4.5 : Fallback sessionStorage \u2014 DOM pas encore mis \u00e0 jour (timing MutationObserver)\r\n                return !!sessionStorage.getItem('FormatSelect');\r\n            }\r\n            \/\/ Autres espaces en mode popup \u2192 toujours vrai\r\n            return true;\r\n        }\r\n        const hasWhiteBg = $droppable.find('.EspPubFormatContainer').toArray().some(el => {\r\n            return $(el).css('background-color') === 'rgb(255, 255, 255)';\r\n        });\r\n        if (hasWhiteBg) return true;\r\n        \/\/ \u2705 v1.16.0 : Fallback sessionStorage Formatchoisi\r\n        if (sessionStorage.getItem('Formatchoisi') === 'Yes') return true;\r\n        \/\/ \u2705 v2.4.5 : Fallback FormatSelect \u2014 cas du chargement initial avec format d\u00e9j\u00e0 s\u00e9lectionn\u00e9\r\n        \/\/ (Formatchoisi peut \u00eatre remis \u00e0 No au chargement, mais FormatSelect persiste)\r\n        if (sessionStorage.getItem('FormatSelect')) return true;\r\n        \/\/ \u2705 v2.4.9 : Fallback _FormatSelectApplied \u2014 survit au clear de yearbook-media.js init\r\n        return !!sessionStorage.getItem('_FormatSelectApplied');\r\n    },\r\n    \r\n    \/**\r\n     * Met \u00e0 jour la couleur du titre .SelectionFormatTitre\r\n     * Blanc si un format est s\u00e9lectionn\u00e9, rouge #FB5E2A sinon\r\n     *\/\r\n    updateTitleColor($droppable) {\r\n        \/\/ \u2705 v2.4.5 : Ele0A \u2014 ne jamais afficher SelectionFormatTitre\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes' && $droppable.attr('id') === 'Ele0A') {\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n            return;\r\n        }\r\n\r\n        if (this.hasSelectedFormat($droppable)) {\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n            console.log('\u2705 SelectionFormatTitreBlanc affich\u00e9 (format s\u00e9lectionn\u00e9)');\r\n        } else {\r\n            $droppable.find('.SelectionFormatTitre').show();\r\n            $droppable.find('.SelectionFormatTitreBlanc').hide();\r\n            console.log('\u26a0\ufe0f SelectionFormatTitre affich\u00e9 (aucun format s\u00e9lectionn\u00e9)');\r\n        }\r\n    },\r\n    \r\n    \/**\r\n     * Flash visuel sur le titre pour indiquer qu'un format est requis\r\n     *\/\r\n    flashTitle($element) {\r\n        const $droppable = $element.closest('.droppable');\r\n        const $titre = $droppable.find('.SelectionFormatTitre');\r\n        if (!$titre.length) return;\r\n        \r\n        \/\/ Flash rouge rapide 3 fois\r\n        let count = 0;\r\n        const originalColor = $titre.css('color');\r\n        \r\n        const flash = setInterval(() => {\r\n            $titre.css('color', count % 2 === 0 ? '#FF0000' : '#FB5E2A');\r\n            count++;\r\n            if (count >= 6) {\r\n                clearInterval(flash);\r\n                $titre.css('color', '#FB5E2A');\r\n            }\r\n        }, 250);\r\n        \r\n        console.log('\u26a0\ufe0f Flash titre format - action bloqu\u00e9e (aucun format s\u00e9lectionn\u00e9)');\r\n    },\r\n    \r\n    \/**\r\n     * Met \u00e0 jour l'\u00e9tat de la checkbox \"R\u00e9server cet espace publicitaire\"\r\n     * La checkbox est activable si : format s\u00e9lectionn\u00e9 ET (fichier d\u00e9pos\u00e9 OU envoi diff\u00e9r\u00e9)\r\n     *\/\r\n    updateReserverCheckboxState($droppable) {\r\n        \/\/ \u2705 Chercher le label : dynamique ou Elementor statique\r\n        let $label = null;\r\n        let $container = null;\r\n        \r\n        \/\/ 1. Bouton dynamique dans le droppable\r\n        $container = $droppable.find('.reserver-dynamic-container');\r\n        if (!$container.length) {\r\n            $container = $droppable.next('.reserver-dynamic-container');\r\n        }\r\n        if (!$container.length) {\r\n            \/\/ Mobile : checkbox attach\u00e9e au body avec data-droppable-id\r\n            $container = $('body > .reserver-dynamic-container[data-droppable-id=\"' + $droppable.attr('id') + '\"]');\r\n        }\r\n        if (!$container.length) {\r\n            $container = $('body > .reserver-dynamic-container');\r\n        }\r\n        \r\n        if ($container.length) {\r\n            $label = $container.find('.reserver-dynamic-label');\r\n            $container.find('.reserver-dynamic-option, .elementor-field-option').css('opacity', '1');\r\n        }\r\n        \r\n        \/\/ 2. Bouton Elementor statique - chercher dans le droppable puis globalement\r\n        let $reserverStatique = $droppable.find('.elementor-field-group-ReserverEspacePublicitaire label');\r\n        if (!$reserverStatique.length) {\r\n            $reserverStatique = $droppable.find('label[for^=\"form-field-ReserverEspacePublicitaire\"]');\r\n        }\r\n        if (!$reserverStatique.length) {\r\n            \/\/ Fallback global : le formulaire peut \u00eatre en dehors du droppable\r\n            $reserverStatique = $('.elementor-field-group-ReserverEspacePublicitaire .elementor-field-option label');\r\n        }\r\n        \r\n        const hasFormat = this.hasSelectedFormat($droppable);\r\n        const hasFile = StateManager.get('FileReceived') === 'Yes';\r\n        const hasEnvoiDiffere = $droppable.find('input[name*=\"EnvoiUlterieur\"]:checked').length > 0;\r\n        \r\n        const canReserve = hasFormat && (hasFile || hasEnvoiDiffere);\r\n        \r\n        \/\/ \u2705 Si la checkbox R\u00e9server est coch\u00e9e \u2192 label vert \"Espace publicitaire r\u00e9serv\u00e9\"\r\n        const isChecked = $droppable.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked') ||\r\n                          ($container.length && $container.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked'));\r\n        \/\/ \u2705 v2.4.7 : Signal de restauration r\u00e9serv\u00e9e \u2014 checkbox pas encore coch\u00e9e (setTimeout 150ms)\r\n        \/\/             mais on sait d\u00e9j\u00e0 que l'espace est r\u00e9serv\u00e9 \u2192 traiter comme coch\u00e9\r\n        const _isReservedRestoration = sessionStorage.getItem('_isReservedRestoration') === 'Yes';\r\n        const isCheckedOrReservedRestore = isChecked || _isReservedRestoration;\r\n        \r\n        if ($label && $label.length) {\r\n            if (isCheckedOrReservedRestore) {\r\n                $label.text('Espace publicitaire r\u00e9serv\u00e9').css('color', 'rgb(62, 170, 19)');\r\n            } else {\r\n                $label.text('R\u00e9server cet espace publicitaire').css('color', canReserve ? '#FB5E2A' : '');\r\n            }\r\n        }\r\n        if ($reserverStatique.length) {\r\n            if (isCheckedOrReservedRestore) {\r\n                $reserverStatique.attr('style', 'color: rgb(62, 170, 19) !important;');\r\n            } else if (canReserve) {\r\n                $reserverStatique.attr('style', 'color: #FB5E2A !important;');\r\n            } else {\r\n                $reserverStatique.removeAttr('style');\r\n            }\r\n        }\r\n        \r\n        console.log('\ud83d\udd04 updateReserverCheckboxState:', { hasFormat, hasFile, hasEnvoiDiffere, canReserve, dynamicLabel: !!($label && $label.length), staticLabel: $reserverStatique.length });\r\n    },\r\n    \r\n    \/**\r\n     * Initialise les listeners pour le changement de format et la checkbox R\u00e9server\r\n     *\/\r\n    init() {\r\n        \/\/ \u2705 \u00c9couter les clics sur les conteneurs de format et leurs parents\r\n        jQuery(document).on('click', '.EspPubFormatContainer, .EspPubFormatListe, .EspPubFormatMainContainer', (e) => {\r\n            const $droppable = jQuery(e.target).closest('.droppable');\r\n            if (!$droppable.length) return;\r\n            \r\n            \/\/ Multiples d\u00e9lais pour couvrir les traitements asynchrones\r\n            [50, 200, 500].forEach(delay => {\r\n                setTimeout(() => {\r\n                    this.updateTitleColor($droppable);\r\n                    this.updateReserverCheckboxState($droppable);\r\n                }, delay);\r\n            });\r\n\r\n            \/\/ \u2705 v2.2.0 : Si un format (non Cr\u00e9ation) est cliqu\u00e9, notifier le parent pour mettre \u00e0 jour le Kit\r\n            const $btn = jQuery(e.target).closest('.EspPubFormatContainer');\r\n            if ($btn.length && !$btn.hasClass('FormatIdCreation') && !$btn.hasClass('FormatIdPopUp')) {\r\n                \/\/ \u2705 v2.3.4 : FormatIdPopUp g\u00e9r\u00e9 par clickFormatFromIframe (Entete.txt) \u2014 ne pas doubler\r\n                var classes = $btn.attr('class') || '';\r\n                var match = classes.match(\/FormatId(\\w+)\/);\r\n                if (match && match[1]) {\r\n                    var _rankEP = $droppable.attr('id') || '';\r\n                    setTimeout(function() {\r\n                        MessageManager.sendToParent('formatChangedInIframe', { formatSelect: match[1], rank: _rankEP });\r\n                        console.log('\ud83d\udd04 formatChangedInIframe envoy\u00e9:', match[1], '| rank:', _rankEP);\r\n                    }, 100);\r\n                }\r\n            }\r\n        });\r\n        \r\n        \/\/ \u2705 MutationObserver sur les conteneurs de format pour d\u00e9tecter les changements de style\r\n        setTimeout(() => {\r\n            this.observeFormatChanges();\r\n            \r\n            \/\/ Initialiser les couleurs des titres au chargement\r\n            jQuery('.droppable').each((i, el) => {\r\n                this.updateTitleColor(jQuery(el));\r\n            });\r\n            \r\n            \/\/ \u2705 v2.3.4 : Popup \u2192 restaurer FormatIdPopUp + format sous-jacent (sans \u00e9craser applyFormatState)\r\n            if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n                jQuery('.FormatIdPopUp').css({'background-color': '#ffffff'});\r\n                jQuery('.FormatIdPopUp').find('.EspPubFormat').css({'color': '#37D900'});\r\n                \/\/ Restaurer aussi le format sous-jacent dans Ele0A\r\n                var _fmtSS = sessionStorage.getItem('FormatSelect') || '';\r\n                if (_fmtSS) {\r\n                    var _fmtSSNorm = _fmtSS.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                    jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdCreation').each(function() {\r\n                        var _cls = this.className.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                        if (_cls.includes(_fmtSSNorm)) {\r\n                            jQuery(this).css({'background-color': '#ffffff'});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        }\r\n                    });\r\n                }\r\n                jQuery('.droppable').each((i, el) => {\r\n                    this.updateTitleColor(jQuery(el));\r\n                });\r\n            }\r\n        }, 500);\r\n        \r\n        \/\/ \u2705 v1.16.0 : Re-v\u00e9rifier apr\u00e8s un d\u00e9lai plus long (format venant de l'accord\u00e9on via postMessage)\r\n        [1500, 3000].forEach(delay => {\r\n            setTimeout(() => {\r\n                \/\/ \u2705 v2.3.4 : Popup \u2192 restaurer FormatIdPopUp + format sous-jacent\r\n                if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n                    jQuery('.FormatIdPopUp').css({'background-color': '#ffffff'});\r\n                    jQuery('.FormatIdPopUp').find('.EspPubFormat').css({'color': '#37D900'});\r\n                    var _fmtSSR = sessionStorage.getItem('FormatSelect') || '';\r\n                    if (_fmtSSR) {\r\n                        var _fmtSSRNorm = _fmtSSR.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                        jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdCreation').each(function() {\r\n                            var _cls = this.className.normalize('NFD').replace(\/[\u0300-\u036f]\/g, '').toLowerCase();\r\n                            if (_cls.includes(_fmtSSRNorm)) {\r\n                                jQuery(this).css({'background-color': '#ffffff'});\r\n                                jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                            }\r\n                        });\r\n                    }\r\n                    jQuery('.droppable').each((i, el) => {\r\n                        this.updateTitleColor(jQuery(el));\r\n                    });\r\n                    return;\r\n                }\r\n                if (sessionStorage.getItem('Formatchoisi') === 'Yes') {\r\n                    jQuery('.droppable').each((i, el) => {\r\n                        this.updateTitleColor(jQuery(el));\r\n                    });\r\n                }\r\n            }, delay);\r\n        });\r\n    },\r\n    \r\n    \/**\r\n     * Attache un MutationObserver sur chaque .EspPubFormatContainer\r\n     * pour d\u00e9tecter tout changement de style (background-color) \r\n     * quel que soit le script qui le d\u00e9clenche\r\n     *\/\r\n    observeFormatChanges() {\r\n        \/\/ \u2705 Guard global anti-boucle \u2014 un seul verrou pour tous les observers\r\n        window._formatObserverLocked = false;\r\n        \r\n        jQuery('.EspPubFormatContainer').each((i, el) => {\r\n            const observer = new MutationObserver(() => {\r\n                if (window._formatObserverLocked) return;\r\n                window._formatObserverLocked = true;\r\n                \/\/ \u2705 v2.4.12 : Debounce 150ms \u2014 applyFormatState manipule plusieurs containers\r\n                \/\/ en s\u00e9quence rapide, le MutationObserver peut firer sur un \u00e9tat interm\u00e9diaire\r\n                clearTimeout(window._formatObserverTimer);\r\n                window._formatObserverTimer = setTimeout(() => {\r\n                    const $droppable = jQuery(el).closest('.droppable');\r\n                    this.updateTitleColor($droppable);\r\n                    this.updateReserverCheckboxState($droppable);\r\n                    window._formatObserverLocked = false;\r\n                }, 150);\r\n            });\r\n            observer.observe(el, { \r\n                attributes: true, \r\n                attributeFilter: ['style', 'class'] \r\n            });\r\n        });\r\n        console.log('\u2705 MutationObserver attach\u00e9 aux conteneurs de format');\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de communication avec la page parente\r\n *\/\r\nconst MessageManager = {\r\n    sendToParent(type, data = {}) {\r\n        try {\r\n            window.parent.postMessage({\r\n                type: type,\r\n                iframeId: CONFIG.iframeId,\r\n                data: data\r\n            }, '*');\r\n        } catch (error) {\r\n            console.error('Error sending message to parent:', error);\r\n            window.parent.postMessage({\r\n                type: 'error',\r\n                error: error.message,\r\n                iframeId: CONFIG.iframeId\r\n            }, '*');\r\n        }\r\n    },\r\n    \r\n    sendDataToParent(data) {\r\n        this.sendToParent('dataFromIframeEspacePub', data);\r\n    },\r\n    \r\n    sendDelAdToParent(data) {\r\n        this.sendToParent('dataDelAd', data);\r\n    },\r\n    \r\n    prepareUploadData() {\r\n        const keys = [\r\n            'AddNewRefInVosCampagnes',\r\n            'FirstUploadFileorMoved',\r\n            'LoadedPageUrl',\r\n            'codePage',\r\n            'Rank_Emplacement_Page_Web',\r\n            'Commande_Emplacement_Page_Web',\r\n            'dragstart_Commande_Emplacement_Page_Web',\r\n            'dragstart_Rank_Emplacement_Page_Web',  \r\n            'FullPathAdFile',\r\n            'Upload_File_Name',\r\n            'FileReceived',\r\n            'PageWebDisplayed',\r\n            'Commande_Format_Transmis',\r\n            'EspPubLienAnnonce',\r\n            'EnvoiUlterieur',\r\n            'Formatchoisi'\r\n        ];\r\n        \r\n        const data = StateManager.getMultiple(keys);\r\n        \r\n        \/\/ \u2705 v2.3.4 : Popup (Ele0A) \u2014 lire le format sous-jacent depuis le DOM\r\n        \/\/ StateManager contient 'PopUp' (virtuel), mais le vrai format est visuellement s\u00e9lectionn\u00e9 dans #Ele0A\r\n        if (data.Rank_Emplacement_Page_Web === 'Ele0A' || sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            var _ele0AFormatDOM = '';\r\n            jQuery('#Ele0A').find('.EspPubFormatContainer').not('.FormatIdPopUp').each(function() {\r\n                if (jQuery(this).css('background-color') === 'rgb(255, 255, 255)') {\r\n                    var _cls = this.className || '';\r\n                    var _match = _cls.match(\/FormatId(\\S+)\/);\r\n                    if (_match) { _ele0AFormatDOM = _match[1]; return false; }\r\n                }\r\n            });\r\n            if (_ele0AFormatDOM) {\r\n                data.Commande_Format_Transmis = _ele0AFormatDOM;\r\n            }\r\n        }\r\n        \r\n        console.log('\ud83d\udce4 prepareUploadData:', {\r\n            FirstUploadFileorMoved: data.FirstUploadFileorMoved,\r\n            dragstart_Commande_Emplacement_Page_Web: data.dragstart_Commande_Emplacement_Page_Web,\r\n            Commande_Emplacement_Page_Web: data.Commande_Emplacement_Page_Web\r\n        });\r\n    \r\n        return data;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de rendu des aper\u00e7us de fichiers\r\n *\/\r\nconst PreviewRenderer = {\r\n    _getPositionLibelle(rankId) {\r\n        if (!rankId) return '';\r\n        var match = rankId.match(\/Ele(\\d+)[A-Z]\/);\r\n        if (!match) return '';\r\n        var rang = parseInt(match[1]);\r\n        if (rang === 0) return 'Pop-up';\r\n        if (rang === 1 || rang === 2) return 'Haut de page';\r\n        return 'Corps de page';\r\n    },\r\n    renderVideo(objectUrl, fileName, $dropZone) {\r\n        const videoElement = jQuery('<video controls autoplay muted>').attr({\r\n            'src': objectUrl,\r\n            'width': 'auto',\r\n            'height': 'auto',\r\n            'id': fileName\r\n        }).css({\r\n            'max-width': '100%',\r\n            'max-height': '100%'\r\n        });\r\n        \r\n        if (UIManager.isDesktop()) {\r\n            $dropZone.empty().append(videoElement.clone());\r\n            jQuery('#ApercuMobile').css({\r\n                'display': 'flex',\r\n                'justify-content': 'center',\r\n                'align-items': 'center'\r\n            }).append(videoElement);\r\n        } else {\r\n            const img = document.createElement('img');\r\n            img.src = objectUrl;\r\n            img.style.width = 'auto';\r\n            img.style.height = 'auto';\r\n            img.style.maxWidth = 'calc(100% - 4px)';  \/\/ \u2705 v2.4.5 : 2px retrait inset box-shadow\r\n            img.style.maxHeight = '115px';\r\n            \r\n            const container = $dropZone[0];\r\n            while (container.firstChild) {\r\n                container.removeChild(container.firstChild);\r\n            }\r\n            container.appendChild(img);\r\n        }\r\n        \r\n        StateManager.setMultiple({\r\n            'Commande_Format': 'Vid\u00e9o',\r\n            'Commande_Format_Transmis': 'Vid\u00e9o',\r\n            'videoSrc': objectUrl,\r\n            'FormatAnnonceSelection': 'Yes',\r\n            'PositionAnnonceSelection': 'Yes'\r\n        });\r\n        \r\n        jQuery('#FormatDataStep3').html('Vid\u00e9o').css({'color': '#56BE50'});\r\n        jQuery('#TarifDataStep3').css({'color': '#96894D'});\r\n    },\r\n    \r\n    renderImage(objectUrl, $dropZone) {\r\n        const maxHeight = UIManager.isMobile() ? 105 : $dropZone.closest('.HTMLUploadfileConteneur').height();\r\n    \r\n        $dropZone.css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center',\r\n            'width': '100%',\r\n            'height': maxHeight + 'px',\r\n            'overflow': 'hidden',\r\n            'position': UIManager.isMobile() ? 'relative' : '',\r\n            'top': UIManager.isMobile() ? '45px' : '',\r\n            'padding': UIManager.isMobile() ? '0 2px' : ''  \/\/ \u2705 v2.4.5 : 2px retrait inset box-shadow mobile\r\n        });\r\n    \r\n        \/\/ \u2705 v1.19.2 : Image charg\u00e9e en arri\u00e8re-plan, remplace le message d'attente au onload\r\n        \/\/ \u2705 v2.4.5 : max-width calc(100%-4px) sur mobile pour ne pas recouvrir le box-shadow inset 2px\r\n        var _mxw = UIManager.isMobile() ? 'calc(100% - 4px)' : '100%';\r\n        var img = new Image();\r\n        img.style.cssText = 'max-width:' + _mxw + '; max-height:' + maxHeight + 'px; width:auto; height:auto; object-fit:contain;';\r\n        img.onload = function() {\r\n            $dropZone.empty().append(img);\r\n        };\r\n        img.onerror = function() {\r\n            $dropZone.html('<img decoding=\"async\" src=\"' + objectUrl + '\" style=\"max-width:' + _mxw + '; max-height:' + maxHeight + 'px; width:auto; height:auto; object-fit:contain;\">');\r\n        };\r\n        img.src = objectUrl;\r\n    \r\n        StateManager.setMultiple({\r\n            'Commande_Format_Transmis': 'Image',\r\n            'FormatAnnonceSelection': 'Yes',\r\n            'PositionAnnonceSelection': 'Yes'\r\n        });\r\n    \r\n        console.log('Image ajout\u00e9e avec succ\u00e8s');\r\n    },\r\n    \r\n    async renderWord(fileObj, $dropZone) {\r\n        return new Promise((resolve, reject) => {\r\n            const reader = new FileReader();\r\n            \r\n            reader.onload = async (e) => {\r\n                try {\r\n                    const arrayBuffer = e.target.result;\r\n                    const result = await mammoth.convertToHtml({arrayBuffer: arrayBuffer});\r\n                    \r\n                    const htmlContent = result.value;\r\n                    const tempContainer = document.createElement('div');\r\n                    tempContainer.innerHTML = htmlContent;\r\n                    \r\n                    const textContent = tempContainer.textContent || \"\";\r\n                    const normalizedText = this.normalizeText(textContent);\r\n                    const firstImage = tempContainer.querySelector('img');\r\n                    \r\n                    const titleText = this.findDocumentTitle(normalizedText);\r\n                    \r\n                    if (firstImage) {\r\n                        this.renderDocumentPreview(\r\n                            $dropZone,\r\n                            firstImage.src,\r\n                            titleText,\r\n                            textContent,\r\n                            htmlContent\r\n                        );\r\n                    } else {\r\n                        \/\/ \u2705 v1.19.0 : Accepter les documents sans image\r\n                        this.renderDocumentPreview(\r\n                            $dropZone,\r\n                            null,\r\n                            titleText,\r\n                            textContent,\r\n                            htmlContent\r\n                        );\r\n                        console.log('\u2139\ufe0f Document Word sans image \u2014 aper\u00e7u texte seul');\r\n                    }\r\n                    resolve();\r\n                } catch (error) {\r\n                    $dropZone.html(`<p style=\"color: #FB5E2A; font-weight: 600; font-family: Roboto, Arial, sans-serif; font-size: 12px; text-align: center; padding: 15px;\">Erreur lors de la lecture du document<\/p>`);\r\n                    reject(error);\r\n                }\r\n            };\r\n            \r\n            reader.readAsArrayBuffer(fileObj);\r\n        });\r\n        \r\n        this.finalizeRedactionnelUpload();\r\n    },\r\n    \r\n    renderDocumentPreview($dropZone, imageSrc, title, text, htmlContent = null) {\r\n        \/\/ \u2705 v1.19.0 : Deux layouts \u2014 avec image ou texte seul\r\n        let previewHtml;\r\n\r\n        if (imageSrc) {\r\n            \/\/ Layout avec miniature image\r\n            previewHtml = `\r\n                <div class=\"doc-preview-container\">\r\n                    <div class=\"doc-preview-thumbnail\">\r\n                        <img decoding=\"async\" src=\"${imageSrc}\" alt=\"Document image\">\r\n                    <\/div>\r\n                    <div class=\"doc-preview-info\">\r\n                        <div class=\"doc-preview-title\" id=\"AdTitle\">${title}<\/div>\r\n                        <div class=\"doc-preview-description\" id=\"AdText\">${this.getTextPreview(text, 13)}<\/div>\r\n                        <div class=\"doc-preview-readmore\" id=\"AdLirelasuite\">Ouvrir et visualiser<\/div>\r\n                        <div class=\"doc-preview-FullPathAdFile\" id=\"AdFullPathAdFile\">${StateManager.get(\"FullPathAdFile\")}<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            `;\r\n        } else {\r\n            \/\/ Layout texte seul (sans image)\r\n            previewHtml = `\r\n                <div class=\"doc-preview-container doc-preview-noimage\">\r\n                    <div class=\"doc-preview-icon\">\r\n                        <svg width=\"36\" height=\"36\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#213864\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n                            <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\/><polyline points=\"14 2 14 8 20 8\"\/><line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"\/><line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"\/><polyline points=\"10 9 9 9 8 9\"\/>\r\n                        <\/svg>\r\n                    <\/div>\r\n                    <div class=\"doc-preview-info doc-preview-info-full\">\r\n                        <div class=\"doc-preview-title\" id=\"AdTitle\">${title}<\/div>\r\n                        <div class=\"doc-preview-description\" id=\"AdText\">${this.getTextPreview(text, 25)}<\/div>\r\n                        <div class=\"doc-preview-readmore\" id=\"AdLirelasuite\">Ouvrir et visualiser<\/div>\r\n                        <div class=\"doc-preview-FullPathAdFile\" id=\"AdFullPathAdFile\">${StateManager.get(\"FullPathAdFile\")}<\/div>\r\n                    <\/div>\r\n                <\/div>\r\n            `;\r\n        }\r\n        \r\n        $dropZone.html(previewHtml + this.getPreviewStyles());\r\n        \r\n        if (htmlContent) {\r\n            this.attachWordPreviewHandler($dropZone, title, htmlContent);\r\n        }\r\n    },\r\n    \r\n    attachWordPreviewHandler($dropZone, titleText, htmlContent) {\r\n        var $droppable = $dropZone.closest('.droppable');\r\n\r\n        \/\/ \u2705 Adapter le libell\u00e9 selon le type de document\r\n        var isInterview = (titleText || '').toLowerCase().indexOf('interview') !== -1;\r\n        var formatLabel = isInterview ? 'l\\'interview' : 'le communiqu\u00e9';\r\n        $droppable.find('.doc-preview-readmore').text('Ouvrir et visualiser ' + formatLabel);\r\n\r\n        \/\/ \u2705 v2.0.11 : D\u00e9l\u00e9gation d'\u00e9v\u00e9nement \u2014 plus robuste sur mobile (survit aux manipulations DOM)\r\n        $droppable.off('click.docpreview').on('click.docpreview', '.doc-preview-readmore', (event) => {\r\n            event.preventDefault();\r\n            event.stopPropagation();\r\n            \r\n            if (htmlContent) {\r\n                var popupTitle = isInterview ? 'Interview' : 'Communiqu\u00e9';\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    htmlContent: htmlContent\r\n                });\r\n            } else {\r\n                console.warn('Le document est encore en cours de traitement.');\r\n            }\r\n        });\r\n    },\r\n    \r\n    normalizeText(text) {\r\n        return text\r\n            .toLowerCase()\r\n            .normalize(\"NFD\")\r\n            .replace(\/[\\u0300-\\u036f]\/g, \"\");\r\n    },\r\n    \r\n    findDocumentTitle(normalizedText) {\r\n        const foundKeyword = CONFIG.keywords.find(keyword => \r\n            normalizedText.includes(keyword.normal)\r\n        );\r\n        if (foundKeyword) return foundKeyword.display;\r\n        \r\n        \/\/ \u2705 v1.19.1 : Fallback \u2014 utiliser le format s\u00e9lectionn\u00e9 (FormatSelect)\r\n        var formatSelect = (sessionStorage.getItem('FormatSelect') || '').toLowerCase();\r\n        if (formatSelect.indexOf('interview') !== -1) return 'Interview';\r\n        if (formatSelect.indexOf('communiq') !== -1) return 'Communiqu\u00e9';\r\n        \r\n        return \"Document\";\r\n    },\r\n    \r\n    getTextPreview(text, maxWords) {\r\n        const words = text.split(' ');\r\n        if (words.length > maxWords) {\r\n            return words.slice(0, maxWords).join(' ') + ' ...';\r\n        }\r\n        return text;\r\n    },\r\n    \r\n    getPreviewStyles() {\r\n        return `\r\n            <style>\r\n                @import url('https:\/\/fonts.googleapis.com\/css2?family=Roboto:wght@400;600&display=swap');\r\n                \r\n                .doc-preview-container {\r\n                    margin: 0px 0;\r\n                    display: flex;\r\n                    width: 100%;\r\n                    max-height: 140px;\r\n                    overflow: hidden;\r\n                    box-sizing: border-box;  \/* \u2705 v2.4.5 *\/\r\n                    background: white;\r\n                    background-color: #f8f8f8;\r\n                }\r\n                .doc-preview-thumbnail {\r\n                    width: 50%; \r\n                    height: 130px;\r\n                    overflow: hidden;\r\n                    display: flex;\r\n                    align-items: center;\r\n                    justify-content: center;\r\n                    margin-top: 0px;\r\n                }\r\n                .doc-preview-thumbnail img {\r\n                    max-width: 75%;\r\n                    max-height: 75%;\r\n                    object-position: center;\r\n                    object-fit: fill;\r\n                }\r\n                .doc-preview-info {\r\n                    width: 50%;\r\n                    height: 130px; \r\n                    flex: 1;\r\n                    padding: 10px;\r\n                    display: flex;\r\n                    flex-direction: column; \r\n                }\r\n                .doc-preview-title {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #213864;\r\n                    font-size: 14px;\r\n                    font-weight: 600;\r\n                    text-align: left;\r\n                    margin-bottom: 5px;\r\n                }\r\n                .doc-preview-description {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #213864;\r\n                    font-size: 11px;\r\n                    font-weight: 400;\r\n                    text-align: left;\r\n                    overflow: hidden;\r\n                    margin-bottom: 5px;\r\n                    flex: 1;\r\n                }\r\n                .doc-preview-readmore {\r\n                    font-family: 'Roboto', sans-serif;\r\n                    color: #958848;\r\n                    font-size: 13px;\r\n                    font-weight: 600;\r\n                    text-align: left;\r\n                    cursor: pointer;\r\n                    padding: 4px 0;\r\n                    -webkit-tap-highlight-color: rgba(149,136,72,0.2);\r\n                }\r\n                @media (max-width: 999px) {\r\n                    .doc-preview-readmore { font-size: 12px; }\r\n                    \/* \u2705 Laisser 3px tout autour pour que le liser\u00e9 vert (box-shadow\/outline sur parent) soit visible *\/\r\n                    .doc-preview-container {\r\n                        width: calc(100% - 16px) !important;\r\n                        max-height: 109px !important;\r\n                        margin: 3px !important;\r\n                        margin-top: 23px !important;\r\n                        box-sizing: border-box !important;\r\n                    }\r\n                }\r\n                .doc-preview-FullPathAdFile {\r\n                    display: none;\r\n                }\r\n                \/* \u2705 v1.19.0 : Layout sans image *\/\r\n                .doc-preview-noimage {\r\n                    flex-direction: row;\r\n                    align-items: flex-start;\r\n                    gap: 10px;\r\n                    padding: 8px 10px;\r\n                }\r\n                .doc-preview-icon {\r\n                    flex-shrink: 0;\r\n                    display: flex;\r\n                    align-items: center;\r\n                    justify-content: center;\r\n                    width: 44px;\r\n                    height: 44px;\r\n                    background: #eef2f7;\r\n                    border-radius: 6px;\r\n                    margin-top: 4px;\r\n                }\r\n                .doc-preview-info-full {\r\n                    width: 100%;\r\n                    height: auto;\r\n                    max-height: 130px;\r\n                }\r\n                .doc-preview-noimage .doc-preview-description {\r\n                    font-size: 11px;\r\n                    line-height: 1.35;\r\n                    max-height: 60px;\r\n                    overflow: hidden;\r\n                }\r\n            <\/style>\r\n        `;\r\n    },\r\n    \r\n    finalizeRedactionnelUpload() {\r\n        \/\/ \u2705 v1.19.5 : D\u00e9terminer le format r\u00e9dactionnel correct\r\n        \/\/ Si le format s\u00e9lectionn\u00e9 est \"Interview\", on garde \"Interview\"\r\n        \/\/ Sinon on met \"Communiqu\u00e9\" par d\u00e9faut (au lieu de \"R\u00e9dactionnel\" qui n'est pas un format tarifaire valide)\r\n        var formatSelect = sessionStorage.getItem('FormatSelect') || '';\r\n        var formatTransmis = 'Communiqu\u00e9'; \/\/ Par d\u00e9faut\r\n        \r\n        if (formatSelect.toLowerCase().indexOf('interview') !== -1) {\r\n            formatTransmis = 'Interview';\r\n        } else if (formatSelect.toLowerCase().indexOf('communiq') !== -1) {\r\n            formatTransmis = 'Communiqu\u00e9';\r\n        }\r\n        \r\n        StateManager.set('Commande_Format_Transmis', formatTransmis);\r\n        console.log('\u2705 Format r\u00e9dactionnel d\u00e9termin\u00e9:', formatTransmis, '(FormatSelect:', formatSelect, ')');\r\n        \r\n        if (StateManager.get(\"TarifDirectSelectionne\") === 'Yes') {\r\n            const formatText = jQuery('#FormatDataStep3').text();\r\n            if (formatText !== 'Vid\u00e9o' && formatText !== 'Banni\u00e8re') {\r\n                jQuery('#form-field-RedactionnelSelection')\r\n                    .val(formatText)\r\n                    .css({'color': '#56BE50'});\r\n            }\r\n        }\r\n        \r\n        RedactionnelDepose();\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'upload\r\n *\/\r\nconst UploadManager = {\r\n    isRunning: false,\r\n    \r\n    \/\/ \u2705 Reset manuel espace publicitaire\r\n    resetEspaceManuel: function($droppable) {\r\n        console.log('\ud83d\udd27 Reset manuel espace publicitaire');\r\n        \r\n        var $dropZone = $droppable.find('#drop_file_zone_achat');\r\n        var $uploadContainer = $droppable.find('.HTMLUploadfileConteneur');\r\n        var $container = $droppable.find('.OrdiMobileConteneurClass');\r\n        \r\n        \/\/ 1. Vider la zone de drop et restaurer le HTML par d\u00e9faut\r\n        $dropZone.empty().html(\r\n            '<div id=\"drag_upload_file_achat\">' +\r\n                '<p class=\"UploadIci\" style=\"color: #FB5E2A; font-weight: 600;\">Ici glisser \u2013 d\u00e9poser ou<br>t\u00e9l\u00e9charger une annonce<\/p>' +\r\n            '<\/div>'\r\n        );\r\n        \r\n        \/\/ 2. Afficher les \u00e9l\u00e9ments cach\u00e9s lors de l'upload\r\n        $droppable.find('.UploadIci').show();\r\n        $droppable.find('.EnvoiUlterieurTexte').show();\r\n        $droppable.find('.EnvoiUlterieurContainer').show();\r\n        $droppable.find('.EspPubFormatMainContainer').show();\r\n        $droppable.find('.EspPubFormatListe').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireClass').show();\r\n        $droppable.find('.GlisserDeposerConteneur').show();\r\n        $droppable.find('.OUClass').show();\r\n        $droppable.find('.TexteMobileAnnonce').show();\r\n        $droppable.find('.PositionReference').show();\r\n        $droppable.find('.ClassHdpCdp').show();\r\n        $droppable.find('.ClassRefEsp').show();\r\n        \r\n        \/\/ 3. Cacher les \u00e9l\u00e9ments d'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle').hide();\r\n        $droppable.find('#CroixResetAnnonce').hide();\r\n        $droppable.find('.CroixResetAnnonceContainer').hide();\r\n        $droppable.find('.DeplaceAnnonce').hide();\r\n        $droppable.find('.RefEspacePublicitaire').hide();\r\n        $droppable.find('.AdDroppedTextNotDisplayed').hide();\r\n        \r\n        \/\/ 4. Reset des styles\r\n        $uploadContainer.css({\r\n            'border': 'none',\r\n            'background-color': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': ''\r\n        });\r\n        \r\n        $container.css({\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'top': '',\r\n            'height': ''\r\n        });\r\n        \r\n        \/\/ \u2705 Reset des positionnements desktop appliqu\u00e9s par adjustDesktopLayout\r\n        $droppable.closest('.ToBeHidden').css({'top': '', 'min-height': ''});\r\n        $droppable.parent().css('overflow', '');\r\n        \/\/ \u2705 v2.0.11 : Cleanup event namespace docpreview\r\n        $droppable.off('click.docpreview');\r\n        \r\n        \/\/ 5. Reset des formats s\u00e9lectionn\u00e9s\r\n        $droppable.find('.EspPubFormatContainer').css({\r\n            'background-color': '',\r\n            'border': ''\r\n        });\r\n        \r\n        \/\/ 6. Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ 7. Restaurer .PositionEspacePublicitaireContainer et .ReserverContainer\r\n        $droppable.find('.PositionEspacePublicitaireContainer').show();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        console.log('\u2705 Reset manuel termin\u00e9');\r\n    },\r\n    \r\n    async handleFileUpload(fileObj, $dropZone) {\r\n        console.log('fileObj:', fileObj);\r\n        \r\n        \/\/ \u2705 v2.4.6 : Contr\u00f4les d'extension EN PREMIER \u2014 avant tout affichage\r\n        const extension = FileManager.getExtension(fileObj.name);\r\n        StateManager.set('FileExtension', extension);\r\n        console.log('FileExtension:', extension);\r\n        \r\n        \/\/ \u2705 v2.6 : jpg\/jpeg accept\u00e9s sur desktop et mobile\r\n        \r\n        if (!FileManager.isAllowedExtension(extension)) {\r\n            UIManager.showFormatError($dropZone);\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.5 : Afficher le message d'attente seulement si le format est valide\r\n        var _waitMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.html('<div class=\"ad-loading-msg\" style=\"color:#00ff19; background:white; padding:12px 20px; border-radius:6px; font-weight:700; text-align:center; font-size:18px; line-height:1.4;\">' + _waitMsg + '<\/div>');\r\n        \r\n        this.prepareUIForUpload($dropZone);\r\n        \r\n        const formData = new FormData();\r\n        formData.append('file', fileObj);\r\n        formData.append('action', 'upload_annonce_file_v3');\r\n        \r\n        UIManager.showUploadProgress($dropZone);\r\n        \r\n        try {\r\n            const response = await this.sendUploadRequest(formData);\r\n            await this.handleUploadResponse(response, fileObj, $dropZone, extension);\r\n        } catch (error) {\r\n            console.error('Upload error:', error);\r\n        }\r\n    },\r\n    \r\n    prepareUIForUpload($dropZone) {\r\n        if (!UIManager.isMobile()) {\r\n            jQuery('.ChoisirEspacePublicitaireClass').show();\r\n            jQuery('.ChoisirEspacePublicitaire2ndLigne').show();\r\n            jQuery('.GlisserDeposerConteneur').show();\r\n            jQuery('.OUClass').show();\r\n            \/\/ \u2705 Cibler uniquement le droppable courant \u2014 ne pas r\u00e9afficher sur les espaces d\u00e9j\u00e0 upload\u00e9s\r\n            $dropZone.closest('.droppable').find('.UploadIci').show();\r\n        }\r\n        \r\n        if (StateManager.get(\"PopUpChoice\") === 'Yes') {\r\n            \/\/ \u2705 Ne masquer DeplaceAnnonce QUE sur Ele0A \u2014 pas sur Ele1A qui a deja une annonce chargee\r\n            $dropZone.closest('.OrdiMobileConteneurClass').find('.DeplaceAnnonce').each(function() {\r\n                var _d = jQuery(this).closest('.droppable')[0];\r\n                if (_d && _d.getAttribute('data-via-ad-loaded') === 'true') { return; }\r\n                jQuery(this).hide();\r\n            });\r\n            $('.AnnonceDragIcone').show().find('img').attr('alt', '');\r\n        } else {\r\n            $('.AnnonceDragIcone').hide();\r\n        }\r\n        \r\n        if (StateManager.get(\"Commande_Page\") === 'Home Page') {\r\n            jQuery('#HPTarifConteneur').css({'background-color': '#B5FFB1'});\r\n        }\r\n        \r\n        jQuery('.ChoisirEspacePublicitaireClass').css({'color': '#ffffff'});\r\n        jQuery('.InterfaceTitreDore').not('#PageWebTitreDore')\r\n            .html(\"Merci de choisir les \u00e9l\u00e9ments de votre campagne publicitaire\");\r\n        jQuery('#ProcessCommande').show();\r\n    },\r\n    \r\n    sendUploadRequest(formData) {\r\n        \/\/ \u2705 v2.6 : dataType 'text' pour eviter parsererror si texte parasite apres le JSON\r\n        return jQuery.ajax({\r\n            url: CONFIG.ajaxUrl,\r\n            type: 'POST',\r\n            data: formData,\r\n            cache: false,\r\n            contentType: false,\r\n            processData: false,\r\n            dataType: 'text'\r\n        }).then(function(text) {\r\n            \/\/ Extraire le JSON meme si du texte parasite suit\r\n            var _json = null;\r\n            try {\r\n                var _match = text.match(\/(\\{[\\s\\S]*?\\})(?:[^{]|$)\/);\r\n                _json = JSON.parse(_match ? _match[1] : text);\r\n            } catch(_e) {\r\n                return jQuery.Deferred().reject({ responseText: text }).promise();\r\n            }\r\n            \/\/ Normaliser le format vers {success, data} attendu par handleUploadResponse\r\n            if (_json.status === 'success') {\r\n                var _fp = _json.file_path || '';\r\n                var _baseUrl = CONFIG.ajaxUrl.replace('\/wp-admin\/admin-ajax.php', '\/wp-content\/');\r\n                return {\r\n                    success: true,\r\n                    data: {\r\n                        file_url:  _baseUrl + _fp,\r\n                        file_name: _fp.replace(\/^.*\\\/\/, ''),\r\n                        file_path: _fp\r\n                    }\r\n                };\r\n            }\r\n            \/\/ Format WordPress standard {success, data} - retourner tel quel\r\n            return _json;\r\n        });\r\n    },\r\n    \r\n    async handleUploadResponse(response, fileObj, $dropZone, extension) {\r\n        console.log('\u2705 R\u00e9ponse re\u00e7ue');\r\n        \r\n        if (response.responseJSON) {\r\n            response = response.responseJSON;\r\n        }\r\n        \r\n        console.log('\u2705 Response pars\u00e9e:', response);\r\n        \r\n        if (!response.success || !response.data) {\r\n            \/\/ \u2705 v2.1.2 : Si c'est une restauration (_isAdRestoration = 'Yes'),\r\n            \/\/ le fichier existe d\u00e9j\u00e0 sur le serveur \u2192 afficher l'image depuis le fileObj local\r\n            if (StateManager.get('_isAdRestoration') === 'Yes' && fileObj) {\r\n                console.log('\ud83d\udd04 Restauration: upload \u00e9chou\u00e9 (fichier existant) \u2192 rendu local');\r\n                \r\n                FileManager.createObjectUrl(fileObj);\r\n                StateManager.set('FileReceived', 'Yes');\r\n                \r\n                \/\/ \u2705 v2.1.2 : Restaurer l'\u00e9tat EnvoiUlterieur depuis le sessionStorage parent\r\n                var _restoredEnvoi = sessionStorage.getItem('_restoredEnvoiUlterieur');\r\n                if (_restoredEnvoi === 'true') {\r\n                    StateManager.set('EnvoiUlterieur', 'true');\r\n                    StateManager.set('FileReceived', 'No');\r\n                    StateManager.set('FullPathAdFile', '');\r\n                    console.log('\ud83d\udce4 Restauration EnvoiUlterieur = true');\r\n                }\r\n                \r\n                var _objUrl = StateManager.get('objectUrl');\r\n                var _fileType = FileManager.getFileType(extension);\r\n                \r\n                StateManager.set('FormatReconnu', 'No');\r\n                \r\n                switch (_fileType) {\r\n                    case 'video':\r\n                        PreviewRenderer.renderVideo(_objUrl, fileObj.name, $dropZone);\r\n                        StateManager.set('FormatReconnu', 'Yes');\r\n                        break;\r\n                    case 'image':\r\n                        PreviewRenderer.renderImage(_objUrl, $dropZone);\r\n                        StateManager.set('FormatReconnu', 'Yes');\r\n                        break;\r\n                    case 'document':\r\n                        \/\/ \u2705 v2.1.2 : Documents Word\/PDF aussi en restauration\r\n                        await this.handleDocumentUpload(extension, fileObj, $dropZone);\r\n                        break;\r\n                }\r\n                \r\n                UIManager.updateAfterSuccessfulUpload($dropZone);\r\n                \r\n                if (StateManager.get('FormatReconnu') === 'Yes') {\r\n                    this.finalizeUpload($dropZone);\r\n                    $('#MsgSelectEspace').hide();\r\n                }\r\n                \r\n                FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n                console.log('\u2705 Restauration visuelle termin\u00e9e (upload bypass)');\r\n                StateManager.set('_isAdRestoration', 'No');\r\n            }\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 SAUVEGARDER les infos de d\u00e9placement AVANT updateStateAfterUpload\r\n        const isMoved = StateManager.get('FirstUploadFileorMoved') === 'Moved';\r\n        const dragstartRankId = StateManager.get('dragstart_Rank_Emplacement_Page_Web');\r\n        const currentRankId = StateManager.get('Rank_Emplacement_Page_Web');\r\n        const shouldResetOldSpace = isMoved && dragstartRankId && dragstartRankId !== currentRankId;\r\n        \r\n        console.log('\ud83d\udd0d D\u00e9placement?', { isMoved, dragstartRankId, currentRankId, shouldResetOldSpace });\r\n        \r\n        this.updateStateAfterUploadWithoutReset(response, fileObj);\r\n        \r\n        const fileType = FileManager.getFileType(extension);\r\n        \r\n        StateManager.set('FormatReconnu', 'No');\r\n        \r\n        \/\/ \u2705 v1.19.2 : Message d'attente IMM\u00c9DIAT avant le rendu de l'annonce\r\n        var _waitMsg = 'Loading in progress <span class=\"dot-container\"><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><span class=\"dot\">.<\/span><\/span>';\r\n        $dropZone.html('<div class=\"ad-loading-msg\" style=\"color:#00ff19; background:white; padding:12px 20px; border-radius:6px; font-weight:700; text-align:center; font-size:18px; line-height:1.4;\">' + _waitMsg + '<\/div>');\r\n        \r\n        switch (fileType) {\r\n            case 'video':\r\n                PreviewRenderer.renderVideo(StateManager.get('objectUrl'), fileObj.name, $dropZone);\r\n                StateManager.set('FormatReconnu', 'Yes');\r\n                break;\r\n                \r\n            case 'image':\r\n                PreviewRenderer.renderImage(StateManager.get('objectUrl'), $dropZone);\r\n                StateManager.set('FormatReconnu', 'Yes');\r\n                break;\r\n                \r\n            case 'document':\r\n                await this.handleDocumentUpload(extension, fileObj, $dropZone);\r\n                break;\r\n        }\r\n        \r\n        UIManager.updateAfterSuccessfulUpload($dropZone);\r\n        \r\n        if (StateManager.get('FormatReconnu') === 'Yes') {\r\n            this.finalizeUpload($dropZone);\r\n            $('#MsgSelectEspace').hide();\r\n        }\r\n        \r\n        \/\/ \u2705 RESET L'ANCIEN ESPACE ICI - APR\u00c8S avoir affich\u00e9 la nouvelle image\r\n        \/\/ \u2705 v2.4.5 : Toujours initialiser \u00e0 false avant le bloc (\u00e9vite la valeur r\u00e9siduelle)\r\n        var _sourceWasReserved = false;\r\n        StateManager.set('_sourceWasReserved', 'No');\r\n        \r\n        if (shouldResetOldSpace) {\r\n            console.log('\ud83d\udd04 Reset ancien espace:', dragstartRankId);\r\n            \r\n            var $oldDroppable = $('#' + dragstartRankId);\r\n            \r\n            if ($oldDroppable.length) {\r\n                var $container = $oldDroppable.find('.OrdiMobileConteneurClass').first();\r\n                \r\n                \/\/ \u2705 v2.4.5 : Utiliser l'\u00e9tat captur\u00e9 au dragstart (fiable vs re-check async)\r\n                if ($container.length) {\r\n                    _sourceWasReserved = StateManager.get('dragstart_ReserverChecked') === 'Yes';\r\n                    console.log('[d\u00e9placement] ReserverChecked au dragstart:', _sourceWasReserved, '| rank:', dragstartRankId);\r\n                    StateManager.set('_sourceWasReserved', _sourceWasReserved ? 'Yes' : 'No');\r\n                    RestoreadSpaceTemplateLocal($container[0]);\r\n                }\r\n            }\r\n        }\r\n        StateManager.set(\"EnvoiUlterieur\", 'false');\r\n        \r\n        \/\/ \u2705 v1.19.1 : Positionner l'espace \u00e0 10px du haut du viewport apr\u00e8s upload\r\n        setTimeout(function() {\r\n            var el = $dropZone.closest('.droppable').find('.HTMLUploadfileConteneur')[0]\r\n                     || $dropZone.closest('.droppable')[0];\r\n            if (el) {\r\n                ScrollHelper.scrollElementTo(el, 10);\r\n            }\r\n        }, 400);\r\n        \r\n        \/\/ \u2705 NE PLUS envoyer automatiquement - c'est la checkbox \"R\u00e9server\" qui d\u00e9clenche\r\n        \/\/ On met \u00e0 jour l'\u00e9tat de la checkbox pour qu'elle devienne activable\r\n        FormatUIManager.updateReserverCheckboxState($dropZone.closest('.droppable'));\r\n        \r\n        \/\/ \u2705 v2.4.5 : Si l'espace source \u00e9tait r\u00e9serv\u00e9, cocher la checkbox de l'espace cible\r\n        if (StateManager.get('_sourceWasReserved') === 'Yes') {\r\n            var $targetCb = $dropZone.closest('.droppable').find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n            if ($targetCb.length && !$targetCb.prop('checked')) {\r\n                $targetCb.prop('checked', true).trigger('change');\r\n                console.log('\u2705 [d\u00e9placement] Checkbox R\u00e9server coch\u00e9e sur espace cible');\r\n            }\r\n            StateManager.set('_sourceWasReserved', 'No');\r\n        }\r\n        \r\n        console.log('\ud83d\udccb Upload termin\u00e9 - en attente de validation via checkbox \"R\u00e9server\"');\r\n    },\r\n    \r\n    updateStateAfterUploadWithoutReset(response, fileObj) {\r\n        StateManager.setMultiple({\r\n            \"PageWhithADType\": StateManager.get('SelectedPageType'),\r\n            \"PageWhithADSecteur\": StateManager.get('SelectedPageSecteur')\r\n        });\r\n        \r\n        $('#BackPageWebWithADCroix').hide();\r\n        jQuery('#ApercuMobile').empty().css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center'\r\n        });\r\n        \r\n        const firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n        \r\n        if (firstUploadOrMoved === 'FirstUpload') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": response.data.file_url,\r\n                \"fileObj\": fileObj,\r\n                \"Upload_File_Name\": fileObj.name\r\n            });\r\n            \r\n            FileManager.createObjectUrl(fileObj);\r\n            \r\n            console.log('\ud83d\udcc1 Fichier upload\u00e9:', {\r\n                fullUrl: response.data.file_url,\r\n                fileName: response.data.file_name,\r\n                filePath: response.data.file_path\r\n            });\r\n        }\r\n    },\r\n    \r\n    updateStateAfterUpload(response, fileObj) {\r\n        StateManager.setMultiple({\r\n            \"PageWhithADType\": StateManager.get('SelectedPageType'),\r\n            \"PageWhithADSecteur\": StateManager.get('SelectedPageSecteur')\r\n        });\r\n        \r\n        $('#BackPageWebWithADCroix').hide();\r\n        jQuery('#ApercuMobile').empty().css({\r\n            'display': 'flex',\r\n            'justify-content': 'center',\r\n            'align-items': 'center'\r\n        });\r\n        \r\n        const firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n        console.log('\ud83d\udd0d FirstUploadFileorMoved:', firstUploadOrMoved);\r\n        \r\n        if (firstUploadOrMoved === 'FirstUpload') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": response.data.file_url,\r\n                \"fileObj\": fileObj,\r\n                \"Upload_File_Name\": fileObj.name\r\n            });\r\n            \r\n            FileManager.createObjectUrl(fileObj);\r\n            \r\n            console.log('\ud83d\udcc1 Fichier upload\u00e9:', {\r\n                fullUrl: response.data.file_url,\r\n                fileName: response.data.file_name,\r\n                filePath: response.data.file_path\r\n            });\r\n        } else if (firstUploadOrMoved === 'Moved') {\r\n            const dragstartRankId = StateManager.get('dragstart_Rank_Emplacement_Page_Web');\r\n            const currentRankId = StateManager.get('Rank_Emplacement_Page_Web');\r\n            \r\n            console.log('\ud83d\udd04 D\u00c9PLACEMENT D\u00c9TECT\u00c9');\r\n            console.log('   Ancien espace (dragstart):', dragstartRankId);\r\n            console.log('   Nouvel espace (current):', currentRankId);\r\n            \r\n            if (dragstartRankId && dragstartRankId !== currentRankId) {\r\n                const $oldDroppable = $('#' + dragstartRankId);\r\n                \r\n                console.log('   $oldDroppable trouv\u00e9:', $oldDroppable.length > 0);\r\n                \r\n                if ($oldDroppable.length) {\r\n                    const $container = $oldDroppable.find('.OrdiMobileConteneurClass');\r\n                    \r\n                    console.log('   $container trouv\u00e9:', $container.length > 0);\r\n                    \r\n                    if ($container.length) {\r\n                        console.log('\ud83d\udd27 Appel RestoreadSpaceTemplate sur:', $container[0]);\r\n                        \r\n                        if (typeof window.RestoreadSpaceTemplate === 'function') {\r\n                            window.RestoreadSpaceTemplate($container[0]);\r\n                            console.log('\u2705 RestoreadSpaceTemplate ex\u00e9cut\u00e9');\r\n                        }\r\n                    } else {\r\n                        console.warn('\u26a0\ufe0f .OrdiMobileConteneurClass non trouv\u00e9 dans', dragstartRankId);\r\n                    }\r\n                }\r\n            } else {\r\n                console.log('\u23ed\ufe0f M\u00eame espace ou dragstartRankId invalide, pas de reset');\r\n            }\r\n        }\r\n    },\r\n        \r\n    async handleDocumentUpload(extension, fileObj, $dropZone) {\r\n        StateManager.set('FormatReconnu', 'Yes');\r\n        \r\n        \/\/ \u2705 Cacher le File r\u00e9dactionnel pour r\u00e9utilisation lors des d\u00e9placements (\u00e9vite CORS)\r\n        window._lastRedactionnelFile = fileObj;\r\n        \r\n        if (extension === 'doc' || extension === 'docx') {\r\n            await new Promise(resolve => window.VIALibraries.loadMammoth(resolve));\r\n            await PreviewRenderer.renderWord(fileObj, $dropZone);\r\n        } else if (extension === 'ppt' || extension === 'pptx') {\r\n            this.renderPowerPoint($dropZone);\r\n            PreviewRenderer.finalizeRedactionnelUpload();\r\n        } else if (extension === 'pdf') {\r\n            await new Promise(resolve => window.VIALibraries.loadPdfJs(resolve));\r\n            await PDFHandler.renderPDF(fileObj, $dropZone);\r\n            PreviewRenderer.finalizeRedactionnelUpload();\r\n        }\r\n    },\r\n    \r\n    renderPowerPoint($dropZone) {\r\n        const img = jQuery('<img \/>', {\r\n            src: '\/wp-content\/uploads\/2024\/06\/microsoft-powerpoint.png',\r\n            css: {\r\n                'width': 'auto',\r\n                'height': 'auto',\r\n                'margin-bottom': '20px',\r\n                'max-width': '150px',\r\n                'max-height': '160px'\r\n            }\r\n        });\r\n        $dropZone.empty().append(img.clone());\r\n        jQuery('#ApercuMobile').append(img);\r\n    },\r\n    \r\n    finalizeUpload($dropZone) {\r\n        \/\/ \u2705 Reset sendDataToParentFlag : nouvel upload = pas encore r\u00e9serv\u00e9\r\n        StateManager.set('sendDataToParentFlag', 'No');\r\n        \r\n        StateManager.setMultiple({\r\n            \"PageAnnonceSelection\": 'Yes',\r\n            \"FormatReconnu\": 'Yes'\r\n        });\r\n        \r\n        jQuery('#MsgChoixPageWeb, #MsgInsererAnnonceConteneur').hide();\r\n        \r\n        if (StateManager.get(\"Commande_Format\") === 'R\u00e9dactionnel') {\r\n            StateManager.set('Commande_Format', '\u00e0 choisir');\r\n            RedactionnelDepose();\r\n        }\r\n        \r\n        if (StateManager.get(\"Commande_Page\") === ' ') {\r\n            jQuery('#HPTarifConteneur').css({'background-color': '#BCFFAD'});\r\n            jQuery('#EmplacementDataStep3').html(\"Home Page\");\r\n            StateManager.setMultiple({\r\n                \"Commande_Page\": 'Home Page',\r\n                \"PageAnnonceSelection\": 'Yes'\r\n            });\r\n        }\r\n        \r\n        $('#PageWeb').css('zoom', '70%');\r\n        $('#PageWebTitreDore').css({'font-size': '14px'});\r\n        \r\n        if (!UIManager.isMobile()) {\r\n            $('#PageWebTitreDore').css({'color': '#213864'});\r\n        }\r\n        \r\n        StateManager.set(\"Page_Web_with_AD_URL\", StateManager.get(\"Page_Web_URL\"));\r\n        \r\n        UIManager.finalizeAdDisplay($dropZone);\r\n        \r\n        \/\/ \u2705 Notifier le parent de l'annonce d\u00e9pos\u00e9e non r\u00e9serv\u00e9e \u2014 pour restauration au retour sur la page\r\n        var _fileRcv = StateManager.get('FileReceived');\r\n        var _isRestoring = StateManager.get('_isAdRestoration') === 'Yes';\r\n        console.log('\ud83d\udfe1 [finalizeUpload] FileReceived:', _fileRcv, '| _isAdRestoration:', _isRestoring);\r\n        if (_fileRcv === 'Yes' && !_isRestoring) {\r\n            var _pendingRank = StateManager.get('Rank_Emplacement_Page_Web') || $dropZone.closest('.droppable').attr('id') || '';\r\n            console.log('\ud83d\udfe1 [finalizeUpload] pendingRank:', _pendingRank, '| FullPathAdFile:', StateManager.get('FullPathAdFile'));\r\n            if (_pendingRank) {\r\n                console.log('\ud83d\udce4 [finalizeUpload] annonceDeposeeSansReservation \u2192 parent rank:', _pendingRank);\r\n                \/\/ \u2705 D\u00e9terminer le vrai format commercial selon le type de fichier d\u00e9pos\u00e9 + format s\u00e9lectionn\u00e9\r\n                var _formatSelect = sessionStorage.getItem('FormatSelect') || StateManager.get('Commande_Format_Transmis') || '';\r\n                var _uploadedExt = (StateManager.get('Upload_File_Name') || '').split('.').pop().toLowerCase();\r\n                var _fileKind = CONFIG.allowedExtensions.video.indexOf(_uploadedExt) !== -1 ? 'video'\r\n                              : CONFIG.allowedExtensions.image.indexOf(_uploadedExt) !== -1 ? 'image'\r\n                              : CONFIG.allowedExtensions.document.indexOf(_uploadedExt) !== -1 ? 'document'\r\n                              : '';\r\n                var _formatPending;\r\n                if (_fileKind === 'video') {\r\n                    \/\/ Vid\u00e9o \u2192 toujours Vid\u00e9o\r\n                    _formatPending = 'Vid\u00e9o';\r\n                } else if (_fileKind === 'image') {\r\n                    \/\/ Image \u2192 Banni\u00e8re ou Parrainage si s\u00e9lectionn\u00e9, sinon Banni\u00e8re par d\u00e9faut\r\n                    var _imgFormats = ['Banni\u00e8re', 'Banniere', 'Parrainage'];\r\n                    _formatPending = (_imgFormats.indexOf(_formatSelect) !== -1) ? _formatSelect : 'Banni\u00e8re';\r\n                } else if (_fileKind === 'document') {\r\n                    \/\/ Document \u2192 Communiqu\u00e9 ou Interview si s\u00e9lectionn\u00e9, sinon Communiqu\u00e9 par d\u00e9faut\r\n                    var _docFormats = ['Communiqu\u00e9', 'Communique', 'Interview'];\r\n                    _formatPending = (_docFormats.indexOf(_formatSelect) !== -1) ? _formatSelect : 'Communiqu\u00e9';\r\n                } else {\r\n                    \/\/ Fallback\r\n                    _formatPending = _formatSelect || StateManager.get('Commande_Format_Transmis') || '';\r\n                }\r\n                \/\/ \u2705 v2.4.9 : Si le format d\u00e9duit diff\u00e8re du format s\u00e9lectionn\u00e9 \u2192 mettre \u00e0 jour vignette + sessionStorage\r\n                if (_formatPending && _formatPending !== _formatSelect) {\r\n                    StateManager.set('FormatSelect', _formatPending);\r\n                    StateManager.set('Commande_Format_Transmis', _formatPending);\r\n                    StateManager.set('Formatchoisi', 'Yes');\r\n                    \/\/ Mettre \u00e0 jour visuellement la vignette dans le droppable courant\r\n                    var _fmtNorm = _formatPending.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    var $_drp = $dropZone.closest('.droppable');\r\n                    $_drp.find('.EspPubFormatContainer').each(function() {\r\n                        var _cls = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                        if (_cls.includes(_fmtNorm)) {\r\n                            jQuery(this).css({'background-color': '#ffffff'});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        } else if (!jQuery(this).hasClass('FormatIdPopUp')) {\r\n                            jQuery(this).css({'background-color': ''});\r\n                            jQuery(this).find('.EspPubFormat').css({'color': ''});\r\n                        }\r\n                    });\r\n                    \/\/ Mettre \u00e0 jour aussi le bandeau parent via postMessage\r\n                    MessageManager.sendToParent('formatChangedInIframe', { formatSelect: _formatPending, rank: _pendingRank });\r\n                    console.log('\ud83d\udd04 [finalizeUpload] Format corrig\u00e9:', _formatSelect, '\u2192', _formatPending);\r\n                }\r\n                var _firstUploadOrMoved = StateManager.get('FirstUploadFileorMoved');\r\n                var _isMoved = _firstUploadOrMoved === 'Moved';\r\n                var _oldRankMoved = _isMoved ? (StateManager.get('dragstart_Rank_Emplacement_Page_Web') || '') : '';\r\n                MessageManager.sendToParent('annonceDeposeeSansReservation', {\r\n                    Rank_Emplacement_Page_Web: _pendingRank,\r\n                    FullPathAdFile: StateManager.get('FullPathAdFile') || '',\r\n                    Upload_File_Name: StateManager.get('Upload_File_Name') || '',\r\n                    LoadedPageUrl: window.location.href,\r\n                    FileReceived: 'Yes',\r\n                    \/\/ \u2705 Lire EnvoiUlterieur depuis la checkbox du droppable courant (pas le StateManager global)\r\n                    \/\/ StateManager.get('EnvoiUlterieur') est global \u2192 peut valoir 'true' si un autre espace a sa checkbox coch\u00e9e\r\n                    EnvoiUlterieur: ($dropZone.closest('.droppable').find('input[name*=\"EnvoiUlterieur\"]').prop('checked') ? 'true' : 'false'),\r\n                    Commande_Format_Transmis: _formatPending,\r\n                    codeSite: StateManager.get('codeSite') || '',\r\n                    codePage: StateManager.get('codePage') || '',\r\n                    Commande_Emplacement_Page_Web: StateManager.buildEmplacementReference(_pendingRank),\r\n                    isMoved: _isMoved,\r\n                    oldRank: _oldRankMoved\r\n                });\r\n            }\r\n        }\r\n    },\r\n    \r\n    activateSendDataToParent($dropZone) {\r\n        if (StateManager.get(\"sendDataToParentFlag\") !== 'Yes') {\r\n            return;\r\n        }\r\n        \r\n        if (StateManager.get(\"FirstUploadFileorMoved\") === 'Moved') {\r\n            const dragstartRef = StateManager.buildEmplacementReference(\r\n                StateManager.get(\"dragstart_Rank_Emplacement_Page_Web\")\r\n            );\r\n            StateManager.set('dragstart_Commande_Emplacement_Page_Web', dragstartRef);\r\n        }\r\n        \r\n        console.log('Esp Pub Ref FirstUploadFileorMoved:', StateManager.get(\"FirstUploadFileorMoved\"));\r\n        console.log('Esp Pub dragstart_Commande:', StateManager.get(\"dragstart_Commande_Emplacement_Page_Web\"));\r\n        \r\n        if (StateManager.get(\"PageAjoutModifAnnonce\") === 'Yes') {\r\n            this.handlePageModification($dropZone);\r\n        } else {\r\n            this.handleNormalUpload();\r\n        }\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        setTimeout(() => {\r\n            StateManager.set(\"AddNewRefInVosCampagnes\", 'Yes');\r\n        }, 4000);\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            StateManager.set('Commande_Format_Transmis', '');\r\n        }\r\n    },\r\n    \r\n    handlePageModification($dropZone) {\r\n        $('#CroixResetAnnonce, .DeplaceAnnonce').hide();\r\n        $('.PageAjoutModifAnnonceCroixResetAnnonce').show();\r\n        \r\n        const emplacementRef = $dropZone.closest('.CampagnesTemplateClass')\r\n            .find('.ReferenceEspace').text();\r\n        \r\n        console.log('Commande_Emplacement_Page_Web:', emplacementRef);\r\n        \r\n        jQuery.ajax({\r\n            type: \"POST\",\r\n            url: CONFIG.ajaxUrl,\r\n            data: {\r\n                action: 'via_update_fichier_annonce',\r\n                commande_ref_url: StateManager.get(\"commande_ref_url\"),\r\n                emplacement_page_web: emplacementRef,\r\n                chemin_fichier: StateManager.get(\"FullPathAdFile\")\r\n            },\r\n            xhrFields: { withCredentials: true },\r\n            success: (response) => {\r\n                if (response.success) {\r\n                    console.log('\u2705 Fichier annonce mis \u00e0 jour:', response.data.message);\r\n                    location.reload();\r\n                } else {\r\n                    console.error('\u274c Erreur:', response.data.message);\r\n                }\r\n            },\r\n            error: (xhr, status, error) => {\r\n                console.error('\u274c Erreur AJAX:', error);\r\n            }\r\n        });\r\n    },\r\n    \r\n    handleNormalUpload() {\r\n        if (StateManager.get(\"EnvoiUlterieur\") === 'true') {\r\n            StateManager.setMultiple({\r\n                \"FullPathAdFile\": '',\r\n                \"Upload_File_Name\": ''\r\n            });\r\n        }\r\n        \r\n        StateManager.set(\"LoadedPageUrl\", window.location.href);\r\n        \r\n        console.log('EnvoiUlterieur:', StateManager.get(\"EnvoiUlterieur\"));\r\n        console.log('LoadedPageUrl:', StateManager.get(\"LoadedPageUrl\"));\r\n        console.log('FileReceived:', StateManager.get(\"FileReceived\"));\r\n        \r\n        const data = MessageManager.prepareUploadData();\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            MessageManager.sendDataToParent(data);\r\n        } else {\r\n            const formatChoisi = StateManager.get(\"Formatchoisi\") === 'Yes';\r\n            const fichierDepose = StateManager.get(\"FileReceived\") === 'Yes';\r\n            const envoiDiffere = StateManager.get(\"EnvoiUlterieur\") === 'true';\r\n            \r\n            console.log('\ud83d\udd0d handleNormalUpload - Conditions:', { formatChoisi, fichierDepose, envoiDiffere });\r\n            \r\n            if (formatChoisi && (fichierDepose || envoiDiffere)) {\r\n                if (typeof window.handleEspacePubData === 'function') {\r\n                    window.handleEspacePubData(data);\r\n                } else {\r\n                    console.warn('\u26a0\ufe0f handleEspacePubData non disponible, fallback direct');\r\n                    if (typeof window.executeWithProcessLoaded === 'function') {\r\n                        window.executeWithProcessLoaded(function() {\r\n                            jQuery('#PopupProcessCommandeContainer').show();\r\n                        });\r\n                    } else {\r\n                        jQuery('#PopupProcessCommandeContainer').show();\r\n                    }\r\n                }\r\n            } else if (formatChoisi) {\r\n                console.log('\ud83d\udcdd Mise \u00e0 jour format uniquement');\r\n                \r\n                const borderStyle = {'box-shadow': 'inset 0 0 0 2px #00FF19', 'box-sizing': 'border-box'};  \/\/ \u2705 v2.4.5\r\n                \r\n                jQuery(\".FormatClassique, .FormatPopup\").css({'border': 'none'});\r\n                \r\n                jQuery('.FormatClassique, .FormatPopup').each(function() {\r\n                    \/\/ \u2705 v2.1.1 : NFD normalize both sides\r\n                    var _cn = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    var _cf = (data.Commande_Format_Transmis || '').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    if (_cn.includes(_cf) && _cf) {\r\n                        jQuery(this).css(borderStyle);\r\n                    }\r\n                });\r\n            }\r\n        }\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        setTimeout(() => {\r\n            StateManager.set(\"AddNewRefInVosCampagnes\", 'Yes');\r\n        }, 4000);\r\n        \r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            StateManager.set('Commande_Format_Transmis', '');\r\n        }\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des fichiers PDF (s\u00e9par\u00e9 pour \u00e9viter la complexit\u00e9)\r\n *\/\r\nconst PDFHandler = {\r\n    pdfData: null,\r\n    pdfDataForViewer: null,\r\n    \r\n    async renderPDF(fileObj, $dropZone) {\r\n        return new Promise((resolve, reject) => {\r\n            const reader = new FileReader();\r\n            \r\n            reader.onload = async (e) => {\r\n                try {\r\n                    const arrayBuffer = e.target.result;\r\n                    this.pdfData = new Uint8Array(arrayBuffer);\r\n                    this.pdfDataForViewer = arrayBuffer;\r\n                    \r\n                    console.log(\"Initial PDF load, size:\", this.pdfData.byteLength);\r\n                    \r\n                    const pdfjsLib = window['pdfjs-dist\/build\/pdf'];\r\n                    pdfjsLib.GlobalWorkerOptions.workerSrc = \r\n                        '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n                    \r\n                    const pdf = await pdfjsLib.getDocument({ data: new Uint8Array(this.pdfData) }).promise;\r\n                    const page = await pdf.getPage(1);\r\n                    \r\n                    const { titleText, pageText } = await this.extractTextFromPage(page);\r\n                    const imageData = await this.extractImageFromPage(page, pdfjsLib);\r\n                    \r\n                    if (imageData) {\r\n                        PreviewRenderer.renderDocumentPreview(\r\n                            $dropZone,\r\n                            imageData.dataUrl,\r\n                            titleText,\r\n                            pageText\r\n                        );\r\n                    } else {\r\n                        \/\/ \u2705 v1.19.0 : Accepter les PDF sans image\r\n                        PreviewRenderer.renderDocumentPreview(\r\n                            $dropZone,\r\n                            null,\r\n                            titleText,\r\n                            pageText\r\n                        );\r\n                        console.log('\u2139\ufe0f PDF sans image \u2014 aper\u00e7u texte seul');\r\n                    }\r\n                    \r\n                    this.attachPDFPreviewHandler($dropZone, titleText);\r\n                    resolve();\r\n                } catch (error) {\r\n                    console.error('Error extracting from PDF:', error);\r\n                    \/\/ \u2705 v1.19.0 : Message d'erreur en fran\u00e7ais\r\n                    $dropZone.html(`\r\n                        <div style=\"padding: 15px; background-color: #f8f8f8; border-radius: 4px; text-align: center;\">\r\n                            <p style=\"color: #FB5E2A; font-weight: 600; font-family: Roboto, Arial, sans-serif; font-size: 12px;\">\r\n                                Erreur lors de la lecture du document\r\n                            <\/p>\r\n                        <\/div>\r\n                    `);\r\n                    reject(error);\r\n                }\r\n            };\r\n            \r\n            reader.readAsArrayBuffer(fileObj);\r\n        });\r\n    },\r\n    \r\n    async extractTextFromPage(page) {\r\n        const textContent = await page.getTextContent();\r\n        \r\n        let text = '';\r\n        let lastX = -1;\r\n        let lastY = -1;\r\n        \r\n        for (const item of textContent.items) {\r\n            if (lastY !== -1 && (Math.abs(lastY - item.transform[5]) > 5)) {\r\n                text += '\\n';\r\n            } else if (lastX !== -1 && (item.transform[4] - lastX > 10)) {\r\n                text += ' ';\r\n            }\r\n            \r\n            text += item.str;\r\n            \r\n            lastX = item.transform[4] + (item.width || 0);\r\n            lastY = item.transform[5];\r\n        }\r\n        \r\n        text = text\r\n            .replace(\/(\\w) (\\w)\/g, (match, p1, p2) => {\r\n                if (\/[\u00e9\u00e8\u00ea\u00eb\u00e0\u00e2\u00e4\u00f4\u00f6\u00fb\u00fc\u00ef\u00ee\u00e7]\/i.test(p2)) {\r\n                    return p1 + p2;\r\n                }\r\n                return match;\r\n            })\r\n            .replace(\/ ([.,;:!?])\/g, '$1');\r\n        \r\n        const normalizedText = PreviewRenderer.normalizeText(text);\r\n        const titleText = PreviewRenderer.findDocumentTitle(normalizedText);\r\n        \r\n        return { titleText, pageText: text };\r\n    },\r\n    \r\n    async extractImageFromPage(page, pdfjsLib) {\r\n        const opList = await page.getOperatorList();\r\n        const imageInfo = [];\r\n        let currentTransform = null;\r\n        \r\n        for (let i = 0; i < opList.fnArray.length; i++) {\r\n            const operator = opList.fnArray[i];\r\n            const args = opList.argsArray[i];\r\n            \r\n            if (operator === pdfjsLib.OPS.transform) {\r\n                currentTransform = args;\r\n            } else if (operator === pdfjsLib.OPS.paintImageXObject) {\r\n                const imageName = args[0];\r\n                \r\n                if (!imageInfo.some(info => info.name === imageName)) {\r\n                    const position = currentTransform ? {\r\n                        x: currentTransform[4] || 0,\r\n                        y: currentTransform[5] || 0\r\n                    } : { x: 0, y: 0 };\r\n                    \r\n                    imageInfo.push({ name: imageName, position: position });\r\n                }\r\n            }\r\n        }\r\n        \r\n        if (imageInfo.length === 0) {\r\n            return null;\r\n        }\r\n        \r\n        imageInfo.sort((a, b) => b.position.y - a.position.y);\r\n        \r\n        const targetImageName = imageInfo[0].name;\r\n        const imageObj = page.objs.get(targetImageName);\r\n        \r\n        if (!imageObj) {\r\n            const img = await page.objs.get(targetImageName, true);\r\n            return this.processImageObject(img);\r\n        }\r\n        \r\n        return this.processImageObject(imageObj);\r\n    },\r\n    \r\n    processImageObject(imageObj) {\r\n        if (!imageObj) {\r\n            throw new Error('Image object is null');\r\n        }\r\n        \r\n        if (imageObj.bitmap instanceof ImageBitmap) {\r\n            const width = imageObj.bitmap.width || imageObj.width || imageObj.w;\r\n            const height = imageObj.bitmap.height || imageObj.height || imageObj.h;\r\n            \r\n            const canvas = document.createElement('canvas');\r\n            canvas.width = width;\r\n            canvas.height = height;\r\n            const ctx = canvas.getContext('2d');\r\n            \r\n            ctx.drawImage(imageObj.bitmap, 0, 0);\r\n            \r\n            return {\r\n                canvas: canvas,\r\n                width: width,\r\n                height: height,\r\n                dataUrl: canvas.toDataURL('image\/jpeg', 0.92)\r\n            };\r\n        }\r\n        \r\n        const width = imageObj.width || imageObj.w;\r\n        const height = imageObj.height || imageObj.h;\r\n        \r\n        if (!width || !height) {\r\n            throw new Error('Could not determine image dimensions');\r\n        }\r\n        \r\n        let imgData = imageObj.data || imageObj.bitmap;\r\n        \r\n        if (!imgData) {\r\n            throw new Error('No valid image data found');\r\n        }\r\n        \r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = width;\r\n        canvas.height = height;\r\n        const ctx = canvas.getContext('2d');\r\n        \r\n        ctx.fillStyle = 'white';\r\n        ctx.fillRect(0, 0, width, height);\r\n        \r\n        const imageData = ctx.createImageData(width, height);\r\n        \r\n        this.fillImageData(imageData, imgData, imageObj.kind, width, height);\r\n        \r\n        ctx.putImageData(imageData, 0, 0);\r\n        \r\n        return {\r\n            canvas: canvas,\r\n            width: width,\r\n            height: height,\r\n            dataUrl: canvas.toDataURL('image\/jpeg', 0.92)\r\n        };\r\n    },\r\n    \r\n    fillImageData(imageData, imgData, kind, width, height) {\r\n        if (kind === 'GRAY') {\r\n            for (let i = 0, j = 0; i < imgData.length; i++, j += 4) {\r\n                const value = imgData[i];\r\n                imageData.data[j] = value;\r\n                imageData.data[j + 1] = value;\r\n                imageData.data[j + 2] = value;\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (kind === 'CMYK') {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 4, j += 4) {\r\n                const c = imgData[i] \/ 255;\r\n                const m = imgData[i + 1] \/ 255;\r\n                const y = imgData[i + 2] \/ 255;\r\n                const k = imgData[i + 3] \/ 255;\r\n                \r\n                imageData.data[j] = 255 * (1 - c) * (1 - k);\r\n                imageData.data[j + 1] = 255 * (1 - m) * (1 - k);\r\n                imageData.data[j + 2] = 255 * (1 - y) * (1 - k);\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (kind === 'RGB24') {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 3, j += 4) {\r\n                imageData.data[j] = imgData[i];\r\n                imageData.data[j + 1] = imgData[i + 1];\r\n                imageData.data[j + 2] = imgData[i + 2];\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else if (imgData.length === width * height * 3) {\r\n            for (let i = 0, j = 0; i < imgData.length; i += 3, j += 4) {\r\n                imageData.data[j] = imgData[i];\r\n                imageData.data[j + 1] = imgData[i + 1];\r\n                imageData.data[j + 2] = imgData[i + 2];\r\n                imageData.data[j + 3] = 255;\r\n            }\r\n        } else {\r\n            const tempArray = new Uint8ClampedArray(imgData.length);\r\n            for (let i = 0; i < imgData.length; i++) {\r\n                tempArray[i] = imgData[i];\r\n            }\r\n            \r\n            if (tempArray.length === imageData.data.length \/ 4 * 3) {\r\n                for (let i = 0, j = 0; i < tempArray.length; i += 3, j += 4) {\r\n                    imageData.data[j] = tempArray[i];\r\n                    imageData.data[j + 1] = tempArray[i + 1];\r\n                    imageData.data[j + 2] = tempArray[i + 2];\r\n                    imageData.data[j + 3] = 255;\r\n                }\r\n            } else if (tempArray.length === imageData.data.length) {\r\n                imageData.data.set(tempArray);\r\n            } else {\r\n                console.warn('Unknown image format - creating placeholder');\r\n                for (let i = 0; i < imageData.data.length; i += 4) {\r\n                    const x = (i\/4) % width;\r\n                    const y = Math.floor((i\/4) \/ width);\r\n                    imageData.data[i] = x % 256;\r\n                    imageData.data[i + 1] = y % 256;\r\n                    imageData.data[i + 2] = 100;\r\n                    imageData.data[i + 3] = 255;\r\n                }\r\n            }\r\n        }\r\n    },\r\n    \r\n    attachPDFPreviewHandler($dropZone, titleText) {\r\n        var $droppable = $dropZone.closest('.droppable');\r\n        var self = this;\r\n\r\n        \/\/ \u2705 Adapter le libell\u00e9 selon le format (communiqu\u00e9 \/ interview)\r\n        var kitFormat = $droppable.data('kitFormatSelect') || '';\r\n        var isInterview = (kitFormat || titleText || '').toLowerCase().indexOf('interview') !== -1;\r\n        var formatLabel = isInterview ? 'l\\'interview' : 'le communiqu\u00e9';\r\n        $droppable.find('.doc-preview-readmore').text('Ouvrir et visualiser ' + formatLabel);\r\n\r\n        \/\/ \u2705 v2.0.11 : D\u00e9l\u00e9gation d'\u00e9v\u00e9nement \u2014 plus robuste sur mobile\r\n        $droppable.off('click.docpreview').on('click.docpreview', '.doc-preview-readmore', (event) => {\r\n            event.preventDefault();\r\n            event.stopPropagation();\r\n            var popupTitle = isInterview ? 'Interview' : 'Communiqu\u00e9';\r\n\r\n            \/\/ \u2705 Priorit\u00e9 1 : pdfImageDataURL dispo (Kit)\r\n            var kitPdfImage = $droppable.data('kitPdfImageDataURL');\r\n            if (kitPdfImage) {\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    pdfDataURL: kitPdfImage\r\n                });\r\n                return;\r\n            }\r\n\r\n            \/\/ \u2705 Priorit\u00e9 2 : PDF upload\u00e9 manuellement \u2192 popup inline aussi\r\n            if (self.pdfDataForViewer && self.pdfDataForViewer.byteLength > 0) {\r\n                PDFHandler.showInlineDocPopup($dropZone, {\r\n                    formatTitle: popupTitle,\r\n                    pdfArrayBuffer: self.pdfDataForViewer\r\n                });\r\n                return;\r\n            }\r\n\r\n            console.error('PDF data is not available');\r\n        });\r\n    },\r\n\r\n    \/\/ \u2705 v1.19.1 : Popup inline document \u2014 position:absolute + ScrollHelper.getVisibleTop()\r\n    \/\/ Le parent envoie visibleTopIframe dans le message scroll \u2192 positionnement fiable.\r\n    showInlineDocPopup($dropZone, options) {\r\n        var existing = document.getElementById('via-pdf-inline-popup');\r\n        if (existing) existing.remove();\r\n\r\n        var $droppable = $dropZone.closest('.droppable');\r\n        var droppableW = $droppable.outerWidth() || 300;\r\n        var popupW = Math.round(droppableW * 1.15);\r\n        \/\/ \u2705 v2.0.11 : Contraindre la largeur au viewport sur mobile (\u00e9vite troncature gauche\/droite)\r\n        var viewportW = document.documentElement.clientWidth || window.innerWidth;\r\n        if (UIManager.isMobile()) {\r\n            popupW = Math.min(popupW, viewportW - 8);\r\n        }\r\n        var popupH = Math.round(popupW * 2.5 * 0.51);\r\n\r\n        \/\/ \u2500\u2500 Position visible r\u00e9elle \u2500\u2500\r\n        var visibleTop = ScrollHelper.getVisibleTop();\r\n        var popupTop = Math.round(visibleTop + 284);\r\n\r\n        \/\/ \u2500\u2500 Popup position:absolute (positionn\u00e9 dans le document iframe) \u2500\u2500\r\n        var popup = document.createElement('div');\r\n        popup.id = 'via-pdf-inline-popup';\r\n        popup.style.cssText =\r\n            'position:absolute;z-index:99999;top:' + popupTop + 'px;' +\r\n            'width:' + popupW + 'px;height:' + popupH + 'px;' +\r\n            'background:#fff;border-radius:8px 8px 0 0;padding:0;' +\r\n            'box-shadow:0 8px 32px rgba(0,0,0,0.35);display:flex;flex-direction:column;' +\r\n            'min-width:200px;min-height:150px;touch-action:none;';\r\n\r\n        \/\/ Centrer horizontalement sur le droppable (coordonn\u00e9es absolues)\r\n        var droppableRect = $droppable[0].getBoundingClientRect();\r\n        var scrollX = window.scrollX || 0;\r\n        var initLeft = Math.round(droppableRect.left + scrollX + (droppableRect.width - popupW) \/ 2);\r\n        initLeft = Math.max(4, initLeft);\r\n        \/\/ \u2705 v2.0.11 : Contraindre \u00e0 droite aussi sur mobile\r\n        if (UIManager.isMobile()) {\r\n            initLeft = Math.min(initLeft, viewportW - popupW - 4);\r\n            initLeft = Math.max(4, initLeft);\r\n        }\r\n        popup.style.left = initLeft + 'px';\r\n\r\n        \/\/ \u2500\u2500 Header \u2500\u2500\r\n        var header = document.createElement('div');\r\n        header.style.cssText =\r\n            'display:flex;align-items:center;justify-content:center;position:relative;' +\r\n            'padding:10px 14px;background:#f0f0f0;color:#494949;flex-shrink:0;' +\r\n            'cursor:grab;user-select:none;border-radius:8px 8px 0 0;';\r\n        var titleEl = document.createElement('span');\r\n        titleEl.style.cssText = 'font-family:Roboto,Arial,sans-serif;font-size:15px;font-weight:600;';\r\n        titleEl.textContent = options.formatTitle || 'Document';\r\n        header.appendChild(titleEl);\r\n\r\n        var closeBtn = document.createElement('button');\r\n        closeBtn.textContent = '\u00d7';\r\n        closeBtn.style.cssText =\r\n            'position:absolute;right:10px;top:50%;transform:translateY(-50%);' +\r\n            'background:transparent;border:none;color:#494949;font-size:20px;' +\r\n            'cursor:pointer;line-height:1;padding:0 4px;';\r\n        closeBtn.addEventListener('click', cleanup);\r\n        header.appendChild(closeBtn);\r\n        popup.appendChild(header);\r\n\r\n        \/\/ \u2500\u2500 Zone scrollable \u2014 pleine largeur \u2500\u2500\r\n        var scrollZone = document.createElement('div');\r\n        scrollZone.style.cssText =\r\n            'flex:1;overflow-y:auto;overflow-x:hidden;padding:0;margin:0;touch-action:pan-y;';\r\n        popup.appendChild(scrollZone);\r\n\r\n        var loader = document.createElement('div');\r\n        loader.style.cssText =\r\n            'text-align:center;padding:30px;font-family:Roboto,Arial,sans-serif;font-size:12px;color:#666;';\r\n        loader.textContent = 'Chargement du document\u2026';\r\n        scrollZone.appendChild(loader);\r\n\r\n        \/\/ \u2500\u2500 8 poign\u00e9es de redimensionnement \u2500\u2500\r\n        var handles = [\r\n            { cursor:'nw-resize', pos:'top:-4px;left:-4px;',       dx:-1, dy:-1 },\r\n            { cursor:'n-resize',  pos:'top:-4px;left:50%;',        dx:0,  dy:-1 },\r\n            { cursor:'ne-resize', pos:'top:-4px;right:-4px;',      dx:1,  dy:-1 },\r\n            { cursor:'w-resize',  pos:'top:50%;left:-4px;',        dx:-1, dy:0  },\r\n            { cursor:'e-resize',  pos:'top:50%;right:-4px;',       dx:1,  dy:0  },\r\n            { cursor:'sw-resize', pos:'bottom:-4px;left:-4px;',    dx:-1, dy:1  },\r\n            { cursor:'s-resize',  pos:'bottom:-4px;left:50%;',     dx:0,  dy:1  },\r\n            { cursor:'se-resize', pos:'bottom:-4px;right:-4px;',   dx:1,  dy:1  }\r\n        ];\r\n        handles.forEach(function(h) {\r\n            var handle = document.createElement('div');\r\n            var isCorner = (h.dx !== 0 && h.dy !== 0);\r\n            handle.style.cssText =\r\n                'position:absolute;touch-action:none;' + h.pos +\r\n                'width:' + (isCorner ? '12px' : (h.dy === 0 ? '8px' : '30px')) + ';' +\r\n                'height:' + (isCorner ? '12px' : (h.dy === 0 ? '30px' : '8px')) + ';' +\r\n                'cursor:' + h.cursor + ';z-index:10;';\r\n            (function(hInfo) {\r\n                handle.addEventListener('pointerdown', function(e) {\r\n                    e.preventDefault(); e.stopPropagation();\r\n                    handle.setPointerCapture(e.pointerId);\r\n                    var startX = e.clientX, startY = e.clientY;\r\n                    var rect0 = popup.getBoundingClientRect();\r\n                    var sY = window.scrollY || 0, sX = window.scrollX || 0;\r\n                    var startW = rect0.width, startH = rect0.height;\r\n                    var startL = rect0.left + sX, startT = rect0.top + sY;\r\n                    function onResize(ev) {\r\n                        ev.preventDefault();\r\n                        var ddx = ev.clientX - startX, ddy = ev.clientY - startY;\r\n                        var newW = startW, newH = startH, newL = startL, newT = startT;\r\n                        if (hInfo.dx === 1)  newW = Math.max(200, startW + ddx);\r\n                        if (hInfo.dx === -1) { newW = Math.max(200, startW - ddx); newL = startL + ddx; }\r\n                        if (hInfo.dy === 1)  newH = Math.max(150, startH + ddy);\r\n                        if (hInfo.dy === -1) { newH = Math.max(150, startH - ddy); newT = startT + ddy; }\r\n                        popup.style.width  = newW + 'px';\r\n                        popup.style.height = newH + 'px';\r\n                        popup.style.left   = newL + 'px';\r\n                        popup.style.top    = newT + 'px';\r\n                    }\r\n                    function onResizeEnd(ev) {\r\n                        handle.releasePointerCapture(ev.pointerId);\r\n                        handle.removeEventListener('pointermove', onResize);\r\n                        handle.removeEventListener('pointerup', onResizeEnd);\r\n                    }\r\n                    handle.addEventListener('pointermove', onResize);\r\n                    handle.addEventListener('pointerup', onResizeEnd);\r\n                });\r\n            })(h);\r\n            popup.appendChild(handle);\r\n        });\r\n\r\n        \/\/ \u2500\u2500 Drag via header \u2500\u2500\r\n        header.style.touchAction = 'none';\r\n        header.addEventListener('pointerdown', function(e) {\r\n            if (e.target === closeBtn) return;\r\n            e.preventDefault();\r\n            header.setPointerCapture(e.pointerId);\r\n            var mx = e.clientX, my = e.clientY;\r\n            var popupRect = popup.getBoundingClientRect();\r\n            var scrollY = window.scrollY || 0;\r\n            var scrollX = window.scrollX || 0;\r\n            var curLeft = popupRect.left + scrollX;\r\n            var curTop  = popupRect.top  + scrollY;\r\n            header.style.cursor = 'grabbing';\r\n            function onMove(ev) {\r\n                ev.preventDefault();\r\n                var dx = ev.clientX - mx;\r\n                var dy = ev.clientY - my;\r\n                curLeft += dx;\r\n                curTop  += dy;\r\n                popup.style.left = curLeft + 'px';\r\n                popup.style.top  = curTop  + 'px';\r\n                mx = ev.clientX;\r\n                my = ev.clientY;\r\n            }\r\n            function onUp(ev) {\r\n                header.releasePointerCapture(ev.pointerId);\r\n                header.style.cursor = 'grab';\r\n                header.removeEventListener('pointermove', onMove);\r\n                header.removeEventListener('pointerup', onUp);\r\n            }\r\n            header.addEventListener('pointermove', onMove);\r\n            header.addEventListener('pointerup', onUp);\r\n        });\r\n\r\n        \/\/ \u2500\u2500 Cleanup \u2500\u2500\r\n        function cleanup() {\r\n            popup.remove();\r\n            document.removeEventListener('keydown', escHandler);\r\n        }\r\n        var escHandler = function(e) { if (e.key === 'Escape') cleanup(); };\r\n        document.addEventListener('keydown', escHandler);\r\n\r\n        document.body.appendChild(popup);\r\n\r\n        \/\/ \u2500\u2500 Rendre le contenu \u2500\u2500\r\n        if (options.pdfDataURL)          this.renderPdfInPopup(scrollZone, options.pdfDataURL, popupW, 'dataurl');\r\n        else if (options.pdfArrayBuffer) this.renderPdfInPopup(scrollZone, options.pdfArrayBuffer, popupW, 'arraybuffer');\r\n        else if (options.htmlContent)    this.renderHtmlInPopup(scrollZone, options.htmlContent);\r\n    },\r\n\r\n    \/\/ Alias pour compatibilit\u00e9\r\n    showInlinePdfPopup($dropZone, pdfImageDataURL, formatTitle) {\r\n        this.showInlineDocPopup($dropZone, { formatTitle: formatTitle, pdfDataURL: pdfImageDataURL });\r\n    },\r\n\r\n    \/\/ \u2705 Rendu PDF dans popup (dataurl ou arraybuffer) \u2014 avec crop des marges blanches\r\n    async renderPdfInPopup(container, pdfData, popupWidth, mode) {\r\n        try {\r\n            var u8;\r\n            if (mode === 'dataurl') {\r\n                var b64 = pdfData.split(',')[1];\r\n                var bstr = atob(b64);\r\n                u8 = new Uint8Array(bstr.length);\r\n                for (var i = 0; i < bstr.length; i++) { u8[i] = bstr.charCodeAt(i); }\r\n            } else {\r\n                u8 = new Uint8Array(pdfData);\r\n            }\r\n\r\n            var pdfjsLib = window['pdfjs-dist\/build\/pdf'];\r\n            if (!pdfjsLib) {\r\n                container.innerHTML = '<div style=\"padding:20px;text-align:center;color:#c00;\">pdf.js non charg\u00e9<\/div>';\r\n                return;\r\n            }\r\n            pdfjsLib.GlobalWorkerOptions.workerSrc =\r\n                '\/\/cdn.jsdelivr.net\/npm\/pdfjs-dist@latest\/build\/pdf.worker.min.js';\r\n\r\n            var pdf = await pdfjsLib.getDocument({ data: u8 }).promise;\r\n            console.log('\ud83d\udcc4 PDF popup :', pdf.numPages, 'pages');\r\n            container.innerHTML = '';\r\n\r\n            var firstPage = await pdf.getPage(1);\r\n            var vpNative = firstPage.getViewport({ scale: 1 });\r\n            var scale = popupWidth \/ vpNative.width;\r\n\r\n            \/\/ \u2705 R\u00e9f\u00e9rence au popup pour ajuster sa hauteur apr\u00e8s rendu\r\n            var _popup = container.closest('#via-pdf-inline-popup');\r\n            var _headerH = _popup ? (_popup.querySelector('div[style*=\"grab\"]') || {offsetHeight: 44}).offsetHeight : 44;\r\n\r\n            \/\/ \u2705 D\u00e9tecte les marges blanches haut\/bas d'un canvas rendu et retourne {top, bottom}\r\n            function detectWhiteMargins(canvas) {\r\n                var ctx = canvas.getContext('2d');\r\n                var data = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\r\n                var W = canvas.width, H = canvas.height;\r\n                var topRow = 0, bottomRow = H - 1;\r\n                \/\/ Chercher la premi\u00e8re ligne non-blanche (tol\u00e9rance 252 pour les artefacts anti-aliasing)\r\n                outer: for (var y = 0; y < H; y++) {\r\n                    for (var x = 0; x < W; x++) {\r\n                        var i = (y * W + x) * 4;\r\n                        if (data[i] < 252 || data[i+1] < 252 || data[i+2] < 252) { topRow = y; break outer; }\r\n                    }\r\n                }\r\n                outer2: for (var y2 = H - 1; y2 >= topRow; y2--) {\r\n                    for (var x2 = 0; x2 < W; x2++) {\r\n                        var i2 = (y2 * W + x2) * 4;\r\n                        if (data[i2] < 252 || data[i2+1] < 252 || data[i2+2] < 252) { bottomRow = y2; break outer2; }\r\n                    }\r\n                }\r\n                return { top: topRow, bottom: bottomRow };\r\n            }\r\n\r\n            for (var pageNum = 1; pageNum <= pdf.numPages; pageNum++) {\r\n                var page = await pdf.getPage(pageNum);\r\n                var vp = page.getViewport({ scale: scale });\r\n                \/\/ Rendre dans un canvas temporaire\r\n                var tmpCanvas = document.createElement('canvas');\r\n                tmpCanvas.width = vp.width;\r\n                tmpCanvas.height = vp.height;\r\n                await page.render({ canvasContext: tmpCanvas.getContext('2d'), viewport: vp }).promise;\r\n\r\n                \/\/ \u2705 Crop marges blanches\r\n                var margins = detectWhiteMargins(tmpCanvas);\r\n                var cropTop = Math.max(0, margins.top - 4);\r\n                var cropBottom = Math.min(tmpCanvas.height - 1, margins.bottom + 4);\r\n                var croppedH = cropBottom - cropTop + 1;\r\n\r\n                \/\/ Canvas final crop\u00e9\r\n                var canvas = document.createElement('canvas');\r\n                canvas.width = tmpCanvas.width;\r\n                canvas.height = croppedH;\r\n                canvas.getContext('2d').drawImage(tmpCanvas, 0, cropTop, tmpCanvas.width, croppedH, 0, 0, tmpCanvas.width, croppedH);\r\n                canvas.style.cssText = 'display:block;width:100%;height:auto;margin:0;padding:0;';\r\n                container.appendChild(canvas);\r\n                console.log('\ud83d\udcc4 Page', pageNum, '- crop:', cropTop, '\u2192', cropBottom, '(', Math.round(cropTop\/vp.height*100), '% top trimmed)');\r\n            }\r\n\r\n            \/\/ \u2705 Ajuster la hauteur du popup \u00e0 la hauteur r\u00e9elle du contenu rendu\r\n            \/\/ (popup \u00e9tait calcul\u00e9 sur popupW*2.5*0.51 qui peut \u00eatre trop grand ou trop petit)\r\n            if (_popup) {\r\n                var _totalH = 0;\r\n                container.querySelectorAll('canvas').forEach(function(c) { _totalH += c.height * (popupWidth \/ c.width); });\r\n                var _viewportH = window.innerHeight || document.documentElement.clientHeight || 600;\r\n                var _maxPopupH = Math.round(_viewportH * 0.88);\r\n                var _idealH = Math.min(_totalH + _headerH + 8, _maxPopupH);\r\n                _popup.style.height = _idealH + 'px';\r\n                console.log('\ud83d\udcd0 Popup redimensionn\u00e9:', Math.round(_idealH), 'px (contenu:', Math.round(_totalH), ')');\r\n            }\r\n        } catch (err) {\r\n            console.error('\u274c Erreur rendu PDF popup:', err);\r\n            container.innerHTML =\r\n                '<div style=\"padding:20px;text-align:center;color:#c00;font-size:12px;\">Erreur lors du chargement du document<\/div>';\r\n        }\r\n    },\r\n\r\n    \/\/ \u2705 Rendu HTML (Word) dans popup \u2014 avec CSS complet pour mammoth\r\n    renderHtmlInPopup(container, htmlContent) {\r\n        container.innerHTML = '';\r\n        \/\/ \u2705 Nettoyer les <p> vides en d\u00e9but\/fin produits par mammoth (marges parasites)\r\n        htmlContent = htmlContent\r\n            .replace(\/^(\\s*<p[^>]*>\\s*(<br\\s*\\\/?>\\s*)*<\\\/p>\\s*)+\/i, '')\r\n            .replace(\/(\\s*<p[^>]*>\\s*(<br\\s*\\\/?>\\s*)*<\\\/p>\\s*)+$\/i, '');\r\n        \/\/ \u2500\u2500 Styles pour le HTML g\u00e9n\u00e9r\u00e9 par mammoth (titres, paragraphes, listes, images) \u2500\u2500\r\n        var style = document.createElement('style');\r\n        style.textContent = [\r\n            '.via-html-popup-body { padding:20px 24px; background:#fff; color:#222; font-family:Georgia,\"Times New Roman\",serif; font-size:15px; line-height:1.7; }',\r\n            '.via-html-popup-body h1 { font-size:22px; font-weight:700; margin:0 0 12px; line-height:1.3; }',\r\n            '.via-html-popup-body h2 { font-size:18px; font-weight:700; margin:18px 0 8px; line-height:1.3; }',\r\n            '.via-html-popup-body h3 { font-size:15px; font-weight:700; margin:14px 0 6px; }',\r\n            '.via-html-popup-body p  { margin:0 0 10px; }',\r\n            '.via-html-popup-body p:first-child { margin-top:0; }',\r\n            '.via-html-popup-body strong, .via-html-popup-body b { font-weight:700; }',\r\n            '.via-html-popup-body em, .via-html-popup-body i { font-style:italic; }',\r\n            '.via-html-popup-body ul, .via-html-popup-body ol { margin:6px 0 10px 22px; padding:0; }',\r\n            '.via-html-popup-body li { margin-bottom:4px; }',\r\n            '.via-html-popup-body img { max-width:100%; height:auto; display:block; margin:10px auto; border-radius:4px; }',\r\n            '.via-html-popup-body table { width:100%; border-collapse:collapse; margin:10px 0; font-size:13px; }',\r\n            '.via-html-popup-body td, .via-html-popup-body th { border:1px solid #ddd; padding:6px 8px; vertical-align:top; }',\r\n            '.via-html-popup-body th { background:#f0f4f8; font-weight:700; }',\r\n            '.via-html-popup-body a { color:#225da9; text-decoration:underline; }'\r\n        ].join('');\r\n        container.appendChild(style);\r\n        var wrapper = document.createElement('div');\r\n        wrapper.className = 'via-html-popup-body';\r\n        wrapper.innerHTML = htmlContent;\r\n        container.appendChild(wrapper);\r\n    },\r\n    \r\n    async renderPDFInWindow(childWindow, container) {\r\n        container.innerHTML = '';\r\n        \r\n        const script = childWindow.document.createElement('script');\r\n        script.src = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.4.120\/pdf.min.js';\r\n        childWindow.document.head.appendChild(script);\r\n        \r\n        script.onload = async () => {\r\n            const pdfjsLib = childWindow.pdfjsLib;\r\n            const viewerContainer = childWindow.document.createElement('div');\r\n            viewerContainer.style.width = '100%';\r\n            viewerContainer.style.backgroundColor = 'white';\r\n            viewerContainer.style.position = 'relative';\r\n            container.appendChild(viewerContainer);\r\n            \r\n            const loadingTask = pdfjsLib.getDocument({data: window.pdfDataToTransfer});\r\n            const pdf = await loadingTask.promise;\r\n            \r\n            const firstPage = await pdf.getPage(1);\r\n            const viewport = firstPage.getViewport({scale: 1.5});\r\n            const pageHeight = viewport.height;\r\n            \r\n            const spacing = -15;\r\n            const totalHeight = (pageHeight * pdf.numPages) + (spacing * (pdf.numPages - 1));\r\n            viewerContainer.style.height = `${totalHeight}px`;\r\n            \r\n            for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {\r\n                const page = await pdf.getPage(pageNum);\r\n                const canvas = childWindow.document.createElement('canvas');\r\n                const context = canvas.getContext('2d');\r\n                \r\n                canvas.width = viewport.width;\r\n                canvas.height = viewport.height;\r\n                \r\n                canvas.style.position = 'absolute';\r\n                canvas.style.left = '50%';\r\n                canvas.style.transform = 'translateX(-50%)';\r\n                canvas.style.top = `${(pageNum - 1) * (pageHeight + spacing)}px`;\r\n                \r\n                await page.render({\r\n                    canvasContext: context,\r\n                    viewport: viewport\r\n                }).promise;\r\n                \r\n                viewerContainer.appendChild(canvas);\r\n            }\r\n        };\r\n    },\r\n    \r\n    arrayBufferToBase64(buffer) {\r\n        let binary = '';\r\n        const bytes = new Uint8Array(buffer);\r\n        const len = bytes.byteLength;\r\n        for (let i = 0; i < len; i++) {\r\n            binary += String.fromCharCode(bytes[i]);\r\n        }\r\n        return window.btoa(binary);\r\n    },\r\n    \r\n    base64ToArrayBuffer(base64) {\r\n        const binaryString = window.atob(base64);\r\n        const len = binaryString.length;\r\n        const bytes = new Uint8Array(len);\r\n        for (let i = 0; i < len; i++) {\r\n            bytes[i] = binaryString.charCodeAt(i);\r\n        }\r\n        return bytes.buffer;\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion des \u00e9v\u00e9nements de drop et d'upload\r\n *\/\r\nconst DropHandler = {\r\n    async handleDrop(e) {\r\n        e.preventDefault();\r\n        \r\n        const $currentTarget = this.findDropTarget(e);\r\n        \r\n        if (!$currentTarget) {\r\n            console.log('No valid drop target found');\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 V\u00c9RIFIER SI C'EST UN D\u00c9PLACEMENT (pas besoin de v\u00e9rifier le format)\r\n        const isMoved = StateManager.get('FirstUploadFileorMoved') === 'Moved';\r\n        const dragstartRef = StateManager.get('dragstart_Commande_Emplacement_Page_Web');\r\n        let hasDragstartRef = false;\r\n        \r\n        if (dragstartRef) {\r\n            if (dragstartRef !== 'No') {\r\n                hasDragstartRef = true;\r\n            }\r\n        }\r\n        \r\n        let isDeplacementAnnonce = false;\r\n        if (isMoved) {\r\n            if (hasDragstartRef) {\r\n                isDeplacementAnnonce = true;\r\n            }\r\n        }\r\n        \r\n        if (isDeplacementAnnonce) {\r\n            console.log('\ud83d\udd04 D\u00e9placement d\u00e9tect\u00e9 - contr\u00f4le format ignor\u00e9');\r\n        } else {\r\n            \/\/ \u2705 CONTR\u00d4LE FORMAT SEULEMENT POUR NOUVEAU D\u00c9P\u00d4T\r\n            \/\/ Utilise FormatUIManager au lieu de showFormatWarning\r\n            if (StateManager.get('Formatchoisi') === 'No') {\r\n                FormatUIManager.flashTitle($currentTarget);\r\n                return;\r\n            }\r\n            \r\n            if (!FormatUIManager.hasSelectedFormat($currentTarget)) {\r\n                FormatUIManager.flashTitle($currentTarget);\r\n                return;\r\n            }\r\n        }\r\n    \r\n        console.log(\"Drop at:\", $currentTarget);\r\n        \r\n        this.updateEmplacementState($currentTarget);\r\n        \r\n        const shouldProcess = this.shouldProcessDrop(e, $currentTarget);\r\n        \r\n        if (shouldProcess) {\r\n            await this.processFileDrop(e, $currentTarget);\r\n        } else {\r\n            this.processVideoDrop($currentTarget);\r\n        }\r\n        \r\n        DragDropManager.clearDataTransferFiles(e);\r\n    },\r\n    \r\n    findDropTarget(e) {\r\n        \/\/ \u2705 v2.4.3 : Si Ele0A est actif et le drop arrive sur Ele1A \u2192 rediriger vers Ele0A\r\n        if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n            var _ele0ADrop = document.querySelector('#Ele0A #drop_file_zone_achat');\r\n            if (_ele0ADrop) {\r\n                console.log('\ud83c\udfaf findDropTarget \u2014 PopUpChoice=Yes \u2192 cible forc\u00e9e: Ele0A');\r\n                return jQuery(_ele0ADrop);\r\n            }\r\n        }\r\n\r\n        let target = e.target.closest('#drop_file_zone_achat');\r\n        \r\n        if (!target) {\r\n            target = e.currentTarget.closest('#drop_file_zone_achat');\r\n            console.log('Drop target found 1');\r\n        }\r\n        \r\n        if (!target) {\r\n            target = jQuery(e.target).closest('#drop_file_zone_achat')[0];\r\n            console.log('Drop target found 2');\r\n        }\r\n        \r\n        return target ? jQuery(target) : null;\r\n    },\r\n    \r\n    updateEmplacementState($target) {\r\n        const espaceId = $target.closest('.droppable').attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', espaceId);\r\n        StateManager.set('Commande_Emplacement_Page_Web',\r\n            StateManager.buildEmplacementReference(espaceId));\r\n        \r\n        UIManager.updateEmplacementDisplay();\r\n        \r\n        console.log(\"Rank_Emplacement_Page_Web:\", StateManager.get('Rank_Emplacement_Page_Web'));\r\n        console.log(\"Droppable at:\", StateManager.get('Commande_Emplacement_Page_Web'));\r\n    },\r\n    \r\n    shouldProcessDrop(e, $target) {\r\n        const hasFiles = e.dataTransfer.files.length > 0;\r\n        const isRedactionnel = StateManager.get('Commande_Format_Transmis') === 'R\u00e9dactionnel';\r\n        const isValidBackground = window.getComputedStyle(\r\n            $target.closest('#UploadFileConteneur')[0]\r\n        ).backgroundColor !== 'rgba(0, 0, 0, 0)';\r\n        \r\n        return (hasFiles || isRedactionnel) && isValidBackground;\r\n    },\r\n    \r\n    async processFileDrop(e, $target) {\r\n        jQuery('.MsgAdNotDisplayed').hide();\r\n        StateManager.setMultiple({\r\n            \"AdDisplayed\": 'Yes',\r\n            \/\/ \u2705 NE PLUS mettre sendDataToParentFlag ici - c'est la checkbox \"R\u00e9server\" qui le fera\r\n            \/\/ \"sendDataToParentFlag\": 'Yes'\r\n        });\r\n        \r\n        console.log('ajaxFileUpload_achat launched');\r\n        console.log(\"FirstUploadFileorMoved:\", StateManager.get('FirstUploadFileorMoved'));\r\n        \r\n        if (UIManager.isMobile()) {\r\n            $target = jQuery('#Ele1A').find('#drop_file_zone_achat');\r\n        }\r\n        \r\n        if (StateManager.get('Commande_Format_Transmis') === 'R\u00e9dactionnel') {\r\n            const fileURL = StateManager.get('FullPathAdFile');\r\n            const filename = fileURL.substring(fileURL.indexOf('_') + 1);\r\n            \r\n            try {\r\n                \/\/ \u2705 R\u00e9utiliser le File cach\u00e9 (\u00e9vite CORS cross-domain)\r\n                let file;\r\n                if (window._lastRedactionnelFile) {\r\n                    file = window._lastRedactionnelFile;\r\n                    console.log('\u267b\ufe0f R\u00e9utilisation du File cach\u00e9:', file.name, Math.round(file.size \/ 1024) + 'KB');\r\n                } else {\r\n                    file = await FileManager.urlToFile(fileURL, filename);\r\n                }\r\n                await UploadManager.handleFileUpload(file, $target);\r\n            } catch (error) {\r\n                console.error('Error:', error);\r\n            }\r\n        } else {\r\n            await UploadManager.handleFileUpload(e.dataTransfer.files[0], $target);\r\n        }\r\n    },\r\n    \r\n    processVideoDrop($target) {\r\n        const isValidBackground = window.getComputedStyle(\r\n            $target.closest('#UploadFileConteneur')[0]\r\n        ).backgroundColor !== 'rgba(0, 0, 0, 0)';\r\n        \r\n        if (!isValidBackground) {\r\n            jQuery('.MsgAdNotDisplayed').show();\r\n            StateManager.set(\"AdDisplayed\", 'No');\r\n            return;\r\n        }\r\n        \r\n        StateManager.set(\"AdDisplayed\", 'Yes');\r\n        \r\n        const objectUrl = StateManager.get('videoSrc');\r\n        const $previousDropZone = $('.drop_file_zone_achat_class').has(`video[src=\"${objectUrl}\"]`);\r\n        window.RestoreadSpaceTemplate($previousDropZone);\r\n        \r\n        const videoElement = jQuery('<video controls autoplay muted>').attr({\r\n            'src': objectUrl,\r\n            'max-width': '100%',\r\n            'max-height': '100%',\r\n            'draggable': 'true'\r\n        }).css({\r\n            'max-width': '100%',\r\n            'max-height': '100%'\r\n        });\r\n        \r\n        $target.empty().append(videoElement);\r\n        \r\n        $target.closest('#UploadFileConteneur').css({'background-color': '#FFFFFF00'});\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass')\r\n            .find('.RefEspacePublicitaire')\r\n            .html('R\u00e9f\u00e9rence de l\\'espace : ' + StateManager.get('Commande_Emplacement_Page_Web'))\r\n            .attr('id', 'RefEspacePublicitaire')\r\n            .each(function() {\r\n                var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                this.style.setProperty('display', 'block', 'important');\r\n            });\r\n        \/\/ \u2705 v2.4.5 : Renseigner et afficher .PositionEspacePublicitaire\r\n        (function() {\r\n            var _rankPosV = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            var _posLibV = PreviewRenderer._getPositionLibelle(_rankPosV);\r\n            if (_posLibV) {\r\n                $target.closest('.OrdiMobileConteneurClass')\r\n                    .find('.PositionEspacePublicitaireDeplacer')\r\n                    .text(_posLibV)\r\n                    .each(function() {\r\n                        var _parent = jQuery(this).closest('.DeplaceAnnonce')[0];\r\n                        if (_parent) { _parent.style.setProperty('display', 'flex', 'important'); }\r\n                        this.style.setProperty('display', 'block', 'important');\r\n                    });\r\n            }\r\n        })();\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass').find('.AdUploadedTitle').show();\r\n        \r\n        $target.closest('.OrdiMobileConteneurClass')\r\n            .css({'top': '60px', 'margin-bottom': '80px'});\r\n        \r\n        $target.closest('.HTMLUploadfileConteneur')\r\n            .not('.AdUploadedTitle')\r\n            .css({\r\n                'top': '0px',\r\n                'margin-bottom': '0px',\r\n                'box-shadow': 'inset 0 0 0 2px #00FF19',  \/\/ \u2705 v2.4.5\r\n                'background-color': 'white'\r\n            });\r\n        \r\n        $target.closest('.droppable')\r\n            .find('.AdDroppedTextNotDisplayed, .ChoisirEspacePublicitaire2ndLigne, span.ClassHdpCdp, .ClassRefEsp, .HideFormButton, .EspPubFormatMainContainer, .EnvoiUlterieurContainer')\r\n            .hide();\r\n        \r\n        jQuery('#MsgElementsCommandeValides, #MessageOptionsacompleterConteneur').hide();\r\n        \r\n        StateManager.set(\"FirstUploadFileorMoved\", 'Moved');\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server (au lieu d'envoyer automatiquement)\r\n        FormatUIManager.updateReserverCheckboxState($target.closest('.droppable'));\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion de l'explorateur de fichiers\r\n *\/\r\nconst FileExplorer = {\r\n    isRunning: false,\r\n\r\n    open(e) {\r\n        if (this.isRunning) {\r\n            return;\r\n        }\r\n        \r\n        const $element = jQuery(e.target).closest('.droppable');\r\n        \r\n        \/\/ \u2705 V\u00e9rifier si un format est s\u00e9lectionn\u00e9 (utilise FormatUIManager)\r\n        if (!FormatUIManager.hasSelectedFormat($element)) {\r\n            FormatUIManager.flashTitle($element);\r\n            return;\r\n        }\r\n        \r\n        this.isRunning = true;\r\n        \r\n        const rankId = $element.attr('id');\r\n        \r\n        StateManager.set('Rank_Emplacement_Page_Web', rankId);\r\n        StateManager.set('Commande_Emplacement_Page_Web',\r\n            StateManager.buildEmplacementReference(rankId));\r\n        \r\n        UIManager.updateEmplacementDisplay();\r\n        \r\n        console.log(\"Drop at:\", StateManager.get('Commande_Emplacement_Page_Web'));\r\n        \r\n        StateManager.set('FirstUploadFileorMoved', 'FirstUpload');\r\n        \r\n        const $currentTarget = jQuery(e.target).closest('#drop_file_zone_achat');\r\n        const $fileInput = jQuery('#selectfile_achat');\r\n        \r\n        console.log(\"currentTarget\", $currentTarget);\r\n        \r\n        $fileInput.off('change');\r\n        $fileInput.off('click');\r\n        \r\n        const onChange = (event) => {\r\n            this.isRunning = false;\r\n            $fileInput.off('change', onChange);\r\n            \r\n            \/\/ \u2705 NE PLUS mettre sendDataToParentFlag ici\r\n            \/\/ StateManager.set(\"sendDataToParentFlag\", 'Yes');\r\n            \r\n            if ($fileInput[0].files.length > 0) {\r\n                UploadManager.handleFileUpload($fileInput[0].files[0], $currentTarget);\r\n            }\r\n        };\r\n        \r\n        const onClick = () => {\r\n            $fileInput.off('click', onClick);\r\n            $fileInput.on('focus', function onFocus() {\r\n                setTimeout(() => {\r\n                    if (!$fileInput.val()) {\r\n                        FileExplorer.isRunning = false;\r\n                    }\r\n                }, 200);\r\n                $fileInput.off('focus', onFocus);\r\n            });\r\n        };\r\n        \r\n        $fileInput.on('change', onChange);\r\n        $fileInput.on('click', onClick);\r\n        \r\n        $fileInput.click();\r\n        \r\n        setTimeout(() => {\r\n            this.isRunning = false;\r\n        }, 300);\r\n    }\r\n};\r\n\r\n\/**\r\n * Module de gestion du reset d'annonce\r\n *\/\r\nconst AdResetHandler = {\r\n    handle(e) {\r\n        e.preventDefault();\r\n        console.log(\"CroixResetAnnonce click\");\r\n        \r\n        \/\/ Reset l'\u00e9tat EnvoiUlterieur\r\n        StateManager.set('EnvoiUlterieur', 'false');\r\n        \r\n        \/\/ \u2705 v1.19.6 : Reset FileReceived mais garder le format s\u00e9lectionn\u00e9\r\n        StateManager.set('FileReceived', 'No');\r\n        \r\n        const $element = jQuery(e.currentTarget);\r\n        const $droppable = $element.closest('.droppable');\r\n        const resetRef = StateManager.buildEmplacementReference($droppable.attr('id'));\r\n        \r\n        console.log(\"Reset_Commande_Emplacement_Page_Web:\", resetRef);\r\n        \r\n        \/\/ \u2705 Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        $droppable.find('.ReserverContainer').hide();\r\n        \r\n        var _rankForDel = $droppable.attr('id') || StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n        if (StateManager.get(\"AchatEspaceCall\") === 'Yes') {\r\n            MessageManager.sendDelAdToParent({\r\n                Commande_Emplacement_Page_Web: resetRef,\r\n                Rank_Emplacement_Page_Web: _rankForDel,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n        } else {\r\n            window.processdataDelAd({\r\n                Commande_Emplacement_Page_Web: resetRef,\r\n                Rank_Emplacement_Page_Web: _rankForDel,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n        }\r\n        \r\n        \/\/ \u2705 v1.16.0 : Appeler RestoreadSpaceTemplateLocal directement (accessible dans ce scope)\r\n        RestoreadSpaceTemplateLocal(e.currentTarget);\r\n        \r\n        window.FonctionCroixResetAnnonce(e.currentTarget);\r\n        \r\n        \/\/ \u2705 v2.1.1 : Sauf popup\r\n        var formatWasSelected = sessionStorage.getItem('FormatSelect') \r\n            || sessionStorage.getItem('Commande_Format_Transmis')\r\n            || $droppable.data('kitFormatSelect');\r\n        \r\n        if (sessionStorage.getItem('PopUpChoice') !== 'Yes' && (formatWasSelected || sessionStorage.getItem('Formatchoisi') === 'Yes')) {\r\n            sessionStorage.setItem('Formatchoisi', 'Yes');\r\n            console.log('\u2705 Formatchoisi forc\u00e9 \u00e0 Yes apr\u00e8s reset');\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.6 : Remettre \u00e0 jour le titre format et r\u00e9afficher la checkbox R\u00e9server\r\n        setTimeout(() => {\r\n            FormatUIManager.updateTitleColor($droppable);\r\n            FormatUIManager.updateReserverCheckboxState($droppable);\r\n            \r\n            \/\/ \u2705 R\u00e9afficher le .ReserverContainer statique\r\n            $droppable.find('.ReserverContainer').show();\r\n        }, 150);\r\n    }\r\n};\r\n\r\n\/**\r\n * \u2705 Template pour r\u00e9initialisation des espaces publicitaires (IFRAME)\r\n *\/\r\nvar adSpaceTemplatesLocal = {};\r\n\r\nfunction saveAdSpaceTemplateLocal() {\r\n    var saved = 0;\r\n    jQuery('.droppable').each(function() {\r\n        var droppableId = jQuery(this).attr('id');\r\n        if (!droppableId) return;\r\n        \r\n        \/\/ \u2705 Ne jamais sauvegarder Ele0A (clone temporaire popup, pas un template d'origine)\r\n        if (droppableId === 'Ele0A') return;\r\n        \r\n        \/\/ \u2705 Ne pas r\u00e9-\u00e9craser un template d\u00e9j\u00e0 sauvegard\u00e9\r\n        if (adSpaceTemplatesLocal[droppableId]) return;\r\n        \r\n        \/\/ \u2705 v2.3.4 : Ne pas sauvegarder si template d\u00e9j\u00e0 connu (\u00e9tat propre sauvegard\u00e9)\r\n        \/\/ Le guard hasAd est supprim\u00e9 \u2014 on veut capturer le template le plus t\u00f4t possible\r\n        \/\/ Si le template existe d\u00e9j\u00e0, on ne le r\u00e9\u00e9crase pas\r\n        \/\/ (le guard anti-\u00e9crasement if (adSpaceTemplatesLocal[droppableId]) return; suffit)\r\n        \r\n        var $content = jQuery(this).find('.OrdiMobileConteneurClass').first();\r\n        if ($content.length > 0) {\r\n            adSpaceTemplatesLocal[droppableId] = $content.clone(true, true);\r\n            saved++;\r\n        }\r\n    });\r\n    if (saved > 0) {\r\n        console.log('\u2705 Templates espaces pub sauvegard\u00e9s:', saved, 'espaces -', Object.keys(adSpaceTemplatesLocal));\r\n        return true;\r\n    }\r\n    return false;\r\n}\r\n\r\nfunction RestoreadSpaceTemplateLocal(element) {\r\n    console.log('\ud83d\udd04 RestoreadSpaceTemplateLocal', element);\r\n    \r\n    var $element = jQuery(element);\r\n    var $droppable = $element.closest('.droppable');\r\n    var droppableId = $droppable.attr('id');\r\n    \r\n    \/\/ \u2705 FIX Ele0A : pas de template sauvegard\u00e9 (clone temporaire popup)\r\n    \/\/ \u2192 pas de remplacement DOM, reset visuel direct sur le contenu existant\r\n    var _isEle0A = (droppableId === 'Ele0A');\r\n\r\n    \/\/ \u2705 v1.19.3 : Chercher le template sp\u00e9cifique \u00e0 CET espace (sauf Ele0A)\r\n    if (!_isEle0A) {\r\n        if (!droppableId || !adSpaceTemplatesLocal[droppableId]) {\r\n            if (!saveAdSpaceTemplateLocal()) {\r\n                console.error('\u274c Template non disponible');\r\n                return false;\r\n            }\r\n            if (!adSpaceTemplatesLocal[droppableId]) {\r\n                console.error('\u274c Template non trouv\u00e9 pour', droppableId);\r\n                return false;\r\n            }\r\n        }\r\n    }\r\n    \r\n    var adSpaceElement = $droppable.find('.OrdiMobileConteneurClass').first();\r\n    \r\n    if (!adSpaceElement || !adSpaceElement.length) {\r\n        console.error('\u274c OrdiMobileConteneurClass non trouv\u00e9');\r\n        return false;\r\n    }\r\n    \r\n    var newElement;\r\n    if (_isEle0A) {\r\n        \/\/ Ele0A : pas de clone \u2014 on remet en \u00e9tat le contenu existant directement\r\n        newElement = adSpaceElement;\r\n        console.log('\u2705 [Ele0A] reset visuel direct (pas de template clone)');\r\n        \/\/ \u2705 Vider le contenu du dropzone et restaurer le HTML par d\u00e9faut\r\n        \/\/ (le replaceWith n'ayant pas lieu, l'image d\u00e9pos\u00e9e et le fond blanc restent sinon)\r\n        var $dz0A = $droppable.find('#drop_file_zone_achat');\r\n        $dz0A.empty().html(\r\n            '<div id=\"drag_upload_file_achat\">' +\r\n                '<p class=\"UploadIci\" style=\"color:#FB5E2A;font-weight:600;\">Ici glisser \u2013 d\u00e9poser ou<br>t\u00e9l\u00e9charger une annonce<\/p>' +\r\n            '<\/div>'\r\n        );\r\n        \/\/ Restaurer le fond bleu #9FC5F3 et retirer les styles d'annonce upload\u00e9e\r\n        $droppable.find('#UploadFileConteneur').css({\r\n            'background-color': '#9FC5F3',\r\n            'border': '',\r\n            'box-sizing': ''\r\n        });\r\n        $droppable.find('.HTMLUploadfileConteneur').css({\r\n            'box-shadow': '',\r\n            'background-color': '',\r\n            'border': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': '',\r\n            'overflow': '',\r\n            'height': '',\r\n            'max-height': ''\r\n        });\r\n        \/\/ Masquer la croix et le titre d'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle, #CroixResetAnnonce, .CroixResetAnnonceContainer, .DeplaceAnnonce').hide();\r\n        $droppable.removeAttr('data-via-ad-loaded').removeAttr('data-from-miniature');\r\n        console.log('\u2705 [Ele0A] dropzone vid\u00e9 + fond restaur\u00e9');\r\n    } else {\r\n        \/\/ \u2705 v1.19.3 : Cloner le template SP\u00c9CIFIQUE \u00e0 cet espace (pas le premier)\r\n        newElement = adSpaceTemplatesLocal[droppableId].clone(true, true);\r\n        console.log('\u2705 Template utilis\u00e9 pour', droppableId);\r\n        adSpaceElement.replaceWith(newElement);\r\n        \/\/ \u2705 v2.4.12 : Effacer data-via-ad-loaded (sinon selectEspaceActif masque .ReserverContainer)\r\n        $droppable.removeAttr('data-via-ad-loaded').removeAttr('data-from-miniature');\r\n        if (window.outerWidth < 1000) {\r\n            newElement.css({'margin-top': '-25px', 'bottom': '0px'});\r\n        }\r\n    }\r\n    \r\n    \/\/ D\u00e9cocher la case Envoi diff\u00e9r\u00e9 si elle existe\r\n    newElement.find('input[name*=\"EnvoiUlterieur\"]').prop('checked', false);\r\n    \r\n    \/\/ \u2705 D\u00e9cocher la checkbox \"R\u00e9server\"\r\n    newElement.find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').prop('checked', false);\r\n    \r\n    \/\/ Reset l'\u00e9tat EnvoiUlterieur\r\n    StateManager.set('EnvoiUlterieur', 'false');\r\n    \r\n    \/\/ \u2705 v1.19.3 : R\u00e9initialiser TOUS les styles inline des conteneurs parents modifi\u00e9s pendant le d\u00e9p\u00f4t\r\n    if ($droppable.length) {\r\n        \/\/ \u2705 v2.0.9 : Restaurer les marges de l'algorithme de positionnement (sauvegard\u00e9es par styleUploadedAd)\r\n        var origMt = $droppable.data('orig-mt');\r\n        $droppable.css({\r\n            'margin-top': (origMt !== undefined) ? origMt + 'px' : '',\r\n            'margin-bottom': '',\r\n            'margin-left': '',\r\n            'margin-right': ''\r\n        });\r\n        \/\/ \u2705 v2.0.11 : Cleanup event namespace docpreview\r\n        $droppable.off('click.docpreview');\r\n        \r\n        \/\/ Reset .OrdiMobileConteneurClass margins\r\n        var $container = $droppable.find('.OrdiMobileConteneurClass');\r\n        var origMb = $container.data('orig-mb');\r\n        $container.css({\r\n            'margin-top': '',\r\n            'margin-bottom': (origMb !== undefined) ? origMb + 'px' : ''\r\n        });\r\n        \r\n        \/\/ Reset .HTMLUploadfileConteneur (set by styleUploadedAd: box-shadow inset, background-color:white)\r\n        $droppable.find('.HTMLUploadfileConteneur').css({\r\n            'border': '',\r\n            'box-shadow': '',\r\n            'outline': '',\r\n            'outline-offset': '',\r\n            'background-color': '',\r\n            'margin-top': '',\r\n            'margin-bottom': '',\r\n            'min-height': '',\r\n            'overflow': '',\r\n            'padding': '',\r\n            'position': ''\r\n        });\r\n        $droppable.find('.via-green-border-overlay').remove();\r\n        \r\n        \/\/ \u2705 Restaurer pointer-events sur OrdiMobileConteneurClass et ses enfants\r\n        $droppable.find('.OrdiMobileConteneurClass').css('pointer-events', '');\r\n        $droppable.find('#CroixResetAnnonce').css({'pointer-events': '', 'position': '', 'z-index': ''});\r\n        \/\/ \u2705 v2.4.5 : Reset margin-right Ele0A (pos\u00e9 par adjustMobileLayout)\r\n        var _croixContReset = $droppable.find('.CroixResetAnnonceContainer')[0];\r\n        if (_croixContReset) { _croixContReset.style.removeProperty('margin-right'); _croixContReset.style.removeProperty('margin-top'); }\r\n        $droppable.find('#PopUpMessageAchattest').css('pointer-events', '');\r\n        \r\n        \/\/ \u2705 v2.0.9 : Restaurer le scale(1.4) sur .UploadFileConteneur (r\u00e9duit \u00e0 scale(1) par styleUploadedAd sur mobile)\r\n        $droppable.find('.UploadFileConteneur').css({\r\n            'transform': '',\r\n            'transform-origin': ''\r\n        });\r\n        \r\n        \/\/ Reset #UploadFileConteneur - Restaurer le fond bleu #9FC5F3 + retirer liser\u00e9 envoi diff\u00e9r\u00e9\r\n        $droppable.find('#UploadFileConteneur').css({\r\n            'width': '',\r\n            'background-color': '#9FC5F3',\r\n            'border': '',\r\n            'box-sizing': ''\r\n        });\r\n        \r\n        \/\/ Reset .ToBeHidden (set by adjustDesktopLayout: top:105px, min-height:300px + overflow mobile)\r\n        $droppable.closest('.ToBeHidden').css({\r\n            'top': '',\r\n            'min-height': '',\r\n            'overflow': ''\r\n        });\r\n        \r\n        \/\/ Reset overflow sur le parent du droppable (set by adjustDesktopLayout)\r\n        $droppable.parent().css('overflow', '');\r\n        \r\n        \/\/ \u2705 v1.19.5 : Gestion device-specific pour les textes\r\n        var isDesktop = window.outerWidth >= 1000;\r\n        \r\n        if (isDesktop) {\r\n            \/\/ Desktop : cacher les textes mobiles, afficher UploadIci\r\n            $droppable.find('.TexteMobile').hide();\r\n            $droppable.find('.TexteMobileAnnonce').hide();\r\n            $droppable.find('.TexteMobileAjoutAnnonce').hide();\r\n            $droppable.find('.UploadIci').show();\r\n        } else {\r\n            \/\/ Mobile : afficher TexteMobileAnnonce\r\n            $droppable.find('.TexteMobileAnnonce').show();\r\n        }\r\n        \r\n        \/\/ R\u00e9-afficher les \u00e9l\u00e9ments masqu\u00e9s pendant l'upload\r\n        $droppable.find('.PositionEspacePublicitaireContainer').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireDisponibiliteConteneur').show();\r\n        $droppable.find('.PositionEspacePublicitaire, .ReferenceEspacePublicitaire, .ChoisirEspacePublicitaireDisponibiliteConteneur > div > .elementor-widget-text-editor').show();\r\n        $droppable.find('.AdDroppedTextNotDisplayed').hide();\r\n        \/\/ \u2705 v2.4.5 : Ele0A + PopUpChoice=Yes \u2192 ne pas r\u00e9-afficher le titre si format d\u00e9j\u00e0 s\u00e9lectionn\u00e9\r\n        var _skipTitre = (sessionStorage.getItem('PopUpChoice') === 'Yes' && $droppable.attr('id') === 'Ele0A');\r\n        $droppable.find('.SelectionFormatTitreBlanc').hide();\r\n        if (!_skipTitre) {\r\n            $droppable.find('.SelectionFormatTitre').show();\r\n        }\r\n        $droppable.find('span.ClassHdpCdp, .ClassRefEsp').show();\r\n        $droppable.find('.EspPubFormatMainContainer').show();\r\n        $droppable.find('.EspPubFormatListe').show();\r\n        $droppable.find('.ChoisirEspacePublicitaireClass').show();\r\n        $droppable.find('.GlisserDeposerConteneur').show();\r\n        $droppable.find('.OUClass').show();\r\n        $droppable.find('.PositionReference').show();\r\n        $droppable.find('.ClassHdpCdp').show();\r\n        $droppable.find('.ClassRefEsp').show();\r\n        $droppable.find('.EnvoiUlterieurTexte').show();\r\n        $droppable.find('.EnvoiUlterieurContainer').show();\r\n        \r\n        \/\/ \u2705 v1.19.5 : R\u00e9afficher le .ReserverContainer (bouton Elementor statique)\r\n        $droppable.find('.ReserverContainer').show();\r\n        newElement.find('.ReserverContainer').show();\r\n        \r\n        \/\/ Masquer les \u00e9l\u00e9ments sp\u00e9cifiques \u00e0 l'annonce upload\u00e9e\r\n        $droppable.find('.AdUploadedTitle, #CroixResetAnnonce, .CroixResetAnnonceContainer, .DeplaceAnnonce').hide();\r\n        $droppable.find('#CroixResetAnnonce').css({'position': '', 'z-index': ''});\r\n        $droppable.find('.RefEspacePublicitaire').hide();\r\n        \r\n        \/\/ Supprimer le bouton \"R\u00e9server\" dynamique\r\n        $droppable.find('.reserver-dynamic-container').remove();\r\n        $droppable.next('.reserver-dynamic-container').remove();\r\n        \r\n        \/\/ \u2705 v1.19.6 : Restaurer le format s\u00e9lectionn\u00e9 visuellement\r\n        \/\/ Chercher le format dans plusieurs sources possibles\r\n        var formatSelect = sessionStorage.getItem('FormatSelect') \r\n            || sessionStorage.getItem('Commande_Format_Transmis')\r\n            || $droppable.data('kitFormatSelect')\r\n            || '';\r\n        \r\n        var formatchoisi = sessionStorage.getItem('Formatchoisi');\r\n        console.log('\ud83d\udcd0 Format \u00e0 restaurer:', formatSelect, '| Formatchoisi:', formatchoisi);\r\n        \r\n        \/\/ D'abord reset tous les formats visuellement (sur newElement ET $droppable)\r\n        var $allFormats = newElement.find('.EspPubFormatContainer').add($droppable.find('.EspPubFormatContainer'));\r\n        $allFormats.css({\r\n            'background-color': '',\r\n            'border': ''\r\n        });\r\n        newElement.find('.EspPubFormat').add($droppable.find('.EspPubFormat')).css({\r\n            'color': ''\r\n        });\r\n        \r\n        \/\/ Si un format \u00e9tait s\u00e9lectionn\u00e9 (via sessionStorage OU visuellement avant)\r\n        \/\/ \u2705 v2.1.1 : Sauf popup\r\n        if ((formatSelect || formatchoisi === 'Yes') && sessionStorage.getItem('PopUpChoice') !== 'Yes') {\r\n            var formatFound = false;\r\n            \r\n            if (formatSelect) {\r\n                \/\/ \u2705 v2.1.1 : Normaliser via NFD (plus fiable que les replace manuels)\r\n                var formatLower = formatSelect.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase().replace(\/ \/g, '');\r\n                \r\n                \/\/ Appliquer sur newElement ET $droppable pour \u00eatre s\u00fbr\r\n                var $allContainers = newElement.find('.EspPubFormatContainer').add($droppable.find('.EspPubFormatContainer'));\r\n                \r\n                $allContainers.each(function() {\r\n                    var className = this.className.normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').toLowerCase();\r\n                    \r\n                    if (className.includes(formatLower)) {\r\n                        jQuery(this).css({'background-color': '#ffffff'});\r\n                        jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                        formatFound = true;\r\n                        \/\/ \u2705 v2.4.12 : M\u00e9moriser le format restaur\u00e9 (lu par selectEspaceActif pour re-surligner apr\u00e8s reset global)\r\n                        $droppable.attr('data-restored-format', formatSelect);\r\n                        console.log('\u2705 Format restaur\u00e9 visuellement:', formatSelect, '- classe:', this.className);\r\n                    }\r\n                });\r\n            }\r\n            \r\n            \/\/ \u2705 IMPORTANT : Pr\u00e9server Formatchoisi = Yes pour permettre l'upload\r\n            sessionStorage.setItem('Formatchoisi', 'Yes');\r\n            console.log('\u2705 Formatchoisi maintenu \u00e0 Yes');\r\n            \r\n            \/\/ Basculer les titres format (sur newElement ET $droppable)\r\n            newElement.find('.SelectionFormatTitre').hide();\r\n            newElement.find('.SelectionFormatTitreBlanc').show();\r\n            $droppable.find('.SelectionFormatTitre').hide();\r\n            $droppable.find('.SelectionFormatTitreBlanc').show();\r\n        }\r\n    }\r\n    \r\n    \/\/ \u2705 v1.19.2 : Relancer InitLoadedPage pour recalculer positions et tailles\r\n    setTimeout(function() {\r\n        if (typeof window.InitLoadedPage === 'function') {\r\n            window.InitLoadedPage();\r\n        }\r\n        \r\n        \/\/ \u2705 v1.19.6 : R\u00e9attacher les MutationObservers sur les formats\r\n        if (typeof FormatUIManager !== 'undefined' && FormatUIManager.observeFormatChanges) {\r\n            FormatUIManager.observeFormatChanges();\r\n        }\r\n    }, 100);\r\n    \r\n    console.log('\u2705 Espace publicitaire r\u00e9initialis\u00e9');\r\n    return true;\r\n}\r\n\r\n\/\/ \u2705 Exposer pour appel depuis yearbook-media.js (suppression popup mode=popup)\r\nwindow.RestoreadSpaceTemplateLocal = RestoreadSpaceTemplateLocal;\r\n\r\nwindow.verifierAffichageMsgSelectEspaceLocal = function() {\r\n    const formatChoisi = StateManager.get('Formatchoisi') === 'Yes';\r\n    const fileReceived = StateManager.get('FileReceived');\r\n    const envoiUlterieur = StateManager.get('EnvoiUlterieur');\r\n    \r\n    var dateDebut, dateFin, pays;\r\n    try {\r\n        dateDebut = window.parent.$('#form-field-DebutCampagne').val();\r\n        dateFin = window.parent.$('#form-field-FinCampagne').val();\r\n        pays = window.parent.$('#form-field-Nationalite_Societe').val();\r\n    } catch(e) {\r\n        jQuery('#MsgSelectEspace').hide();\r\n        return;\r\n    }\r\n    \r\n    if (!dateDebut || !dateFin || !pays || !formatChoisi) {\r\n        jQuery('#MsgSelectEspace').hide();\r\n        return;\r\n    }\r\n    \r\n    if (fileReceived !== 'Yes') {\r\n        if (envoiUlterieur !== 'true') {\r\n            jQuery('#MsgSelectEspace').show();\r\n        } else {\r\n            jQuery('#MsgSelectEspace').hide();\r\n        }\r\n    } else {\r\n        jQuery('#MsgSelectEspace').hide();\r\n    }\r\n};\r\n\r\n\/\/ Sauvegarder les templates au chargement (apr\u00e8s rendu complet Elementor)\r\njQuery(document).ready(function() {\r\n    \/\/ \u2705 v1.19.3 : D\u00e9lai augment\u00e9 + double sauvegarde pour garantir les bonnes dimensions\r\n    setTimeout(saveAdSpaceTemplateLocal, 3000);\r\n    setTimeout(saveAdSpaceTemplateLocal, 6000);\r\n    \/\/ \u2705 v2.3.4 : Sauvegarde imm\u00e9diate d\u00e8s que la page est pr\u00eate dans l'iframe\r\n    \/\/ (avant toute interaction utilisateur)\r\n    setTimeout(saveAdSpaceTemplateLocal, 100);\r\n    setTimeout(saveAdSpaceTemplateLocal, 500);\r\n});\r\n\r\n\/\/ \u2705 v2.3.4 : Forcer sauvegarde \u00e0 la r\u00e9ception de elementsRemoved (espaces visibles + vierges)\r\nwindow.addEventListener('message', function(e) {\r\n    if (e.data && e.data.type === 'elementsRemoved') {\r\n        \/\/ Les espaces sont vierges \u00e0 ce stade \u2192 sauvegarder imm\u00e9diatement\r\n        setTimeout(saveAdSpaceTemplateLocal, 50);\r\n        setTimeout(saveAdSpaceTemplateLocal, 300);\r\n    }\r\n});\r\n\r\n\/**\r\n * Fonction helper pour le d\u00e9p\u00f4t r\u00e9dactionnel\r\n *\/\r\nfunction RedactionnelDepose() {\r\n    jQuery('#Tariftobedisplayed').html('-');\r\n    jQuery('#TarifDataStep3').html('\u00e0 choisir').css({'color': '#FB5E2A'});\r\n    jQuery('#FormatDataStep3').html('\u00e0 choisir').css({'color': '#FB5E2A'});\r\n    jQuery('#ListePaysDirect, #ListeThemeDirect, .ListeArticles, #PageAfficheeMessage').hide();\r\n    StateManager.set(\"PositionAnnonceSelection\", 'Yes');\r\n}\r\n\r\n\/**\r\n * Exposition des fonctions globales n\u00e9cessaires\r\n *\/\r\nwindow.uploadFile_achat = (e) => DropHandler.handleDrop(e);\r\nwindow.fileExplorer_achat = (e) => FileExplorer.open(e);\r\nwindow.ajaxFileUpload_achat = (fileObj, dropZone) => UploadManager.handleFileUpload(fileObj, dropZone);\r\nwindow.ActivatesendDataToParent = (dropZone) => UploadManager.activateSendDataToParent(dropZone);\r\n\/\/ \u2705 v2.3.4 : Exposer FormatUIManager pour appel depuis Entete.txt (selectEspaceActif)\r\nwindow.FormatUIManagerRef = FormatUIManager;\r\n\r\n\/**\r\n * Initialisation de l'application\r\n *\/\r\njQuery(document).ready(() => {\r\n    StateManager.init();\r\n    ScrollHelper.init();\r\n    DragDropManager.init();\r\n    FormatUIManager.init();\r\n    \r\n    if (UIManager.isMobile()) {\r\n        UIManager.initMobileUI();\r\n    } else {\r\n        UIManager.initDesktopUI();\r\n    }\r\n    \r\n    jQuery(document).on('click', '#CroixResetAnnonce', (e) => AdResetHandler.handle(e));\r\n    \r\n    \/\/ \u2705 Clic sur le texte du label \u2192 toggle manuel de la checkbox du m\u00eame conteneur\r\n    jQuery(document).on('click', '.reserver-dynamic-label', function(e) {\r\n        e.preventDefault();\r\n        e.stopPropagation();\r\n        const $cb = $(this).closest('.reserver-dynamic-option, .reserver-dynamic-container').find('.reserver-dynamic-checkbox');\r\n        if ($cb.length) {\r\n            $cb.prop('checked', !$cb.prop('checked')).trigger('change');\r\n        }\r\n    });\r\n\r\n    \/\/ \u2705 CHECKBOX \"R\u00e9server cet espace publicitaire\" \u2014 VALIDATION ET ENVOI DES DONN\u00c9ES\r\n    \/\/ \u2705 v2.4.13 : iOS touchend\r\n    \/\/ \u2705 v2.4.13 : Mobile \u2014 \u00e9couter touchend sur input ET click\/touchend sur label\r\n    jQuery(document).on('touchend', 'input[name=\"form_fields[ReserverEspacePublicitaire]\"]', function() {\r\n        if (this._viaResTouch) { return; }\r\n        this._viaResTouch = true;\r\n        var _self = this;\r\n        setTimeout(function() { _self._viaResTouch = false; }, 500);\r\n        setTimeout(function() { jQuery(_self).trigger('change'); }, 100);\r\n    });\r\n    jQuery(document).on('touchend click', '.elementor-field-group-ReserverEspacePublicitaire label, .reserver-dynamic-label, .reserver-dynamic-option label', function(e) {\r\n        \/\/ Trouver l'input associ\u00e9\r\n        var $input = jQuery(this).closest('.elementor-field-option, .reserver-dynamic-option').find('input[name=\"form_fields[ReserverEspacePublicitaire]\"]');\r\n        if (!$input.length) { $input = jQuery(this).siblings('input[name=\"form_fields[ReserverEspacePublicitaire]\"]'); }\r\n        if (!$input.length) { $input = jQuery('input[name=\"form_fields[ReserverEspacePublicitaire]\"]').first(); }\r\n        if ($input.length) {\r\n            if (e.type === 'touchend') { e.preventDefault(); }\r\n            var _wasChecked = $input.prop('checked');\r\n            $input.prop('checked', !_wasChecked);\r\n            setTimeout(function() {\r\n                $input.trigger('change');\r\n            }, 50);\r\n        }\r\n    });\r\n    jQuery(document).on('change', 'input[name=\"form_fields[ReserverEspacePublicitaire]\"]', function(e) {\r\n        const $checkbox = $(this);\r\n        let $droppable = $checkbox.closest('.droppable');\r\n        if (!$droppable.length) {\r\n            $droppable = $checkbox.closest('.reserver-dynamic-container').prev('.droppable');\r\n        }\r\n        \/\/ \u2705 v2.4.13 : Fallback mobile \u2014 checkbox dans body > .reserver-dynamic-container[data-droppable-id]\r\n        if (!$droppable.length) {\r\n            const $dynContainer = $checkbox.closest('.reserver-dynamic-container');\r\n            const _droppableId = $dynContainer.attr('data-droppable-id') || '';\r\n            if (_droppableId) {\r\n                $droppable = $('#' + _droppableId);\r\n            }\r\n        }\r\n        \/\/ Dernier recours : utiliser le rank en sessionStorage\r\n        if (!$droppable.length) {\r\n            const _rankFallback = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            if (_rankFallback) { $droppable = $('#' + _rankFallback); }\r\n        }\r\n        \r\n        \/\/ Si on d\u00e9coche\r\n        if (!$checkbox.is(':checked')) {\r\n            console.log('\u2610 Checkbox \"R\u00e9server\" d\u00e9coch\u00e9e');\r\n            \/\/ \u2705 Mettre \u00e0 jour le label\r\n            const $lbl = $checkbox.closest('.reserver-dynamic-option, .elementor-field-option').find('.reserver-dynamic-label, label').not('input');\r\n            $lbl.text('R\u00e9server cet espace publicitaire').css('color', '');\r\n            \/\/ \u2705 Notifier le parent pour d\u00e9-r\u00e9server l'item dans le r\u00e9cap\r\n            const _rankDecoche = $droppable.attr('id') || StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            const _emplacementDecoche = StateManager.buildEmplacementReference(_rankDecoche);\r\n            MessageManager.sendToParent('annulationReservation', {\r\n                Rank_Emplacement_Page_Web: _rankDecoche,\r\n                Commande_Emplacement_Page_Web: _emplacementDecoche,\r\n                LoadedPageUrl: window.location.href\r\n            });\r\n            \/\/ \u2705 v2.4.5 : M\u00e9moriser que ce rank a \u00e9t\u00e9 explicitement d\u00e9coch\u00e9\r\n            StateManager.set('_reserverDecoche_' + _rankDecoche, 'Yes');\r\n            console.log('\ud83d\udce4 annulationReservation envoy\u00e9 \u2192 parent | rank:', _rankDecoche, '| emplacement:', _emplacementDecoche);\r\n            return;\r\n        }\r\n        \r\n        \/\/ \u2705 V\u00e9rifier les conditions : format s\u00e9lectionn\u00e9 ET (fichier d\u00e9pos\u00e9 OU envoi diff\u00e9r\u00e9)\r\n        const hasFormat = FormatUIManager.hasSelectedFormat($droppable);\r\n        const hasFile = StateManager.get('FileReceived') === 'Yes';\r\n        const hasEnvoiDiffere = $droppable.find('input[name*=\"EnvoiUlterieur\"]:checked').length > 0;\r\n        \r\n        console.log('\ud83d\udd0d Checkbox \"R\u00e9server\" - Validation:', { hasFormat, hasFile, hasEnvoiDiffere });\r\n        \r\n        if (!hasFormat) {\r\n            \/\/ \u2705 Si un fichier est d\u00e9j\u00e0 d\u00e9pos\u00e9 \u2192 d\u00e9duire le format depuis l'extension (ne pas bloquer)\r\n            if (hasFile) {\r\n                const _uploadedName = StateManager.get('Upload_File_Name') || '';\r\n                const _ext = _uploadedName.split('.').pop().toLowerCase();\r\n                const _fileType = FileManager.getFileType(_ext);\r\n                let _deducedFormat = '';\r\n                if (_fileType === 'video') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Video' : 'Vid\u00e9o';\r\n                } else if (_fileType === 'image') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Banner' : 'Banni\u00e8re';\r\n                } else if (_fileType === 'document') {\r\n                    _deducedFormat = sessionStorage.getItem('SiteLangue') === 'EN' ? 'Press release' : 'Communiqu\u00e9';\r\n                }\r\n                if (_deducedFormat) {\r\n                    StateManager.set('Commande_Format_Transmis', _deducedFormat);\r\n                    StateManager.set('FormatSelect', _deducedFormat);\r\n                    StateManager.set('Formatchoisi', 'Yes');\r\n                    console.log('\u2705 Format d\u00e9duit depuis extension (' + _ext + '):', _deducedFormat);\r\n                    \/\/ Continuer vers l'envoi (pas de return false)\r\n                } else {\r\n                    e.preventDefault();\r\n                    $checkbox.prop('checked', false);\r\n                    FormatUIManager.flashTitle($droppable);\r\n                    console.log('\u274c R\u00e9servation bloqu\u00e9e : format non d\u00e9ductible depuis extension:', _ext);\r\n                    return false;\r\n                }\r\n            } else {\r\n                e.preventDefault();\r\n                $checkbox.prop('checked', false);\r\n                FormatUIManager.flashTitle($droppable);\r\n                console.log('\u274c R\u00e9servation bloqu\u00e9e : aucun format s\u00e9lectionn\u00e9');\r\n                return false;\r\n            }\r\n        }\r\n        \r\n        if (!hasFile && !hasEnvoiDiffere) {\r\n            e.preventDefault();\r\n            $checkbox.prop('checked', false);\r\n            console.log('\u274c R\u00e9servation bloqu\u00e9e : ni annonce d\u00e9pos\u00e9e ni envoi diff\u00e9r\u00e9');\r\n            return false;\r\n        }\r\n        \r\n        \/\/ \u2705 Conditions remplies \u2014 Pr\u00e9parer et envoyer les donn\u00e9es\r\n        console.log('\u2705 Checkbox \"R\u00e9server\" valid\u00e9e \u2014 envoi des donn\u00e9es');\r\n        \r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.setMultiple({\r\n            \"sendDataToParentFlag\": \"Yes\",\r\n            \"Formatchoisi\": \"Yes\",\r\n            \"Rank_Emplacement_Page_Web\": rankId,\r\n            \"Commande_Emplacement_Page_Web\": StateManager.buildEmplacementReference(rankId),\r\n            \"LoadedPageUrl\": window.location.href,\r\n            \/\/ \u2705 v2.3.0 : Forcer avant l'envoi \u2014 le setTimeout(4000) dans activateSendDataToParent\r\n            \/\/ arrive trop tard sur le 1er clic \u2192 AddNewRefInVosCampagnes restait null\r\n            \"AddNewRefInVosCampagnes\": \"Yes\"\r\n        });\r\n        \r\n        \/\/ \u2705 D\u00e9clencher l'envoi des donn\u00e9es via activateSendDataToParent\r\n        const $dropZone = $droppable.find('#drop_file_zone_achat');\r\n        UploadManager.activateSendDataToParent($dropZone);\r\n    });\r\n    \r\n    \/\/ G\u00c9RER \"Envoi diff\u00e9r\u00e9\" \u2014 marquer l'\u00e9tat sans envoyer (c'est \"R\u00e9server\" qui envoie)\r\n    \/\/ \u2705 v2.4.13 : iOS touchend\r\n    jQuery(document).on('touchend', 'input[name*=\"EnvoiUlterieur\"]', function() {\r\n        if (this._viaTouch) { return; }\r\n        this._viaTouch = true;\r\n        var _self = this;\r\n        setTimeout(function() { _self._viaTouch = false; }, 500);\r\n        setTimeout(function() { jQuery(_self).trigger('change'); }, 100);\r\n    });\r\n    jQuery(document).on('change', 'input[name*=\"EnvoiUlterieur\"]', function(e) {\r\n        const $checkbox = $(this);\r\n        let $droppable = $checkbox.closest('.droppable');\r\n        \/\/ \u2705 v2.4.13 : Fallback mobile\r\n        if (!$droppable.length) {\r\n            const $dynContainer = $checkbox.closest('.reserver-dynamic-container');\r\n            const _droppableId = $dynContainer.attr('data-droppable-id') || '';\r\n            if (_droppableId) { $droppable = $('#' + _droppableId); }\r\n        }\r\n        if (!$droppable.length) {\r\n            const _rankFallback = StateManager.get('Rank_Emplacement_Page_Web') || '';\r\n            if (_rankFallback) { $droppable = $('#' + _rankFallback); }\r\n        }\r\n  \r\n        \/\/ Si on d\u00e9coche\r\n        if (!$checkbox.is(':checked')) {\r\n            StateManager.set('EnvoiUlterieur', 'false');\r\n            \r\n            if (typeof window.verifierAffichageMsgSelectEspaceLocal === 'function') {\r\n                window.verifierAffichageMsgSelectEspaceLocal();\r\n            }\r\n            \r\n            \/\/ Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server\r\n            FormatUIManager.updateReserverCheckboxState($droppable);\r\n            return;\r\n        }\r\n        \r\n        \/\/ Si on coche, masquer le message\r\n        jQuery('#MsgSelectEspace').hide();\r\n    \r\n        \/\/ V\u00e9rifier si un format est s\u00e9lectionn\u00e9\r\n        const hasSelectedFormat = FormatUIManager.hasSelectedFormat($droppable);\r\n        \r\n        if (!hasSelectedFormat) {\r\n            e.preventDefault();\r\n            $checkbox.prop('checked', false);\r\n            FormatUIManager.flashTitle($droppable);\r\n            return false;\r\n        }\r\n        \r\n        \/\/ \u2705 FORMAT OK \u2014 Marquer l'\u00e9tat envoi diff\u00e9r\u00e9 (sans envoyer les donn\u00e9es)\r\n        const rankId = $droppable.attr('id');\r\n        \r\n        StateManager.setMultiple({\r\n            \"EnvoiUlterieur\": 'true',\r\n            \"Rank_Emplacement_Page_Web\": rankId,\r\n            \"Commande_Emplacement_Page_Web\": StateManager.buildEmplacementReference(rankId),\r\n            \"LoadedPageUrl\": window.location.href,\r\n            \"FileReceived\": \"No\",\r\n            \"FullPathAdFile\": '',\r\n            \"Upload_File_Name\": '',\r\n            \"Formatchoisi\": 'Yes'\r\n        });\r\n        \r\n        console.log('\ud83d\udcdd Envoi diff\u00e9r\u00e9 coch\u00e9 \u2014 en attente de validation via checkbox \"R\u00e9server\"');\r\n        \r\n        \/\/ \u2705 Mettre \u00e0 jour l'\u00e9tat de la checkbox R\u00e9server (maintenant activable)\r\n        FormatUIManager.updateReserverCheckboxState($droppable);\r\n    });\r\n\r\n    \/\/ \u2705 v2.2.0 : Bouton \"Cr\u00e9ation\" dans espace publicitaire \u2192 Kit Ad Creator dans le parent\r\n    jQuery(document).on('click', '.FormatIdCreation', function(e) {\r\n        e.preventDefault();\r\n        var $btn = jQuery(this);\r\n        var isActive = $btn.data('creationActive') === true;\r\n\r\n        if (isActive) {\r\n            \/\/ D\u00e9sactiver\r\n            $btn.data('creationActive', false);\r\n            $btn.find('.EspPubFormat').css({'color': '#ffffff'});\r\n            $btn.css({'background-color': 'transparent'});\r\n            MessageManager.sendToParent('closeAdCreatorFromIframe', {});\r\n            console.log('\ud83c\udfa8 Cr\u00e9ation iframe \u2192 toggle OFF, fermeture popup parent');\r\n        } else {\r\n            \/\/ Activer : texte vert sur fond blanc\r\n            $btn.data('creationActive', true);\r\n            $btn.find('.EspPubFormat').css({'color': '#37D900'});\r\n            $btn.css({'background-color': '#ffffff'});\r\n            var formatSelect = sessionStorage.getItem('FormatSelect') || '';\r\n            var formatTransmis = sessionStorage.getItem('Commande_Format_Transmis') || '';\r\n            \/\/ \u2705 v2.2.1 : Envoyer aussi Commande_Format_Transmis (format cliqu\u00e9 dans l'iframe, sans accent)\r\n            var _rankKit = $btn.closest('.droppable').attr('id') || sessionStorage.getItem('Rank_Emplacement_Page_Web') || '';\r\n            var _cSite = sessionStorage.getItem('codeSite') || '';\r\n            var _cPage = sessionStorage.getItem('codePage') || '';\r\n            var _sfxKit = _rankKit.replace('Ele', '');\r\n            var _emplKit = (_cSite && _cPage && _sfxKit) ? (_cSite + _cPage + 'L' + _sfxKit) : (sessionStorage.getItem('Commande_Emplacement_Page_Web') || '');\r\n            MessageManager.sendToParent('openAdCreatorFromIframe', { formatSelect: formatSelect, formatTransmis: formatTransmis, rankId: _rankKit, emplacement: _emplKit });\r\n            console.log('\ud83c\udfa8 Cr\u00e9ation iframe \u2192 toggle ON (FormatSelect:', formatSelect, '| Commande_Format_Transmis:', formatTransmis, ')');\r\n        }\r\n    });\r\n\r\n    \/\/ \u2705 v2.2.0 : Messages depuis le parent concernant le bouton Cr\u00e9ation\r\n    window.addEventListener('message', function(event) {\r\n        var msg = event.data;\r\n        if (!msg) return;\r\n\r\n        \/\/ \u2705 v2.2.1 : Fournir la position du titre R\u00e9server pour positionner la miniature\r\n        if (msg.type === 'getReserverLabelRect') {\r\n            var $label = jQuery('.reserver-dynamic-label').first();\r\n            if ($label.length) {\r\n                var r = $label[0].getBoundingClientRect();\r\n                var iframeScale = (window.outerWidth > 1000) ? 0.75 : 0.80; \/\/ \u2705 v2.4.12 : 0.85 \u2192 0.75 (scale r\u00e9el du parent)\r\n                event.source.postMessage({\r\n                    type: 'reserVeurLabelRectResult',\r\n                    \/\/ Retourner bottom en coordonn\u00e9es iframe internes (non scal\u00e9es)\r\n                    bottom: r.bottom,\r\n                    left: r.left,\r\n                    right: r.right,\r\n                    iframeScale: iframeScale\r\n                }, '*');\r\n            } else {\r\n                event.source.postMessage({ type: 'reserVeurLabelRectResult', bottom: null }, '*');\r\n            }\r\n        }\r\n\r\n        \/\/ Fermeture du popup \u2192 d\u00e9s\u00e9lectionner le bouton Cr\u00e9ation\r\n        if (msg.type === 'adCreatorClosedFromParent') {\r\n            jQuery('.FormatIdCreation').each(function() {\r\n                jQuery(this).data('creationActive', false);\r\n                jQuery(this).find('.EspPubFormat').css({'color': '#ffffff'});\r\n                jQuery(this).css({'background-color': 'transparent'});\r\n            });\r\n            console.log('\ud83c\udfa8 adCreatorClosedFromParent re\u00e7u \u2192 bouton Cr\u00e9ation d\u00e9s\u00e9lectionn\u00e9');\r\n        }\r\n\r\n        \/\/ Restaurer le style du bouton Cr\u00e9ation apr\u00e8s un reset de removeElements\r\n        if (msg.type === 'restoreCreationButton') {\r\n            jQuery('.FormatIdCreation').each(function() {\r\n                if (jQuery(this).data('creationActive') === true) {\r\n                    jQuery(this).find('.EspPubFormat').css({'color': '#37D900'});\r\n                    jQuery(this).css({'background-color': '#ffffff'});\r\n                }\r\n            });\r\n            console.log('\ud83c\udfa8 restoreCreationButton re\u00e7u \u2192 style Cr\u00e9ation restaur\u00e9');\r\n        }\r\n    });\r\n\r\n});\r\n\r\n\/\/ =========================================================================\r\n\/\/ \u2705 Listener kitAdCreated \u2014 annonce cr\u00e9\u00e9e par le Kit overlay (mode=kit)\r\n\/\/ Injecte directement dans l'espace pub identifi\u00e9 par rankId\r\nwindow.addEventListener('message', function(event) {\r\n    var msg = event.data;\r\n    if (!msg || msg.action !== 'kitAdCreated') return;\r\n\r\n    var _rankId = msg.rankId || '';\r\n    var _emplacement = msg.emplacement || '';\r\n    console.log('\ud83c\udfa8 [espace_pub] kitAdCreated re\u00e7u | rankId:', _rankId, '| emplacement:', _emplacement);\r\n\r\n    if (!_rankId) { console.warn('\u26a0\ufe0f [kitAdCreated] rankId manquant'); return; }\r\n\r\n    var $droppable = jQuery('#' + _rankId);\r\n    if (!$droppable.length) { console.warn('\u26a0\ufe0f [kitAdCreated] droppable non trouv\u00e9:', _rankId); return; }\r\n    var $dropZone = $droppable.find('.drop_file_zone_achat_class').first();\r\n    if (!$dropZone.length) { $dropZone = $droppable.find('#drop_file_zone_achat').first(); }\r\n    if (!$dropZone.length) { console.warn('\u26a0\ufe0f [kitAdCreated] dropZone non trouv\u00e9e dans', _rankId); return; }\r\n\r\n    var _dataURL = msg.fullResDataURL || msg.pdfDataURL || null;\r\n    var _filename = msg.filename || 'annonce.png';\r\n    var _isPDF = msg.isPDF || false;\r\n    if (!_dataURL) { console.warn('\u26a0\ufe0f [kitAdCreated] aucune donn\u00e9e image'); return; }\r\n\r\n    var _parts = _dataURL.split(',');\r\n    var _mime = (_parts[0].match(\/:(.*?);\/) || [])[1] || (_isPDF ? 'application\/pdf' : 'image\/png');\r\n    var _bStr = atob(_parts[1]);\r\n    var _bytes = new Uint8Array(_bStr.length);\r\n    for (var _i = 0; _i < _bStr.length; _i++) { _bytes[_i] = _bStr.charCodeAt(_i); }\r\n    var _blob = new Blob([_bytes], { type: _mime });\r\n    \/\/ \u2705 Ajouter extension si absente\r\n    var _MIME_EXT = {'image\/png':'.png','image\/jpeg':'.jpg','image\/jpg':'.jpg','image\/webp':'.webp','application\/pdf':'.pdf'};\r\n    if (_filename.indexOf('.') === -1) { _filename = _filename + (_MIME_EXT[_mime] || (_isPDF ? '.pdf' : '.png')); }\r\n    var _file = new File([_blob], _filename, { type: _mime });\r\n\r\n    \/\/ \u2705 Pr\u00e9parer StateManager\r\n    StateManager.set('Rank_Emplacement_Page_Web', _rankId);\r\n    StateManager.set('Commande_Emplacement_Page_Web', _emplacement);\r\n    StateManager.set('Formatchoisi', 'Yes');\r\n    \/\/ \u2705 Marquer le droppable directement en DOM \u2014 r\u00e9siste \u00e0 l'async, lu par styleUploadedAd\r\n    $droppable[0].setAttribute('data-kit-drop', 'true');\r\n    window._dropFromMiniature = true;\r\n\r\n    console.log('\u2705 [kitAdCreated] \u2192 UploadManager.handleFileUpload | rankId:', _rankId);\r\n    UploadManager.handleFileUpload(_file, $dropZone).then(function() {\r\n        console.log('\u2705 [kitAdCreated] handleFileUpload termin\u00e9');\r\n    }).catch(function(err) {\r\n        window._dropFromMiniature = false;\r\n        $droppable[0].removeAttribute('data-kit-drop');\r\n        console.error('\u274c [kitAdCreated] handleFileUpload erreur:', err);\r\n    });\r\n});\r\n\r\n\/\/ \u2705 v1.17.0 : Listener \"thumbnailDropped\" \u2014 d\u00e9p\u00f4t de l'annonce depuis la miniature\r\n\/\/ =========================================================================\r\n\/**\r\n * Re\u00e7oit le drop de l'image-annonce depuis la miniature dans la page parente.\r\n * Identifie l'espace publicitaire sous le curseur, s\u00e9lectionne cet espace,\r\n * et d\u00e9clenche le flux dataFromIframeEspacePub en mode \"envoi diff\u00e9r\u00e9\"\r\n * (l'utilisateur uploadera le vrai fichier depuis le formulaire de commande).\r\n *\r\n * Coordonn\u00e9es re\u00e7ues : viewport de l'iframe (clientX\/clientY relatifs \u00e0 l'iframe)\r\n *\/\r\nwindow.addEventListener('message', function(event) {\r\n    var msg = event.data;\r\n    if (!msg || msg.action !== 'thumbnailDropped') return;\r\n\r\n    console.log('\ud83d\udce8 thumbnailDropped re\u00e7u \u2014 coords iframe:', msg.xRel, msg.yRel);\r\n\r\n    \/\/ \u2705 v1.19.3 : Corriger les coordonn\u00e9es pour le facteur de scale de l'iframe\r\n    \/\/ \u2705 v2.4.10 : 0.75 = scale appliqu\u00e9 par le PARENT sur l'\u00e9l\u00e9ment iframe (et non 0.85 qui est le scale interne OrdiMobileConteneurClass)\r\n    \/\/ Les coords xRel\/yRel viennent de getBoundingClientRect() sur l'iframe scal\u00e9 \u00e0 0.75 dans le parent \u2192 diviser par 0.75\r\n    var iframeScale = (window.outerWidth > 1000) ? 0.75 : 0.80;\r\n    \/\/ \u2705 v2.4.3 : Si Entete a intercept\u00e9 et pos\u00e9 un redirect vers Ele0A, utiliser ces coords\r\n    var _redirect = window._thumbnailDropRedirect || null;\r\n    window._thumbnailDropRedirect = null;\r\n    \/\/ \u2705 v2.4.4 : Les coords de redirect viennent de getBoundingClientRect() dans l'iframe (espace logique)\r\n    \/\/            \u2192 ne pas re-diviser par iframeScale (d\u00e9j\u00e0 en coords iframe-logiques)\r\n    var xAdjusted = _redirect ? _redirect.xRel : (msg.xRel \/ iframeScale);\r\n    var yAdjusted = _redirect ? _redirect.yRel : (msg.yRel \/ iframeScale);\r\n    if (_redirect) { console.log('\ud83d\udd00 [thumbnailDropped] coords redirig\u00e9es vers Ele0A:', Math.round(xAdjusted), Math.round(yAdjusted)); }\r\n    else { console.log('\ud83d\udcd0 Coords ajust\u00e9es (scale', iframeScale, '):', Math.round(xAdjusted), Math.round(yAdjusted)); }\r\n\r\n    \/\/ 1. Identifier l'espace publicitaire le plus proche du point de drop\r\n    \/\/    \u2705 v1.18.1 : Recherche par distance \u2014 coords \u00e9ventuellement redirig\u00e9es par Entete.txt\r\n    var allDroppables = document.querySelectorAll('.droppable');\r\n    var droppableEl = null;\r\n    var closestDist = Infinity;\r\n\r\n    \/\/ \u2705 v2.4.4 : Guard rect Ele0A \u2014 si PopUpChoice=Yes ET curseur dans le rect d'Ele0A \u2192 forcer\r\n    \/\/            (Ele0A est un popup flottant : son centre peut \u00eatre loin du curseur \u2192 algo distance l'ignore)\r\n    \/\/            Ne force PAS si le drop est hors d'Ele0A \u2192 les autres espaces restent accessibles\r\n    if (sessionStorage.getItem('PopUpChoice') === 'Yes') {\r\n        var _ele0ACheck = document.getElementById('Ele0A');\r\n        if (_ele0ACheck) {\r\n            var _r0A = _ele0ACheck.getBoundingClientRect();\r\n            var _margin = 30;\r\n            var _inR0A = (xAdjusted >= _r0A.left - _margin);\r\n            if (_inR0A) { _inR0A = (xAdjusted <= _r0A.right + _margin); }\r\n            if (_inR0A) { _inR0A = (yAdjusted >= _r0A.top - _margin); }\r\n            if (_inR0A) { _inR0A = (yAdjusted <= _r0A.bottom + _margin); }\r\n            if (_inR0A) {\r\n                droppableEl = _ele0ACheck;\r\n                closestDist = 0;\r\n                console.log('\ud83c\udfaf [thumbnailDropped] Ele0A forc\u00e9 (curseur dans rect Ele0A +30px)');\r\n            }\r\n        }\r\n    }\r\n\r\n    if (!droppableEl) {\r\n        allDroppables.forEach(function(d) {\r\n            var r = d.getBoundingClientRect();\r\n            var dCenterX = r.left + r.width  \/ 2;\r\n            var dCenterY = r.top  + r.height \/ 2;\r\n            var dist = Math.abs(dCenterX - xAdjusted) + Math.abs(dCenterY - yAdjusted);\r\n            if (dist < closestDist) { closestDist = dist; droppableEl = d; }\r\n        });\r\n        \/\/ \u2705 v2.4.3 : Si Entete a d\u00e9tect\u00e9 un drop sur Ele0A \u2192 forcer directement\r\n        if (_redirect) { if (_redirect.forceEle0A) {\r\n            var _ele0AForced = document.getElementById('Ele0A');\r\n            if (_ele0AForced) { droppableEl = _ele0AForced; console.log('\ud83c\udfaf [thumbnailDropped] Ele0A forc\u00e9 (redirect Entete)'); }\r\n        } }\r\n    }\r\n\r\n    if (!droppableEl || closestDist > 800) {\r\n        console.warn('thumbnailDropped \u2014 aucun droppable proche (dist min:', closestDist, ')');\r\n        return;\r\n    }\r\n    console.log('\ud83d\udccd Droppable trouv\u00e9:', droppableEl.id, '(dist:', Math.round(closestDist), ')');\r\n\r\n    var $droppable = jQuery(droppableEl);\r\n    var rankId = $droppable.attr('id');\r\n    if (!rankId) { console.warn('thumbnailDropped \u2014 .droppable sans id'); return; }\r\n\r\n    var $dropZone = $droppable.find('#drop_file_zone_achat').first();\r\n    if (!$dropZone.length) { console.warn('thumbnailDropped \u2014 #drop_file_zone_achat introuvable dans', rankId); return; }\r\n\r\n    var emplacementRef = StateManager.buildEmplacementReference(rankId);\r\n    console.log('\u2705 thumbnailDropped \u2014 espace pub:', rankId, '\u2192', emplacementRef);\r\n\r\n    \/\/ 2. Pr\u00e9parer l'\u00e9tat SessionStorage (comme un vrai drop de fichier)\r\n    StateManager.setMultiple({\r\n        'Rank_Emplacement_Page_Web':     rankId,\r\n        'Commande_Emplacement_Page_Web': emplacementRef,\r\n        'FirstUploadFileorMoved':        'FirstUpload',\r\n        'Formatchoisi':                  'Yes',\r\n        'Commande_Format_Transmis':      'Image',\r\n        'EnvoiUlterieur':                'false',\r\n        'FileReceived':                  'No',\r\n        'AdDisplayed':                   'Yes'\r\n    });\r\n\r\n    UIManager.updateEmplacementDisplay();\r\n\r\n    \/\/ 3. Construire le File \u00e0 partir du PDF (communiqu\u00e9\/interview) ou de l'image PNG (autres formats)\r\n    \/\/    puis appeler handleFileUpload \u2192 m\u00eame flux qu'un vrai drag&drop : liser\u00e9 vert, aper\u00e7u, R\u00e9server\r\n    var dataURL, mime, ext;\r\n\r\n    \/\/ \u2705 Stocker le PDF image et le format sur le droppable pour le popup de visualisation inline\r\n    if (msg.pdfImageDataURL) {\r\n        $droppable.data('kitPdfImageDataURL', msg.pdfImageDataURL);\r\n        $droppable.data('kitFormatSelect', msg.FormatSelect || '');\r\n        console.log('\ud83d\udcce pdfImageDataURL stock\u00e9 sur', rankId, '| format:', msg.FormatSelect);\r\n    } else {\r\n        $droppable.removeData('kitPdfImageDataURL');\r\n        $droppable.removeData('kitFormatSelect');\r\n    }\r\n\r\n    if (msg.isPDF && msg.pdfDataURL) {\r\n        \/\/ \u2500\u2500 Format PDF (communiqu\u00e9 \/ interview) \u2500\u2500\u2500\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        dataURL = msg.pdfDataURL;                         \/\/ \"data:application\/pdf;base64,\u2026\"\r\n        mime    = 'application\/pdf';\r\n        ext     = '.pdf';\r\n    } else if (msg.imageDataURL) {\r\n        \/\/ \u2500\u2500 Format image (banni\u00e8re \/ parrainage) \u2500\u2500\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        dataURL = msg.imageDataURL;\r\n        var mimeMatch = dataURL.match(\/^data:([^;]+);base64,\/);\r\n        mime    = mimeMatch ? mimeMatch[1] : 'image\/png';\r\n        ext     = mime === 'image\/jpeg' ? '.jpg' : '.png';\r\n    } else {\r\n        console.warn('thumbnailDropped \u2014 aucune donn\u00e9e image\/pdf disponible');\r\n        return;\r\n    }\r\n\r\n    var baseName = msg.filename ? msg.filename.replace(\/\\.[^.]+$\/, '') : 'annonce-kit';\r\n    var fileName = baseName + ext;\r\n\r\n    \/\/ dataURL \u2192 Uint8Array \u2192 Blob \u2192 File\r\n    var b64  = dataURL.split(',')[1];\r\n    var bstr = atob(b64);\r\n    var u8   = new Uint8Array(bstr.length);\r\n    for (var i = 0; i < bstr.length; i++) { u8[i] = bstr.charCodeAt(i); }\r\n    var blob    = new Blob([u8], { type: mime });\r\n    var fileObj = new File([blob], fileName, { type: mime });\r\n\r\n    console.log('thumbnailDropped \u2192 handleFileUpload:', fileName, Math.round(fileObj.size \/ 1024) + 'KB');\r\n\r\n    \/\/ \u2705 Cacher le File pour r\u00e9utilisation lors des d\u00e9placements (\u00e9vite CORS)\r\n    window._lastRedactionnelFile = fileObj;\r\n\r\n    \/\/ \u2705 v2.4.10 : Signaler \u00e0 adjustDesktopLayout que c'est un drop depuis la miniature\r\n    \/\/ \u2192 applique max-height sur HTMLUploadfileConteneur pour \u00e9viter le d\u00e9bordement vertical (homepage corps de page)\r\n    window._dropFromMiniature = true;\r\n    UploadManager.handleFileUpload(fileObj, $dropZone);\r\n\r\n    \/\/ \u2705 v1.19.1 : Positionner l'espace \u00e0 10px du haut du viewport (tous formats)\r\n    \/\/ \u2705 v2.4.13 : Skip si drop depuis miniature \u2014 selectEspaceActif g\u00e8re d\u00e9j\u00e0 le scroll\r\n    if (!window._dropFromMiniature) {\r\n        setTimeout(function() {\r\n            var el = $droppable.find('.HTMLUploadfileConteneur')[0] || $droppable[0];\r\n            if (el) {\r\n                ScrollHelper.scrollElementTo(el, 10);\r\n            }\r\n        }, 400);\r\n    }\r\n});\r\n\r\nconsole.log('This is a ' + (UIManager.isDesktop() ? 'desktop' : 'non-desktop') + ' device.');\r\n\r\n} \/\/ end _espPubScriptLoaded guard\r\n<\/script>\r\n\r\n<style>\r\n\/* Les styles CSS restent inchang\u00e9s *\/\r\n#drop_file_zone_achat {\r\n    background-color: #FFFFFF00;\r\n    color: #225DA9;\r\n    font-weight: 500;\r\n    text-align: center;\r\n    border: #999 0px dashed;\r\n    width: 100%;\r\n    height: 180px;\r\n    font-size: 11.5px;\r\n    display: flex;\r\n    justify-content: center; \r\n    align-items: center; \r\n    flex-wrap: wrap;\r\n}\r\n\r\n#drag_upload_file_achat {\r\n    margin: 0 auto;\r\n    width: 90%;\r\n    height: 60px;\r\n}\r\n\r\n#drag_upload_file_achat p {\r\n    text-align: center;\r\n}\r\n\r\n\/* \u2705 v1.16.0 : Liser\u00e9 noir fin autour du texte \"Ici glisser \u2013 d\u00e9poser\" *\/\r\n.GlisserDeposerConteneur .elementor-widget-container p {\r\n    border: 1px solid #000000;\r\n    border-radius: 4px;\r\n    padding: 4px 10px;\r\n    display: inline-block;\r\n}\r\n\r\n#selectfile_achat {\r\n    display: none;\r\n}\r\n\r\n.button-2_achat, .button-2_achat-after-reset {\r\n    background-color: #ffffff00!important;\r\n    border: 1px solid white!important;\r\n    border-radius: 8px;\r\n    color: #225DA9!important;\r\n    cursor: pointer;\r\n    display: inline-block;\r\n    font-size: 11px;\r\n    font-weight: 500;\r\n    list-style: none;\r\n    width: 390px;\r\n    height: 62px;\r\n    top: 0px!important; \r\n    margin-top: 0px!important; \r\n    padding-left: 5px!important;\r\n    padding-right: 5px!important;\r\n    margin-bottom: 70px!important;\r\n    margin: 0;\r\n    text-align: center;\r\n    transition: all 200ms;\r\n    vertical-align: baseline;\r\n    white-space: wrap!important;\r\n}\r\n\r\n@media only screen and (max-width: 1000px) {\r\n    .button-2_achat, .button-2_achat-after-reset {\r\n        width: 95%;\r\n        height: 50px;\r\n    }\r\n}\r\n\r\n.newMessageClass {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #56BE50;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 45px;\r\n    bottom: 0px;\r\n    right: 0px;\r\n    left: 0px;\r\n    display: flex;\r\n    justify-content: center;\r\n    align-items: center;\r\n    text-align: center;\r\n}\r\n\r\n.MessageClassFormatnonReconnuTitre {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #FB5E2A;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    margin-top: -300px;\r\n    right: 0px;\r\n    text-align: center;\r\n    line-height: 15px;\r\n}\r\n\r\n.MessageClassFormatnonReconnu {\r\n    background-color: #FFFFFF00!important;\r\n    font-size: 13px; \r\n    font-weight: 600;\r\n    color: #ffffff;\r\n    height: 35px;\r\n    width: 550px; \r\n    position: relative;\r\n    z-index: 99;\r\n    margin-top: -280px;\r\n    right: 0px;\r\n    text-align: center;\r\n    line-height: 15px;\r\n}\r\n\r\n.newButtonClass {\r\n    font-size: 12px; \r\n    font-weight: 500;\r\n    background-color: #ffffff00;\r\n    color: #717171;\r\n    height: 10px;\r\n    width: 100%; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 45px;\r\n    bottom: 0px;\r\n    text-align: center;\r\n    right:  50px;\r\n    line-height: 10px;\r\n    border-radius: 3px;\r\n    border: 0px solid #E8ECF1;\r\n}\r\n\r\n.linkClass {\r\n    width: 15px; \r\n    height: 15px;\r\n    margin-top: -310px;\r\n    margin-bottom: -25px;\r\n    margin-right: -50px;\r\n    position: relative;\r\n    top: 0; \r\n    z-index: 99;\r\n    display: block;\r\n    background-image: url('https:\/\/rdc.via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-blanc.jpg');\r\n    background-size: cover;\r\n}\r\n\r\n.newButtonClassVideo {\r\n    font-size: 12px; \r\n    font-weight: 500;\r\n    background-color: #ffffff00;\r\n    color: #717171;\r\n    height: 10px;\r\n    width: 100%; \r\n    position: relative;\r\n    z-index: 99;\r\n    top: 0px;\r\n    bottom: 0px;\r\n    right: 10px;\r\n    text-align: center;\r\n    line-height: 10px;\r\n    border-radius: 3px;\r\n    border: 0px solid #E8ECF1;\r\n}\r\n\r\n.linkClassVideo {\r\n    width: 15px; \r\n    height: 15px;\r\n    margin-top: -438px;\r\n    margin-bottom: -25px;\r\n    margin-right: -15px;\r\n    position: relative;\r\n    top: 0; \r\n    z-index: 99;\r\n    display: block;\r\n    background-image: url('https:\/\/rdc.via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-blanc.jpg');\r\n    background-size: cover;\r\n}\r\n\r\n.FinCampagneMobileClass .elementor-button,\r\n.DebutCampagneMobileClass .elementor-button,\r\n.FormSelectDevisesMobile .elementor-button,\r\n.HideFormButton .elementor-button {\r\n    display: none !important;\r\n}\r\n\r\n#drag_upload_file_achat {\r\n    margin: 0;\r\n    padding: 0;\r\n    position: relative;\r\n}\r\n\r\n.dot-container {\r\n    display: inline-block;\r\n}\r\n\r\n.dot {\r\n    opacity: 0;\r\n    transition: opacity 0.3s ease;\r\n}\r\n\r\n@keyframes firstDot {\r\n    0%, 100% { opacity: 0; }\r\n    10%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n@keyframes secondDot {\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 thirdDot {\r\n    0%, 40%, 100% { opacity: 0; }\r\n    50%, 70% { opacity: 1; }\r\n    90% { opacity: 0; }\r\n}\r\n\r\n.dot:nth-child(1) {\r\n    animation: firstDot 3s infinite;\r\n}\r\n\r\n.dot:nth-child(2) {\r\n    animation: secondDot 3s infinite;\r\n}\r\n\r\n.dot:nth-child(3) {\r\n    animation: thirdDot 3s infinite;\r\n}\r\n\r\n.droppable .elementor-field-type-checkbox .elementor-field-option {\r\n    display: flex;\r\n    flex-direction: row-reverse;\r\n    align-items: center;\r\n    gap: 8px;\r\n}\r\n\r\n.droppable .elementor-field-type-checkbox .elementor-field-option input[type=\"checkbox\"] {\r\n    width: 12px;\r\n    height: 12px;\r\n    min-width: 12px;\r\n    min-height: 12px;\r\n}\r\n\r\n\/* \u2705 Bouton \"R\u00e9server\" dynamique *\/\r\n.reserver-dynamic-container {\r\n    text-align: center;\r\n    margin-top: -7px;\r\n    margin-bottom: 15px;\r\n    padding: 5px 0;\r\n    transform: scale(1.4);\r\n    transform-origin: center top;\r\n    position: relative;\r\n    z-index: 200;\r\n}\r\n\r\n@media only screen and (min-width: 1001px) {\r\n    .reserver-dynamic-container {\r\n        transform: scale(1);\r\n        margin-top: -200px;\r\n        margin-bottom: 0;\r\n    }\r\n}\r\n\r\n.reserver-dynamic-option {\r\n    display: inline-flex;\r\n    flex-direction: row-reverse;\r\n    align-items: center;\r\n    gap: 8px;\r\n    cursor: pointer;\r\n    color: #213864;\r\n    background-color: #ffffff;\r\n    padding: 2px 4px;\r\n    border-radius: 6px;\r\n}\r\n\r\n.reserver-dynamic-checkbox {\r\n    width: 16px;\r\n    height: 16px;\r\n    min-width: 16px;\r\n    min-height: 16px;\r\n    cursor: pointer;\r\n    pointer-events: auto;\r\n}\r\n\r\n.reserver-dynamic-label {\r\n    cursor: pointer;\r\n    color: #213864;\r\n    font-size: 16px;\r\n    font-weight: 600;\r\n    user-select: none;\r\n}\r\n\r\n@media only screen and (max-width: 1000px) {\r\n    .reserver-dynamic-container {\r\n        transform: scale(0.98);\r\n        margin-bottom: 20px;\r\n        white-space: nowrap;\r\n        z-index: 300;\r\n        pointer-events: auto;\r\n    }\r\n    .reserver-dynamic-option {\r\n        padding-top: 0px;\r\n        padding-bottom: 0px;\r\n    }\r\n}\r\n\r\n\/* \u2705 v2.1.3 : DeplaceAnnonceText \/ DeplaceAnnonce \u2014 desktop uniquement *\/\r\n@media only screen and (min-width: 1001px) {\r\n    .DeplaceAnnonceText {\r\n        margin-top: -5px;\r\n        position: relative;\r\n        z-index: 201;\r\n    }\r\n    .DeplaceAnnonce {\r\n        margin-bottom: -150px;\r\n    }\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<div class=\"elementor-element elementor-element-54e4e530 e-con-full MsgFormatIncorrectConteneur elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"54e4e530\" data-element_type=\"container\" id=\"NotusedAnymore\">\n\t\t\t\t<div class=\"elementor-element elementor-element-531f3cb1 MsgFormatIncorrect elementor-widget__width-inherit elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"531f3cb1\" data-element_type=\"widget\" data-widget_type=\"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 format du fichier n&rsquo;est pas reconnu<\/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-3a352c3f elementor-hidden-desktop TexteMobile TexteMobileAnnonce elementor-widget elementor-widget-text-editor\" data-id=\"3a352c3f\" data-element_type=\"widget\" data-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 ou cliquer ici<br>pour t\u00e9l\u00e9charger une 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-7abb0aba elementor-hidden-desktop TexteMobileAjoutAnnonce elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"7abb0aba\" data-element_type=\"widget\" data-widget_type=\"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;\">Cliquer ici pour t\u00e9l\u00e9charger une annonce<\/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-68e2b2ca UploadIci elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"68e2b2ca\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ici glisser-d\u00e9poser ou t\u00e9l\u00e9charger une annonce<\/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-8d50d33 e-con-full e-flex e-con e-child\" data-id=\"8d50d33\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6ae6ef83 elementor-button-align-center elementor-widget__width-initial HideFormButton EspPubLienAnnonce elementor-widget-mobile__width-initial elementor-widget elementor-widget-form\" data-id=\"6ae6ef83\" data-element_type=\"widget\" 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_URL_annonce\" aria-label=\"Formulaire_URL_annonce\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249875\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"6ae6ef83\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-LienAnnonce elementor-col-100 elementor-sm-100 elementor-field-required\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-LienAnnonce\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tIci renseigner si n\u00e9cessaire le lien hypertexte de l\u2019annonce\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[LienAnnonce]\" id=\"form-field-LienAnnonce\" class=\"elementor-field elementor-size-xs  elementor-field-textual\" placeholder=\"Ici renseigner si n\u00e9cessaire le lien hypertexte de l\u2019annonce\" 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-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=\"ButtonValidURLAnnonce\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-66fd4d36 e-con-full EnvoiUlterieurContainer e-flex e-con e-child\" data-id=\"66fd4d36\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4ea8e2b4 elementor-button-align-center elementor-widget__width-auto HideFormButton EnvoiUlterieur elementor-widget elementor-widget-form\" data-id=\"4ea8e2b4\" data-element_type=\"widget\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249875\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"4ea8e2b4\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-EnvoiUlterieur elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-EnvoiUlterieur\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tEnvoi diff\u00e9r\u00e9 de l'annonce\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=\"Envoi diff\u00e9r\u00e9 de l&#039;annonce\" id=\"form-field-EnvoiUlterieur-0\" name=\"form_fields[EnvoiUlterieur]\"> <label for=\"form-field-EnvoiUlterieur-0\">Envoi diff\u00e9r\u00e9 de l'annonce<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-4a59cf88 EnvoiUlterieurTexte elementor-widget elementor-widget-text-editor\" data-id=\"4a59cf88\" data-element_type=\"widget\" data-widget_type=\"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;\">Envoyer l\u2019annonce jusqu\u2019\u00e0 8 jours apr\u00e8s paiement<br>\nUn lien vous sera adress\u00e9 par <span style=\"color: #ffffff;\"><a style=\"color: #ffffff;\" 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<div class=\"elementor-element elementor-element-17d3ad0c e-con-full ReserverContainer e-flex e-con e-child\" data-id=\"17d3ad0c\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-177c9b71 elementor-button-align-center elementor-widget__width-auto HideFormButton ReserverBouton elementor-widget elementor-widget-form\" data-id=\"177c9b71\" data-element_type=\"widget\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249875\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"177c9b71\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-ReserverEspacePublicitaire elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-ReserverEspacePublicitaire\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tR\u00e9server cet espace publicitaire\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=\"R\u00e9server cet espace publicitaire\" id=\"form-field-ReserverEspacePublicitaire-0\" name=\"form_fields[ReserverEspacePublicitaire]\"> <label for=\"form-field-ReserverEspacePublicitaire-0\">R\u00e9server cet espace publicitaire<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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-5bafe1f3 e-con-full AdUploadedTitle DeplaceAnnonce elementor-hidden-tablet elementor-hidden-mobile elementor-hidden-desktop e-flex e-con e-child\" data-id=\"5bafe1f3\" data-element_type=\"container\" id=\"DeplaceAnnonceId\">\n\t\t<div class=\"elementor-element elementor-element-432cc2a1 e-con-full DeplaceAnnonceSubContainer e-flex e-con e-child\" data-id=\"432cc2a1\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-446e8565 elementor-hidden-tablet elementor-hidden-mobile EspaceReserve elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"446e8565\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Espace r\u00e9serv\u00e9<br \/>Annonce transmise<\/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-60df49d0 elementor-hidden-tablet elementor-hidden-mobile DeplaceAnnonceText elementor-widget elementor-widget-text-editor\" data-id=\"60df49d0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\tSi vous souhaitez un autre emplacement, vous pouvez d\u00e9placer cette annonce\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-62ef38f0 e-con-full e-flex e-con e-child\" data-id=\"62ef38f0\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f4f51cb elementor-hidden-tablet elementor-hidden-mobile PositionEspacePublicitaireDeplacer elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"f4f51cb\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Position<\/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-f214306 elementor-hidden-tablet elementor-hidden-mobile RefEspacePublicitaire elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"f214306\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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>\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-1c5a5ed5 e-con-full AdUploadedOverlay elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile e-flex e-con e-child\" data-id=\"1c5a5ed5\" data-element_type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4740d3e8 e-con-full OverlayHeader e-flex e-con e-child\" data-id=\"4740d3e8\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e964c6b elementor-hidden-tablet elementor-hidden-mobile OverlayRefEspace elementor-hidden-desktop elementor-widget elementor-widget-text-editor\" data-id=\"e964c6b\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>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-30eb836c OverlayCroixReset elementor-widget elementor-widget-image\" data-id=\"30eb836c\" data-element_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:\/\/via-agency.media\/wp-content\/uploads\/2024\/06\/Croix-retour-HP-fond-transparent.png\" 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-342c88b1 e-con-full OverlayPreviewZone e-flex e-con e-child\" data-id=\"342c88b1\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3c7e790f OverlayDeplaceTexte elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"3c7e790f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Si vous souhaitez un autre emplacement, vous pouvez d\u00e9placer cette annonce<\/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-51f00578 elementor-button-align-center elementor-widget__width-auto HideFormButton OverlayReserverForm elementor-widget elementor-widget-form\" data-id=\"51f00578\" data-element_type=\"widget\" id=\"Formulaire_Reserver_Overlay\" 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_Envoi_Ulterieur\" aria-label=\"Formulaire_Envoi_Ulterieur\" action=\"\">\n\t\t\t<input type=\"hidden\" name=\"post_id\" value=\"249875\"\/>\n\t\t\t<input type=\"hidden\" name=\"form_id\" value=\"51f00578\"\/>\n\t\t\t<input type=\"hidden\" name=\"referer_title\" value=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n\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-ReserverEspacePublicitaire elementor-col-100 elementor-sm-100\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label for=\"form-field-ReserverEspacePublicitaire\" class=\"elementor-field-label elementor-screen-only\">\n\t\t\t\t\t\t\t\tR\u00e9server cet espace publicitaire\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=\"R\u00e9server cet espace publicitaire\" id=\"form-field-ReserverEspacePublicitaire-0\" name=\"form_fields[ReserverEspacePublicitaire]\"> <label for=\"form-field-ReserverEspacePublicitaire-0\">R\u00e9server cet espace publicitaire<\/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=\"ButtonValidEnvoiUlterieur\">\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<input type=\"hidden\" name=\"trp-form-language\" value=\"fr\"\/><\/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<\/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<\/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>",
        "protected": false
    },
    "excerpt": {
        "rendered": "<p>Le Togo a connu ces derni\u00e8res ann\u00e9es un d\u00e9veloppement significatif de ses infrastructures gr\u00e2ce principalement \u00e0 l\u2019investissement public : 80% de routes rev\u00eatues projet\u00e9es en 2025, de nombreux ponts construits ou r\u00e9habilit\u00e9s et un souci de l\u2019am\u00e9nagement urbain. L\u2019enjeu d\u00e9sormais est de capitaliser sur ces r\u00e9alisations en d\u00e9veloppant une nouvelle g\u00e9n\u00e9ration d\u2019infrastructures mettant ainsi en &#8230; <a title=\"Togo &#8211; BTP &#8211; De grands chantiers\" class=\"read-more\" href=\"https:\/\/togo-en.yearbook-media.com\/fr\/togo-btp-de-grands-chantiers\/\" aria-label=\"Plus sur Togo &#8211; BTP &#8211; De grands chantiers\">Lire plus<\/a><\/p>",
        "protected": false
    },
    "author": 1,
    "featured_media": 41406,
    "comment_status": "closed",
    "ping_status": "open",
    "sticky": false,
    "template": "",
    "format": "standard",
    "meta": {
        "_acf_changed": false,
        "footnotes": ""
    },
    "categories": [
        111,
        285,
        7,
        169
    ],
    "tags": [],
    "class_list": [
        "post-38623",
        "post",
        "type-post",
        "status-publish",
        "format-standard",
        "has-post-thumbnail",
        "hentry",
        "category-btp",
        "category-page-pays-only",
        "category-togo",
        "category-togo-btp",
        "generate-columns",
        "tablet-grid-50",
        "mobile-grid-100",
        "grid-parent",
        "grid-20"
    ],
    "acf": [],
    "yoast_head": "<!-- This site is optimized with the Yoast SEO plugin v24.8.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Togo - BTP - De grands chantiers<\/title>\n<meta name=\"description\" content=\"Le Togo a connu ces derni\u00e8res ann\u00e9es un d\u00e9veloppement significatif de ses infrastructures gr\u00e2ce principalement \u00e0 l\u2019investissement public.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/togo-en.yearbook-media.com\/fr\/togo-btp-de-grands-chantiers\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Togo - BTP - De grands chantiers\" \/>\n<meta property=\"og:description\" content=\"Le Togo a connu ces derni\u00e8res ann\u00e9es un d\u00e9veloppement significatif de ses infrastructures gr\u00e2ce principalement \u00e0 l\u2019investissement public.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/togo-en.yearbook-media.com\/fr\/togo-btp-de-grands-chantiers\/\" \/>\n<meta property=\"og:site_name\" content=\"TOGO YEARBOOK RAPPORT ECONOMIQUE\" \/>\n<meta property=\"article:published_time\" content=\"2025-06-02T08:14:18+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-04T11:08:35+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/togo-en.yearbook-media.com\/wp-content\/uploads\/2024\/03\/640px-Route_de_Lome-e1719506931907.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"605\" \/>\n\t<meta property=\"og:image:height\" content=\"311\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Via Media\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u00c9crit par\" \/>\n\t<meta name=\"twitter:data1\" content=\"Via Media\" \/>\n\t<meta name=\"twitter:label2\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/\",\"url\":\"https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/\",\"name\":\"Togo - BTP - De grands chantiers\",\"isPartOf\":{\"@id\":\"https:\/\/togo-en.yearbook-media.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/togo-en.yearbook-media.com\/wp-content\/uploads\/2024\/03\/640px-Route_de_Lome-e1719506931907.jpg\",\"datePublished\":\"2025-06-02T08:14:18+00:00\",\"dateModified\":\"2025-06-04T11:08:35+00:00\",\"author\":{\"@id\":\"https:\/\/togo-en.yearbook-media.com\/#\/schema\/person\/513c11c393392c49324dfc4a34c9f9ed\"},\"description\":\"Le Togo a connu ces derni\u00e8res ann\u00e9es un d\u00e9veloppement significatif de ses infrastructures gr\u00e2ce principalement \u00e0 l\u2019investissement public.\",\"breadcrumb\":{\"@id\":\"https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/#breadcrumb\"},\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/#primaryimage\",\"url\":\"https:\/\/togo-en.yearbook-media.com\/wp-content\/uploads\/2024\/03\/640px-Route_de_Lome-e1719506931907.jpg\",\"contentUrl\":\"https:\/\/togo-en.yearbook-media.com\/wp-content\/uploads\/2024\/03\/640px-Route_de_Lome-e1719506931907.jpg\",\"width\":605,\"height\":311},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/togo-en.yearbook-media.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Togo &#8211; BTP &#8211; De grands chantiers\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/togo-en.yearbook-media.com\/#website\",\"url\":\"https:\/\/togo-en.yearbook-media.com\/\",\"name\":\"TOGO YEARBOOK RAPPORT ECONOMIQUE\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/togo-en.yearbook-media.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"fr-FR\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/togo-en.yearbook-media.com\/#\/schema\/person\/513c11c393392c49324dfc4a34c9f9ed\",\"name\":\"Via Media\",\"sameAs\":[\"https:\/\/togo-en.yearbook-media.com\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->",
    "yoast_head_json": {
        "title": "Togo - BTP - De grands chantiers",
        "description": "Le Togo a connu ces derni\u00e8res ann\u00e9es un d\u00e9veloppement significatif de ses infrastructures gr\u00e2ce principalement \u00e0 l\u2019investissement public.",
        "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:\/\/togo-en.yearbook-media.com\/fr\/togo-btp-de-grands-chantiers\/",
        "og_locale": "fr_FR",
        "og_type": "article",
        "og_title": "Togo - BTP - De grands chantiers",
        "og_description": "Le Togo a connu ces derni\u00e8res ann\u00e9es un d\u00e9veloppement significatif de ses infrastructures gr\u00e2ce principalement \u00e0 l\u2019investissement public.",
        "og_url": "https:\/\/togo-en.yearbook-media.com\/fr\/togo-btp-de-grands-chantiers\/",
        "og_site_name": "TOGO YEARBOOK RAPPORT ECONOMIQUE",
        "article_published_time": "2025-06-02T08:14:18+00:00",
        "article_modified_time": "2025-06-04T11:08:35+00:00",
        "og_image": [
            {
                "width": 605,
                "height": 311,
                "url": "https:\/\/togo-en.yearbook-media.com\/wp-content\/uploads\/2024\/03\/640px-Route_de_Lome-e1719506931907.jpg",
                "type": "image\/jpeg"
            }
        ],
        "author": "Via Media",
        "twitter_card": "summary_large_image",
        "twitter_misc": {
            "\u00c9crit par": "Via Media",
            "Dur\u00e9e de lecture estim\u00e9e": "4 minutes"
        },
        "schema": {
            "@context": "https:\/\/schema.org",
            "@graph": [
                {
                    "@type": "WebPage",
                    "@id": "https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/",
                    "url": "https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/",
                    "name": "Togo - BTP - De grands chantiers",
                    "isPartOf": {
                        "@id": "https:\/\/togo-en.yearbook-media.com\/#website"
                    },
                    "primaryImageOfPage": {
                        "@id": "https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/#primaryimage"
                    },
                    "image": {
                        "@id": "https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/#primaryimage"
                    },
                    "thumbnailUrl": "https:\/\/togo-en.yearbook-media.com\/wp-content\/uploads\/2024\/03\/640px-Route_de_Lome-e1719506931907.jpg",
                    "datePublished": "2025-06-02T08:14:18+00:00",
                    "dateModified": "2025-06-04T11:08:35+00:00",
                    "author": {
                        "@id": "https:\/\/togo-en.yearbook-media.com\/#\/schema\/person\/513c11c393392c49324dfc4a34c9f9ed"
                    },
                    "description": "Le Togo a connu ces derni\u00e8res ann\u00e9es un d\u00e9veloppement significatif de ses infrastructures gr\u00e2ce principalement \u00e0 l\u2019investissement public.",
                    "breadcrumb": {
                        "@id": "https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/#breadcrumb"
                    },
                    "inLanguage": "fr-FR",
                    "potentialAction": [
                        {
                            "@type": "ReadAction",
                            "target": [
                                "https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/"
                            ]
                        }
                    ]
                },
                {
                    "@type": "ImageObject",
                    "inLanguage": "fr-FR",
                    "@id": "https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/#primaryimage",
                    "url": "https:\/\/togo-en.yearbook-media.com\/wp-content\/uploads\/2024\/03\/640px-Route_de_Lome-e1719506931907.jpg",
                    "contentUrl": "https:\/\/togo-en.yearbook-media.com\/wp-content\/uploads\/2024\/03\/640px-Route_de_Lome-e1719506931907.jpg",
                    "width": 605,
                    "height": 311
                },
                {
                    "@type": "BreadcrumbList",
                    "@id": "https:\/\/togo-en.yearbook-media.com\/togo-btp-de-grands-chantiers\/#breadcrumb",
                    "itemListElement": [
                        {
                            "@type": "ListItem",
                            "position": 1,
                            "name": "Accueil",
                            "item": "https:\/\/togo-en.yearbook-media.com\/"
                        },
                        {
                            "@type": "ListItem",
                            "position": 2,
                            "name": "Togo &#8211; BTP &#8211; De grands chantiers"
                        }
                    ]
                },
                {
                    "@type": "WebSite",
                    "@id": "https:\/\/togo-en.yearbook-media.com\/#website",
                    "url": "https:\/\/togo-en.yearbook-media.com\/",
                    "name": "TOGO YEARBOOK RAPPORT ECONOMIQUE",
                    "description": "",
                    "potentialAction": [
                        {
                            "@type": "SearchAction",
                            "target": {
                                "@type": "EntryPoint",
                                "urlTemplate": "https:\/\/togo-en.yearbook-media.com\/?s={search_term_string}"
                            },
                            "query-input": {
                                "@type": "PropertyValueSpecification",
                                "valueRequired": true,
                                "valueName": "search_term_string"
                            }
                        }
                    ],
                    "inLanguage": "fr-FR"
                },
                {
                    "@type": "Person",
                    "@id": "https:\/\/togo-en.yearbook-media.com\/#\/schema\/person\/513c11c393392c49324dfc4a34c9f9ed",
                    "name": "Via Media",
                    "sameAs": [
                        "https:\/\/togo-en.yearbook-media.com"
                    ]
                }
            ]
        }
    },
    "_links": {
        "self": [
            {
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/posts\/38623"
            }
        ],
        "collection": [
            {
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/posts"
            }
        ],
        "about": [
            {
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/types\/post"
            }
        ],
        "author": [
            {
                "embeddable": true,
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/users\/1"
            }
        ],
        "replies": [
            {
                "embeddable": true,
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/comments?post=38623"
            }
        ],
        "version-history": [
            {
                "count": 2,
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/posts\/38623\/revisions"
            }
        ],
        "predecessor-version": [
            {
                "id": 186252,
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/posts\/38623\/revisions\/186252"
            }
        ],
        "wp:featuredmedia": [
            {
                "embeddable": true,
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/media\/41406"
            }
        ],
        "wp:attachment": [
            {
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/media?parent=38623"
            }
        ],
        "wp:term": [
            {
                "taxonomy": "category",
                "embeddable": true,
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/categories?post=38623"
            },
            {
                "taxonomy": "post_tag",
                "embeddable": true,
                "href": "https:\/\/togo-en.yearbook-media.com\/fr\/wp-json\/wp\/v2\/tags?post=38623"
            }
        ],
        "curies": [
            {
                "name": "wp",
                "href": "https:\/\/api.w.org\/{rel}",
                "templated": true
            }
        ]
    }
}