var/cache/dev/twig/b9/b932b00f9926f3af0cf9914133167a94.php line 45

Open in your IDE?
  1. <?php
  2. use Twig\Environment;
  3. use Twig\Error\LoaderError;
  4. use Twig\Error\RuntimeError;
  5. use Twig\Extension\CoreExtension;
  6. use Twig\Extension\SandboxExtension;
  7. use Twig\Markup;
  8. use Twig\Sandbox\SecurityError;
  9. use Twig\Sandbox\SecurityNotAllowedTagError;
  10. use Twig\Sandbox\SecurityNotAllowedFilterError;
  11. use Twig\Sandbox\SecurityNotAllowedFunctionError;
  12. use Twig\Source;
  13. use Twig\Template;
  14. use Twig\TemplateWrapper;
  15. /* Parent/DetailsSejour.html.twig */
  16. class __TwigTemplate_2e4d9af98367fb875e9538af7eac3dac extends Template
  17. {
  18.     private Source $source;
  19.     /**
  20.      * @var array<string, Template>
  21.      */
  22.     private array $macros = [];
  23.     public function __construct(Environment $env)
  24.     {
  25.         parent::__construct($env);
  26.         $this->source $this->getSourceContext();
  27.         $this->blocks = [
  28.             'LinksCss' => [$this'block_LinksCss'],
  29.             'Content' => [$this'block_Content'],
  30.             'Javascript' => [$this'block_Javascript'],
  31.         ];
  32.     }
  33.     protected function doGetParent(array $context): bool|string|Template|TemplateWrapper
  34.     {
  35.         // line 1
  36.         return "Parent/LayoutParent.html.twig";
  37.     }
  38.     protected function doDisplay(array $context, array $blocks = []): iterable
  39.     {
  40.         $macros $this->macros;
  41.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  42.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""Parent/DetailsSejour.html.twig"));
  43.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  44.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""Parent/DetailsSejour.html.twig"));
  45.         // line 33
  46.         $context["pageMenu"] = CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'33$this->source); })()), "session", [], "any"falsefalsefalse33), "get", ["pageMenu"], "method"falsefalsefalse33);
  47.         // line 1
  48.         $this->parent $this->load("Parent/LayoutParent.html.twig"1);
  49.         yield from $this->parent->unwrap()->yield($contextarray_merge($this->blocks$blocks));
  50.         
  51.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  52.         
  53.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  54.     }
  55.     /**
  56.      * @return iterable<null|scalar|\Stringable>
  57.      */
  58.     public function block_LinksCss(array $context, array $blocks = []): iterable
  59.     {
  60.         $macros $this->macros;
  61.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  62.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""LinksCss"));
  63.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  64.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""LinksCss"));
  65.         // line 2
  66.         yield from $this->yieldParentBlock("LinksCss"$context$blocks);
  67.         yield "
  68. <script src=\"https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.js\" defer></script>
  69. <link rel=\"stylesheet\" href=\"";
  70.         // line 5
  71.         yield "/css/Parent/css/premiercnx.css";
  72.         yield "\" />
  73. <link href=\"";
  74.         // line 6
  75.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("css/Parent/css/detailsejour.css"), "html"nulltrue);
  76.         yield "\" type=\"text/css\" rel=\"stylesheet\" />
  77. <link rel=\"stylesheet\" href=\"";
  78.         // line 7
  79.         yield "/css/Accompagnateur/imgzoom.css";
  80.         yield "\" />
  81. <link rel=\"stylesheet\" href=\"";
  82.         // line 8
  83.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("Plugins/css/dropzone.css"), "html"nulltrue);
  84.         yield "\" />
  85. <link rel=\"stylesheet\" href=\"";
  86.         // line 9
  87.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("css/splide.min.css"), "html"nulltrue);
  88.         yield "\" />
  89. <link rel=\"stylesheet\" href=\"";
  90.         // line 10
  91.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("css/favorites-sidebar.css"), "html"nulltrue);
  92.         yield "\" />
  93. ";
  94.         // line 11
  95.         $context["destination"] = "detailsejour";
  96.         // line 12
  97.         yield "<style>
  98. .btn-close {
  99.   font-size: 1.2rem;
  100.      border: none;
  101.     background: transparent;
  102. }
  103. .slide img {
  104.   max-width: 100%;
  105.   max-height: 100%;
  106.   object-fit: contain;
  107.   border-radius: 8px;
  108.   box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
  109.   transition: transform 0.3s ease;
  110.   cursor: pointer;
  111. }
  112. .slide img.zoomed {
  113.   transform: scale(1.5);
  114.   cursor: zoom-in;
  115. }
  116. </style>
  117. ";
  118.         
  119.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  120.         
  121.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  122.         yield from [];
  123.     }
  124.     // line 33
  125.     /**
  126.      * @return iterable<null|scalar|\Stringable>
  127.      */
  128.     public function block_Content(array $context, array $blocks = []): iterable
  129.     {
  130.         $macros $this->macros;
  131.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  132.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""Content"));
  133.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  134.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""Content"));
  135.         // line 35
  136.         yield "
  137. ";
  138.         // line 37
  139.         yield from $this->load("components/parents/_cro_layers.html.twig"37)->unwrap()->yield(CoreExtension::merge($context, ["sejour" => (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'37$this->source); })()), "ctx" => ((array_key_exists("ctx"$context)) ? (Twig\Extension\CoreExtension::default((isset($context["ctx"]) || array_key_exists("ctx"$context) ? $context["ctx"] : (function () { throw new RuntimeError('Variable "ctx" does not exist.'37$this->source); })()), [])) : ([]))]));
  140.         // line 38
  141.         yield "
  142. <!-- Alerte pour inciter à acheter -->
  143. <div id=\"purchase-alert\" class=\"purchase-alert hidden\" style=\"display: none;\">
  144.   <button class=\"close-btn\" onclick=\"closePurchaseAlert()\">&times;</button>
  145.   <div id=\"purchase-alert-content\">
  146.     <!-- Le contenu de l'alerte sera mis à jour dynamiquement en fonction du nombre de favoris -->
  147.   </div>
  148. </div>
  149. <div
  150.   id=\"verifImg\"
  151.   class=\"modal fade\"
  152.   role=\"dialog\"
  153.   style=\"background-color: rgba(112, 112, 112, 0.56); z-index: 1000000\"
  154. >
  155. </div>
  156. <div class=\"main-content\">
  157.   <div class=\"row no-margin\">
  158.     <!-- Bouton cadeau attractif e-commerce -->
  159.     <div
  160.       class=\"gift-button\"
  161.       id=\"gift-button-trigger\"
  162.       style=\"cursor: pointer;\"
  163.     >
  164.       <i id=\"gift-icon-payment\" class=\"bi bi-gift gift-pulse\"></i>
  165.       <label
  166.         id=\"giftCount\"
  167.         class=\"labelGiftCount gift-count-bounce\"
  168.         style=\"background-color: #f56040\"
  169.       >
  170.         ";
  171.         // line 72
  172.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'72$this->source); })())), "html"nulltrue);
  173.         yield "
  174.       </label>
  175.       <!-- Message flottant attractif -->
  176.       <div class=\"gift-tooltip\" id=\"giftTooltip\">
  177.         <div class=\"gift-tooltip-content\">
  178.           <div class=\"gift-tooltip-header\">
  179.             <i class=\"bi bi-clock-history\"></i>
  180.             <strong>Offre limitée !</strong>
  181.           </div>
  182.           <p>Commandez vite ! Les photos seront disponibles seulement pendant <strong>6 semaines</strong> après la fin du séjour.</p>
  183.           <div class=\"gift-tooltip-cta\">
  184.             <i class=\"bi bi-lightning-charge\"></i>
  185.             Commander maintenant
  186.           </div>
  187.         </div>
  188.       </div>
  189.     </div>
  190.     <!-- Sidebar E-commerce -->
  191.     <div id=\"ecommerce-sidebar\">
  192.       <div class=\"ecommerce-header\">
  193.         <h2 class=\"ecommerce-title\" id=\"ecommerce-title\">
  194.           🎉 Vos souvenirs favoris sont prêts !
  195.         </h2>
  196.         <p class=\"ecommerce-subtitle\" id=\"ecommerce-subtitle\">
  197.           ";
  198.         // line 97
  199.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'97$this->source); })())), "html"nulltrue);
  200.         yield " photos sélectionnées avec amour ❤️
  201.         </p>
  202.         <button class=\"ecommerce-close\" onclick=\"closeEcommerceSidebar()\">
  203.           <i class=\"bi bi-x\"></i>
  204.         </button>
  205.       </div>
  206.       <div class=\"ecommerce-content\">
  207.         <!-- Bannière d'urgence -->
  208.         <div class=\"urgency-banner\" id=\"urgency-banner\">
  209.           <div>
  210.             <i class=\"bi bi-clock-history\"></i>
  211.             <strong>⏳ Commandez vite !</strong>
  212.           </div>
  213.           <div>Vos photos seront disponibles seulement <strong>6 semaines</strong> après la fin du séjour</div>
  214.           <div class=\"countdown\" id=\"countdown-timer\" style=\"display: none;\">
  215.             Plus que <span id=\"days-left\">0</span> jours !
  216.           </div>
  217.         </div>
  218.         <!-- Produits recommandés -->
  219.         <div id=\"products-container\">
  220.           <!-- Album Photo -->
  221.           <div class=\"product-card popular\">
  222.             <div class=\"product-header\">
  223.               <div class=\"product-icon\">
  224.                 <img src=\"/images/produit/Album5sur5-3.jpg\" alt=\"Album Photo Premium\" style=\"width: 100%; height: 100%; object-fit: contain; border-radius: 8px;\">
  225.               </div>
  226.               <div class=\"product-info\">
  227.                 <h4>Album Photo Premium</h4>
  228.                 <div class=\"product-pricing\">
  229.                   <span class=\"current-price\">24,90€</span>
  230.                   <span class=\"original-price\">28,90€</span>
  231.                   <span class=\"savings\">-14%</span>
  232.                 </div>
  233.               </div>
  234.               <div class=\"product-favorites-indicator\" title=\"Photos favorites sélectionnées\">
  235.                 <i class=\"bi bi-heart-fill\" style=\"color: #f56040\"></i>
  236.                 <span id=\"album-fav-count\">";
  237.         // line 135
  238.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'135$this->source); })())), "html"nulltrue);
  239.         yield "</span>
  240.               </div>
  241.             </div>
  242.             <p class=\"product-description\">
  243.               Album photo personnalisé avec vos <strong id=\"album-count\">";
  244.         // line 139
  245.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'139$this->source); })())), "html"nulltrue);
  246.         yield "</strong> photos favorites. Papier de qualité supérieure, reliure rigide.
  247.             </p>
  248.             <button class=\"product-cta\" onclick=\"orderProduct('album')\" 
  249.                     title=\"Commander l'album photo avec vos photos favorites\">
  250.               <i class=\"bi bi-cart-plus\"></i>
  251.               Commander l'album
  252.             </button>
  253.           </div>
  254.           <!-- Pack Numérique -->
  255.           <div class=\"product-card\">
  256.             <div class=\"product-header\">
  257.               <div class=\"product-icon\">
  258.                 <img src=\"/images/produit/photoNumerique.jpg\" alt=\"Pack Numérique HD\" style=\"width: 100%; height: 100%; object-fit: contain; border-radius: 8px;\">
  259.               </div>
  260.               <div class=\"product-info\">
  261.                 <h4>Pack Numérique HD</h4>
  262.                 <p class=\"price\">À partir de 3,90€</p>
  263.               </div>
  264.                 <div class=\"product-favorites-indicator\" title=\"Photos favorites sélectionnées\">
  265.                   <i class=\"bi bi-heart-fill\" style=\"color: #f56040\"></i>
  266.                   <span id=\"digital-fav-count\">";
  267.         // line 160
  268.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'160$this->source); })())), "html"nulltrue);
  269.         yield "</span>
  270.                 </div>
  271.             </div>
  272.             <p class=\"product-description\">
  273.               Téléchargement immédiat de vos <strong id=\"digital-count\">";
  274.         // line 164
  275.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'164$this->source); })())), "html"nulltrue);
  276.         yield "</strong> photos en haute définition. Qualité professionnelle garantie.
  277.             </p>
  278.             <button class=\"product-cta\" onclick=\"orderProduct('digital')\" 
  279.                     title=\"Télécharger vos photos en haute définition\">
  280.               <i class=\"bi bi-download\"></i>
  281.               Télécharger HD
  282.             </button>
  283.           </div>
  284.           <!-- Pochette Tirages -->
  285.           <div class=\"product-card\" id=\"prints-card\" style=\"display: none;\">
  286.             <div class=\"product-header\">
  287.               <div class=\"product-icon\">
  288.                 <i class=\"bi bi-images\"></i>
  289.               </div>
  290.               <div class=\"product-info\">
  291.                 <h4>Pochette Tirages</h4>
  292.                 <p class=\"price\">À partir de 9,90€</p>
  293.               </div>
  294.             </div>
  295.             <p class=\"product-description\">
  296.               <strong id=\"prints-count\">12</strong> tirages photo 10x15cm de vos favoris. Papier brillant professionnel, envoi sous 48h.
  297.             </p>
  298.             <button class=\"product-cta\" onclick=\"orderProduct('prints')\" 
  299.                     title=\"Commander des tirages photo de vos favoris\">
  300.               <i class=\"bi bi-printer\"></i>
  301.               Commander les tirages
  302.             </button>
  303.           </div>
  304.         </div>
  305.         <!-- Réassurance -->
  306.         <div class=\"reassurance\">
  307.           <i class=\"bi bi-shield-check\" style=\"color: #10b981; margin-right: 8px;\"></i>
  308.           <strong>Imprimé par l'équipe 5sur5 – satisfaction garantie ✅</strong>
  309.         </div>
  310.         
  311.       </div>
  312.     </div>
  313.     <div class=\"selection-popover\" id=\"selectionPopover\">
  314.       <h4>Votre sélection</h4>
  315.       <p>Tirages : ";
  316.         // line 206
  317.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'206$this->source); })())), "html"nulltrue);
  318.         yield " / 12</p>
  319.       <p>Numériques : ";
  320.         // line 207
  321.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'207$this->source); })())), "html"nulltrue);
  322.         yield " / 15</p>
  323.       <p>Album : ";
  324.         // line 208
  325.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["likes"]) || array_key_exists("likes"$context) ? $context["likes"] : (function () { throw new RuntimeError('Variable "likes" does not exist.'208$this->source); })())), "html"nulltrue);
  326.         yield " / 20</p>
  327.       <button class=\"finalize-button\" onclick=\"openEcommerceSidebar()\" 
  328.               title=\"Voir les produits disponibles avec vos favoris\">
  329.         <i class=\"bi bi-gift\"></i>
  330.         Finaliser ma commande
  331.       </button>
  332.     </div>
  333.     
  334.     <style>
  335.       /* Amélioration des boutons de produits */
  336.       .product-cta {
  337.         background: #3a8d95;
  338.         border: none;
  339.         border-radius: 25px;
  340.         color: white;
  341.         padding: 12px 24px;
  342.         font-weight: 600;
  343.         cursor: pointer;
  344.         transition: all 0.3s ease;
  345.         display: flex;
  346.         align-items: center;
  347.         gap: 8px;
  348.         width: 100%;
  349.         justify-content: center;
  350.         margin-top: 10px;
  351.       }
  352.       
  353.       .product-cta:hover {
  354.         transform: translateY(-2px);
  355.         box-shadow: 0 5px 15px rgba(58, 141, 149, 0.4);
  356.         background: #2f7a82;
  357.       }
  358.       
  359.       .product-cta:active {
  360.         transform: translateY(0);
  361.       }
  362.       
  363.       .product-cta:disabled {
  364.         background: #ccc;
  365.         cursor: not-allowed;
  366.         transform: none;
  367.         box-shadow: none;
  368.       }
  369.       
  370.       .finalize-button {
  371.         background: linear-gradient(135deg, #e91e63 0%, #ad1457 100%);
  372.         border: none;
  373.         border-radius: 25px;
  374.         color: white;
  375.         padding: 12px 24px;
  376.         font-weight: 600;
  377.         cursor: pointer;
  378.         transition: all 0.3s ease;
  379.         display: flex;
  380.         align-items: center;
  381.         gap: 8px;
  382.         width: 100%;
  383.         justify-content: center;
  384.         margin-top: 15px;
  385.       }
  386.       
  387.       .finalize-button:hover {
  388.         transform: translateY(-2px);
  389.         box-shadow: 0 5px 15px rgba(233, 30, 99, 0.4);
  390.         background: linear-gradient(135deg, #d81b60 0%, #9c1450 100%);
  391.       }
  392.       
  393.       /* Amélioration des cartes de produits */
  394.       .product-card {
  395.         border-radius: 12px;
  396.         box-shadow: 0 4px 15px rgba(0,0,0,0.1);
  397.         transition: all 0.3s ease;
  398.         margin-bottom: 20px;
  399.         overflow: hidden;
  400.       }
  401.       
  402.       .product-card:hover {
  403.         transform: translateY(-5px);
  404.         box-shadow: 0 8px 25px rgba(0,0,0,0.15);
  405.       }
  406.       
  407.       .product-header {
  408.         display: flex;
  409.         align-items: center;
  410.         gap: 15px;
  411.         padding: 20px;
  412.         background: #f8f9fa;
  413.       }
  414.       
  415.       .product-icon {
  416.         width: 60px;
  417.         height: 60px;
  418.         border-radius: 8px;
  419.         overflow: hidden;
  420.         flex-shrink: 0;
  421.       }
  422.       
  423.       .product-info h4 {
  424.         margin: 0 0 5px 0;
  425.         color: #333;
  426.         font-weight: 600;
  427.       }
  428.       
  429.       .product-pricing {
  430.         display: flex;
  431.         align-items: center;
  432.         gap: 10px;
  433.         margin: 5px 0;
  434.       }
  435.       
  436.       .current-price {
  437.         font-size: 1.2rem;
  438.         font-weight: 700;
  439.         color: #e91e63;
  440.       }
  441.       
  442.       .original-price {
  443.         text-decoration: line-through;
  444.         color: #666;
  445.         font-size: 0.9rem;
  446.       }
  447.       
  448.       .savings {
  449.         background: #4caf50;
  450.         color: white;
  451.         padding: 2px 8px;
  452.         border-radius: 12px;
  453.         font-size: 0.8rem;
  454.         font-weight: 600;
  455.       }
  456.       
  457.       .product-description {
  458.         padding: 0 20px 20px 20px;
  459.         color: #666;
  460.         line-height: 1.5;
  461.       }
  462.       
  463.       .product-favorites-indicator {
  464.         display: flex;
  465.         align-items: center;
  466.         gap: 5px;
  467.         background: rgba(245, 96, 64, 0.1);
  468.         padding: 5px 10px;
  469.         border-radius: 15px;
  470.         font-size: 0.9rem;
  471.         color: #f56040;
  472.         font-weight: 600;
  473.       }
  474.     </style>
  475.   </div>
  476.   <div class=\"divSliderModern\">
  477.     <input type=\"hidden\" id=\"nbFavCurrent\" value=\"";
  478.         // line 360
  479.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'360$this->source); })()), "html"nulltrue);
  480.         yield "\" />
  481.    <input  id=\"likeCount\" type=\"hidden\" value=\"";
  482.         // line 361
  483.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'361$this->source); })()), "html"nulltrue);
  484.         yield "\" />
  485.     <div
  486.       class=\"splide no-padding no-margin\"
  487.       id=\"imageSlider\"
  488.       style=\"max-height: 200px\"
  489.     >
  490.       <div class=\"splide__track\">
  491.         <ul class=\"splide__list\">
  492.           <!-- Slide 1 -->
  493.           <li class=\"splide__slide\">
  494.             <div class=\"slider-content\" style=\"background: white\">
  495.               <div class=\"namePRD\" style=\"display: block\">
  496.                 <h4
  497.                   class=\"titleProdbienvenu titleProdbienvenu1\"
  498.                   style=\"color: #41a2aa\"
  499.                 >
  500.                   Ajoutez vos favoris dès maintenant
  501.                 </h4>
  502.                 <h4
  503.                   class=\"titleProdbienvenu titleProdbienvenu2\"
  504.                   style=\"color: #f09e7a\"
  505.                 >
  506.                   et profitez de nos produits souvenirs personnalisés !
  507.                 </h4>
  508.               </div>
  509.               <img
  510.                 src=\"";
  511.         // line 389
  512.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("/images/imgSliderEmpty2.png"), "html"nulltrue);
  513.         yield "\"
  514.                 class=\"imgslider\"
  515.                 alt=\"Image 1\"
  516.               />
  517.             </div>
  518.           </li>
  519.           <!-- Slide 2 -->
  520.           <li class=\"splide__slide\">
  521.             <div class=\"slider-content\" style=\"background: white\">
  522.               <div class=\"namePRD\" style=\"display: block\">
  523.                 <h4
  524.                   class=\"titleProdbienvenu titleProdbienvenu1\"
  525.                   style=\"color: #f09e7a\"
  526.                 >
  527.                   Pensez à commander le livre du séjour
  528.                 </h4>
  529.                 <h4
  530.                   class=\"titleProdbienvenu titleProdbienvenu2\"
  531.                   style=\"color: #41a2aa\"
  532.                 >
  533.                   et offrez lui le plus beau des cadeaux !
  534.                 </h4>
  535.               </div>
  536.               <img
  537.                 src=\"";
  538.         // line 413
  539.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("/images/imgSliderEmpty1.png"), "html"nulltrue);
  540.         yield "\"
  541.                 class=\"imgslider\"
  542.                 alt=\"Image 2\"
  543.               />
  544.             </div>
  545.           </li>
  546.         </ul>
  547.       </div>
  548.     </div>
  549.   </div>
  550.   <!-- Section de contenu à atteindre après le scroll -->
  551.   <div
  552.     class=\"no-margin\"
  553.     id=\"scrollTarget\"
  554.     style=\"width: 100%; background: #f9f9f9; padding-top: 30px\"
  555.   >
  556.     <div class=\"no-margin\" id=\"scrollTarget\" style=\"width: 100%\">
  557.       <!-- Header compact 2 bandes -->
  558.       <div class=\"header-restructured\">
  559.         <!-- Ligne 1: Icône + Titre + Stats (alignés) -->
  560.         <div class=\"header-line-1\">
  561.           <div class=\"header-content\">
  562.             <img src=\"/Accueil/imagesAccueil/sejour.png\" alt=\"Icône séjour\" width=\"40\" height=\"40\">
  563.             <h1 class=\"titreDetailSej\" style=\"display:flex; align-items:center; gap:10px;\">Séjour ";
  564.         // line 436
  565.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'436$this->source); })()), "themSejour", [], "any"falsefalsefalse436), "html"nulltrue);
  566.         yield "
  567.               <button id=\"croTestAll\" class=\"btn btn-sm btn-outline-secondary d-none\">
  568.                 Tester CRO
  569.               </button>
  570.             </h1>
  571.             <nav class=\"header-pills\" aria-label=\"Statistiques du séjour\">
  572.              
  573.                
  574.               <button id=\"filtre_photos_voir\" class=\"pill stat-pill\" data-filter=\"photos\" aria-label=\"Voir ";
  575.         // line 444
  576.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["attachementsCount"]) || array_key_exists("attachementsCount"$context) ? $context["attachementsCount"] : (function () { throw new RuntimeError('Variable "attachementsCount" does not exist.'444$this->source); })()), "html"nulltrue);
  577.         yield " photos et vidéos partagées\">
  578.                 <i class=\"bi bi-images\"></i> ";
  579.         // line 445
  580.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["attachementsCount"]) || array_key_exists("attachementsCount"$context) ? $context["attachementsCount"] : (function () { throw new RuntimeError('Variable "attachementsCount" does not exist.'445$this->source); })()), "html"nulltrue);
  581.         yield "
  582.               </button>
  583.               <button class=\"pill stat-pill\" data-filter=\"audios\" aria-label=\"Voir ";
  584.         // line 447
  585.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["nbmessages"]) || array_key_exists("nbmessages"$context) ? $context["nbmessages"] : (function () { throw new RuntimeError('Variable "nbmessages" does not exist.'447$this->source); })()), "html"nulltrue);
  586.         yield " messages audio enregistrés\">
  587.                 <i class=\"bi bi-mic-fill\"></i> ";
  588.         // line 448
  589.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["nbmessages"]) || array_key_exists("nbmessages"$context) ? $context["nbmessages"] : (function () { throw new RuntimeError('Variable "nbmessages" does not exist.'448$this->source); })()), "html"nulltrue);
  590.         yield "
  591.               </button>
  592.               <button class=\"pill stat-pill\" data-filter=\"favoris\" aria-label=\"Voir ";
  593.         // line 450
  594.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'450$this->source); })()), "html"nulltrue);
  595.         yield " contenus marqués en favoris\">
  596.                 <i class=\"bi bi-heart-fill\"></i> ";
  597.         // line 451
  598.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'451$this->source); })()), "html"nulltrue);
  599.         yield "
  600.               </button>
  601.             </nav>
  602.           </div>
  603.         </div>
  604.         <!-- Ligne 2: Dates (gris clair) -->
  605.         <div class=\"header-line-2\">
  606.           du ";
  607.         // line 459
  608.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::replace($this->extensions['Twig\Extension\CoreExtension']->formatDate(CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'459$this->source); })()), "dateDebutSejour", [], "any"falsefalsefalse459), "d M Y"), ["Jan" => "janv.""Feb" => "févr.""Mar" => "mars""Apr" => "avr.""May" => "mai""Jun" => "juin""Jul" => "juil.""Aug" => "août""Sep" => "sept.""Oct." => "oct.""Nov." => "nov.""Dec." => "déc."]), "html"nulltrue);
  609.         yield "
  610.           au ";
  611.         // line 460
  612.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::replace($this->extensions['Twig\Extension\CoreExtension']->formatDate(CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'460$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse460), "d M Y"), ["Jan" => "janv.""Feb" => "févr.""Mar" => "mars""Apr" => "avr.""May" => "mai""Jun" => "juin""Jul" => "juil.""Aug" => "août""Sep" => "sept.""Oct." => "oct.""Nov." => "nov.""Dec." => "déc."]), "html"nulltrue);
  613.         yield "
  614.           · Code&nbsp;: ";
  615.         // line 461
  616.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'461$this->source); })()), "codeSejour", [], "any"falsefalsefalse461), "html"nulltrue);
  617.         yield "
  618.         </div>
  619.         <!-- 🎯 MEDIA TOOLBAR CAPSULE (Senior UX) -->
  620.         <nav class=\"media-toolbar\" aria-label=\"Filtres médias\">
  621.           <div class=\"mtb-inner\" role=\"group\">
  622.             <!-- Tout -->
  623.             <button class=\"mtb-btn active\" data-filter=\"all\" title=\"Tout\">
  624.               <i class=\"bi bi-grid-3x3-gap-fill\" aria-hidden=\"true\"></i>
  625.               <span class=\"mtb-count\">Tout ";
  626.         // line 471
  627.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["attachementsCount"]) || array_key_exists("attachementsCount"$context) ? $context["attachementsCount"] : (function () { throw new RuntimeError('Variable "attachementsCount" does not exist.'471$this->source); })()), "html"nulltrue);
  628.         yield "</span>
  629.             </button>
  630.         
  631.             <!-- Audios -->
  632.             <button class=\"mtb-btn\" data-filter=\"audio\" title=\"Audios\">
  633.              
  634.        
  635. <span class=\"icon-telephone-voicemail\" >
  636.   <i class=\"bi bi-telephone-fill tel text-secandary\" style=\"color:#ffd700\"></i>
  637.   <i class=\"bi bi-voicemail vm text-secandary\" style=\"color:#ffd700\"></i>
  638. </span>
  639.               <span class=\"mtb-count\" data-bind=\"audio\">0</span>
  640.             </button>
  641.           
  642.    
  643.             <!-- Favoris -->
  644.             <button class=\"mtb-btn\" data-filter=\"favoris\" title=\"Favoris\">
  645.               <i class=\"bi bi-heart-fill\" style=\"color:#f56040\" aria-hidden=\"true\"></i>
  646.               <span class=\"mtb-count\" data-bind=\"fav\" id=\"mesFavCount\">";
  647.         // line 494
  648.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'494$this->source); })()), "html"nulltrue);
  649.         yield "</span>
  650.             </button>
  651.                <!-- Photos -->
  652.             <button class=\"mtb-btn\" data-filter=\"photos\" aria-pressed=\"false\" title=\"Voir toutes les photos\">
  653.               <i class=\"bi bi-eye-fill\" aria-hidden=\"true\"></i>
  654.           
  655.             </button>
  656.           </div>
  657.         </nav>
  658.         <!-- Navigation par jours -->
  659.         <div class=\"section-days\">
  660.           <div class=\"date-navigation\">
  661.           
  662.      
  663.             <div class=\"date-container\">
  664.               ";
  665.         // line 512
  666.         $context['_parent'] = $context;
  667.         $context['_seq'] = CoreExtension::ensureTraversable((isset($context["listeattach"]) || array_key_exists("listeattach"$context) ? $context["listeattach"] : (function () { throw new RuntimeError('Variable "listeattach" does not exist.'512$this->source); })()));
  668.         $context['loop'] = [
  669.           'parent' => $context['_parent'],
  670.           'index0' => 0,
  671.           'index'  => 1,
  672.           'first'  => true,
  673.         ];
  674.         if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
  675.             $length count($context['_seq']);
  676.             $context['loop']['revindex0'] = $length 1;
  677.             $context['loop']['revindex'] = $length;
  678.             $context['loop']['length'] = $length;
  679.             $context['loop']['last'] = === $length;
  680.         }
  681.         foreach ($context['_seq'] as $context["x"] => $context["groupAttach"]) {
  682.             // line 513
  683.             yield "                ";
  684.             $context["xDate"] = $this->extensions['Twig\Extension\CoreExtension']->convertDate($context["x"]);
  685.             // line 514
  686.             yield "                ";
  687.             $context["finDate"] = $this->extensions['Twig\Extension\CoreExtension']->convertDate(CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'514$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse514));
  688.             // line 515
  689.             yield "                ";
  690.             if (((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'515$this->source); })()) <= (isset($context["finDate"]) || array_key_exists("finDate"$context) ? $context["finDate"] : (function () { throw new RuntimeError('Variable "finDate" does not exist.'515$this->source); })()))) {
  691.                 // line 516
  692.                 yield "                  <div
  693.                     class=\"date-card modern-card ";
  694.                 // line 517
  695.                 if ((CoreExtension::getAttribute($this->env$this->source$context["loop"], "last", [], "any"falsefalsefalse517) && ((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'517$this->source); })()) <= (isset($context["finDate"]) || array_key_exists("finDate"$context) ? $context["finDate"] : (function () { throw new RuntimeError('Variable "finDate" does not exist.'517$this->source); })())))) {
  696.                     yield " active ";
  697.                 }
  698.                 yield "\"
  699.                     data-aos=\"fade-up\"
  700.                     data-bs-toggle=\"collapse\"
  701.                     data-day-id=\"";
  702.                 // line 520
  703.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatDate((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'520$this->source); })()), "Y-m-d"), "html"nulltrue);
  704.                 yield "\"
  705.                     data-bs-target=\"#demP";
  706.                 // line 521
  707.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse521), "html"nulltrue);
  708.                 yield "\"
  709.                     id=\"iconedemoP";
  710.                 // line 522
  711.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse522), "html"nulltrue);
  712.                 yield "\"
  713.                     role=\"button\"
  714.                     aria-label=\"Contenu du ";
  715.                 // line 524
  716.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::replace($this->extensions['Twig\Extension\CoreExtension']->formatDate((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'524$this->source); })()), "d F Y"), ["Jan" => "janvier""Feb" => "février""Mar" => "mars""Apr" => "avril""May" => "mai""Jun" => "juin""Jul" => "juillet""Aug" => "août""Sep" => "septembre""Oct" => "octobre""Nov" => "novembre""Dec" => "décembre"]), "html"nulltrue);
  717.                 // line 528
  718.                 yield " : ";
  719.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse528), "html"nulltrue);
  720.                 yield " photos, ";
  721.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse528), "html"nulltrue);
  722.                 yield " audios, ";
  723.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse528), "html"nulltrue);
  724.                 yield " vidéos\"
  725.                     tabindex=\"0\"
  726.                   >
  727.                     <div class=\"card-content\">
  728.                       <span class=\"title-line\">
  729.                       
  730.                           <span class=\"full-date\">
  731.                             ";
  732.                 // line 535
  733.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::replace($this->extensions['Twig\Extension\CoreExtension']->formatDate((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'535$this->source); })()), "D"), ["Mon" => "lun.""Tue" => "mar.""Wed" => "mer.""Thu" => "jeu.""Fri" => "ven.""Sat" => "sam.""Sun" => "dim."]), "html"nulltrue);
  734.                 // line 537
  735.                 yield "
  736.                         
  737.                             ";
  738.                 // line 539
  739.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::replace($this->extensions['Twig\Extension\CoreExtension']->formatDate((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'539$this->source); })()), "d M"), ["Jan" => "janv.""Feb" => "févr.""Mar" => "mars""Apr" => "avr.""May" => "mai""Jun" => "juin""Jul" => "juil.""Aug" => "août""Sep" => "sept.""Oct." => "oct.""Nov." => "nov.""Dec." => "déc."]), "html"nulltrue);
  740.                 // line 542
  741.                 yield "
  742.                              ";
  743.                 // line 543
  744.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "isFirstDay", [], "any"falsefalsefalse543) == "yes")) {
  745.                     // line 544
  746.                     yield "                              <span class=\"day-badge first\">Début</span>
  747.                             ";
  748.                 } elseif ((CoreExtension::getAttribute($this->env$this->source,                 // line 545
  749. $context["groupAttach"], "isLastDay", [], "any"falsefalsefalse545) == "yes")) {
  750.                     // line 546
  751.                     yield "                              <span class=\"day-badge last\">Dernier</span>
  752.                      
  753.                          
  754.                         ";
  755.                 }
  756.                 // line 550
  757.                 yield "                      </span>
  758.                       
  759.                      
  760.                           <span class=\"badge-new d-none\" aria-label=\"Nouveau contenu\"></span>
  761.                     
  762.                       </span>
  763.                       <ul class=\"media-list-horizontal\">
  764.                         ";
  765.                 // line 558
  766.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse558) > 0)) {
  767.                     // line 559
  768.                     yield "                        <li><i class=\"bi bi-images\"></i>";
  769.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse559), "html"nulltrue);
  770.                     yield "</li>
  771.                         ";
  772.                 }
  773.                 // line 561
  774.                 yield "                        ";
  775.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse561) > 0)) {
  776.                     // line 562
  777.                     yield "                        <li><span class=\"icon-telephone-voicemail\">
  778.   <i class=\"bi bi-telephone-fill tel text-secandary\" style=\"color:#ffd700!important\"></i>
  779.   <i class=\"bi bi-voicemail vm text-secandary\" style=\"color:#ffd700!important;  transform: translate(-8%, -46%);font-size:0.4rem!important\"></i>
  780. </span>";
  781.                     // line 565
  782.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse565), "html"nulltrue);
  783.                     yield "</li>
  784.                         ";
  785.                 }
  786.                 // line 567
  787.                 yield "                        ";
  788.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse567) > 0)) {
  789.                     // line 568
  790.                     yield "                        <li><i class=\"bi bi-camera-video-fill\"></i>";
  791.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse568), "html"nulltrue);
  792.                     yield "</li>
  793.                         ";
  794.                 }
  795.                 // line 570
  796.                 yield "                      </ul>
  797.                     </div>
  798.                   </div>
  799.                 ";
  800.             }
  801.             // line 574
  802.             yield "              ";
  803.             ++$context['loop']['index0'];
  804.             ++$context['loop']['index'];
  805.             $context['loop']['first'] = false;
  806.             if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
  807.                 --$context['loop']['revindex0'];
  808.                 --$context['loop']['revindex'];
  809.                 $context['loop']['last'] = === $context['loop']['revindex0'];
  810.             }
  811.         }
  812.         $_parent $context['_parent'];
  813.         unset($context['_seq'], $context['x'], $context['groupAttach'], $context['_parent'], $context['loop']);
  814.         $context array_intersect_key($context$_parent) + $_parent;
  815.         // line 575
  816.         yield "      </div>
  817.     </div>
  818.             </div>
  819.           </div>
  820.         </div>
  821.     <!-- Carte produit flottante -->
  822.     <div id=\"dynamic-card\" class=\"dynamic-card\" style=\"display:none\">
  823.       <div id=\"dynamic-card-content\" class=\"dynamic-card-content\" >
  824.         <!-- Le contenu dynamique (album, pochette, montage vidéo) sera injecté ici -->
  825.       </div>
  826.     </div>
  827.     <!-- Descriptions and Attachments -->
  828.     <div class=\"container--gallery modern\">
  829.       ";
  830.         // line 590
  831.         $context["lastValidIndex"] = 0;
  832.         // line 591
  833.         yield "      ";
  834.         $context["hasAttachments"] = false;
  835.         // line 592
  836.         yield "      ";
  837.         $context['_parent'] = $context;
  838.         $context['_seq'] = CoreExtension::ensureTraversable((isset($context["listeattach"]) || array_key_exists("listeattach"$context) ? $context["listeattach"] : (function () { throw new RuntimeError('Variable "listeattach" does not exist.'592$this->source); })()));
  839.         $context['loop'] = [
  840.           'parent' => $context['_parent'],
  841.           'index0' => 0,
  842.           'index'  => 1,
  843.           'first'  => true,
  844.         ];
  845.         if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) {
  846.             $length count($context['_seq']);
  847.             $context['loop']['revindex0'] = $length 1;
  848.             $context['loop']['revindex'] = $length;
  849.             $context['loop']['length'] = $length;
  850.             $context['loop']['last'] = === $length;
  851.         }
  852.         foreach ($context['_seq'] as $context["x"] => $context["groupAttach"]) {
  853.             // line 593
  854.             yield "      ";
  855.             $context["xDate"] = $this->extensions['Twig\Extension\CoreExtension']->convertDate($context["x"]);
  856.             // line 594
  857.             yield "      ";
  858.             $context["finDate"] = $this->extensions['Twig\Extension\CoreExtension']->convertDate(CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'594$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse594));
  859.             // line 595
  860.             yield "      ";
  861.             if (((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'595$this->source); })()) <= (isset($context["finDate"]) || array_key_exists("finDate"$context) ? $context["finDate"] : (function () { throw new RuntimeError('Variable "finDate" does not exist.'595$this->source); })()))) {
  862.                 // line 596
  863.                 yield "      ";
  864.                 $context["lastValidIndex"] = CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse596);
  865.                 // line 597
  866.                 yield "      ";
  867.                 $context["hasAttachments"] = true;
  868.                 // line 598
  869.                 yield "      <div
  870.         id=\"demP";
  871.                 // line 599
  872.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse599), "html"nulltrue);
  873.                 yield "\"
  874.         class=\"collapse ";
  875.                 // line 600
  876.                 if ((CoreExtension::getAttribute($this->env$this->source$context["loop"], "last", [], "any"falsefalsefalse600) && ((isset($context["xDate"]) || array_key_exists("xDate"$context) ? $context["xDate"] : (function () { throw new RuntimeError('Variable "xDate" does not exist.'600$this->source); })()) <= (isset($context["finDate"]) || array_key_exists("finDate"$context) ? $context["finDate"] : (function () { throw new RuntimeError('Variable "finDate" does not exist.'600$this->source); })())))) {
  877.                     yield "show";
  878.                 }
  879.                 yield "\"
  880.         style=\"padding: 2%; padding-top: 0%\"
  881.       >
  882.         <div class=\"journal-entry\">
  883.         <div class=\"entry-header\" style=\"
  884.     display: none;
  885.     align-items: center;
  886.     justify-content: space-between;
  887.     background: #ffffff;
  888.     padding: 8px 15px;
  889.     border-radius: 10px;
  890.     margin-bottom: 20px;
  891.     box-shadow: 0 2px 8px rgba(0,0,0,0.05);
  892.     border-bottom: 1px solid #eee;
  893.     flex-wrap: wrap;
  894. \">
  895.  
  896.  
  897.   <!-- Centre : Date + Médias -->
  898.   <div style=\"
  899.       flex-grow: 1;
  900.       display: flex;
  901.       align-items: center;
  902.       justify-content: center;
  903.       flex-wrap: wrap;
  904.       gap: 12px;
  905.   \">
  906.     <!-- Date -->
  907.     <div style=\"font-weight: bold; font-size: 16px; color: #333;\">
  908.       ";
  909.                 // line 630
  910.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(Twig\Extension\CoreExtension::replace($this->extensions['Twig\Extension\CoreExtension']->formatDate($context["x"], "l d F Y"), ["Monday" => "Lundi""Tuesday" => "Mardi""Wednesday" => "Mercredi""Thursday" => "Jeudi""Friday" => "Vendredi""Saturday" => "Samedi""Sunday" => "Dimanche""January" => "Janvier""February" => "Février""March" => "Mars""April" => "Avril""May" => "Mai""June" => "Juin""July" => "Juillet""August" => "Août""September" => "Septembre""October" => "Octobre""November" => "Novembre""December" => "Décembre"]), "html"nulltrue);
  911.                 // line 638
  912.                 yield "
  913.     </div>
  914.   <!-- Filtres Médias -->
  915. <div class=\"filter-icons\" style=\"display: flex; gap: 8px; flex-wrap: wrap;\">
  916.     <span class=\"filter-badge active\" data-filter=\"all\" title=\"Afficher tout\">
  917.         <i class=\"bi bi-grid-3x3-gap-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> Tout
  918.     </span>
  919.     ";
  920.                 // line 647
  921.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse647) > 0)) {
  922.                     // line 648
  923.                     yield "    <span class=\"filter-badge\" data-filter=\"photo\" title=\"Filtrer les photos\">
  924.         <i class=\"bi bi-image\" style=\"margin-right: 5px; font-size: 14px;\"></i> ";
  925.                     // line 649
  926.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse649), "html"nulltrue);
  927.                     yield "
  928.     </span>
  929.     ";
  930.                 }
  931.                 // line 652
  932.                 yield "
  933.     ";
  934.                 // line 653
  935.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse653) > 0)) {
  936.                     // line 654
  937.                     yield "    <span class=\"filter-badge\" data-filter=\"video\" title=\"Filtrer les vidéos\">
  938.         <i class=\"bi bi-camera-video-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> ";
  939.                     // line 655
  940.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse655), "html"nulltrue);
  941.                     yield "
  942.     </span>
  943.     ";
  944.                 }
  945.                 // line 658
  946.                 yield "
  947.     ";
  948.                 // line 659
  949.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse659) > 0)) {
  950.                     // line 660
  951.                     yield "    <span class=\"filter-badge\" data-filter=\"audio\" title=\"Filtrer les messages audio\">
  952.         <i class=\"bi bi-mic-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> ";
  953.                     // line 661
  954.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse661), "html"nulltrue);
  955.                     yield "
  956.     </span>
  957.     ";
  958.                 }
  959.                 // line 664
  960.                 yield "</div>
  961.   </div>
  962.    
  963.    
  964.         </div>
  965.   <!-- Bouton Jour Suivant -->
  966.         <!-- Contenu -->
  967.         <div class=\"entry-content\" id=\"TourContent\">
  968.           <!-- Dropdown de filtrage par jour -->
  969.           <div class=\"day-filter-dropdown\" data-day-index=\"";
  970.                 // line 682
  971.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["loop"], "index", [], "any"falsefalsefalse682), "html"nulltrue);
  972.                 yield "\">
  973.             <button class=\"filter-toggle\" type=\"button\" aria-label=\"Options de filtrage\">
  974.               <i class=\"bi bi-three-dots\"></i>
  975.             </button>
  976.             <div class=\"filter-dropdown-menu\">
  977.               <div class=\"filter-option active\" data-filter=\"all\">
  978.                 <i class=\"bi bi-grid-3x3-gap-fill\"></i>
  979.                 <span>Tout</span>
  980.                 <span class=\"count\" data-count-all>0</span>
  981.               </div>
  982.               <div class=\"filter-option\" data-filter=\"photo\">
  983.                 <i class=\"bi bi-image\"></i>
  984.                 <span>Photos</span>
  985.                 <span class=\"count\" data-count-photo>";
  986.                 // line 695
  987.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"truetruefalse695)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countPhotos", [], "any"falsefalsefalse695), 0)) : (0)), "html"nulltrue);
  988.                 yield "</span>
  989.               </div>
  990.               <div class=\"filter-option\" data-filter=\"video\">
  991.                 <i class=\"bi bi-camera-video-fill\"></i>
  992.                 <span>Vidéos</span>
  993.                 <span class=\"count\" data-count-video>";
  994.                 // line 700
  995.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"truetruefalse700)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countVideos", [], "any"falsefalsefalse700), 0)) : (0)), "html"nulltrue);
  996.                 yield "</span>
  997.               </div>
  998.               <div class=\"filter-option\" data-filter=\"audio\">
  999.                 <i class=\"bi bi-mic-fill\"></i>
  1000.                 <span>Messages</span>
  1001.                 <span class=\"count\" data-count-audio>";
  1002.                 // line 705
  1003.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"truetruefalse705)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse705), 0)) : (0)), "html"nulltrue);
  1004.                 yield "</span>
  1005.               </div>
  1006.             </div>
  1007.           </div>
  1008.       
  1009.           <p class=\"description\" style=\"margin-left:2%;width:95%;margin-top:1%;margin-bottom:1%;text-align:left\">
  1010.             ";
  1011.                 // line 711
  1012.                 $context['_parent'] = $context;
  1013.                 $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'711$this->source); })()), "jourdescripdate", [], "any"falsefalsefalse711));
  1014.                 foreach ($context['_seq'] as $context["_key"] => $context["description"]) {
  1015.                     yield " ";
  1016.                     if (($this->extensions['Twig\Extension\CoreExtension']->formatDate(CoreExtension::getAttribute($this->env$this->source,                     // line 712
  1017. $context["description"], "datejourphoto", [], "any"falsefalsefalse712), "m/d/Y") == $this->extensions['Twig\Extension\CoreExtension']->formatDate($context["x"], "m/d/Y"))) {
  1018.                         // line 713
  1019.                         yield "            ";
  1020.                         yield Twig\Extension\CoreExtension::nl2br($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["description"], "description", [], "any"falsefalsefalse713), "html"nulltrue));
  1021.                         yield "
  1022.             ";
  1023.                     }
  1024.                     // line 714
  1025.                     yield " ";
  1026.                 }
  1027.                 $_parent $context['_parent'];
  1028.                 unset($context['_seq'], $context['_key'], $context['description'], $context['_parent']);
  1029.                 $context array_intersect_key($context$_parent) + $_parent;
  1030.                 // line 715
  1031.                 yield "          </p>
  1032.  
  1033.           <!-- Conteneur des photos et vidéos -->
  1034.           <div
  1035.             class=\"rowimag no-margin\"
  1036.             style=\"
  1037.               width: 100%;
  1038.               display: flex;
  1039.               flex-wrap: wrap;
  1040.               margin: 0;
  1041.               box-sizing: border-box;
  1042.             \"
  1043.           >
  1044.             <!-- Afficher les Photos et Vidéos -->
  1045.             ";
  1046.                 // line 730
  1047.                 $context['_parent'] = $context;
  1048.                 $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "attachments", [], "any"falsefalsefalse730));
  1049.                 foreach ($context['_seq'] as $context["_key"] => $context["attach"]) {
  1050.                     // line 731
  1051.                     yield "              ";
  1052.                     if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse731) == "photo")) {
  1053.                         // line 732
  1054.                         yield "           
  1055.             <div class=\"column\" data-type=\"";
  1056.                         // line 733
  1057.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse733), "html"nulltrue);
  1058.                         yield "\">
  1059.             
  1060.               <div class=\"photo-zoom photo-item\">
  1061.                 <!-- Image sans lien -->
  1062.                 <img src=\"";
  1063.                         // line 737
  1064.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse737), "html"nulltrue);
  1065.                         yield "\" alt=\"";
  1066.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse737), "html"nulltrue);
  1067.                         yield "\" loading=\"lazy\" decoding=\"async\" />
  1068.                 <!-- Icône \"voir\" pour ouvrir le slider -->
  1069.                 <div class=\"view-icon\" onclick=\"viewImage('";
  1070.                         // line 740
  1071.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "id_attchment", [], "any"falsefalsefalse740), "html"nulltrue);
  1072.                         yield "', this)\" title=\"Voir en plein écran\">
  1073.                   <i class=\"bi bi-eye-fill\"></i>
  1074.                 </div>
  1075.                 <!-- Icône du cœur avec logique existante -->
  1076.                 <div
  1077.                   class=\"heart-icon\"
  1078.                   id=\"coeur";
  1079.                         // line 747
  1080.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "id_attchment", [], "any"falsefalsefalse747), "html"nulltrue);
  1081.                         yield "\"
  1082.                   data-id=\"";
  1083.                         // line 748
  1084.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "id_attchment", [], "any"falsefalsefalse748), "html"nulltrue);
  1085.                         yield "\"
  1086.                   data-sejour-id=\"";
  1087.                         // line 749
  1088.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'749$this->source); })()), "id", [], "any"falsefalsefalse749), "html"nulltrue);
  1089.                         yield "\"
  1090.                   data-path=\"";
  1091.                         // line 750
  1092.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse750), "html"nulltrue);
  1093.                         yield "\"
  1094.                   data-description=\"";
  1095.                         // line 751
  1096.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse751), "html"nulltrue);
  1097.                         yield "\"
  1098.                 >
  1099.                   ";
  1100.                         // line 753
  1101.                         if ((($tmp CoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'753$this->source); })()), "user", [], "any"falsefalsefalse753)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1102.                             yield " ";
  1103.                             if ((($tmp CoreExtension::getAttribute($this->env$this->source$context["attach"], "is_favorite", [], "any"falsefalsefalse753)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1104.                                 // line 754
  1105.                                 yield "                  <i
  1106.                     class=\"bi bi-heart-fill\"
  1107.                     title=\"Sélectionnée\"
  1108.                     style=\"color: #f56040\"
  1109.                   ></i>
  1110.                   ";
  1111.                             } else {
  1112.                                 // line 760
  1113.                                 yield "                  <i class=\"bi bi-heart\" title=\"Ajouter à ma sélection\"></i>
  1114.                   ";
  1115.                             }
  1116.                             // line 761
  1117.                             yield " ";
  1118.                         }
  1119.                         // line 762
  1120.                         yield "                </div>
  1121.                 <div class=\"photo-actions\" style=\"display: none\">
  1122.                   <button class=\"menu-btn\">⋮</button>
  1123.                   <div class=\"menu-options\">
  1124.                     <button onclick=\"addToPack('tirage')\">
  1125.                       🖨️ Ajouter au tirage
  1126.                     </button>
  1127.                     <button onclick=\"addToPack('numerique')\">
  1128.                       💾 Ajouter au numérique
  1129.                     </button>
  1130.                   </div>
  1131.                 </div>
  1132.               
  1133.               </div>
  1134.               ";
  1135.                         // line 776
  1136.                         if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse776) != "")) {
  1137.                             // line 777
  1138.                             yield "              <h4 class=\"description\">";
  1139.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse777), "html"nulltrue);
  1140.                             yield "</h4>
  1141.               ";
  1142.                         }
  1143.                         // line 779
  1144.                         yield "            </div>
  1145.             ";
  1146.                     }
  1147.                     // line 783
  1148.                     yield 
  1149.              ";
  1150.                     // line 786
  1151.                     if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse786) == "video")) {
  1152.                         // line 787
  1153.                         yield "           
  1154.             <div class=\"column\" data-type=\"";
  1155.                         // line 788
  1156.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse788), "html"nulltrue);
  1157.                         yield "\">
  1158.                  
  1159.             
  1160.                  <div class=\"video-container\" style=\"position: relative; display: inline-block; width: 100%; border-radius: 8px; overflow: hidden;\">
  1161.                         <video class=\"photo-zoom\" controls controlslist=\"nodownload noplaybackrate\" style=\"width: 100%;\">
  1162.                           <source src=\"";
  1163.                         // line 793
  1164.                         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse793), "html"nulltrue);
  1165.                         yield "\" type=\"video/mp4\" />
  1166.                           Votre navigateur ne supporte pas la lecture vidéo.
  1167.                         </video>
  1168.                       
  1169.                       </div>
  1170.               ";
  1171.                         // line 798
  1172.                         if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse798) != "")) {
  1173.                             // line 799
  1174.                             yield "              <h4 class=\"description\">";
  1175.                             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse799), "html"nulltrue);
  1176.                             yield "</h4>
  1177.               ";
  1178.                         }
  1179.                         // line 801
  1180.                         yield "            </div>
  1181.             ";
  1182.                     }
  1183.                     // line 802
  1184.                     yield 
  1185.             
  1186.             ";
  1187.                 }
  1188.                 $_parent $context['_parent'];
  1189.                 unset($context['_seq'], $context['_key'], $context['attach'], $context['_parent']);
  1190.                 $context array_intersect_key($context$_parent) + $_parent;
  1191.                 // line 805
  1192.                 yield "          </div>
  1193.           <!-- Section séparée pour les messages audio -->
  1194.           ";
  1195.                 // line 808
  1196.                 if ((CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse808) > 0)) {
  1197.                     // line 809
  1198.                     yield "          <div class=\"audio-messages-section\" style=\"margin-top:15px; border-top: 1px solid #eee; padding: 30px;\">
  1199.             <h4 style=\"margin-bottom: 15px; color: #555\">
  1200.             
  1201.               <i class=\"bi bi-mic-fill\" style=\"margin-right: 8px; color: #ffa500\"></i>
  1202.               Messages vocaux (";
  1203.                     // line 813
  1204.                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "countAudio", [], "any"falsefalsefalse813), "html"nulltrue);
  1205.                     yield ")
  1206.             </h4>
  1207.             
  1208.             ";
  1209.                     // line 816
  1210.                     if ((Twig\Extension\CoreExtension::slice($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'816$this->source); })()), "codeSejour", [], "any"falsefalsefalse816), 02) == "PF")) {
  1211.                         // line 817
  1212.                         yield "              ";
  1213.                         // line 818
  1214.                         yield "              <div class=\"audio-messages-container\" data-type=\"audio\" style=\"display: flex; flex-wrap: wrap; gap: 15px\">
  1215.                 ";
  1216.                         // line 819
  1217.                         $context['_parent'] = $context;
  1218.                         $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "attachments", [], "any"falsefalsefalse819));
  1219.                         foreach ($context['_seq'] as $context["_key"] => $context["attach"]) {
  1220.                             // line 820
  1221.                             yield "                  ";
  1222.                             if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse820) == "message")) {
  1223.                                 // line 821
  1224.                                 yield "                    <div class=\"audio-message-item\" data-type=\"audio\" style=\"background: #f9f9f9; border-radius: 8px; padding: 12px; display: flex; flex-direction: column; width: calc(33.33% - 10px); min-width: 250px; flex-grow: 1;\">
  1225.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  1226.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  1227.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\">
  1228.                           <source src=\"";
  1229.                                 // line 825
  1230.                                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse825), "html"nulltrue);
  1231.                                 yield "\" type=\"audio/mp3\" />
  1232.                           Votre navigateur ne supporte pas la lecture audio.
  1233.                         </audio>
  1234.                       </div>
  1235.                       ";
  1236.                                 // line 829
  1237.                                 if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse829) != "")) {
  1238.                                     // line 830
  1239.                                     yield "                        <div class=\"audio-description\" style=\"padding-left: 30px\">
  1240.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  1241.                             ";
  1242.                                     // line 832
  1243.                                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse832), "html"nulltrue);
  1244.                                     yield "
  1245.                           </p>
  1246.                         </div>
  1247.                       ";
  1248.                                 }
  1249.                                 // line 836
  1250.                                 yield "                    </div>
  1251.                   ";
  1252.                             }
  1253.                             // line 838
  1254.                             yield "                ";
  1255.                         }
  1256.                         $_parent $context['_parent'];
  1257.                         unset($context['_seq'], $context['_key'], $context['attach'], $context['_parent']);
  1258.                         $context array_intersect_key($context$_parent) + $_parent;
  1259.                         // line 839
  1260.                         yield "              </div>
  1261.             
  1262.             ";
  1263.                     } elseif ((((Twig\Extension\CoreExtension::slice($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source,                     // line 841
  1264. (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'841$this->source); })()), "codeSejour", [], "any"falsefalsefalse841), 02) == "PP") && (CoreExtension::getAttribute($this->env$this->source, (isset($context["parentsejour"]) || array_key_exists("parentsejour"$context) ? $context["parentsejour"] : (function () { throw new RuntimeError('Variable "parentsejour" does not exist.'841$this->source); })()), "payment", [], "any"falsefalsefalse841) == 1)) || ((Twig\Extension\CoreExtension::slice($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'841$this->source); })()), "codeSejour", [], "any"falsefalsefalse841), 02) == "EF") && (CoreExtension::getAttribute($this->env$this->source, (isset($context["parentsejour"]) || array_key_exists("parentsejour"$context) ? $context["parentsejour"] : (function () { throw new RuntimeError('Variable "parentsejour" does not exist.'841$this->source); })()), "payment", [], "any"falsefalsefalse841) == 1)))) {
  1265.                         // line 842
  1266.                         yield "              ";
  1267.                         // line 843
  1268.                         yield "              <div class=\"audio-messages-container\" data-type=\"audio\" style=\"display: flex; flex-wrap: wrap; gap: 15px\">
  1269.                 ";
  1270.                         // line 844
  1271.                         $context['_parent'] = $context;
  1272.                         $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "attachments", [], "any"falsefalsefalse844));
  1273.                         foreach ($context['_seq'] as $context["_key"] => $context["attach"]) {
  1274.                             // line 845
  1275.                             yield "                  ";
  1276.                             if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse845) == "message")) {
  1277.                                 // line 846
  1278.                                 yield "                    <div class=\"audio-message-item\" data-type=\"audio\" style=\"background: #f9f9f9; border-radius: 8px; padding: 12px; display: flex; flex-direction: column; width: calc(33.33% - 10px); min-width: 250px; flex-grow: 1;\">
  1279.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  1280.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  1281.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\">
  1282.                           <source src=\"";
  1283.                                 // line 850
  1284.                                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse850), "html"nulltrue);
  1285.                                 yield "\" type=\"audio/mp3\" />
  1286.                           Votre navigateur ne supporte pas la lecture audio.
  1287.                         </audio>
  1288.                       </div>
  1289.                       ";
  1290.                                 // line 854
  1291.                                 if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse854) != "")) {
  1292.                                     // line 855
  1293.                                     yield "                        <div class=\"audio-description\" style=\"padding-left: 30px\">
  1294.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  1295.                             ";
  1296.                                     // line 857
  1297.                                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse857), "html"nulltrue);
  1298.                                     yield "
  1299.                           </p>
  1300.                         </div>
  1301.                       ";
  1302.                                 }
  1303.                                 // line 861
  1304.                                 yield "                    </div>
  1305.                   ";
  1306.                             }
  1307.                             // line 863
  1308.                             yield "                ";
  1309.                         }
  1310.                         $_parent $context['_parent'];
  1311.                         unset($context['_seq'], $context['_key'], $context['attach'], $context['_parent']);
  1312.                         $context array_intersect_key($context$_parent) + $_parent;
  1313.                         // line 864
  1314.                         yield "              </div>
  1315.             
  1316.             ";
  1317.                     } elseif ((((Twig\Extension\CoreExtension::slice($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source,                     // line 866
  1318. (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'866$this->source); })()), "codeSejour", [], "any"falsefalsefalse866), 02) == "PP") && (CoreExtension::getAttribute($this->env$this->source, (isset($context["parentsejour"]) || array_key_exists("parentsejour"$context) ? $context["parentsejour"] : (function () { throw new RuntimeError('Variable "parentsejour" does not exist.'866$this->source); })()), "payment", [], "any"falsefalsefalse866) == 0)) || ((Twig\Extension\CoreExtension::slice($this->env->getCharset(), CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'866$this->source); })()), "codeSejour", [], "any"falsefalsefalse866), 02) == "EF") && (CoreExtension::getAttribute($this->env$this->source, (isset($context["parentsejour"]) || array_key_exists("parentsejour"$context) ? $context["parentsejour"] : (function () { throw new RuntimeError('Variable "parentsejour" does not exist.'866$this->source); })()), "payment", [], "any"falsefalsefalse866) == 0)))) {
  1319.                         // line 867
  1320.                         yield "              ";
  1321.                         // line 868
  1322.                         yield "              <div class=\"audio-messages-container\" style=\"display: flex; flex-wrap: wrap; gap: 15px; opacity: 0.5; pointer-events: none; filter: grayscale(100%);\">
  1323.                 <div class=\"audio-messages-restricted\" data-type=\"audio\" style=\"padding: 20px; background: #f0f0f0; border-radius: 8px; text-align: center; margin-bottom: 15px; width: 100%;\">
  1324.                   <i class=\"bi bi-lock-fill\" style=\"font-size: 24px; color: #808080; margin-bottom: 10px;\"></i>
  1325.                   <p style=\"margin: 0; color: #555;\">📢 Les messages vocaux sont disponibles via la boîte vocale premium. Un paiement est requis pour l’activer et y accéder.</p>
  1326.                 </div>
  1327.                 ";
  1328.                         // line 873
  1329.                         $context['_parent'] = $context;
  1330.                         $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source$context["groupAttach"], "attachments", [], "any"falsefalsefalse873));
  1331.                         foreach ($context['_seq'] as $context["_key"] => $context["attach"]) {
  1332.                             // line 874
  1333.                             yield "                  ";
  1334.                             if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "libiller", [], "any"falsefalsefalse874) == "message")) {
  1335.                                 // line 875
  1336.                                 yield "                    <div class=\"audio-message-item\" data-type=\"audio\" style=\"background: #f9f9f9; border-radius: 8px; padding: 12px; display: flex; flex-direction: column; width: calc(33.33% - 10px); min-width: 250px; flex-grow: 1;\">
  1337.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  1338.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  1339.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\" disabled>
  1340.                           <source src=\"";
  1341.                                 // line 879
  1342.                                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "path", [], "any"falsefalsefalse879), "html"nulltrue);
  1343.                                 yield "\" type=\"audio/mp3\" />
  1344.                           Votre navigateur ne supporte pas la lecture audio.
  1345.                         </audio>
  1346.                       </div>
  1347.                       ";
  1348.                                 // line 883
  1349.                                 if ((CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse883) != "")) {
  1350.                                     // line 884
  1351.                                     yield "                        <div class=\"audio-description\" style=\"padding-left: 30px\">
  1352.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  1353.                             ";
  1354.                                     // line 886
  1355.                                     yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["attach"], "descreption", [], "any"falsefalsefalse886), "html"nulltrue);
  1356.                                     yield "
  1357.                           </p>
  1358.                         </div>
  1359.                       ";
  1360.                                 }
  1361.                                 // line 890
  1362.                                 yield "                    </div>
  1363.                   ";
  1364.                             }
  1365.                             // line 892
  1366.                             yield "                ";
  1367.                         }
  1368.                         $_parent $context['_parent'];
  1369.                         unset($context['_seq'], $context['_key'], $context['attach'], $context['_parent']);
  1370.                         $context array_intersect_key($context$_parent) + $_parent;
  1371.                         // line 893
  1372.                         yield "              </div>
  1373.             ";
  1374.                     }
  1375.                     // line 895
  1376.                     yield "          </div>
  1377.         ";
  1378.                 }
  1379.                 // line 897
  1380.                 yield "        </div>
  1381.       </div>
  1382.     </div>
  1383.     ";
  1384.             }
  1385.             // line 901
  1386.             yield "    ";
  1387.             ++$context['loop']['index0'];
  1388.             ++$context['loop']['index'];
  1389.             $context['loop']['first'] = false;
  1390.             if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) {
  1391.                 --$context['loop']['revindex0'];
  1392.                 --$context['loop']['revindex'];
  1393.                 $context['loop']['last'] = === $context['loop']['revindex0'];
  1394.             }
  1395.         }
  1396.         $_parent $context['_parent'];
  1397.         unset($context['_seq'], $context['x'], $context['groupAttach'], $context['_parent'], $context['loop']);
  1398.         $context array_intersect_key($context$_parent) + $_parent;
  1399.         // line 902
  1400.         yield "    ";
  1401.         if ((($tmp =  !(isset($context["hasAttachments"]) || array_key_exists("hasAttachments"$context) ? $context["hasAttachments"] : (function () { throw new RuntimeError('Variable "hasAttachments" does not exist.'902$this->source); })())) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  1402.             // line 903
  1403.             yield "    <div class=\"welcome-message\" style=\"padding: 50px 20px; text-align: center; background: #f9f9f9; border-radius: 15px; margin: 30px auto; max-width: 800px; box-shadow: 0 5px 15px rgba(0,0,0,0.05);\">
  1404.       <img src=\"/images/welcome-icon.svg\" alt=\"Bienvenue\" style=\"width: 80px; margin-bottom: 20px;\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" onerror=\"this.src='/images/Accompagnateur/Picto5sur5.svg'; this.style.width='120px';\">
  1405.       
  1406.       <h2 style=\"color: #41a2aa; margin-bottom: 20px; font-size: 24px;\">Bienvenue sur votre espace séjour !</h2>
  1407.       
  1408.       <p style=\"font-size: 18px; color: #555; margin-bottom: 15px;\">
  1409.         Aucun contenu n'a encore été partagé pour ce séjour.
  1410.       </p>
  1411.       
  1412.       <p style=\"font-size: 16px; color: #666; margin-bottom: 25px;\">
  1413.         L'accompagnateur partagera bientôt des photos, vidéos et messages vocaux.
  1414.         <br>Revenez consulter cette page régulièrement pour suivre les aventures du séjour !
  1415.       </p>
  1416.       
  1417.       <div style=\"display: flex; justify-content: center; gap: 15px; flex-wrap: wrap;\">
  1418.         <div style=\"display: flex; align-items: center; background: #fff; padding: 15px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);\">
  1419.           <i class=\"bi bi-images\" style=\"font-size: 24px; color: #3a8d95; margin-right: 10px;\"></i>
  1420.           <span>Photos du séjour</span>
  1421.         </div>
  1422.         
  1423.         <div style=\"display: flex; align-items: center; background: #fff; padding: 15px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);\">
  1424.           <i class=\"bi bi-camera-video-fill\" style=\"font-size: 24px; color: #41a2aa; margin-right: 10px;\"></i>
  1425.           <span>Vidéos des activités</span>
  1426.         </div>
  1427.         
  1428.         <div style=\"display: flex; align-items: center; background: #fff; padding: 15px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);\">
  1429.           <i class=\"bi bi-mic-fill\" style=\"font-size: 24px; color: #ffa500; margin-right: 10px;\"></i>
  1430.           <span>Messages vocaux</span>
  1431.         </div>
  1432.       </div>
  1433.     </div>
  1434.     
  1435.     <!-- Espace supplémentaire pour déplacer le footer vers le bas -->
  1436.     <div style=\"height: 300px;\"></div>
  1437.     ";
  1438.         }
  1439.         // line 938
  1440.         yield "    
  1441.     <!-- JavaScript pour les pills et la gestion du nouveau contenu -->
  1442.     <script>
  1443.       document.addEventListener('DOMContentLoaded', function() {
  1444.         // Valider les liens de produits au chargement
  1445.         setTimeout(() => {
  1446.           if (typeof window.validateProductLinks === 'function') {
  1447.             window.validateProductLinks();
  1448.           }
  1449.         }, 1000);
  1450.         
  1451.         // ⚡ OPTIMISATION: Event delegation avec throttling pour éviter les clics multiples
  1452.         let clickThrottleTimeout = null;
  1453.         document.addEventListener('click', function(e) {
  1454.           // Throttling pour éviter les clics multiples rapides
  1455.           if (clickThrottleTimeout) return;
  1456.           
  1457.           const pill = e.target.closest('.stat-pill');
  1458.           if (pill) {
  1459.             clickThrottleTimeout = setTimeout(() => {
  1460.               clickThrottleTimeout = null;
  1461.             }, 100);
  1462.             
  1463.             // ⚡ OPTIMISÉ: Une seule boucle pour gérer les états actifs
  1464.             const statPills = document.querySelectorAll('.stat-pill');
  1465.             for (let i = 0; i < statPills.length; i++) {
  1466.               const p = statPills[i];
  1467.               if (p && p.classList) {
  1468.                 if (p === pill) {
  1469.                   p.classList.add('active');
  1470.                 } else {
  1471.                   p.classList.remove('active');
  1472.                 }
  1473.               }
  1474.             }
  1475.             
  1476.             // Déclencher le filtrage du contenu
  1477.             const filter = pill.getAttribute('data-filter');
  1478.             if (typeof window.filterContent === 'function') {
  1479.               window.filterContent(filter);
  1480.             }
  1481.           }
  1482.         });
  1483.         // Fonction de filtrage du contenu - globale
  1484.         window.filterContent = function(filter) {
  1485.           // ⚡ OPTIMISÉ: Suppression des console.log en production
  1486.           if (window.location.hostname === 'localhost' || window.location.hostname.includes('dev')) {
  1487.             console.log('Filtrage par:', filter);
  1488.           }
  1489.           
  1490.           const dateNavigation = document.querySelector('.date-navigation');
  1491.           const sectionDays = document.querySelector('.section-days');
  1492.           
  1493.           if (filter === 'favoris') {
  1494.             // Afficher la vue des favoris
  1495.             showFavoritesView();
  1496.           } else if (filter === 'audio') {
  1497.             // Afficher la vue des messages audio
  1498.             showAudiosView();
  1499.           } else if (filter === 'photos') {
  1500.             // Ouvrir le carrousel du jour actif ou du dernier jour
  1501.             openCurrentDayCarousel();
  1502.           } else {
  1503.             // Restaurer la vue normale des jours
  1504.             showDaysView();
  1505.           }
  1506.         }
  1507.         // Fonction pour afficher la vue des favoris - globale
  1508.         window.showFavoritesView = function() {
  1509.           const sectionDays = document.querySelector('.section-days');
  1510.           const containerGallery = document.querySelector('.container--gallery');
  1511.           
  1512.           // Masquer le container gallery
  1513.           if (containerGallery) {
  1514.             containerGallery.style.display = 'none';
  1515.           }
  1516.           
  1517.           // Mettre à jour l'état des boutons
  1518.           updatePhotosButtonState('favorites');
  1519.           updateAudioButtonState('favorites');
  1520.           updateFavoritesButtonState('favorites');
  1521.           
  1522.           const favoriteCount = getCurrentFavoriteCount();
  1523.           
  1524.           // sla vue des favoris avec e-commerce
  1525.           const favoritesHTML = `
  1526.             <div class=\"favorites-ecommerce-view\">
  1527.               <!-- Header avec progression -->
  1528.               <div class=\"favorites-header\">
  1529.                 <div class=\"favorites-title\">
  1530.                   <h3>Vos souvenirs sélectionnés</h3>
  1531.                   <span class=\"favorites-count\" id=\"favorites-count\">\${favoriteCount} photos</span>
  1532.                 </div>
  1533.                 <button class=\"btn-back-to-days\" onclick=\"window.showDaysView()\">
  1534.                   <i class=\"bi bi-arrow-left\"></i>
  1535.                   Retour aux jours
  1536.                 </button>
  1537.               </div>
  1538.             
  1539.               <!-- Grille des favoris -->
  1540.               <div class=\"favorites-content\">
  1541.                 <div class=\"favorites-grid\" id=\"favoritesGrid\">
  1542.                   \${generateFavoritesGrid()}
  1543.                 </div>
  1544.                 
  1545.                 <!-- Propositions de produits -->
  1546.                 <div class=\"product-suggestions\">
  1547.                   \${generateProductSuggestions(favoriteCount)}
  1548.                 </div>
  1549.               </div>
  1550.             </div>
  1551.           `;
  1552.           
  1553.           sectionDays.innerHTML = favoritesHTML;
  1554.         }
  1555.         // Fonction pour afficher la vue des messages audio - globale
  1556.         window.showAudiosView = function() {
  1557.           const sectionDays = document.querySelector('.section-days');
  1558.           const containerGallery = document.querySelector('.container--gallery');
  1559.           
  1560.           // Masquer le container gallery
  1561.           if (containerGallery) {
  1562.             containerGallery.style.display = 'none';
  1563.           }
  1564.           
  1565.           // Mettre à jour l'état des boutons
  1566.           updatePhotosButtonState('audios');
  1567.           updateAudioButtonState('audios');
  1568.           updateFavoritesButtonState('audios');
  1569.           
  1570.           // Collecter tous les messages audio de tous les jours
  1571.           const allAudioMessages = [];
  1572.           const audioItems = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  1573.           
  1574.           audioItems.forEach(item => {
  1575.             const audio = item.querySelector('audio source');
  1576.             const description = item.querySelector('.audio-description p');
  1577.             const dayContainer = item.closest('[id^=\"demP\"]');
  1578.             let dayTitle = 'Jour inconnu';
  1579.             
  1580.             if (dayContainer) {
  1581.               // Trouver le titre du jour
  1582.               const dayIndex = dayContainer.id.replace('demP', '');
  1583.               const dayCard = document.querySelector(`[data-target=\"#demP\${dayIndex}\"]`);
  1584.               if (dayCard) {
  1585.                 dayTitle = dayCard.textContent.trim();
  1586.               } else {
  1587.                 // Essayer de trouver dans les cartes de date
  1588.                 const dateCard = document.querySelector(`.date-card[data-bs-target=\"#demP\${dayIndex}\"], .date-card[data-target=\"#demP\${dayIndex}\"]`);
  1589.                 if (dateCard) {
  1590.                   const dateText = dateCard.querySelector('.date-text, .card-title, h5, .title-line');
  1591.                   if (dateText) {
  1592.                     dayTitle = dateText.textContent.trim();
  1593.                   }
  1594.                 }
  1595.               }
  1596.             }
  1597.             
  1598.             if (audio) {
  1599.               allAudioMessages.push({
  1600.                 src: audio.src,
  1601.                 description: description ? description.textContent.trim() : '',
  1602.                 day: dayTitle,
  1603.                 isRestricted: item.closest('.audio-messages-container[style*=\"opacity: 0.5\"]') !== null
  1604.               });
  1605.             }
  1606.           });
  1607.           
  1608.           // Créer la vue des messages audio
  1609.           const audiosHTML = `
  1610.             <div class=\"audios-view\">
  1611.               <!-- Header -->
  1612.               <div class=\"audios-header\" style=\"display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding: 20px; background: #f8f9fa; border-radius: 10px;\">
  1613.                 <div class=\"audios-title\">
  1614.                   <h3><span class=\"icon-telephone-voicemail\">
  1615.   <i class=\"bi bi-telephone-fill tel\"  style=\"color: #ffd700;font-size:1.5em\"></i>
  1616.   <i class=\"bi bi-voicemail vm\" style=\"color: #ffd700;font-size: 0.9rem;
  1617.     transform: translate(-40%, -46%);\"></i>
  1618. </span>
  1619.                   <span class=\"audios-count\">\${allAudioMessages.length} messages</span>
  1620.                 </div>
  1621.                 <button class=\"btn-back-to-days\" onclick=\"window.showDaysView()\" style=\"background: #6c757d; color: white; border: none; padding: 8px 16px; border-radius: 5px; cursor: pointer;\">
  1622.                   <i class=\"bi bi-arrow-left\"></i>
  1623.                   Retour aux jours
  1624.                 </button>
  1625.               </div>
  1626.               <!-- Grille des messages audio -->
  1627.               <div class=\"audios-content\" style=\"display: flex; flex-wrap: wrap; gap: 20px;\">
  1628.                 \${allAudioMessages.map(msg => `
  1629.                   <div class=\"audio-message-card\" style=\"background: #f9f9f9; border-radius: 12px; padding: 20px; width: calc(50% - 10px); min-width: 300px; \${msg.isRestricted ? 'opacity: 0.5; filter: grayscale(100%);' : ''}\">
  1630.                     \${msg.day && msg.day !== 'Jour inconnu' ? `
  1631.                       <div class=\"audio-day-tag\" style=\"background: #e9ecef; color: #495057; padding: 4px 8px; border-radius: 15px; font-size: 12px; margin-bottom: 12px; display: inline-block;\">
  1632.                         \${msg.day}
  1633.                       </div>
  1634.                     ` : ''}
  1635.                     <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 12px;\">
  1636.                       <i class=\"bi bi-mic-fill\" style=\"font-size: 24px; margin-right: 15px; color: #ffa500;\"></i>
  1637.                       <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1; border-radius: 5px;\" \${msg.isRestricted ? 'disabled' : ''}>
  1638.                         <source src=\"\${msg.src}\" type=\"audio/mp3\" />
  1639.                         Votre navigateur ne supporte pas la lecture audio.
  1640.                       </audio>
  1641.                     </div>
  1642.                     \${msg.description ? `
  1643.                       <div class=\"audio-description\" style=\"padding-left: 39px;\">
  1644.                         <p style=\"margin: 0; font-size: 14px; color: #666; line-height: 1.4;\">\${msg.description}</p>
  1645.                       </div>
  1646.                     ` : ''}
  1647.                     \${msg.isRestricted ? `
  1648.                       <div class=\"audio-restricted-notice\" style=\"text-align: center; margin-top: 10px; padding: 8px; background: #fff3cd; border-radius: 5px; border: 1px solid #ffeaa7;\">
  1649.                         <i class=\"bi bi-lock-fill\" style=\"color: #856404; margin-right: 5px;\"></i>
  1650.                         <small style=\"color: #856404;\">Accès premium requis</small>
  1651.                       </div>
  1652.                     ` : ''}
  1653.                   </div>
  1654.                 `).join('')}
  1655.               </div>
  1656.               
  1657.               \${allAudioMessages.length === 0 ? `
  1658.                 <div class=\"no-audios\" style=\"text-align: center; padding: 60px 20px; color: #6c757d;\">
  1659.                   <i class=\"bi bi-mic\" style=\"font-size: 4rem; margin-bottom: 20px; opacity: 0.3;\"></i>
  1660.                   <h4>Aucun message vocal</h4>
  1661.                   <p>Il n'y a pas encore de messages vocaux dans ce séjour.</p>
  1662.                 </div>
  1663.               ` : ''}
  1664.             </div>
  1665.           `;
  1666.           
  1667.           sectionDays.innerHTML = audiosHTML;
  1668.         }
  1669.         
  1670.         // Variables pour sauvegarder le contenu original
  1671.         let originalDaysContent = null;
  1672.         
  1673.         // Sauvegarder le contenu original au chargement
  1674.         document.addEventListener('DOMContentLoaded', function() {
  1675.           setTimeout(() => {
  1676.             const containerGallery = document.querySelector('.container--gallery');
  1677.             if (containerGallery) {
  1678.               originalDaysContent = containerGallery.outerHTML;
  1679.             }
  1680.           }, 1000);
  1681.         });
  1682.         
  1683.       
  1684.         // Fonction pour ouvrir le carrousel contextuel - globale
  1685.         window.openCurrentDayCarousel = function() {
  1686.           // Détecter la vue active
  1687.           const currentView = detectCurrentView();
  1688.           
  1689.           switch (currentView) {
  1690.             case 'favorites':
  1691.               openFavoritesCarousel();
  1692.               break;
  1693.             case 'audios':
  1694.               // Dans la vue audios, pas de carrousel photos pertinent
  1695.               console.log('Carrousel photos non disponible dans la vue audios');
  1696.               return;
  1697.             case 'days':
  1698.             default:
  1699.               openActiveDayCarousel();
  1700.               break;
  1701.           }
  1702.         }
  1703.         
  1704.         // Fonction pour mettre à jour l'état du bouton photos selon le contexte
  1705.         function updatePhotosButtonState(currentView) {
  1706.           const photosBtn = document.querySelector('.mtb-btn[data-filter=\"photos\"]');
  1707.           if (!photosBtn) return;
  1708.           
  1709.           const btnIcon = photosBtn.querySelector('i');
  1710.           const btnCount = photosBtn.querySelector('.mtb-count');
  1711.           
  1712.           switch (currentView) {
  1713.             case 'favorites':
  1714.               // Dans les favoris : bouton actif, ouvre le carrousel des favoris
  1715.               photosBtn.style.opacity = '1';
  1716.               photosBtn.style.pointerEvents = 'auto';
  1717.               photosBtn.title = 'Voir le carrousel des favoris';
  1718.               if (btnIcon) btnIcon.style.color = '#007bff';
  1719.               if (btnCount) btnCount.style.display = 'none'; // Cacher le compteur
  1720.               break;
  1721.               
  1722.             case 'audios':
  1723.               // Dans les audios : bouton désactivé
  1724.               photosBtn.style.opacity = '0.4';
  1725.               photosBtn.style.pointerEvents = 'none';
  1726.               photosBtn.title = 'Carrousel non disponible dans la vue audios';
  1727.               if (btnIcon) btnIcon.style.color = '#6c757d';
  1728.               if (btnCount) btnCount.style.display = 'none';
  1729.               break;
  1730.               
  1731.             case 'days':
  1732.             default:
  1733.               // Vue normale : utiliser la logique existante du carrousel
  1734.               photosBtn.style.opacity = '1';
  1735.               photosBtn.style.pointerEvents = 'auto';
  1736.               photosBtn.title = 'Voir les photos du jour actif';
  1737.               if (btnIcon) btnIcon.style.color = '';
  1738.               if (btnCount) btnCount.style.display = 'none'; // Cacher le compteur pour éviter la confusion
  1739.               break;
  1740.           }
  1741.         }
  1742.         
  1743.         // Fonction pour mettre à jour l'état du bouton audio selon le contexte
  1744.         window.updateAudioButtonState = function updateAudioButtonState(currentView) {
  1745.           const audioBtn = document.querySelector('.mtb-btn[data-filter=\"audio\"]');
  1746.           if (!audioBtn) return;
  1747.           
  1748.           const btnCount = audioBtn.querySelector('.mtb-count');
  1749.           
  1750.           switch (currentView) {
  1751.             case 'favorites':
  1752.               // Dans les favoris : pas d'action sur le compteur audio
  1753.               break;
  1754.               
  1755.             case 'audios':
  1756.               // Dans les audios : afficher le nombre total calculé par le frontend
  1757.               const totalAudioCount = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]').length;
  1758.               if (btnCount) {
  1759.                 btnCount.textContent = totalAudioCount;
  1760.               }
  1761.               break;
  1762.               
  1763.             case 'days':
  1764.             default:
  1765.               // Vue normale : compter les audios du jour actif
  1766.               const activeDayAudioCount = countActiveDayAudios();
  1767.               if (btnCount) {
  1768.                 btnCount.textContent = activeDayAudioCount;
  1769.               }
  1770.               break;
  1771.           }
  1772.         }
  1773.         
  1774.         // Fonction pour mettre à jour l'état du bouton favoris selon le contexte
  1775.         window.updateFavoritesButtonState = function updateFavoritesButtonState(currentView) {
  1776.           const favoritesBtn = document.querySelector('.mtb-btn[data-filter=\"favoris\"]');
  1777.           if (!favoritesBtn) return;
  1778.           
  1779.           const btnIcon = favoritesBtn.querySelector('i');
  1780.           const btnCount = favoritesBtn.querySelector('.mtb-count');
  1781.           
  1782.           switch (currentView) {
  1783.             case 'favorites':
  1784.               // Dans les favoris : bouton actif
  1785.               favoritesBtn.style.opacity = '1';
  1786.               favoritesBtn.style.pointerEvents = 'auto';
  1787.               favoritesBtn.title = 'Vous êtes dans la vue favoris';
  1788.               if (btnIcon) btnIcon.style.color = '#f56040';
  1789.               if (btnCount) btnCount.style.display = 'inline';
  1790.               favoritesBtn.classList.add('active');
  1791.               break;
  1792.               
  1793.             case 'audios':
  1794.               // Dans les audios : bouton désactivé
  1795.               favoritesBtn.style.opacity = '0.4';
  1796.               favoritesBtn.style.pointerEvents = 'none';
  1797.               favoritesBtn.title = 'Favoris non disponibles dans la vue audios';
  1798.               if (btnIcon) btnIcon.style.color = '#6c757d';
  1799.               if (btnCount) btnCount.style.display = 'none';
  1800.               favoritesBtn.classList.remove('active');
  1801.               break;
  1802.               
  1803.             case 'days':
  1804.             default:
  1805.               // Vue normale : bouton normal
  1806.               favoritesBtn.style.opacity = '1';
  1807.               favoritesBtn.style.pointerEvents = 'auto';
  1808.               favoritesBtn.title = 'Voir les favoris';
  1809.               if (btnIcon) btnIcon.style.color = '#f56040';
  1810.               if (btnCount) btnCount.style.display = 'inline';
  1811.               favoritesBtn.classList.remove('active');
  1812.               break;
  1813.           }
  1814.         }
  1815.         
  1816.         // Fonction pour compter les audios du jour actif (réutilise la même logique)
  1817.         // ⚡ OPTIMISÉ: Cache des éléments DOM pour éviter les requêtes répétitives
  1818.         let cachedActiveDay = null;
  1819.         let cachedAudioCount = 0;
  1820.         let lastCacheTime = 0;
  1821.         const CACHE_DURATION = 1000; // 1 seconde
  1822.         
  1823.         function countActiveDayAudios() {
  1824.           const now = Date.now();
  1825.           
  1826.           // Utiliser le cache si récent
  1827.           if (cachedActiveDay && (now - lastCacheTime) < CACHE_DURATION) {
  1828.             return cachedAudioCount;
  1829.           }
  1830.           
  1831.           // Trouver le jour actuellement ouvert
  1832.           let activeDay = document.querySelector('.collapse.show[id^=\"demP\"]');
  1833.           
  1834.           // Si aucun jour ouvert, prendre le dernier jour
  1835.           if (!activeDay) {
  1836.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  1837.             activeDay = allDays[allDays.length - 1];
  1838.           }
  1839.           
  1840.           if (!activeDay) {
  1841.             cachedActiveDay = null;
  1842.             cachedAudioCount = 0;
  1843.             lastCacheTime = now;
  1844.             return 0;
  1845.           }
  1846.           
  1847.           // Compter les messages audio dans ce jour
  1848.           const audiosInDay = activeDay.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  1849.           const count = audiosInDay.length;
  1850.           
  1851.           // Mettre à jour le cache
  1852.           cachedActiveDay = activeDay;
  1853.           cachedAudioCount = count;
  1854.           lastCacheTime = now;
  1855.           
  1856.           return count;
  1857.         }
  1858.         
  1859.         // Fonction pour détecter la vue active
  1860.         // ⚡ OPTIMISÉ: Cache de la vue active pour éviter les requêtes DOM répétitives
  1861.         let cachedCurrentView = null;
  1862.         let lastViewCheck = 0;
  1863.         const VIEW_CACHE_DURATION = 500; // 500ms
  1864.         
  1865.         function detectCurrentView() {
  1866.           const now = Date.now();
  1867.           
  1868.           // Utiliser le cache si récent
  1869.           if (cachedCurrentView && (now - lastViewCheck) < VIEW_CACHE_DURATION) {
  1870.             return cachedCurrentView;
  1871.           }
  1872.           
  1873.           let view = 'days';
  1874.           if (document.querySelector('.favorites-ecommerce-view')) {
  1875.             view = 'favorites';
  1876.           } else if (document.querySelector('.audios-view')) {
  1877.             view = 'audios';
  1878.           }
  1879.           
  1880.           // Mettre à jour le cache
  1881.           cachedCurrentView = view;
  1882.           lastViewCheck = now;
  1883.           
  1884.           return view;
  1885.         }
  1886.         
  1887.         // ⚡ OPTIMISÉ: Cache global des éléments DOM fréquemment utilisés
  1888.         const domCache = {
  1889.           favoritesGrid: null,
  1890.           lastFavoritesUpdate: 0,
  1891.           CACHE_DURATION: 2000 // 2 secondes
  1892.         };
  1893.         
  1894.         function getCachedFavorites() {
  1895.           const now = Date.now();
  1896.           if (!domCache.favoritesGrid || (now - domCache.lastFavoritesUpdate) > domCache.CACHE_DURATION) {
  1897.             domCache.favoritesGrid = document.querySelector('.favorites-grid');
  1898.             domCache.lastFavoritesUpdate = now;
  1899.           }
  1900.           return domCache.favoritesGrid;
  1901.         }
  1902.         
  1903.         // Fonction pour ouvrir le carrousel des favoris
  1904.         function openFavoritesCarousel() {
  1905.           const favoritesGrid = getCachedFavorites();
  1906.           const favoriteItems = favoritesGrid ? favoritesGrid.querySelectorAll('.favorite-item') : [];
  1907.           if (favoriteItems.length > 0) {
  1908.             // Trouver le premier favori avec une action de vue
  1909.             const firstFavorite = favoriteItems[0];
  1910.             const viewBtn = firstFavorite.querySelector('.btn-view-favorite');
  1911.             if (viewBtn && viewBtn.onclick) {
  1912.               viewBtn.click();
  1913.             } else {
  1914.               // Fallback : extraire l'ID du data-id et utiliser viewImage
  1915.               const favoriteId = firstFavorite.dataset.id;
  1916.               if (favoriteId && typeof window.viewImage === 'function') {
  1917.                 window.viewImage(favoriteId, firstFavorite);
  1918.               }
  1919.             }
  1920.           } else {
  1921.             console.log('Aucun favori trouvé pour ouvrir le carrousel');
  1922.           }
  1923.         }
  1924.         
  1925.         // Fonction pour ouvrir le carrousel du jour actif
  1926.         function openActiveDayCarousel() {
  1927.           // Trouver le jour actuellement ouvert (avec classe 'show')
  1928.           let activeDay = document.querySelector('.collapse.show[id^=\"demP\"]');
  1929.           
  1930.           // Si aucun jour n'est ouvert, prendre le dernier jour
  1931.           if (!activeDay) {
  1932.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  1933.             activeDay = allDays[allDays.length - 1]; // Dernier jour
  1934.           }
  1935.           
  1936.           if (!activeDay) {
  1937.             console.warn('Aucun jour trouvé pour ouvrir le carrousel');
  1938.             return;
  1939.           }
  1940.           
  1941.           // Trouver la première photo de ce jour
  1942.           const viewIcon = activeDay.querySelector('.view-icon[onclick*=\"viewImage\"]');
  1943.           if (viewIcon) {
  1944.             // Extraire l'ID de la photo du onclick
  1945.             const onclickAttr = viewIcon.getAttribute('onclick');
  1946.             const match = onclickAttr.match(/viewImage\\('(\\d+)'/);
  1947.             if (match) {
  1948.               const imageId = match[1];
  1949.               // Ouvrir le slider avec cette image
  1950.               if (typeof window.viewImage === 'function') {
  1951.                 window.viewImage(imageId, viewIcon);
  1952.               }
  1953.             }
  1954.           } else {
  1955.             // Fallback : chercher dans tous les jours
  1956.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  1957.             for (let day of allDays) {
  1958.               const photoInDay = day.querySelector('.view-icon[onclick*=\"viewImage\"]');
  1959.               if (photoInDay) {
  1960.                 photoInDay.click();
  1961.                 break;
  1962.               }
  1963.             }
  1964.           }
  1965.         }
  1966.         // Fonction pour afficher la vue normale des jours - globale
  1967.         window.showDaysView = function() {
  1968.           const sectionDays = document.querySelector('.section-days');
  1969.           const containerGallery = document.querySelector('.container--gallery');
  1970.           
  1971.           // Si la section days contient des vues spéciales (favoris/audios), les supprimer
  1972.           if (sectionDays && (sectionDays.innerHTML.includes('favorites-ecommerce-view') || sectionDays.innerHTML.includes('audios-view'))) {
  1973.             // Restaurer le contenu original si disponible
  1974.             if (originalDaysContent) {
  1975.               sectionDays.innerHTML = originalDaysContent;
  1976.             } else {
  1977.               // Fallback : recharger la page si pas de sauvegarde
  1978.               location.reload();
  1979.               return;
  1980.             }
  1981.           }
  1982.           
  1983.           // Restaurer la visibilité du container gallery
  1984.           if (containerGallery) {
  1985.             containerGallery.style.display = 'block';
  1986.           }
  1987.           
  1988.           // Appeler le filtre \"all\" pour restaurer l'affichage complet
  1989.           if (typeof window.filterContent === 'function') {
  1990.             window.filterContent('toutVoir');
  1991.           }
  1992.           
  1993.           // Mettre à jour l'état des boutons
  1994.           updatePhotosButtonState('days');
  1995.           updateAudioButtonState('days');
  1996.           updateFavoritesButtonState('days');
  1997.         }
  1998.         // Fonction pour générer les cartes de jours (alternative simple)
  1999.         function generateDaysCards() {
  2000.           // Cette fonction pourrait régénérer les cartes, mais pour simplifier
  2001.           // on recharge la page dans showDaysView()
  2002.           return '';
  2003.         }
  2004.         // Fonction pour revenir à la vue des jours
  2005.      
  2006.         // Fonction pour générer la grille des favoris
  2007.         function generateFavoritesGrid() {
  2008.           const favorites = getFavoriteItems();
  2009.           
  2010.           if (favorites.length === 0) {
  2011.             return `
  2012.               <div class=\"no-favorites\">
  2013.                 <i class=\"bi bi-heart\" style=\"font-size: 3rem; color: #ccc; margin-bottom: 1rem;\"></i>
  2014.                 <h4>Aucun favori sélectionné</h4>
  2015.                 <p>Cliquez sur <i class=\"bi bi-heart\" style=\"color: #e91e63;\"></i> sur vos photos préférées pour les ajouter ici.</p>
  2016.               </div>
  2017.             `;
  2018.           }
  2019.           
  2020.           return favorites.map(item => `
  2021.             <div class=\"favorite-item\" data-id=\"\${item.id}\">
  2022.               \${item.type === 'image' ? 
  2023.                 `<img src=\"\${item.url}\" alt=\"Photo favorite\" loading=\"lazy\">` :
  2024.                 item.type === 'video' ? 
  2025.                 `<video src=\"\${item.url}\" poster=\"\${item.thumbnail}\"></video>
  2026.                  <div class=\"video-overlay\"><i class=\"bi bi-play-circle\"></i></div>` :
  2027.                 `<div class=\"audio-item\">
  2028.                    <i class=\"bi bi-mic-fill\"></i>
  2029.                    <span>Audio \${item.duration || '00:00'}</span>
  2030.                  </div>`
  2031.               }
  2032.               <!-- Actions overlay -->
  2033.               <div class=\"favorite-actions\">
  2034.                 <button class=\"btn-view-favorite\" onclick=\"viewFavorite('\${item.id}')\" title=\"Voir en grand\">
  2035.                   <i class=\"bi bi-eye\"></i>
  2036.                   <span>Voir</span>
  2037.                 </button>
  2038.                 <button class=\"btn-remove-favorite\" onclick=\"removeFavorite('\${item.id}')\" title=\"Retirer des favoris\">
  2039.                   <i class=\"bi bi-heart-fill\"></i>
  2040.                   <span>Retirer</span>
  2041.                 </button>
  2042.               </div>
  2043.             </div>
  2044.           `).join('');
  2045.         }
  2046.         // Fonction pour réorganiser la grille des favoris
  2047.         function reorganizeFavoritesGrid() {
  2048.           const favoritesGrid = document.getElementById('favoritesGrid');
  2049.           if (!favoritesGrid) return;
  2050.           
  2051.           const remainingItems = favoritesGrid.querySelectorAll('.favorite-item');
  2052.           if (remainingItems.length === 0) {
  2053.             // Afficher le message \"Aucun favori\"
  2054.             favoritesGrid.innerHTML = `
  2055.               <div class=\"no-favorites\">
  2056.                 <i class=\"bi bi-heart\" style=\"font-size: 3rem; color: #ccc; margin-bottom: 1rem;\"></i>
  2057.                 <h4>Aucun favori sélectionné</h4>
  2058.                 <p>Cliquez sur <i class=\"bi bi-heart\" style=\"color: #e91e63;\"></i> sur vos photos préférées pour les ajouter ici.</p>
  2059.               </div>
  2060.             `;
  2061.           } else {
  2062.             // Réorganiser les éléments restants avec une animation douce
  2063.             remainingItems.forEach((item, index) => {
  2064.               item.style.transition = 'all 0.3s ease';
  2065.               item.style.order = index;
  2066.             });
  2067.           }
  2068.         }
  2069.         // Fonction pour récupérer les éléments favoris
  2070.         function getFavoriteItems() {
  2071.           const favorites = [];
  2072.           
  2073.           // ⚡ OPTIMISÉ: Cache et parcours plus efficace des favoris
  2074.           const heartIcons = document.querySelectorAll('.heart-icon');
  2075.           for (let i = 0; i < heartIcons.length; i++) {
  2076.             const heartIcon = heartIcons[i];
  2077.             const heartFill = heartIcon.querySelector('.bi-heart-fill');
  2078.             if (heartFill) {
  2079.               const id = heartIcon.getAttribute('data-id');
  2080.               const path = heartIcon.getAttribute('data-path');
  2081.               const description = heartIcon.getAttribute('data-description');
  2082.               
  2083.               if (id && path) {
  2084.                 // Déterminer le type de média
  2085.                 let type = 'image';
  2086.                 let url = path;
  2087.                 let thumbnail = path;
  2088.                 
  2089.                 if (path.includes('.mp4') || path.includes('.mov') || path.includes('.avi')) {
  2090.                   type = 'video';
  2091.                   thumbnail = path.replace(/\\.(mp4|mov|avi)\$/i, '_thumb.jpg');
  2092.                 } else if (path.includes('.mp3') || path.includes('.wav') || path.includes('.m4a')) {
  2093.                   type = 'audio';
  2094.                   url = path;
  2095.                 }
  2096.                 
  2097.                 // Récupérer la date depuis le conteneur parent
  2098.                 const dateCard = heartIcon.closest('[id^=\"demP\"]');
  2099.                 let date = 'Date inconnue';
  2100.                 if (dateCard) {
  2101.                   const dateElement = dateCard.querySelector('.full-date, .day-title');
  2102.                   if (dateElement) {
  2103.                     date = dateElement.textContent.trim();
  2104.                   }
  2105.                 }
  2106.                 
  2107.                 favorites.push({
  2108.                   id: id,
  2109.                   url: url,
  2110.                   thumbnail: thumbnail,
  2111.                   type: type,
  2112.                   date: date,
  2113.                   description: description || ''
  2114.                 });
  2115.               }
  2116.             }
  2117.           }
  2118.           
  2119.           // ⚡ OPTIMISÉ: Log conditionnel pour réduire l'impact performance
  2120.           if (favorites.length > 0) {
  2121.             console.log('Favoris trouvés:', favorites.length);
  2122.           }
  2123.           return favorites;
  2124.         }
  2125.         // Rendre les fonctions accessibles globalement
  2126.         window.viewFavorite = viewFavorite;
  2127.         window.removeFavorite = removeFavorite;
  2128.         window.getFavoriteItems = getFavoriteItems;
  2129.         // Fonction pour supprimer un favori
  2130.         function removeFavorite(id) {
  2131.          
  2132.           const heartIcon = document.querySelector(`[data-id=\"\${id}\"]`);
  2133.          
  2134.           if (heartIcon) {
  2135.             const heartFill = heartIcon.querySelector('.bi-heart-fill');
  2136.             if (heartFill && heartFill.classList) {
  2137.               heartFill.classList.remove('bi-heart-fill');
  2138.               heartFill.classList.add('bi-heart');
  2139.               heartFill.style.color = '';
  2140.             }
  2141.           }
  2142.           const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${id}\"]`);
  2143.         
  2144.           if (favoriteItem) {
  2145.             // Animation de disparition puis suppression complète
  2146.             favoriteItem.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
  2147.             favoriteItem.style.opacity = '0';
  2148.             favoriteItem.style.transform = 'scale(0.8)';
  2149.             
  2150.             setTimeout(() => {
  2151.               favoriteItem.remove();
  2152.               
  2153.               // Appeler la fonction métier si présente
  2154.               const heartIcon = document.querySelector(`#coeur\${id}`);
  2155.               const sejourId = heartIcon && heartIcon.dataset.sejourId ? heartIcon.dataset.sejourId : '';
  2156.               supprimerFavoris(id, sejourId);
  2157.               
  2158.               // Mettre à jour les compteurs
  2159.               updateAllFavoriteCounters();
  2160.               
  2161.               // Réorganiser la grille si nécessaire
  2162.               reorganizeFavoritesGrid();
  2163.             }, 300);
  2164.       
  2165.      
  2166.    
  2167.   }
  2168.           
  2169.         }
  2170.         // Slider plein écran pour les favoris
  2171.         class FavoritesSlider {
  2172.           constructor() {
  2173.             this.currentIndex = 0;
  2174.             this.favorites = [];
  2175.             this.isOpen = false;
  2176.             this.touchStartX = 0;
  2177.             this.touchEndX = 0;
  2178.           }
  2179.           open(favoriteId) {
  2180.             console.log('Ouverture du slider pour:', favoriteId);
  2181.             
  2182.             // Récupérer tous les favoris images
  2183.             this.favorites = getFavoriteItems().filter(item => item.type === 'image');
  2184.             
  2185.             if (this.favorites.length === 0) {
  2186.               console.error('Aucun favori image trouvé');
  2187.               return;
  2188.             }
  2189.             // Trouver l'index de l'image courante
  2190.             this.currentIndex = this.favorites.findIndex(fav => fav.id === favoriteId);
  2191.             if (this.currentIndex === -1) this.currentIndex = 0;
  2192.             console.log('Index courant:', this.currentIndex, 'Total:', this.favorites.length);
  2193.             this.createSlider();
  2194.             this.showSlide(this.currentIndex);
  2195.             this.attachEvents();
  2196.             this.isOpen = true;
  2197.             // Animation d'ouverture immédiate pour favoris avec diagnostic
  2198.             setTimeout(() => {
  2199.               if (window.diagnoseSliderDisplay) {
  2200.                 window.diagnoseSliderDisplay('#favoritesSlider');
  2201.               }
  2202.             }, 50);
  2203.           }
  2204.           createSlider() {
  2205.             // ⚡ OPTIMISATION: Créer le slider seulement quand nécessaire
  2206.             if (document.querySelector('#favoritesSlider')) {
  2207.               return; // Déjà créé, ne pas recréer
  2208.             }
  2209.             
  2210.             // Structure HTML minimale et optimisée
  2211.             const sliderHTML = `
  2212.               <div class=\"favorites-slider\" id=\"favoritesSlider\" style=\"
  2213.                 position: fixed !important; 
  2214.                 top: 0 !important; 
  2215.                 left: 0 !important; 
  2216.                 width: 100% !important; 
  2217.                 height: 100% !important; 
  2218.                 background: rgba(0,0,0,0.95) !important; 
  2219.                 z-index: 9999 !important; 
  2220.                 display: flex !important; 
  2221.                 align-items: center !important; 
  2222.                 justify-content: center !important; 
  2223.                 opacity: 1 !important; 
  2224.                 visibility: visible !important;
  2225.               \">
  2226.                 <div class=\"slider-overlay\"></div>
  2227.                 
  2228.                 <!-- Header avec contrôles -->
  2229.                 <div class=\"slider-header\">
  2230.                   <div class=\"slider-controls\">
  2231.                     <button class=\"slider-btn favorite-btn\" title=\"Retirer des favoris\">
  2232.                       <i class=\"bi bi-heart-fill\"></i>
  2233.                     </button>
  2234.                     <button class=\"slider-btn zoom-btn\" title=\"Zoom\">
  2235.                       <i class=\"bi bi-zoom-in\"></i>
  2236.                     </button>
  2237.                     <button class=\"slider-btn close-btn\" title=\"Fermer\">
  2238.                       <i class=\"bi bi-x-lg\"></i>
  2239.                     </button>
  2240.                   </div>
  2241.                 </div>
  2242.                 <!-- Navigation -->
  2243.                 <button class=\"slider-nav prev-btn\" title=\"Précédent\">
  2244.                   <i class=\"bi bi-arrow-left-circle-fill\"></i>
  2245.                 </button>
  2246.                 <button class=\"slider-nav next-btn\" title=\"Suivant\">
  2247.                   <i class=\"bi bi-arrow-right-circle-fill\"></i>
  2248.                 </button>
  2249.                 <!-- Container des slides -->
  2250.                 <div class=\"slider-container\">
  2251.                   <div class=\"slider-track\" id=\"sliderTrack\">
  2252.                     \${this.favorites.map((fav, index) => `
  2253.                       <div class=\"slide\" data-index=\"\${index}\">
  2254.                         <div class=\"slide-content\">
  2255.                           <img src=\"\${fav.url}\" alt=\"\${fav.description || 'Photo favorite'}\" 
  2256.                                loading=\"\${index <= 2 ? 'eager' : 'lazy'}\"
  2257.                                draggable=\"false\">
  2258.                         </div>
  2259.                         <div class=\"slide-info\">
  2260.                           <h4>\${fav.description || 'Photo favorite'}</h4>
  2261.                           <p>\${fav.date || 'Date inconnue'}</p>
  2262.                         </div>
  2263.                       </div>
  2264.                     `).join('')}
  2265.                   </div>
  2266.                 </div>
  2267.                 <!-- Thumbnails -->
  2268.                 <div class=\"slider-thumbnails\">
  2269.                   \${this.favorites.map((fav, index) => `
  2270.                     <div class=\"thumbnail \${index === this.currentIndex ? 'active' : ''}\" 
  2271.                          data-index=\"\${index}\">
  2272.                       <img src=\"\${fav.url}\" alt=\"Thumbnail \${index + 1}\">
  2273.                     </div>
  2274.                   `).join('')}
  2275.                 </div>
  2276.               </div>
  2277.             `;
  2278.             // Injecter dans le DOM
  2279.             document.body.insertAdjacentHTML('beforeend', sliderHTML);
  2280.           }
  2281.           showSlide(index) {
  2282.             if (index < 0 || index >= this.favorites.length) return;
  2283.             this.currentIndex = index;
  2284.             const track = document.getElementById('sliderTrack');
  2285.             const translateX = -index * 100;
  2286.             
  2287.             track.style.transform = `translateX(\${translateX}%)`;
  2288.             // ⚡ OPTIMISÉ: Éviter forEach sur querySelectorAll (mémoire)
  2289.             const thumbnails = document.querySelectorAll('.thumbnail');
  2290.             for (let i = 0; i < thumbnails.length; i++) {
  2291.               const thumb = thumbnails[i];
  2292.               if (thumb?.classList) {
  2293.                 thumb.classList.toggle('active', i === index);
  2294.               }
  2295.             }
  2296.             // Mettre à jour le bouton favori
  2297.             const currentFav = this.favorites[index];
  2298.             const favoriteBtn = document.querySelector('.slider-controls .favorite-btn');
  2299.             if (favoriteBtn && currentFav) {
  2300.               favoriteBtn.setAttribute('data-id', currentFav.id);
  2301.             }
  2302.           }
  2303.           nextSlide() {
  2304.             const nextIndex = (this.currentIndex + 1) % this.favorites.length;
  2305.             this.showSlide(nextIndex);
  2306.           }
  2307.           prevSlide() {
  2308.             const prevIndex = (this.currentIndex - 1 + this.favorites.length) % this.favorites.length;
  2309.             this.showSlide(prevIndex);
  2310.           }
  2311.           close() {
  2312.             if (!this.isOpen) return;
  2313.             const slider = document.querySelector('.favorites-slider');
  2314.             if (slider && slider.classList) {
  2315.               slider.classList.remove('active');
  2316.               
  2317.               setTimeout(() => {
  2318.                 slider.remove();
  2319.                 this.isOpen = false;
  2320.               }, 300);
  2321.             }
  2322.           }
  2323.           attachEvents() {
  2324.             const slider = document.getElementById('favoritesSlider');
  2325.             
  2326.             // Bouton fermer
  2327.             slider.querySelector('.close-btn').addEventListener('click', () => this.close());
  2328.             
  2329.             // Navigation
  2330.             slider.querySelector('.prev-btn').addEventListener('click', () => this.prevSlide());
  2331.             slider.querySelector('.next-btn').addEventListener('click', () => this.nextSlide());
  2332.             
  2333.             // ⚡ OPTIMISÉ: Event delegation au lieu de listeners multiples
  2334.             const thumbContainer = slider.querySelector('.thumbnails-container') || slider;
  2335.             if (thumbContainer && !thumbContainer.hasAttribute('data-thumb-delegated')) {
  2336.               thumbContainer.addEventListener('click', (e) => {
  2337.                 const thumb = e.target.closest('.thumbnail');
  2338.                 if (thumb) {
  2339.                   const thumbnails = slider.querySelectorAll('.thumbnail');
  2340.                   const index = Array.from(thumbnails).indexOf(thumb);
  2341.                   if (index !== -1) this.showSlide(index);
  2342.                 }
  2343.               });
  2344.               thumbContainer.setAttribute('data-thumb-delegated', 'true');
  2345.             }
  2346.             // Bouton favori
  2347.             slider.querySelector('.favorite-btn').addEventListener('click', (e) => {
  2348.               const favoriteId = e.currentTarget.getAttribute('data-id');
  2349.               if (favoriteId) {
  2350.                 removeFavorite(favoriteId);
  2351.                 // Recharger le slider avec les favoris mis à jour
  2352.                 setTimeout(() => {
  2353.                   this.close();
  2354.                   if (getFavoriteItems().filter(item => item.type === 'image').length > 0) {
  2355.                     this.open(this.favorites[0]?.id);
  2356.                   }
  2357.                 }, 100);
  2358.               }
  2359.             });
  2360.             // Clavier
  2361.             document.addEventListener('keydown', this.handleKeyboard.bind(this));
  2362.             
  2363.             // Clic sur overlay pour fermer
  2364.             slider.querySelector('.slider-overlay').addEventListener('click', () => this.close());
  2365.             // Touch/swipe sur mobile
  2366.             const track = slider.querySelector('.slider-track');
  2367.             track.addEventListener('touchstart', this.handleTouchStart.bind(this), { passive: true });
  2368.             track.addEventListener('touchend', this.handleTouchEnd.bind(this), { passive: true });
  2369.             // Zoom sur clic simple (5 niveaux) + double-clic (legacy)
  2370.             slider.querySelectorAll('.slide img').forEach(img => {
  2371.               let zoomLevel = 1;
  2372.               let isDragging = false;
  2373.               let startX, startY, translateX = 0, translateY = 0;
  2374.               
  2375.               // Zoom sur clic simple (nouveau système 5 niveaux)
  2376.               img.addEventListener('click', (e) => {
  2377.                 e.preventDefault();
  2378.                 e.stopPropagation();
  2379.                 
  2380.                 // Cycle à travers 5 niveaux de zoom
  2381.                 switch(zoomLevel) {
  2382.                   case 1: zoomLevel = 1.5; break;  // 1x → 1.5x
  2383.                   case 1.5: zoomLevel = 2; break;  // 1.5x → 2x
  2384.                   case 2: zoomLevel = 3; break;    // 2x → 3x
  2385.                   case 3: zoomLevel = 4; break;    // 3x → 4x
  2386.                   case 4: zoomLevel = 5; break;    // 4x → 5x
  2387.                   case 5: 
  2388.                     zoomLevel = 1;                 // 5x → 1x (reset)
  2389.                     translateX = 0;
  2390.                     translateY = 0;
  2391.                     break;
  2392.                 }
  2393.                 console.log('FavoritesSlider - Zoom niveau:', zoomLevel);
  2394.                 img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  2395.                 
  2396.                 // Curseur selon le niveau
  2397.                 if (zoomLevel === 1) {
  2398.                   img.style.cursor = 'zoom-in';
  2399.                   img.removeAttribute('data-zoomed');
  2400.                 } else if (zoomLevel === 5) {
  2401.                   img.style.cursor = 'zoom-out';
  2402.                   img.setAttribute('data-zoomed', zoomLevel);
  2403.                 } else {
  2404.                   img.style.cursor = 'zoom-in';
  2405.                   img.setAttribute('data-zoomed', zoomLevel);
  2406.                 }
  2407.               });
  2408.               
  2409.               // Drag pour déplacer l'image zoomée
  2410.               img.addEventListener('mousedown', (e) => {
  2411.                 if (zoomLevel > 1) {
  2412.                   isDragging = true;
  2413.                   startX = e.clientX - translateX;
  2414.                   startY = e.clientY - translateY;
  2415.                   img.style.cursor = 'grabbing';
  2416.                   e.preventDefault();
  2417.                   e.stopPropagation();
  2418.                 }
  2419.               });
  2420.               const handleMouseMove = (e) => {
  2421.                 if (isDragging && zoomLevel > 1) {
  2422.                   translateX = e.clientX - startX;
  2423.                   translateY = e.clientY - startY;
  2424.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  2425.                 }
  2426.               };
  2427.               const handleMouseUp = () => {
  2428.                 if (isDragging) {
  2429.                   isDragging = false;
  2430.                   if (zoomLevel === 1) {
  2431.                     img.style.cursor = 'zoom-in';
  2432.                   } else if (zoomLevel === 5) {
  2433.                     img.style.cursor = 'zoom-out';
  2434.                   } else {
  2435.                     img.style.cursor = 'zoom-in';
  2436.                   }
  2437.                 }
  2438.               };
  2439.               document.addEventListener('mousemove', handleMouseMove);
  2440.               document.addEventListener('mouseup', handleMouseUp);
  2441.               // Support tactile pour mobile
  2442.               img.addEventListener('touchstart', (e) => {
  2443.                 if (zoomLevel > 1 && e.touches.length === 1) {
  2444.                   isDragging = true;
  2445.                   const touch = e.touches[0];
  2446.                   startX = touch.clientX - translateX;
  2447.                   startY = touch.clientY - translateY;
  2448.                   e.preventDefault();
  2449.                 }
  2450.               });
  2451.               img.addEventListener('touchmove', (e) => {
  2452.                 if (isDragging && zoomLevel > 1 && e.touches.length === 1) {
  2453.                   const touch = e.touches[0];
  2454.                   translateX = touch.clientX - startX;
  2455.                   translateY = touch.clientY - startY;
  2456.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  2457.                   e.preventDefault();
  2458.                 }
  2459.               });
  2460.               img.addEventListener('touchend', () => {
  2461.                 isDragging = false;
  2462.               });
  2463.               // Initialiser le curseur
  2464.               img.style.cursor = 'zoom-in';
  2465.               
  2466.               // Garder aussi le double-clic pour compatibilité (legacy)
  2467.               img.addEventListener('dblclick', this.handleZoom.bind(this));
  2468.             });
  2469.           }
  2470.           handleKeyboard(e) {
  2471.             if (!this.isOpen) return;
  2472.             
  2473.             switch(e.key) {
  2474.               case 'Escape':
  2475.                 this.close();
  2476.                 break;
  2477.               case 'ArrowLeft':
  2478.                 e.preventDefault();
  2479.                 this.prevSlide();
  2480.                 break;
  2481.               case 'ArrowRight':
  2482.                 e.preventDefault();
  2483.                 this.nextSlide();
  2484.                 break;
  2485.             }
  2486.           }
  2487.           handleTouchStart(e) {
  2488.             this.touchStartX = e.changedTouches[0].screenX;
  2489.           }
  2490.           handleTouchEnd(e) {
  2491.             this.touchEndX = e.changedTouches[0].screenX;
  2492.             this.handleSwipe();
  2493.           }
  2494.           handleSwipe() {
  2495.             const swipeThreshold = 50;
  2496.             const diff = this.touchStartX - this.touchEndX;
  2497.             if (Math.abs(diff) > swipeThreshold) {
  2498.               if (diff > 0) {
  2499.                 this.nextSlide(); // Swipe left -> next
  2500.               } else {
  2501.                 this.prevSlide(); // Swipe right -> prev
  2502.               }
  2503.             }
  2504.           }
  2505.           handleZoom(e) {
  2506.             const img = e.target;
  2507.             
  2508.             // Vérifier que l'élément et ses propriétés existent
  2509.             if (!img || !img.classList) {
  2510.               console.warn('Élément image invalide pour le zoom');
  2511.               return;
  2512.             }
  2513.             
  2514.             // Gérer les différents niveaux de zoom
  2515.             if (img.classList.contains('zoom-4x')) {
  2516.               // Retour à la taille normale
  2517.               img.classList.remove('zoom-4x', 'zoom-3x', 'zoom-2x', 'zoomed');
  2518.               img.style.cursor = 'pointer';
  2519.               img.style.transform = 'scale(1)'; // Réinitialiser la position
  2520.             } else if (img.classList.contains('zoom-3x')) {
  2521.               // Passer au zoom 4x
  2522.               img.classList.remove('zoom-3x');
  2523.               img.classList.add('zoom-4x');
  2524.               img.style.cursor = 'zoom-out';
  2525.               img.style.transform = 'scale(4)'; // Réinitialiser la position
  2526.             } else if (img.classList.contains('zoom-2x')) {
  2527.               // Passer au zoom 3x
  2528.               img.classList.remove('zoom-2x');
  2529.               img.classList.add('zoom-3x');
  2530.               img.style.cursor = 'zoom-in';
  2531.               img.style.transform = 'scale(3)'; // Réinitialiser la position
  2532.             } else if (img.classList.contains('zoomed')) {
  2533.               // Passer au zoom 2x
  2534.               img.classList.remove('zoomed');
  2535.               img.classList.add('zoom-2x');
  2536.               img.style.cursor = 'zoom-in';
  2537.               img.style.transform = 'scale(2)'; // Réinitialiser la position
  2538.             } else {
  2539.               // Premier zoom (1.5x)
  2540.               img.classList.add('zoomed');
  2541.               img.style.cursor = 'zoom-in';
  2542.               img.style.transform = 'scale(1.5)'; // Réinitialiser la position
  2543.             }
  2544.           }
  2545.         }
  2546.         // Slider universel pour toutes les images (favoris + galerie normale)
  2547.         class UniversalImageSlider {
  2548.           constructor() {
  2549.             this.currentIndex = 0;
  2550.             this.images = [];
  2551.             this.isOpen = false;
  2552.             this.touchStartX = 0;
  2553.             this.touchEndX = 0;
  2554.           }
  2555.           // Ouvrir avec une image spécifique depuis les favoris
  2556.           openFromFavorites(favoriteId) {
  2557.             console.log('Ouverture du slider depuis favoris:', favoriteId);
  2558.             
  2559.             // Récupérer tous les favoris images
  2560.             this.images = getFavoriteItems().filter(item => item.type === 'image');
  2561.             
  2562.             if (this.images.length === 0) {
  2563.               console.error('Aucun favori image trouvé');
  2564.               return;
  2565.             }
  2566.             // Trouver l'index de l'image courante
  2567.             this.currentIndex = this.images.findIndex(img => img.id === favoriteId);
  2568.             if (this.currentIndex === -1) this.currentIndex = 0;
  2569.             this.openSlider();
  2570.           }
  2571.           // Ouvrir avec une image spécifique depuis la galerie normale
  2572.           openFromGallery(imageId, dayContainer) {
  2573.             console.log('Ouverture du slider depuis galerie:', imageId, dayContainer);
  2574.             
  2575.             // Récupérer toutes les images du jour courant
  2576.             const dayImages = [];
  2577.             
  2578.             // Chercher dans le container du jour (peut être .dynamic-card ou autre)
  2579.             let photoItems;
  2580.             if (dayContainer) {
  2581.               photoItems = dayContainer.querySelectorAll('.photo-item');
  2582.             } else {
  2583.               // Fallback: chercher dans tout le document
  2584.               photoItems = document.querySelectorAll('.photo-item');
  2585.             }
  2586.             
  2587.             console.log('Photo items trouvés:', photoItems.length);
  2588.             
  2589.             photoItems.forEach(item => {
  2590.               const img = item.querySelector('img');
  2591.               const heartIcon = item.querySelector('.heart-icon');
  2592.               
  2593.               console.log('Processing item:', {
  2594.                 img: !!img,
  2595.                 heartIcon: !!heartIcon,
  2596.                 imgSrc: img ? img.src : null,
  2597.                 heartIconId: heartIcon ? heartIcon.getAttribute('data-id') : null
  2598.               });
  2599.               
  2600.               if (img && heartIcon) {
  2601.                 dayImages.push({
  2602.                   id: heartIcon.getAttribute('data-id'),
  2603.                   url: heartIcon.getAttribute('data-path') || img.src,
  2604.                   description: heartIcon.getAttribute('data-description') || img.alt || 'Photo',
  2605.                   date: '', // Pas de date spécifique pour les images de galerie
  2606.                   type: 'image'
  2607.                 });
  2608.               }
  2609.             });
  2610.             console.log('Images trouvées:', dayImages);
  2611.             this.images = dayImages;
  2612.             
  2613.             if (this.images.length === 0) {
  2614.               console.error('Aucune image trouvée dans ce jour');
  2615.               // Essayer de créer au moins l'image courante
  2616.               const currentHeartIcon = document.querySelector(`[data-id=\"\${imageId}\"]`);
  2617.               if (currentHeartIcon) {
  2618.                 const currentImg = currentHeartIcon.closest('.photo-item').querySelector('img');
  2619.                 if (currentImg) {
  2620.                   this.images = [{
  2621.                     id: imageId,
  2622.                     url: currentHeartIcon.getAttribute('data-path') || currentImg.src,
  2623.                     description: currentHeartIcon.getAttribute('data-description') || currentImg.alt || 'Photo',
  2624.                     date: '',
  2625.                     type: 'image'
  2626.                   }];
  2627.                   console.log('Image de fallback créée:', this.images);
  2628.                 }
  2629.               }
  2630.               
  2631.               if (this.images.length === 0) {
  2632.                 return;
  2633.               }
  2634.             }
  2635.             // Trouver l'index de l'image courante
  2636.             this.currentIndex = this.images.findIndex(img => img.id === imageId);
  2637.             if (this.currentIndex === -1) this.currentIndex = 0;
  2638.             console.log('Index trouvé:', this.currentIndex);
  2639.             this.openSlider();
  2640.           }
  2641.           openSlider() {
  2642.             console.log('=== openSlider appelée ===');
  2643.             console.log('Index courant:', this.currentIndex, 'Total:', this.images.length);
  2644.             console.log('Images à afficher:', this.images);
  2645.             // Supprimer tout slider existant
  2646.             const existingSlider = document.querySelector('.universal-slider');
  2647.             if (existingSlider) {
  2648.               console.log('Suppression du slider existant');
  2649.               existingSlider.remove();
  2650.             }
  2651.             this.createSlider();
  2652.             this.showSlide(this.currentIndex);
  2653.             this.attachEvents();
  2654.             this.isOpen = true;
  2655.               // Animation d'ouverture immédiate et garantie avec diagnostic
  2656.               setTimeout(() => {
  2657.                 if (window.diagnoseSliderDisplay) {
  2658.                   window.diagnoseSliderDisplay('#universalSlider');
  2659.                 }
  2660.               }, 50);
  2661.           }
  2662.           createSlider() {
  2663.             // ⚡ OPTIMISATION: Créer seulement si nécessaire
  2664.             if (document.querySelector('#universalSlider')) {
  2665.               return; // Déjà créé
  2666.             }
  2667.             
  2668.             console.log('Création slider pour', this.images.length, 'images');
  2669.             
  2670.             // HTML optimisé et minimal
  2671.             const sliderHTML = `
  2672.               <div class=\"universal-slider\" id=\"universalSlider\" style=\"
  2673.                 position: fixed !important; 
  2674.                 top: 0 !important; 
  2675.                 left: 0 !important; 
  2676.                 width: 100% !important; 
  2677.                 height: 100% !important; 
  2678.                 background: rgba(0,0,0,0.95) !important; 
  2679.                 z-index: 9999 !important; 
  2680.                 display: flex !important; 
  2681.                 align-items: center !important; 
  2682.                 justify-content: center !important; 
  2683.                 opacity: 1 !important; 
  2684.                 visibility: visible !important;
  2685.               \">
  2686.                 <div class=\"slider-overlay\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; cursor: pointer;\"></div>
  2687.                 
  2688.                 <!-- Header avec contrôles -->
  2689.                 <div class=\"slider-header\" style=\"
  2690.                   position: absolute; 
  2691.                   top: 20px; 
  2692.                   right: 20px; 
  2693.                   display: flex; 
  2694.                   align-items: center; 
  2695.                   gap: 15px; 
  2696.                   z-index: 10001;
  2697.                 \">
  2698.                   <button class=\"slider-btn close-btn\" title=\"Fermer\" style=\"
  2699.                     background: rgba(255,255,255,0.2); 
  2700.                     border: none; 
  2701.                     color: white; 
  2702.                     width: 40px; 
  2703.                     height: 40px; 
  2704.                     border-radius: 50%; 
  2705.                     cursor: pointer; 
  2706.                     display: flex; 
  2707.                     align-items: center; 
  2708.                     justify-content: center;
  2709.                     transition: background 0.2s ease;
  2710.                   \">
  2711.                     <i class=\"bi bi-x-lg\"></i>
  2712.                   </button>
  2713.                 </div>
  2714.                 <!-- Navigation -->
  2715.                 <button class=\"slider-nav prev-btn\" title=\"Précédent\" style=\"
  2716.                   position: absolute; 
  2717.                   left: 20px; 
  2718.                   top: 50%; 
  2719.                   transform: translateY(-50%); 
  2720.                   background: rgba(255,255,255,0.2); 
  2721.                   border: none; 
  2722.                   color: white; 
  2723.                   width: 50px; 
  2724.                   height: 50px; 
  2725.                   border-radius: 50%; 
  2726.                   cursor: pointer; 
  2727.                   display: \${this.images.length > 1 ? 'flex' : 'none'}; 
  2728.                   align-items: center; 
  2729.                   justify-content: center; 
  2730.                   z-index: 10001;
  2731.                   transition: background 0.2s ease;
  2732.                 \">
  2733.                   <i class=\"bi bi-arrow-left-circle-fill\" style=\"font-size: 20px;\"></i>
  2734.                 </button>
  2735.                 <button class=\"slider-nav next-btn\" title=\"Suivant\" style=\"
  2736.                   position: absolute; 
  2737.                   right: 20px; 
  2738.                   top: 50%; 
  2739.                   transform: translateY(-50%); 
  2740.                   background: rgba(255,255,255,0.2); 
  2741.                   border: none; 
  2742.                   color: white; 
  2743.                   width: 50px; 
  2744.                   height: 50px; 
  2745.                   border-radius: 50%; 
  2746.                   cursor: pointer; 
  2747.                   display: \${this.images.length > 1 ? 'flex' : 'none'}; 
  2748.                   align-items: center; 
  2749.                   justify-content: center; 
  2750.                   z-index: 10001;
  2751.                   transition: background 0.2s ease;
  2752.                 \">
  2753.                   <i class=\"bi bi-arrow-right-circle-fill\" style=\"font-size: 20px;\"></i>
  2754.                 </button>
  2755.                 <!-- Container des slides -->
  2756.                 <div class=\"slider-container\" style=\"
  2757.                   position: relative; 
  2758.                   width: 90%; 
  2759.                   height: 90%; 
  2760.                   display: flex; 
  2761.                   align-items: center; 
  2762.                   justify-content: center; 
  2763.                   z-index: 10000;
  2764.                 \">
  2765.                   <div class=\"slider-track\" id=\"universalSliderTrack\" style=\"
  2766.                     position: relative; 
  2767.                     width: 100%; 
  2768.                     height: 100%; 
  2769.                     display: flex; 
  2770.                     align-items: center; 
  2771.                     justify-content: center;
  2772.                     overflow: hidden;
  2773.                   \">
  2774.                     \${this.images.map((img, index) => `
  2775.                       <div class=\"slide\" data-index=\"\${index}\" style=\"
  2776.                         position: absolute; 
  2777.                         width: 100%; 
  2778.                         height: 100%; 
  2779.                         display: \${index === 0 ? 'flex' : 'none'}; 
  2780.                         align-items: center; 
  2781.                         justify-content: center; 
  2782.                         flex-direction: column;
  2783.                       \">
  2784.                         <div class=\"slide-content\" style=\"
  2785.                           position: relative; 
  2786.                           max-width: 100%; 
  2787.                           max-height: 90%; 
  2788.                           display: flex; 
  2789.                           align-items: center; 
  2790.                           justify-content: center;
  2791.                         \">
  2792.                           <img src=\"\${img.url}\" alt=\"\${img.description || 'Photo'}\" 
  2793.                                loading=\"\${index <= 2 ? 'eager' : 'lazy'}\"
  2794.                                draggable=\"false\"
  2795.                                style=\"
  2796.                                  max-width: 100%; 
  2797.                                  max-height: 100%; 
  2798.                                  object-fit: contain; 
  2799.                                  cursor: zoom-in;
  2800.                                  transition: transform 0.3s ease;
  2801.                                  user-select: none;
  2802.                                \">
  2803.                         </div>
  2804.                         \${img.description ? `
  2805.                         <div class=\"slide-info\" style=\"
  2806.                           position: absolute; 
  2807.                           bottom: 60px; 
  2808.                           left: 50%; 
  2809.                           transform: translateX(-50%); 
  2810.                           text-align: center; 
  2811.                           color: white; 
  2812.                           background: rgba(0,0,0,0.6); 
  2813.                           padding: 8px 16px; 
  2814.                           border-radius: 20px; 
  2815.                           max-width: 80%;
  2816.                           font-size: 14px;
  2817.                         \">
  2818.                           \${img.description}
  2819.                         </div>
  2820.                         ` : ''}
  2821.                       </div>
  2822.                     `).join('')}
  2823.                   </div>
  2824.                 </div>
  2825.                 <!-- Galerie de thumbnails révolutionnaire -->
  2826.                 <div class=\"cinema-gallery\" style=\"
  2827.                   position: absolute; 
  2828.                   bottom: 0; 
  2829.                   left: 0; 
  2830.                   right: 0;
  2831.                   height: 180px;
  2832.                   background: linear-gradient(0deg, rgba(0,0,0,0.95) 0%, rgba(0,0,0,0.7) 50%, transparent 100%);
  2833.                   z-index: 10001;
  2834.                   display: flex;
  2835.                   flex-direction: column;
  2836.                   justify-content: flex-end;
  2837.                   padding: 0 20px 20px;
  2838.                 \">
  2839.                   
  2840.                   <!-- Info header avec compteur élégant -->
  2841.                   <div class=\"gallery-header\" style=\"
  2842.                     display: flex;
  2843.                     justify-content: space-between;
  2844.                     align-items: center;
  2845.                     margin-bottom: 15px;
  2846.                   \">
  2847.                     <div class=\"photo-counter\" style=\"
  2848.                       color: white;
  2849.                       font-size: 16px;
  2850.                       font-weight: 600;
  2851.                       display: flex;
  2852.                       align-items: center;
  2853.                       gap: 8px;
  2854.                     \">
  2855.                       <div style=\"
  2856.                         width: 8px;
  2857.                         height: 8px;
  2858.                         background: #10b981;
  2859.                         border-radius: 50%;
  2860.                         animation: pulse 2s infinite;
  2861.                       \"></div>
  2862.                       <span>\${(this.currentIndex || 0) + 1}</span>
  2863.                       <span style=\"opacity: 0.6;\">sur</span>
  2864.                       <span>\${this.images.length}</span>
  2865.                     </div>
  2866.                     <div class=\"gallery-controls\" style=\"
  2867.                       display: flex;
  2868.                       gap: 12px;
  2869.                       align-items: center;
  2870.                     \">
  2871.                       <div style=\"color: rgba(255,255,255,0.7); font-size: 12px;\">
  2872.                         Clic = Zoom 5x • Drag = Déplacer
  2873.                       </div>
  2874.                     </div>
  2875.                   </div>
  2876.                   
  2877.                   <!-- Carrousel de thumbnails cinématographique -->
  2878.                   <div class=\"cinema-carousel\" style=\"
  2879.                     position: relative;
  2880.                     height: 80px;
  2881.                     overflow: hidden;
  2882.                   \">
  2883.                     <!-- Container scrollable -->
  2884.                     <div class=\"carousel-track\" id=\"carouselTrack\" style=\"
  2885.                       display: flex;
  2886.                       gap: 12px;
  2887.                       height: 100%;
  2888.                       overflow-x: auto;
  2889.                       overflow-y: hidden;
  2890.                       scroll-behavior: smooth;
  2891.                       scrollbar-width: none;
  2892.                       -ms-overflow-style: none;
  2893.                       padding: 0 50px;
  2894.                     \">
  2895.                       \${this.images.map((img, index) => `
  2896.                         <div class=\"cinema-thumb \${index === 0 ? 'active' : ''}\" 
  2897.                              data-index=\"\${index}\" 
  2898.                              style=\"
  2899.                                flex: 0 0 auto;
  2900.                                width: \${index === 0 ? '100px' : '70px'};
  2901.                                height: 70px;
  2902.                                border-radius: 8px;
  2903.                                overflow: hidden;
  2904.                                cursor: pointer;
  2905.                                position: relative;
  2906.                                transition: transform 0.2s ease, opacity 0.2s ease;
  2907.                                transform: \${index === 0 ? 'translateY(-4px)' : 'translateY(0)'};
  2908.                                opacity: \${index === 0 ? '1' : '0.7'};
  2909.                                border: \${index === 0 ? '2px solid #10b981' : '1px solid rgba(255,255,255,0.3)'};
  2910.                              \"
  2911.                              onmouseenter=\"
  2912.                                if (\${index} !== (window.universalSlider?.currentIndex || 0)) {
  2913.                                  this.style.opacity = '0.9';
  2914.                                }
  2915.                              \"
  2916.                              onmouseleave=\"
  2917.                                if (\${index} !== (window.universalSlider?.currentIndex || 0)) {
  2918.                                  this.style.opacity = '0.7';
  2919.                                }
  2920.                              \">
  2921.                           
  2922.                           <!-- Image principale -->
  2923.                           <img src=\"\${img.url}\" 
  2924.                                alt=\"\${img.description || 'Photo'}\" 
  2925.                                loading=\"lazy\" 
  2926.                                decoding=\"async\"
  2927.                                style=\"
  2928.                                  width: 100%; 
  2929.                                  height: 100%; 
  2930.                                  object-fit: cover;
  2931.                                \">
  2932.                           
  2933.                           <!-- Numéro simplifié -->
  2934.                           <div class=\"thumb-number\" style=\"
  2935.                             position: absolute;
  2936.                             top: 4px;
  2937.                             right: 4px;
  2938.                             background: \${index === 0 ? '#10b981' : 'rgba(0,0,0,0.8)'};
  2939.                             color: white;
  2940.                             font-size: 10px;
  2941.                             font-weight: 500;
  2942.                             padding: 2px 5px;
  2943.                             border-radius: 4px;
  2944.                             min-width: 16px;
  2945.                             text-align: center;
  2946.                           \">
  2947.                             \${index + 1}
  2948.                           </div>
  2949.                           
  2950.                           <!-- Indicateur actif simplifié -->
  2951.                           \${index === 0 ? `
  2952.                           <div class=\"active-indicator\" style=\"
  2953.                             position: absolute;
  2954.                             bottom: -1px;
  2955.                             left: 50%;
  2956.                             transform: translateX(-50%);
  2957.                             width: 16px;
  2958.                             height: 2px;
  2959.                             background: #10b981;
  2960.                             border-radius: 1px;
  2961.                           \"></div>
  2962.                           ` : ''}
  2963.                           
  2964.                           <!-- Preview au hover pour les non-actifs -->
  2965.                           \${index !== 0 ? `
  2966.                           <div class=\"hover-preview\" style=\"
  2967.                             position: absolute;
  2968.                             bottom: -40px;
  2969.                             left: 50%;
  2970.                             transform: translateX(-50%);
  2971.                             background: rgba(0,0,0,0.9);
  2972.                             color: white;
  2973.                             font-size: 11px;
  2974.                             padding: 4px 8px;
  2975.                             border-radius: 6px;
  2976.                             opacity: 0;
  2977.                             pointer-events: none;
  2978.                             transition: all 0.3s ease;
  2979.                             white-space: nowrap;
  2980.                             z-index: 1000;
  2981.                           \">
  2982.                             Photo \${index + 1}
  2983.                           </div>
  2984.                           ` : ''}
  2985.                         </div>
  2986.                       `).join('')}
  2987.                     </div>
  2988.                     
  2989.                     <!-- Gradients de fade sur les côtés -->
  2990.                     <div style=\"
  2991.                       position: absolute;
  2992.                       left: 0;
  2993.                       top: 0;
  2994.                       bottom: 0;
  2995.                       width: 50px;
  2996.                       background: linear-gradient(90deg, rgba(0,0,0,0.8), transparent);
  2997.                       pointer-events: none;
  2998.                       z-index: 1;
  2999.                     \"></div>
  3000.                     <div style=\"
  3001.                       position: absolute;
  3002.                       right: 0;
  3003.                       top: 0;
  3004.                       bottom: 0;
  3005.                       width: 50px;
  3006.                       background: linear-gradient(-90deg, rgba(0,0,0,0.8), transparent);
  3007.                       pointer-events: none;
  3008.                       z-index: 1;
  3009.                     \"></div>
  3010.                   </div>
  3011.                 </div>
  3012.                 <!-- Animations CSS Optimisées -->
  3013.                 <style>
  3014.                   /* Optimisation: animations réduites et ciblées */
  3015.                   @keyframes pulse {
  3016.                     0%, 100% { opacity: 1; }
  3017.                     50% { opacity: 0.7; }
  3018.                   }
  3019.                   
  3020.                   /* Suppression du glow coûteux - remplacé par border simple */
  3021.                   .cinema-thumb.active .active-indicator {
  3022.                     background: #10b981;
  3023.                     animation: none; /* Suppression de l'animation glow */
  3024.                   }
  3025.                   
  3026.                   /* Hover optimisé - moins d'effets */
  3027.                   .cinema-thumb:hover .hover-preview {
  3028.                     opacity: 1 !important;
  3029.                     bottom: -35px !important;
  3030.                   }
  3031.                   
  3032.                   /* Masquer scrollbar */
  3033.                   .carousel-track::-webkit-scrollbar {
  3034.                     display: none;
  3035.                   }
  3036.                   
  3037.                   /* Optimisation: will-change pour les éléments animés */
  3038.                   .cinema-thumb {
  3039.                     will-change: transform, filter;
  3040.                   }
  3041.                   
  3042.                   .progress-bar {
  3043.                     will-change: width;
  3044.                   }
  3045.                 </style>
  3046.               </div>
  3047.             `;
  3048.             // Injecter dans le DOM
  3049.             console.log('Ajout du slider au DOM');
  3050.             document.body.insertAdjacentHTML('beforeend', sliderHTML);
  3051.             
  3052.             // Vérifier que le slider a été ajouté
  3053.             const addedSlider = document.querySelector('#universalSlider');
  3054.             console.log('Slider ajouté:', !!addedSlider);
  3055.             if (addedSlider) {
  3056.               console.log('Slider trouvé dans le DOM');
  3057.               console.log('Styles du slider:', {
  3058.                 display: addedSlider.style.display,
  3059.                 opacity: addedSlider.style.opacity,
  3060.                 visibility: addedSlider.style.visibility,
  3061.                 zIndex: addedSlider.style.zIndex,
  3062.                 position: addedSlider.style.position
  3063.               });
  3064.               console.log('Slider dans viewport:', addedSlider.getBoundingClientRect());
  3065.             } else {
  3066.               console.error('Erreur: slider non trouvé après ajout');
  3067.             }
  3068.           }
  3069.           showSlide(index) {
  3070.             console.log('=== showSlide appelée ===', 'index:', index, 'total:', this.images.length);
  3071.             if (index < 0 || index >= this.images.length) {
  3072.               console.log('Index invalide, arrêt');
  3073.               return;
  3074.             }
  3075.             this.currentIndex = index;
  3076.             // Masquer toutes les slides et afficher seulement la courante
  3077.             const slides = document.querySelectorAll('#universalSlider .slide');
  3078.             console.log('Slides trouvées:', slides.length);
  3079.             slides.forEach((slide, i) => {
  3080.               slide.style.display = i === index ? 'flex' : 'none';
  3081.               console.log(`Slide \${i}:`, i === index ? 'visible' : 'cachée');
  3082.             });
  3083.             // Mettre à jour le compteur
  3084.             const currentSlideSpan = document.querySelector('#universalSlider .current-slide');
  3085.             if (currentSlideSpan) {
  3086.               currentSlideSpan.textContent = index + 1;
  3087.               console.log('Compteur mis à jour:', index + 1);
  3088.             }
  3089.             // Mettre à jour les boutons de navigation
  3090.             const prevBtn = document.querySelector('#universalSlider .prev-btn');
  3091.             const nextBtn = document.querySelector('#universalSlider .next-btn');
  3092.             
  3093.             if (prevBtn) {
  3094.               prevBtn.style.opacity = index > 0 ? '1' : '0.5';
  3095.             }
  3096.             if (nextBtn) {
  3097.               nextBtn.style.opacity = index < this.images.length - 1 ? '1' : '0.5';
  3098.             }
  3099.             // Mettre à jour la galerie cinématographique
  3100.             this.updateCinemaGallery(index);
  3101.             // Mettre à jour le bouton favori
  3102.             this.updateFavoriteButton();
  3103.           }
  3104.           updateCinemaGallery(activeIndex) {
  3105.             // Mettre à jour la progress bar (optimisé)
  3106.             const progressBar = document.querySelector('.progress-bar');
  3107.             if (progressBar) {
  3108.               progressBar.style.width = `\${(activeIndex + 1) / this.images.length * 100}%`;
  3109.             }
  3110.             // Mettre à jour le compteur (optimisé)
  3111.             const counter = document.querySelector('.photo-counter span');
  3112.             if (counter) {
  3113.               counter.textContent = activeIndex + 1;
  3114.             }
  3115.             // Mettre à jour les thumbnails - optimisé avec moins de calculs
  3116.             const cinemaThumbs = document.querySelectorAll('.cinema-thumb');
  3117.             cinemaThumbs.forEach((thumb, i) => {
  3118.               const isActive = i === activeIndex;
  3119.               
  3120.               // Optimisation: changements minimaux
  3121.               if (isActive) {
  3122.                 thumb.style.width = '100px';
  3123.                 thumb.style.transform = 'translateY(-4px)';
  3124.                 thumb.style.opacity = '1';
  3125.                 thumb.style.borderColor = '#10b981';
  3126.                 thumb.style.borderWidth = '2px';
  3127.                 
  3128.                 // Numéro actif - simplifié
  3129.                 const number = thumb.querySelector('.thumb-number');
  3130.                 if (number) {
  3131.                   number.style.background = '#10b981';
  3132.                 }
  3133.               } else {
  3134.                 thumb.style.width = '70px';
  3135.                 thumb.style.transform = 'translateY(0)';
  3136.                 thumb.style.opacity = '0.7';
  3137.                 thumb.style.borderColor = 'rgba(255,255,255,0.3)';
  3138.                 thumb.style.borderWidth = '1px';
  3139.                 
  3140.                 // Numéro inactif - simplifié
  3141.                 const number = thumb.querySelector('.thumb-number');
  3142.                 if (number) {
  3143.                   number.style.background = 'rgba(0,0,0,0.8)';
  3144.                 }
  3145.               }
  3146.             });
  3147.             // Auto-scroll optimisé avec throttling
  3148.             if (!this.scrollTimeout) {
  3149.               this.scrollTimeout = setTimeout(() => {
  3150.                 const track = document.getElementById('carouselTrack');
  3151.                 const activeThumb = document.querySelector(`.cinema-thumb[data-index=\"\${activeIndex}\"]`);
  3152.                 if (track && activeThumb) {
  3153.                   const scrollLeft = activeThumb.offsetLeft - (track.clientWidth / 2) + (activeThumb.clientWidth / 2);
  3154.                   track.scrollTo({
  3155.                     left: scrollLeft,
  3156.                     behavior: 'smooth'
  3157.                   });
  3158.                 }
  3159.                 this.scrollTimeout = null;
  3160.               }, 50); // Throttle à 50ms
  3161.             }
  3162.           }
  3163.           updateFavoriteButton() {
  3164.             const currentImage = this.images[this.currentIndex];
  3165.             const favoriteBtn = document.querySelector('.slider-controls .favorite-btn');
  3166.             
  3167.             if (favoriteBtn && currentImage) {
  3168.               favoriteBtn.setAttribute('data-id', currentImage.id);
  3169.               
  3170.               // Vérifier si l'image est déjà en favoris
  3171.               const heartIcon = document.querySelector(`[data-id=\"\${currentImage.id}\"]`);
  3172.               const isFavorite = heartIcon && heartIcon.querySelector('i.bi-heart-fill');
  3173.               
  3174.               const icon = favoriteBtn.querySelector('i');
  3175.               if (isFavorite) {
  3176.                 icon.className = 'bi bi-heart-fill';
  3177.                 favoriteBtn.style.color = '#e91e63';
  3178.               } else {
  3179.                 icon.className = 'bi bi-heart';
  3180.                 favoriteBtn.style.color = 'white';
  3181.               }
  3182.             }
  3183.           }
  3184.           nextSlide() {
  3185.             const nextIndex = (this.currentIndex + 1) % this.images.length;
  3186.             this.showSlide(nextIndex);
  3187.           }
  3188.           prevSlide() {
  3189.             const prevIndex = (this.currentIndex - 1 + this.images.length) % this.images.length;
  3190.             this.showSlide(prevIndex);
  3191.           }
  3192.           close() {
  3193.             if (!this.isOpen) return;
  3194.             const slider = document.querySelector('.universal-slider');
  3195.             if (slider) {
  3196.               slider.classList.remove('active');
  3197.               
  3198.               setTimeout(() => {
  3199.                 slider.remove();
  3200.                 this.isOpen = false;
  3201.               }, 300);
  3202.             }
  3203.           }
  3204.           attachEvents() {
  3205.             console.log('=== attachEvents appelée ===');
  3206.             const slider = document.getElementById('universalSlider');
  3207.             if (!slider) {
  3208.               console.error('Slider non trouvé pour attachEvents');
  3209.               return;
  3210.             }
  3211.             console.log('Slider trouvé pour attachEvents');
  3212.             
  3213.             // Bouton fermer
  3214.             const closeBtn = slider.querySelector('.close-btn');
  3215.             if (closeBtn) {
  3216.               console.log('Bouton fermer trouvé');
  3217.               closeBtn.addEventListener('click', () => {
  3218.                 console.log('Clic fermer');
  3219.                 this.close();
  3220.               });
  3221.             }
  3222.             
  3223.             // Navigation
  3224.             const prevBtn = slider.querySelector('.prev-btn');
  3225.             const nextBtn = slider.querySelector('.next-btn');
  3226.             if (prevBtn) {
  3227.               console.log('Bouton précédent trouvé');
  3228.               prevBtn.addEventListener('click', () => {
  3229.                 console.log('Clic précédent');
  3230.                 this.prevSlide();
  3231.               });
  3232.             }
  3233.             if (nextBtn) {
  3234.               console.log('Bouton suivant trouvé');
  3235.               nextBtn.addEventListener('click', () => {
  3236.                 console.log('Clic suivant');
  3237.                 this.nextSlide();
  3238.               });
  3239.             }
  3240.             // Navigation cinématographique des thumbnails
  3241.             const cinemaThumbs = slider.querySelectorAll('.cinema-thumb');
  3242.             cinemaThumbs.forEach((thumb, index) => {
  3243.               thumb.addEventListener('click', () => {
  3244.                 console.log('Clic cinema thumbnail:', index);
  3245.                 this.showSlide(index);
  3246.                 this.updateCinemaGallery(index);
  3247.               });
  3248.             });
  3249.             console.log('Cinema thumbnails cliquables:', cinemaThumbs.length);
  3250.             // Clic sur overlay pour fermer
  3251.             const overlay = slider.querySelector('.slider-overlay');
  3252.             if (overlay) {
  3253.               overlay.addEventListener('click', () => {
  3254.                 console.log('Clic overlay');
  3255.                 this.close();
  3256.               });
  3257.             }
  3258.             // Clavier
  3259.             this.keyboardHandler = this.handleKeyboard.bind(this);
  3260.             document.addEventListener('keydown', this.keyboardHandler);
  3261.             console.log('Événements clavier attachés');
  3262.             // Zoom sur les images
  3263.             this.attachZoomEvents(slider);
  3264.             console.log('Événements zoom attachés');
  3265.             console.log('Événements attachés avec succès');
  3266.           }
  3267.           close() {
  3268.             console.log('=== close appelée ===');
  3269.             const slider = document.querySelector('.universal-slider');
  3270.             if (slider) {
  3271.               console.log('Fermeture du slider');
  3272.               // Animation de fermeture
  3273.               slider.style.opacity = '0';
  3274.               
  3275.               setTimeout(() => {
  3276.                 slider.remove();
  3277.                 console.log('Slider supprimé du DOM');
  3278.                 
  3279.                 // Nettoyer les événements
  3280.                 if (this.keyboardHandler) {
  3281.                   document.removeEventListener('keydown', this.keyboardHandler);
  3282.                   this.keyboardHandler = null;
  3283.                 }
  3284.                 
  3285.                 this.isOpen = false;
  3286.               }, 300);
  3287.             }
  3288.           }
  3289.           nextSlide() {
  3290.             if (this.currentIndex < this.images.length - 1) {
  3291.               this.showSlide(this.currentIndex + 1);
  3292.             }
  3293.           }
  3294.           prevSlide() {
  3295.             if (this.currentIndex > 0) {
  3296.               this.showSlide(this.currentIndex - 1);
  3297.             }
  3298.           }
  3299.           handleKeyboard(e) {
  3300.             if (!this.isOpen) return;
  3301.             
  3302.             switch (e.key) {
  3303.               case 'Escape':
  3304.                 this.close();
  3305.                 break;
  3306.               case 'ArrowLeft':
  3307.                 this.prevSlide();
  3308.                 break;
  3309.               case 'ArrowRight':
  3310.                 this.nextSlide();
  3311.                 break;
  3312.             }
  3313.           }
  3314.           attachZoomEvents(slider) {
  3315.             // Fonctionnalité de zoom à 5 niveaux pour les images
  3316.             const images = slider.querySelectorAll('.slide img');
  3317.             images.forEach(img => {
  3318.               let zoomLevel = 1; // 1x, 1.5x, 2x, 3x, 4x, 5x
  3319.               let isDragging = false;
  3320.               let startX = 0;
  3321.               let startY = 0;
  3322.               let translateX = 0;
  3323.               let translateY = 0;
  3324.               // Clic simple pour zoom progressif (5 niveaux)
  3325.               img.addEventListener('click', (e) => {
  3326.                 e.preventDefault();
  3327.                 e.stopPropagation();
  3328.                 
  3329.                 // Cycle à travers 5 niveaux de zoom
  3330.                 switch(zoomLevel) {
  3331.                   case 1: zoomLevel = 1.5; break;  // 1x → 1.5x
  3332.                   case 1.5: zoomLevel = 2; break;  // 1.5x → 2x
  3333.                   case 2: zoomLevel = 3; break;    // 2x → 3x
  3334.                   case 3: zoomLevel = 4; break;    // 3x → 4x
  3335.                   case 4: zoomLevel = 5; break;    // 4x → 5x
  3336.                   case 5: 
  3337.                     zoomLevel = 1;                 // 5x → 1x (reset)
  3338.                     translateX = 0;
  3339.                     translateY = 0;
  3340.                     break;
  3341.                 }
  3342.                 console.log('Zoom niveau:', zoomLevel);
  3343.                 img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  3344.                 
  3345.                 // Curseur selon le niveau
  3346.                 if (zoomLevel === 1) {
  3347.                   img.style.cursor = 'zoom-in';
  3348.                   img.removeAttribute('data-zoomed');
  3349.                 } else if (zoomLevel === 5) {
  3350.                   img.style.cursor = 'zoom-out';
  3351.                   img.setAttribute('data-zoomed', zoomLevel);
  3352.                 } else {
  3353.                   img.style.cursor = 'zoom-in';
  3354.                   img.setAttribute('data-zoomed', zoomLevel);
  3355.                 }
  3356.               });
  3357.               // Drag pour déplacer l'image zoomée
  3358.               img.addEventListener('mousedown', (e) => {
  3359.                 if (zoomLevel > 1) {
  3360.                   isDragging = true;
  3361.                   startX = e.clientX - translateX;
  3362.                   startY = e.clientY - translateY;
  3363.                   img.style.cursor = 'grabbing';
  3364.                   e.preventDefault();
  3365.                   e.stopPropagation();
  3366.                 }
  3367.               });
  3368.               // Mousemove global pour le drag
  3369.               const handleMouseMove = (e) => {
  3370.                 if (isDragging && zoomLevel > 1) {
  3371.                   translateX = e.clientX - startX;
  3372.                   translateY = e.clientY - startY;
  3373.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  3374.                 }
  3375.               };
  3376.               // Mouseup global pour arrêter le drag
  3377.               const handleMouseUp = () => {
  3378.                 if (isDragging) {
  3379.                   isDragging = false;
  3380.                   if (zoomLevel === 1) {
  3381.                     img.style.cursor = 'zoom-in';
  3382.                   } else if (zoomLevel === 5) {
  3383.                     img.style.cursor = 'zoom-out';
  3384.                   } else {
  3385.                     img.style.cursor = 'zoom-in';
  3386.                   }
  3387.                 }
  3388.               };
  3389.               document.addEventListener('mousemove', handleMouseMove);
  3390.               document.addEventListener('mouseup', handleMouseUp);
  3391.               // Touch support pour mobile
  3392.               img.addEventListener('touchstart', (e) => {
  3393.                 if (zoomLevel > 1 && e.touches.length === 1) {
  3394.                   isDragging = true;
  3395.                   const touch = e.touches[0];
  3396.                   startX = touch.clientX - translateX;
  3397.                   startY = touch.clientY - translateY;
  3398.                   e.preventDefault();
  3399.                 }
  3400.               });
  3401.               img.addEventListener('touchmove', (e) => {
  3402.                 if (isDragging && zoomLevel > 1 && e.touches.length === 1) {
  3403.                   const touch = e.touches[0];
  3404.                   translateX = touch.clientX - startX;
  3405.                   translateY = touch.clientY - startY;
  3406.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  3407.                   e.preventDefault();
  3408.                 }
  3409.               });
  3410.               img.addEventListener('touchend', () => {
  3411.                 isDragging = false;
  3412.               });
  3413.               // Initialiser le curseur
  3414.               img.style.cursor = 'zoom-in';
  3415.             });
  3416.           }
  3417.         }
  3418.         // ⚡ OPTIMISATION MAJEURE: Sliders lazy (créés seulement quand utilisés)
  3419.         let favoritesSlider = null;
  3420.         let universalSlider = null;
  3421.         
  3422.         // Fonctions pour créer les sliders à la demande
  3423.         function getFavoritesSlider() {
  3424.           if (!favoritesSlider) {
  3425.             favoritesSlider = new FavoritesSlider();
  3426.           }
  3427.           return favoritesSlider;
  3428.         }
  3429.         
  3430.         function getUniversalSlider() {
  3431.           if (!universalSlider) {
  3432.             universalSlider = new UniversalImageSlider();
  3433.           }
  3434.           return universalSlider;
  3435.         }
  3436.         // Fonction pour voir un favori avec le slider plein écran
  3437.         function viewFavorite(id) {
  3438.           console.log('Ouverture du slider pour favori:', id);
  3439.           // ⚡ OPTIMISÉ: Utiliser le slider lazy
  3440.           const slider = getUniversalSlider();
  3441.           if (slider && slider.openFromFavorites) {
  3442.             slider.openFromFavorites(id);
  3443.           } else {
  3444.             console.error('Erreur slider favoris');
  3445.           }
  3446.         }
  3447.         // Fonction pour voir une image depuis la galerie normale
  3448.         function viewImage(imageId, clickedElement) {
  3449.           console.log('=== viewImage appelée ===');
  3450.           console.log('imageId:', imageId);
  3451.           console.log('clickedElement:', clickedElement);
  3452.           
  3453.           // Trouver le container du jour - peut être plusieurs niveaux au-dessus
  3454.           let dayContainer = clickedElement;
  3455.           
  3456.           // Remonter jusqu'à trouver un container approprié
  3457.           while (dayContainer && dayContainer !== document.body) {
  3458.             console.log('Checking element:', dayContainer.tagName, dayContainer.className, dayContainer.id);
  3459.             if (dayContainer && dayContainer.classList && (
  3460.                 dayContainer.classList.contains('dynamic-card') || 
  3461.                 dayContainer.classList.contains('collapse') ||
  3462.                 dayContainer.id && dayContainer.id.startsWith('demP')
  3463.             )) {
  3464.               break;
  3465.             }
  3466.             dayContainer = dayContainer.parentElement;
  3467.           }
  3468.           
  3469.           // ⚡ OPTIMISÉ: Logs réduits pour performance
  3470.           
  3471.           // ⚡ OPTIMISÉ: Utiliser le slider lazy
  3472.           const slider = getUniversalSlider();
  3473.           if (slider && slider.openFromGallery) {
  3474.             slider.openFromGallery(imageId, dayContainer);
  3475.           } else {
  3476.             console.error('Erreur slider galerie');
  3477.           }
  3478.         }
  3479.         // ⚡ OPTIMISÉ: Fonctions globales avec sliders lazy
  3480.         window.viewImage = viewImage;
  3481.         window.viewFavorite = viewFavorite;
  3482.         window.getUniversalSlider = getUniversalSlider; // Fonction lazy au lieu de l'instance
  3483.         // Variables globales pour éviter les ReferenceError
  3484.         if (typeof favoriteCount === 'undefined') {
  3485.           window.favoriteCount = 0;
  3486.         }
  3487.         if (typeof favButton === 'undefined') {
  3488.           window.favButton = null;
  3489.         }
  3490.         if (typeof favoriteButton === 'undefined') {
  3491.           window.favoriteButton = null;
  3492.         }
  3493.         if (typeof purchaseAlertTimeout === 'undefined') {
  3494.           window.purchaseAlertTimeout = null;
  3495.         }
  3496.         
  3497.         // Définir favoriteCount globalement pour éviter les ReferenceError
  3498.         let favoriteCount = window.favoriteCount || 0;
  3499.         // Fonction de sécurité pour vérifier les éléments DOM
  3500.         function safeAddEventListener(selector, event, callback) {
  3501.           const element = document.querySelector(selector);
  3502.           if (element) {
  3503.             element.addEventListener(event, callback);
  3504.           } else {
  3505.             console.warn(`Élément non trouvé: \${selector}`);
  3506.           }
  3507.         }
  3508.         // Fonction utilitaire pour manipuler classList de manière sécurisée
  3509.         function safeClassList(element, action, ...classes) {
  3510.           if (!element || !element.classList) {
  3511.             console.warn('Élément ou classList invalide:', element);
  3512.             return false;
  3513.           }
  3514.           
  3515.           try {
  3516.             switch(action) {
  3517.               case 'add':
  3518.                 element.classList.add(...classes);
  3519.                 break;
  3520.               case 'remove':
  3521.                 element.classList.remove(...classes);
  3522.                 break;
  3523.               case 'toggle':
  3524.                 return element.classList.toggle(classes[0], classes[1]);
  3525.               case 'contains':
  3526.                 return element.classList.contains(classes[0]);
  3527.               default:
  3528.                 console.warn('Action classList inconnue:', action);
  3529.                 return false;
  3530.             }
  3531.             return true;
  3532.           } catch (error) {
  3533.             console.warn('Erreur lors de la manipulation de classList:', error);
  3534.             return false;
  3535.           }
  3536.         }
  3537.         // Rendre la fonction utilitaire globale
  3538.         window.safeClassList = safeClassList;
  3539.         // Fonction pour sécuriser automatiquement tous les accès à classList
  3540.         function secureClassListAccess() {
  3541.           // Intercepter les erreurs classList globalement
  3542.           window.addEventListener('error', function(e) {
  3543.             if (e.message && (e.message.includes('classList') || e.message.includes('Cannot read properties of null'))) {
  3544.               console.warn('Erreur DOM interceptée et corrigée:', e.message, 'Ligne:', e.lineno, 'Fichier:', e.filename);
  3545.               e.preventDefault(); // Empêcher l'erreur de se propager
  3546.               return true;
  3547.             }
  3548.           });
  3549.           
  3550.           // Intercepter les erreurs non catchées
  3551.           window.addEventListener('unhandledrejection', function(e) {
  3552.             if (e.reason && e.reason.message && e.reason.message.includes('classList')) {
  3553.               console.warn('Promise rejection classList interceptée:', e.reason.message);
  3554.               e.preventDefault();
  3555.               return true;
  3556.             }
  3557.           });
  3558.           
  3559.           console.log('Système de sécurisation DOM/classList activé');
  3560.         }
  3561.         // Activer la sécurisation
  3562.         secureClassListAccess();
  3563.         // Fonction de diagnostic pour vérifier l'affichage du slider
  3564.         function diagnoseSliderDisplay(sliderId) {
  3565.           const slider = document.querySelector(sliderId);
  3566.           if (!slider) {
  3567.             console.error('Diagnostic: Slider non trouvé -', sliderId);
  3568.             return false;
  3569.           }
  3570.           
  3571.           const styles = window.getComputedStyle(slider);
  3572.           const rect = slider.getBoundingClientRect();
  3573.           
  3574.           console.log('=== DIAGNOSTIC SLIDER ===', sliderId);
  3575.           console.log('Élément présent:', !!slider);
  3576.           console.log('Styles calculés:', {
  3577.             display: styles.display,
  3578.             opacity: styles.opacity,
  3579.             visibility: styles.visibility,
  3580.             zIndex: styles.zIndex,
  3581.             position: styles.position
  3582.           });
  3583.           console.log('Position/Taille:', rect);
  3584.           console.log('Dans le viewport:', rect.width > 0 && rect.height > 0);
  3585.           console.log('Parent:', slider.parentElement?.tagName);
  3586.           
  3587.           // Vérifier les règles CSS qui pourraient masquer le slider
  3588.           const hiddenReasons = [];
  3589.           if (styles.display === 'none') hiddenReasons.push('display: none');
  3590.           if (styles.opacity === '0') hiddenReasons.push('opacity: 0');
  3591.           if (styles.visibility === 'hidden') hiddenReasons.push('visibility: hidden');
  3592.           if (parseInt(styles.zIndex) < 0) hiddenReasons.push('z-index négatif');
  3593.           
  3594.           if (hiddenReasons.length > 0) {
  3595.             console.warn('Raisons du masquage:', hiddenReasons);
  3596.             
  3597.             // Forcer l'affichage
  3598.             console.log('Forçage de l\\'affichage...');
  3599.             slider.style.display = 'flex';
  3600.             slider.style.opacity = '1';
  3601.             slider.style.visibility = 'visible';
  3602.             slider.style.zIndex = '9999';
  3603.             slider.style.position = 'fixed';
  3604.             slider.style.top = '0';
  3605.             slider.style.left = '0';
  3606.             slider.style.width = '100%';
  3607.             slider.style.height = '100%';
  3608.             
  3609.             console.log('Slider forcé visible');
  3610.           } else {
  3611.             console.log('✅ Slider devrait être visible');
  3612.           }
  3613.           
  3614.           return true;
  3615.         }
  3616.         // Rendre la fonction globale
  3617.         window.diagnoseSliderDisplay = diagnoseSliderDisplay;
  3618.         // Fonction de sécurité pour checkFavorites
  3619.         function checkFavorites() {
  3620.           try {
  3621.             let count = 0;
  3622.             if (typeof getFavoriteItems === 'function') {
  3623.               count = getFavoriteItems().length;
  3624.             } else {
  3625.               // Fallback : compter depuis le DOM
  3626.               const giftCount = document.getElementById('giftCount');
  3627.               if (giftCount && giftCount.textContent) {
  3628.                 count = parseInt(giftCount.textContent.trim()) || 0;
  3629.               }
  3630.             }
  3631.             
  3632.             // Mettre à jour les variables globales
  3633.             window.favoriteCount = count;
  3634.             favoriteCount = count;
  3635.             
  3636.             console.log('Favoris vérifiés:', count);
  3637.             return count;
  3638.           } catch (error) {
  3639.             console.warn('Erreur lors de la vérification des favoris:', error);
  3640.             return 0;
  3641.           }
  3642.         }
  3643.         // Rendre checkFavorites globale si elle n'existe pas
  3644.         if (typeof window.checkFavorites === 'undefined') {
  3645.           window.checkFavorites = checkFavorites;
  3646.         }
  3647.         // Initialisation sécurisée après chargement du DOM
  3648.         document.addEventListener('DOMContentLoaded', function() {
  3649.           console.log('=== DOM chargé, initialisation des sliders ===');
  3650.           console.log('viewImage disponible:', typeof window.viewImage);
  3651.           console.log('viewFavorite disponible:', typeof window.viewFavorite);
  3652.           console.log('universalSlider disponible:', typeof window.universalSlider);
  3653.           
  3654.           // Vérifier que les éléments critiques existent
  3655.           const criticalElements = [
  3656.             'filtre_photos_voir',
  3657.             // Ajoutez d'autres IDs critiques ici si nécessaire
  3658.           ];
  3659.           
  3660.           criticalElements.forEach(id => {
  3661.             const element = document.getElementById(id);
  3662.             if (element) {
  3663.               console.log(`✓ Élément trouvé: \${id}`);
  3664.             } else {
  3665.               console.warn(`⚠ Élément manquant: \${id}`);
  3666.             }
  3667.           });
  3668.           
  3669.           // Initialiser checkFavorites si la fonction existe
  3670.           if (typeof window.checkFavorites === 'function') {
  3671.             window.checkFavorites();
  3672.           }
  3673.         });
  3674.       
  3675.         // Fonction pour obtenir l'image d'un produit selon son type
  3676.         function getProductImage(productId) {
  3677.           const productImages = {
  3678.             'album': '/images/produit/Album5sur5-3.jpg',
  3679.             'digital': '/images/produit/photoNumerique.jpg', 
  3680.             'prints': '/images/produit/PochettePhoto5sur5-2.jpg',
  3681.             'calendrier': '/images/produit/Calendrier5sur5-1.jpg',
  3682.             'livre': '/images/produit/LivreSouvenir5sur5-1.jpg',
  3683.             'coffret': '/images/produit/CoffretCadeau5sur5-2.jpg',
  3684.             'retro': '/images/produit/PochetteRetro5sur5-1.jpg'
  3685.           };
  3686.           
  3687.           return productImages[productId] || '/images/produit/albumm.PNG';
  3688.         }
  3689.         
  3690.         // Fonction pour générer les suggestions de produits (synchronisées avec ecommerce-sidebar)
  3691.         function generateProductSuggestions(favoriteCount) {
  3692.           if (favoriteCount === 0) {
  3693.             return `
  3694.               <div class=\"no-favorites-cta\">
  3695.                 <div class=\"cta-content\">
  3696.                   <i class=\"bi bi-heart\" style=\"font-size: 4rem; color: #e91e63; margin-bottom: 1rem;\"></i>
  3697.                   <h3>Commencez par sélectionner vos photos préférées</h3>
  3698.                   <p>Cliquez sur <i class=\"bi bi-heart\" style=\"color: #e91e63;\"></i> sur vos plus beaux souvenirs pour débloquer nos produits personnalisés.</p>
  3699.                   <button class=\"btn-start-selection\" onclick=\"window.showDaysView()\">
  3700.                     <i class=\"bi bi-images\"></i>
  3701.                     Parcourir les photos
  3702.                   </button>
  3703.                 </div>
  3704.               </div>
  3705.             `;
  3706.           }
  3707.           let suggestionsHTML = '<div class=\"suggestions-header\"><h4><i class=\"bi bi-gift\"></i> Produits recommandés pour vous</h4></div>';
  3708.           
  3709.           // Utiliser les mêmes produits que dans ecommerce-sidebar
  3710.           const products = [];
  3711.           
  3712.           // Album Photo Premium (toujours disponible)
  3713.           products.push({
  3714.             id: 'album',
  3715.             name: 'Album Photo Premium',
  3716.             description: `Album photo personnalisé avec vos \${favoriteCount} photos favorites. Papier de qualité supérieure, reliure rigide.`,
  3717.             currentPrice: '24,90€',
  3718.             originalPrice: '28,90€',
  3719.             savings: '-14%',
  3720.             badge: 'Populaire',
  3721.             available: favoriteCount > 0,
  3722.             disabled: favoriteCount === 0
  3723.           });
  3724.           // Pack Numérique HD (toujours disponible)
  3725.           products.push({
  3726.             id: 'digital',
  3727.             name: 'Pack Numérique HD',
  3728.             description: `Téléchargement immédiat de vos photos en haute définition. Qualité professionnelle garantie.`,
  3729.             currentPrice: '3,90€',
  3730.             originalPrice: '',
  3731.             savings: '',
  3732.             badge: 'Nouveau',
  3733.             available: favoriteCount > 0,
  3734.             disabled: favoriteCount === 0
  3735.           });
  3736.           // Tirages Premium (disponible si >= 12 favoris)
  3737.          
  3738.             products.push({
  3739.               id: 'prints',
  3740.               name: 'Tirages Premium',
  3741.               description: `\${Math.min(favoriteCount, 12)} tirages photo 10x15cm de vos favoris. Papier brillant professionnel, livraison gratuite.`,
  3742.               currentPrice: '9.9€',
  3743.               originalPrice: '',
  3744.               savings: '',
  3745.               badge: 'Débloqué !',
  3746.               available: true,
  3747.               disabled: false
  3748.             });
  3749.           
  3750.           suggestionsHTML += '<div class=\"products-grid\">';
  3751.           
  3752.           products.forEach(product => {
  3753.             suggestionsHTML += `
  3754.               <div class=\"product-card \${product.disabled ? 'disabled' : ''}\" data-product=\"\${product.id}\">
  3755.                 <div class=\"product-badge \${product.disabled ? 'disabled' : ''}\">\${product.badge}</div>
  3756.                 <div class=\"product-image\">
  3757.                   <img src=\"\${getProductImage(product.id)}\" alt=\"\${product.name}\" onerror=\"this.src='/images/produit/albumm.PNG'\">
  3758.                 </div>
  3759.                 <div class=\"product-info\">
  3760.                   <h5>\${product.name}</h5>
  3761.                   <p>\${product.description}</p>
  3762.                   <div class=\"product-pricing\">
  3763.                     <span class=\"current-price\">\${product.currentPrice}</span>
  3764.                     \${product.originalPrice ? `<span class=\"original-price\">\${product.originalPrice}</span>` : ''}
  3765.                     \${product.savings ? `<span class=\"savings\">\${product.savings}</span>` : ''}
  3766.                   </div>
  3767.                   <button class=\"btn-add-to-cart \${product.disabled ? 'disabled' : ''}\" 
  3768.                           onclick=\"orderProduct('\${product.id}')\" 
  3769.                           \${product.disabled ? 'disabled title=\"Ajoutez des favoris pour commander\"' : ''}>
  3770.                     <i class=\"bi bi-cart-plus\"></i>
  3771.                     \${product.disabled ? 'Ajoutez des favoris' : 'Commander'}
  3772.                   </button>
  3773.                 </div>
  3774.               </div>
  3775.             `;
  3776.           });
  3777.           
  3778.           suggestionsHTML += '</div>';
  3779.           // Message d'encouragement
  3780.           if (favoriteCount < 12) {
  3781.             const remaining = 12 - favoriteCount;
  3782.             suggestionsHTML += `
  3783.               <div class=\"encouragement-card\">
  3784.                 <div class=\"encouragement-content\">
  3785.                   <div class=\"encouragement-icon\">🎯</div>
  3786.                   <div class=\"encouragement-text\">
  3787.                     <h5>Encore \${remaining} photo\${remaining > 1 ? 's' : ''} pour débloquer les Tirages Premium !</h5>
  3788.                     <p>Sélectionnez \${remaining} photo\${remaining > 1 ? 's' : ''} supplémentaire\${remaining > 1 ? 's' : ''} pour accéder à tous nos produits</p>
  3789.                   </div>
  3790.                 </div>
  3791.               </div>
  3792.             `;
  3793.           }
  3794.           return suggestionsHTML;
  3795.         }
  3796.         // Fonction pour ajouter au panier
  3797.         function addToCart(productId) {
  3798.           // Animation du bouton cadeau
  3799.           const giftButton = document.querySelector('.gift-button');
  3800.           if (giftButton) {
  3801.             if (giftButton.classList) {
  3802.               giftButton.classList.add('active');
  3803.               setTimeout(() => {
  3804.                 if (giftButton.classList) {
  3805.                   giftButton.classList.remove('active');
  3806.                 }
  3807.               }, 600);
  3808.             }
  3809.           }
  3810.           // Afficher une notification
  3811.           showNotification(`Produit ajouté au panier !`, 'success');
  3812.           
  3813.           // Ici vous pourriez ajouter la logique d'ajout au panier réel
  3814.           console.log('Ajout au panier:', productId);
  3815.         }
  3816.         // Fonction pour afficher une notification
  3817.         function showNotification(message, type = 'info') {
  3818.           const notification = document.createElement('div');
  3819.           notification.className = `notification \${type}`;
  3820.           notification.innerHTML = `
  3821.             <i class=\"bi bi-check-circle\"></i>
  3822.             <span>\${message}</span>
  3823.           `;
  3824.           
  3825.           document.body.appendChild(notification);
  3826.           
  3827.           setTimeout(() => {
  3828.             if (notification && notification.classList) {
  3829.               notification.classList.add('show');
  3830.             }
  3831.           }, 100);
  3832.           
  3833.           setTimeout(() => {
  3834.             if (notification && notification.classList) {
  3835.               notification.classList.remove('show');
  3836.               setTimeout(() => {
  3837.                 if (document.body.contains(notification)) {
  3838.                   document.body.removeChild(notification);
  3839.                 }
  3840.               }, 300);
  3841.             }
  3842.           }, 3000);
  3843.         }
  3844.         // Fonction pour obtenir le nombre actuel de favoris
  3845.         function getCurrentFavoriteCount() {
  3846.           return getFavoriteItems().length;
  3847.         }
  3848.         // Gestion du localStorage pour l'indicateur \"nouveau contenu\"
  3849.         const lastVisitKey = 'lastVisitISO';
  3850.         const currentVisit = new Date().toISOString();
  3851.         
  3852.         // Sauvegarder la visite actuelle
  3853.         localStorage.setItem(lastVisitKey, currentVisit);
  3854.         
  3855.         // Vérifier et marquer les jours avec nouveau contenu
  3856.         const dateCards = document.querySelectorAll('.date-card.modern-card');
  3857.         dateCards.forEach(card => {
  3858.           // Ici vous devriez comparer avec updatedAt du backend
  3859.           // Pour l'instant, on simule avec un attribut data-updated
  3860.           const updatedAt = card.getAttribute('data-updated');
  3861.           if (updatedAt) {
  3862.             const lastVisit = localStorage.getItem(lastVisitKey);
  3863.             if (new Date(updatedAt) > new Date(lastVisit)) {
  3864.               if (card && card.classList) {
  3865.                 card.classList.add('has-new-content');
  3866.               }
  3867.               // Ajouter le badge \"nouveau\" si pas déjà présent
  3868.               if (!card.querySelector('.badge-new')) {
  3869.                 const badge = document.createElement('span');
  3870.                 badge.className = 'badge-new';
  3871.                 badge.setAttribute('aria-label', 'Nouveau contenu');
  3872.                 card.querySelector('.title-line').appendChild(badge);
  3873.               }
  3874.             }
  3875.           }
  3876.         });
  3877.         // Gestion des aria-label dynamiques pour les cartes de jours
  3878.         dateCards.forEach(card => {
  3879.           const dayText = card.querySelector('.day').textContent.trim();
  3880.           const dateText = card.querySelector('.full-date').textContent.trim();
  3881.           const photos = card.querySelector('.media-list-horizontal li:nth-child(1)')?.textContent.trim() || '0';
  3882.           const audios = card.querySelector('.media-list-horizontal li:nth-child(2)')?.textContent.trim() || '0';
  3883.           const videos = card.querySelector('.media-list-horizontal li:nth-child(3)')?.textContent.trim() || '0';
  3884.           
  3885.           const ariaLabel = `Contenu du \${dateText} : \${photos} photos, \${audios} audios, \${videos} vidéos`;
  3886.           card.setAttribute('aria-label', ariaLabel);
  3887.         });
  3888.       });
  3889.     </script>
  3890.     
  3891.     <!-- Make sure we're showing the right content by default if no valid content is marked 'show' -->
  3892.     ";
  3893.         // line 3527
  3894.         if (((isset($context["lastValidIndex"]) || array_key_exists("lastValidIndex"$context) ? $context["lastValidIndex"] : (function () { throw new RuntimeError('Variable "lastValidIndex" does not exist.'3527$this->source); })()) > 0)) {
  3895.             // line 3528
  3896.             yield "    <script>
  3897.       document.addEventListener('DOMContentLoaded', function() {
  3898.         // Check if no content is showing
  3899.         if (document.querySelectorAll('.container--gallery .collapse.show').length === 0) {
  3900.           // Show the content for the last valid date
  3901.           var lastValidContent = document.getElementById('demP";
  3902.             // line 3533
  3903.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["lastValidIndex"]) || array_key_exists("lastValidIndex"$context) ? $context["lastValidIndex"] : (function () { throw new RuntimeError('Variable "lastValidIndex" does not exist.'3533$this->source); })()), "html"nulltrue);
  3904.             yield "');
  3905.           if (lastValidContent) {
  3906.             if (lastValidContent.classList) {
  3907.               lastValidContent.classList.add('show');
  3908.             }
  3909.             
  3910.             // Also mark the corresponding date card as active
  3911.             var dateCards = document.querySelectorAll('.date-card');
  3912.             if (dateCards.length >= ";
  3913.             // line 3541
  3914.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["lastValidIndex"]) || array_key_exists("lastValidIndex"$context) ? $context["lastValidIndex"] : (function () { throw new RuntimeError('Variable "lastValidIndex" does not exist.'3541$this->source); })()), "html"nulltrue);
  3915.             yield ") {
  3916.               dateCards.forEach(card => {
  3917.                 if (card && card.classList) {
  3918.                   card.classList.remove('active');
  3919.                 }
  3920.               });
  3921.               const targetCard = dateCards[";
  3922.             // line 3547
  3923.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((isset($context["lastValidIndex"]) || array_key_exists("lastValidIndex"$context) ? $context["lastValidIndex"] : (function () { throw new RuntimeError('Variable "lastValidIndex" does not exist.'3547$this->source); })()) - 1), "html"nulltrue);
  3924.             yield "];
  3925.               if (targetCard && targetCard.classList) {
  3926.                 targetCard.classList.add('active');
  3927.               }
  3928.             }
  3929.           }
  3930.         }
  3931.       });
  3932.     </script>
  3933.     ";
  3934.         }
  3935.         // line 3557
  3936.         yield "  </div>
  3937. </div>
  3938.   ";
  3939.         
  3940.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  3941.         
  3942.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  3943.         yield from [];
  3944.     }
  3945.     // line 3560
  3946.     /**
  3947.      * @return iterable<null|scalar|\Stringable>
  3948.      */
  3949.     public function block_Javascript(array $context, array $blocks = []): iterable
  3950.     {
  3951.         $macros $this->macros;
  3952.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  3953.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""Javascript"));
  3954.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  3955.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""Javascript"));
  3956.         // line 3561
  3957.         yield "  ";
  3958.         yield from $this->yieldParentBlock("Javascript"$context$blocks);
  3959.         yield "
  3960.   <script>// Gestion de la sidebar des favoris
  3961. document.addEventListener('DOMContentLoaded', function() {
  3962.     const sidebar = document.getElementById('favorites-sidebar');
  3963.     const openBtn = document.getElementById('openFavoritesSidebar');
  3964.     const closeBtn = document.querySelector('.favorites-close');
  3965.     const giftButton = document.querySelector('.gift-button');
  3966.     function openSidebar() {
  3967.         if (sidebar && sidebar.classList) {
  3968.           sidebar.classList.add('active');
  3969.           updateFavoritesSidebar();
  3970.         }
  3971.     }
  3972.     function closeSidebar() {
  3973.         if (sidebar && sidebar.classList) {
  3974.           sidebar.classList.remove('active');
  3975.         }
  3976.     }
  3977.     function updateFavoritesSidebar() {
  3978.         const grid = document.getElementById('favorites-grid');
  3979.         const counter = document.getElementById('favorites-counter');
  3980.         const emptyState = document.getElementById('favorites-empty-state');
  3981.         const progress = document.getElementById('favorites-progress');
  3982.         
  3983.         const count = parseInt(document.getElementById('likeCount').textContent);
  3984.         counter.textContent = count +1;
  3985.         
  3986.         if (count === 0) {
  3987.             emptyState.style.display = 'flex';
  3988.             grid.style.display = 'none';
  3989.         } else {
  3990.             emptyState.style.display = 'none';
  3991.             grid.style.display = 'grid';
  3992.             const percentage = (count / 20) * 100;
  3993.             progress.style.width = `\${percentage}%`;
  3994.         }
  3995.     }
  3996.     if (openBtn) {
  3997.         openBtn.addEventListener('click', openSidebar);
  3998.     }
  3999.     if (favButton) {
  4000.         favButton.addEventListener('click', openSidebar);
  4001.     }
  4002.     if (closeBtn) {
  4003.         closeBtn.addEventListener('click', closeSidebar);
  4004.     }
  4005.     document.addEventListener('click', (e) => {
  4006.         if (sidebar && sidebar.classList && sidebar.classList.contains('active') && 
  4007.             !sidebar.contains(e.target) && 
  4008.             (!favButton || !favButton.contains(e.target)) && 
  4009.             (!openBtn || !openBtn.contains(e.target))) {
  4010.             closeSidebar();
  4011.         }
  4012.     });
  4013. });
  4014. // Modification des fonctions existantes
  4015. const originalAddFavoris = window.AddFavoris;
  4016. window.AddFavoris = function(\$id, \$idSejour, \$urlimg, \$description) {
  4017.     if (originalAddFavoris) {
  4018.         originalAddFavoris(\$id, \$idSejour, \$urlimg, \$description);
  4019.     }
  4020.     
  4021.   
  4022.     
  4023.     // Vérifier si la sidebar est ouverte - noter que nous vérifions la valeur CSS right: 0
  4024.     if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  4025.         // Recharger les favoris
  4026.         loadFavorites();
  4027.     }
  4028. };
  4029. const originalSupprimerFavoris = window.supprimerFavoris;
  4030. window.supprimerFavoris = function(\$id, \$idSejour) {
  4031.     if (originalSupprimerFavoris) {
  4032.         originalSupprimerFavoris(\$id, \$idSejour);
  4033.     }
  4034.     
  4035.     // Mettre à jour tous les compteurs de favoris
  4036.     updateAllFavoriteCounters();
  4037.     
  4038.     // Vérifier si la sidebar est ouverte
  4039.     if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  4040.         // Recharger les favoris
  4041.         loadFavorites();
  4042.     }
  4043. };
  4044. // Variables globales
  4045. let selectedFavorites = [];
  4046. let allFavorites = [];
  4047. // Fonction pour mettre à jour la sidebar
  4048. function loadFavorites() {
  4049.     \$(\"#favorites-grid\").html(\"<div style='text-align:center;padding:20px;'>Chargement...</div>\");
  4050.     
  4051.     \$.ajax({
  4052.         url: \"/Parent/mes-favoris\",
  4053.         type: \"GET\",
  4054.         dataType: \"json\",
  4055.         success: function(data) {
  4056.             \$(\"#favorites-grid\").empty();
  4057.             allFavorites = data.data || [];
  4058.             
  4059.             if (allFavorites.length > 0) {
  4060.                 \$(\"#favorites-empty-state\").hide();
  4061.                 
  4062.                 \$.each(allFavorites, function(i, fav) {
  4063.                     var isSelected = selectedFavorites.includes(fav.id);
  4064.                     
  4065.                     var item = \$(\"<div class='favorite-item' style='position:relative;border-radius:8px;overflow:hidden;aspect-ratio:1;cursor:pointer;'></div>\");
  4066.                     var img = \$(\"<img style='width:100%;height:100%;object-fit:cover;transition:transform 0.3s ease;'>\").attr(\"src\", fav.path).attr(\"alt\", fav.descreption || \"Photo favorite\");
  4067.                     
  4068.                     // Overlay de sélection
  4069.                     var selectionOverlay = \$(\"<div class='selection-overlay' style='position:absolute;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.3);display:flex;align-items:center;justify-content:center;'></div>\");
  4070.                     
  4071.                     // Icône de sélection
  4072.                     var checkIcon = \$(\"<div style='width:25px;height:25px;border-radius:50%;border:2px solid white;display:flex;align-items:center;justify-content:center;background:\" + (isSelected ? \"#F56040\" : \"transparent\") + \";transition:background 0.2s;'></div>\");
  4073.                     if (isSelected) {
  4074.                         checkIcon.append(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  4075.                     }
  4076.                     
  4077.                     selectionOverlay.append(checkIcon);
  4078.                     
  4079.                     // Overlay d'action (bouton supprimer)
  4080.                     var actionOverlay = \$(\"<div class='action-overlay' style='position:absolute;top:5px;right:5px;opacity:0;transition:opacity 0.2s;'></div>\");
  4081.                   
  4082.                     actionOverlay.append(deleteBtn);
  4083.                     
  4084.                     // Ajouter les événements
  4085.                     item.hover(
  4086.                         function() { \$(this).find(\".action-overlay\").css(\"opacity\", \"1\"); },
  4087.                         function() { \$(this).find(\".action-overlay\").css(\"opacity\", \"0\"); }
  4088.                     );
  4089.                     
  4090.                     item.click(function() {
  4091.                         toggleSelection(fav.id, \$(this).find(\".selection-overlay > div\"));
  4092.                     });
  4093.                     
  4094.                     item.append(img).append(selectionOverlay).append(actionOverlay);
  4095.                     \$(\"#favorites-grid\").append(item);
  4096.                 });
  4097.                 
  4098.                 \$(\"#favorites-counter\").text(allFavorites.length);
  4099.                 
  4100.                 // Mettre à jour le compteur sur le bouton également
  4101.                 \$(\"#openFavoritesSidebar span\").text(allFavorites.length);
  4102.                 
  4103.                 // Mettre à jour l'interface produits
  4104.                 updateProductsView();
  4105.                 
  4106.             } else {
  4107.                 \$(\"#favorites-empty-state\").show();
  4108.                 \$(\"#favorites-counter\").text(\"0\");
  4109.                 \$(\"#openFavoritesSidebar span\").text(\"0\");
  4110.                 \$(\"#selection-count\").text(\"0\");
  4111.                 updateProductsView();
  4112.             }
  4113.         },
  4114.         error: function() {
  4115.             \$(\"#favorites-grid\").html(\"<div style='color:red;text-align:center;padding:20px;'>Erreur de chargement</div>\");
  4116.         }
  4117.     });
  4118. }
  4119. // Fonction pour supprimer un favori
  4120. function removeFavorite(id) {
  4121.     \$.ajax({
  4122.         url: \"/Parent/remove-favorite/\" + id,
  4123.         type: \"POST\",
  4124.         success: function() {
  4125.             // Retirer de la sélection si présent
  4126.             selectedFavorites = selectedFavorites.filter(favId => favId != id);
  4127.             
  4128.             // Mettre à jour le compteur de sélection
  4129.             \$(\"#selection-count\").text(selectedFavorites.length);
  4130.             
  4131.             // Recharger les favoris
  4132.             loadFavorites();
  4133.             
  4134.             // Mettre à jour tous les compteurs de favoris
  4135.             updateAllFavoriteCounters();
  4136.             
  4137.             // Mettre à jour l'interface produits
  4138.             updateProductsView();
  4139.         },
  4140.         error: function() {
  4141.             alert(\"Erreur lors de la suppression du favori\");
  4142.         }
  4143.     });
  4144. }
  4145. // Fonction pour basculer la sélection d'une photo
  4146. function toggleSelection(id, checkElement) {
  4147.     const index = selectedFavorites.indexOf(id);
  4148.     
  4149.     if (index === -1) {
  4150.         // Ajouter à la sélection
  4151.         selectedFavorites.push(id);
  4152.         checkElement.css(\"background\", \"#F56040\");
  4153.         checkElement.html(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  4154.     } else {
  4155.         // Retirer de la sélection
  4156.         selectedFavorites.splice(index, 1);
  4157.         checkElement.css(\"background\", \"transparent\");
  4158.         checkElement.html(\"\");
  4159.     }
  4160.     
  4161.     // Mettre à jour le compteur
  4162.     \$(\"#selection-count\").text(selectedFavorites.length);
  4163.     
  4164.     // Mettre à jour l'interface produits
  4165.     updateProductsView();
  4166. }
  4167. // Fonction pour mettre à jour la vue des produits
  4168. function updateProductsView() {
  4169.     const current = selectedFavorites.length;
  4170.     \$(\"#product-photo-count\").text(current);
  4171.     
  4172.     let remainingForAlbum = Math.max(0, 20 - current);
  4173.     let remainingForPochette = Math.max(0, 12 - current);
  4174.     let remainingForPack = Math.max(0, 12 - current);
  4175.     const progressBar = (count, total, color) => `
  4176.         <div style=\"margin: 5px 0;\">
  4177.             <div style=\"background-color: #e9ecef; border-radius: 5px; overflow: hidden; height: 8px;\">
  4178.                 <div style=\"width: \${(count / total) * 100}%; background-color: \${color}; height: 100%;\"></div>
  4179.             </div>
  4180.             <small style=\"font-size: 12px;\">\${count}/\${total} photos</small>
  4181.         </div>
  4182.     `;
  4183.     // Liste des produits
  4184.     const products = [
  4185.         {
  4186.             name: \"Pack numérique (20 photos)\",
  4187.             required: 20,
  4188.             remaining: Math.max(0, 20 - current),
  4189.             image: \"/images/produit/photoNumerique.jpg\",
  4190.             color: \"#4caf50\",
  4191.             link: \"";
  4192.         // line 3808
  4193.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("PackPhotosNumerique_Favoris", ["nbr" => 20]);
  4194.         yield "\",
  4195.         },
  4196.        +
  4197.         {
  4198.             name: \"Pochette photo (12 photos)\",
  4199.             required: 12,
  4200.             remaining: Math.max(0, 12 - current),
  4201.             image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  4202.             color: \"#2196f3\",
  4203.             link: \"";
  4204.         // line 3817
  4205.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("AjoutPochettePhotos_Favoris", ["nbr" => 12]);
  4206.         yield "\",
  4207.         },
  4208.     ].sort((a, b) => a.remaining - b.remaining);
  4209.     const productList = products
  4210.         .map((product) => {
  4211.             const count = current;
  4212.             const total = product.required;
  4213.             const remaining = product.remaining;
  4214.             return `
  4215.                 <li style=\"margin-bottom: 20px;\">
  4216.                     <div style=\"display: flex; align-items: center; gap: 10px;\">
  4217.                         <img src=\"\${product.image}\" alt=\"\${product.name}\" style=\"width: 70px; height: 70px; border-radius: 5px; object-fit: cover;\" />
  4218.                         <div style=\"flex: 1;\">
  4219.                             <strong style=\"font-size: 14px;\">\${product.name}</strong>
  4220.                             \${progressBar(count, total, product.color)}
  4221.                             \${
  4222.                                 `<small style=\"color: \${product.color}; font-size: 12px;\">
  4223.                                     Encore \${remaining} photos pour compléter \${product.name.toLowerCase()}
  4224.                                 </small>
  4225.                                 <button
  4226.                                     style=\"
  4227.                                         margin-top: 5px;
  4228.                                         padding: 6px 12px;
  4229.                                         background-color: \${product.color};
  4230.                                         color: white;
  4231.                                         border: none;
  4232.                                         border-radius: 5px;
  4233.                                         font-size: 13px;
  4234.                                         cursor: pointer;
  4235.                                     \"
  4236.                                     onclick=\"window.location.href='\${product.link}'\"
  4237.                                 >
  4238.                                     Commander
  4239.                                 </button>`
  4240.                             }
  4241.                         </div>
  4242.                     </div>
  4243.                 </li>
  4244.             `;
  4245.         })
  4246.         .join(\"\");
  4247.     const boutiqueButton = `
  4248.         <li style=\"margin-top: 25px; text-align: center;\">
  4249.             <button
  4250.                 style=\"
  4251.                     padding: 8px 15px;
  4252.                     background-color: #F56040;
  4253.                     color: white;
  4254.                     border: none;
  4255.                     border-radius: 5px;
  4256.                     font-size: 14px;
  4257.                     width: 170px;
  4258.                     height: 40px;
  4259.                     cursor: pointer;
  4260.                 \"
  4261.                 onclick=\"window.location.href='";
  4262.         // line 3875
  4263.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  4264.         yield "'\"
  4265.             >
  4266.                 Voir toute la boutique
  4267.             </button>
  4268.         </li>
  4269.     `;
  4270.     \$(\"#product-list\").html(productList + boutiqueButton);
  4271. }
  4272. // Modifications au script existant
  4273. \$(document).ready(function() {
  4274.     // Fonctions pour ouvrir/fermer la sidebar
  4275.     \$(\"#openFavoritesSidebar\").click(function() {
  4276.         \$(\"#favorites-sidebar\").css(\"right\", \"0\");
  4277.         loadFavorites();
  4278.     });
  4279.     
  4280.     \$(\"#close-favorites-btn\").click(function() {
  4281.         closeFavoritesSidebar();
  4282.     });
  4283.     
  4284.     // Fonction pour fermer la sidebar
  4285.     window.closeFavoritesSidebar = function() {
  4286.         \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  4287.     };
  4288.     
  4289.     // Tout sélectionner / Tout désélectionner
  4290.     \$(\"#select-all-btn\").click(function() {
  4291.         if (selectedFavorites.length === allFavorites.length) {
  4292.             // Tout désélectionner
  4293.             selectedFavorites = [];
  4294.             \$(\".selection-overlay > div\").css(\"background\", \"transparent\").html(\"\");
  4295.             \$(this).text(\"Tout sélectionner\");
  4296.         } else {
  4297.             // Tout sélectionner
  4298.             selectedFavorites = allFavorites.map(fav => fav.id);
  4299.             \$(\".selection-overlay > div\").css(\"background\", \"#F56040\").html(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  4300.             \$(this).text(\"Tout désélectionner\");
  4301.         }
  4302.         
  4303.         // Mettre à jour le compteur
  4304.         \$(\"#selection-count\").text(selectedFavorites.length);
  4305.         
  4306.         // Mettre à jour l'interface produits
  4307.         updateProductsView();
  4308.     });
  4309.     
  4310.     // Gestion des onglets
  4311.     \$(\".sidebar-tab\").click(function() {
  4312.         \$(\".sidebar-tab\").removeClass(\"active\").css({
  4313.             \"color\": \"#666\",
  4314.             \"border-bottom\": \"none\"
  4315.         });
  4316.         \$(this).addClass(\"active\").css({
  4317.             \"color\": \"#F56040\",
  4318.             \"border-bottom\": \"2px solid #F56040\"
  4319.         });
  4320.         
  4321.         const tabId = \$(this).attr(\"id\");
  4322.         \$(\".tab-content\").hide();
  4323.         
  4324.         if (tabId === \"tab-photos\") {
  4325.             \$(\"#photos-content\").show();
  4326.         } else if (tabId === \"tab-products\") {
  4327.             \$(\"#products-content\").show();
  4328.         }
  4329.     });
  4330.     
  4331.     // Modifier les fonctions existantes pour intercepter l'ajout/suppression de favoris
  4332.     const originalAddFavoris = window.AddFavoris;
  4333.     window.AddFavoris = function(\$id, \$idSejour, \$urlimg, \$description) {
  4334.         if (originalAddFavoris) {
  4335.             originalAddFavoris(\$id, \$idSejour, \$urlimg, \$description);
  4336.         }
  4337.         
  4338.         // Mettre à jour tous les compteurs de favoris
  4339.         updateAllFavoriteCounters();
  4340.         
  4341.         // Recharger les favoris si la sidebar est ouverte
  4342.         if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  4343.             loadFavorites();
  4344.         }
  4345.     };
  4346.     const originalSupprimerFavoris = window.supprimerFavoris;
  4347.     window.supprimerFavoris = function(\$id, \$idSejour) {
  4348.         if (originalSupprimerFavoris) {
  4349.             originalSupprimerFavoris(\$id, \$idSejour);
  4350.         }
  4351.         
  4352.         // Mettre à jour tous les compteurs de favoris
  4353.         updateAllFavoriteCounters();
  4354.         
  4355.         // Recharger les favoris si la sidebar est ouverte
  4356.         if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  4357.             // Retirer de la sélection si présent
  4358.             selectedFavorites = selectedFavorites.filter(favId => favId != \$id);
  4359.             loadFavorites();
  4360.         }
  4361.     };
  4362.     
  4363.     // Fermer en cliquant en dehors
  4364.     \$(document).click(function(event) {
  4365.         if (!\$(event.target).closest(\"#favorites-sidebar\").length && 
  4366.             !\$(event.target).closest(\"#openFavoritesSidebar\").length && 
  4367.             \$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  4368.             closeFavoritesSidebar();
  4369.         }
  4370.     });
  4371. });
  4372. // Initialisation de la sidebar
  4373. \$(document).ready(function() {
  4374.     // Fonctions pour ouvrir/fermer la sidebar
  4375.     \$(\"#openFavoritesSidebar\").click(function() {
  4376.         \$(\"#favorites-sidebar\").css(\"right\", \"0\");
  4377.         loadFavorites();
  4378.     });
  4379.     
  4380.     \$(\"#close-favorites-btn\").click(function() {
  4381.         \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  4382.     });
  4383.     
  4384.     // Fermer en cliquant en dehors
  4385.     \$(document).click(function(event) {
  4386.         if (!\$(event.target).closest(\"#favorites-sidebar\").length && 
  4387.             !\$(event.target).closest(\"#openFavoritesSidebar\").length && 
  4388.             \$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  4389.             \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  4390.         }
  4391.     });
  4392. });
  4393.   </script>
  4394.   <script src=\"";
  4395.         // line 4008
  4396.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("js/splide.min.js"), "html"nulltrue);
  4397.         yield "\" defer></script>
  4398.    
  4399. <script>
  4400.   document.addEventListener('DOMContentLoaded', function () {
  4401.     const openBtn = document.getElementById('openFavoritesSidebar');
  4402.     const sidebar = document.getElementById('favorites-sidebar');
  4403.     const closeBtn = document.getElementById('favorites-close');
  4404.     if (openBtn && sidebar) {
  4405.       openBtn.addEventListener('click', () => {
  4406.         if (sidebar && sidebar.classList) {
  4407.           sidebar.classList.add('active');
  4408.         }
  4409.       });
  4410.     }
  4411.     if (closeBtn && sidebar) {
  4412.       closeBtn.addEventListener('click', () => {
  4413.         if (sidebar && sidebar.classList) {
  4414.           sidebar.classList.remove('active');
  4415.         }
  4416.       });
  4417.     }
  4418.   });
  4419. </script>
  4420.  
  4421. <script>
  4422. document.addEventListener('DOMContentLoaded', function() {
  4423.   const filterBadges = document.querySelectorAll('.filter-badge');
  4424.   filterBadges.forEach(badge => {
  4425.     badge.addEventListener('click', function() {
  4426.       // Désactiver tous les badges
  4427.       filterBadges.forEach(b => {
  4428.         if (b && b.classList) {
  4429.           b.classList.remove('active');
  4430.         }
  4431.       });
  4432.       // Activer le badge cliqué
  4433.       if (this && this.classList) {
  4434.         this.classList.add('active');
  4435.       }
  4436.     });
  4437.   });
  4438. });
  4439. </script>
  4440.   <script
  4441.     type=\"text/javascript\"
  4442.     src=\"";
  4443.         // line 4061
  4444.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("Accueil/js/jquery.magnific-popup.min.js"), "html"nulltrue);
  4445.         yield "\"
  4446.   ></script>
  4447.   <script>
  4448. document.addEventListener('DOMContentLoaded', function () {
  4449.   const prevButtons = document.querySelectorAll('.btn-prev-day');
  4450.   const nextButtons = document.querySelectorAll('.btn-next-day');
  4451.   const dateCards = document.querySelectorAll('.date-card.modern-card');
  4452.   const collapseSections = document.querySelectorAll('.collapse');
  4453.   // 🎯 MEDIA TOOLBAR CAPSULE - État global et logique (Senior UX)
  4454.   (() => {
  4455.     // État global de filtre
  4456.     const MediaFilter = { current: 'all' };
  4457.     // Compteurs dynamiques
  4458.     const counters = { photo: 0, audio: 0, video: 0, fav: 0 };
  4459.     
  4460.     const updateCounts = () => {
  4461.       // Compter les médias dans le DOM
  4462.       counters.photo = document.querySelectorAll('.photo-item, [data-media-type=\"photo\"]').length;
  4463.       counters.video = document.querySelectorAll('[data-media-type=\"video\"]').length;
  4464.       counters.audio = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]').length;
  4465.       // NE PAS recalculer seulement les favoris - ils utilisent ";
  4466.         // line 4083
  4467.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'4083$this->source); })()), "html"nulltrue);
  4468.         yield "
  4469.       
  4470.       // Mettre à jour l'affichage (sauf favoris)
  4471.       Object.entries(counters).forEach(([k, v]) => {
  4472.         if (k !== 'fav') { // Garder seulement le compteur favoris intact
  4473.           document.querySelectorAll(`.mtb-count[data-bind=\"\${k}\"]`).forEach(el => el.textContent = v);
  4474.         }
  4475.       });
  4476.     };
  4477.     // Simple fonction pour le filtre actuel
  4478.     function setActive(filter) {
  4479.       MediaFilter.current = filter;
  4480.       
  4481.       // Exception : ne pas ajouter de classe active au bouton photos
  4482.       if (filter === 'photos') {
  4483.         const photosBtn = document.querySelector('.mtb-btn[data-filter=\"photos\"]');
  4484.         if (photosBtn) {
  4485.           photosBtn.classList.remove('active', 'is-active');
  4486.         }
  4487.       }
  4488.     }
  4489.     // Fonction simplifiée qui mappe et appelle filterContent
  4490.     function applyFilter(filter) {
  4491.       // Mapper les filtres de la capsule vers les filtres existants si nécessaire
  4492.       const filterMap = {
  4493.         'all': 'toutVoir',
  4494.         'photos': 'photos', 
  4495.         'audio': 'audio',
  4496.         'videos': 'videos',
  4497.         'favoris': 'favoris'
  4498.       };
  4499.       
  4500.       const mappedFilter = filterMap[filter] || filter;
  4501.       
  4502.       // Pour le filtre \"all\", s'assurer que la vue des jours est restaurée
  4503.       if (filter === 'all') {
  4504.         const containerGallery = document.querySelector('.container--gallery');
  4505.         if (containerGallery) {
  4506.           containerGallery.style.display = 'block';
  4507.         }
  4508.       }
  4509.       
  4510.       if (typeof window.filterContent === 'function') {
  4511.         window.filterContent(mappedFilter);
  4512.       } else {
  4513.         console.error('window.filterContent n\\'est pas disponible');
  4514.       }
  4515.     }
  4516.     // Click handlers - exactement la même logique que stat-pill
  4517.     document.addEventListener('click', (e) => {
  4518.       const btn = e.target.closest('.mtb-btn');
  4519.       if (!btn) return;
  4520.       // Bouton fermer
  4521.       if (btn.classList.contains('mtb-close')) {
  4522.         document.querySelector('.media-toolbar')?.remove();
  4523.         return;
  4524.       }
  4525.       const filter = btn.dataset.filter;
  4526.       if (!filter) return;
  4527.       // Debug spécifique pour le bouton favoris
  4528.       if (filter === 'favoris') {
  4529.         console.log('🔍 Bouton favoris cliqué - Debug:', {
  4530.           btn: btn,
  4531.           filter: filter,
  4532.           hasFilterContent: typeof window.filterContent === 'function',
  4533.           mesFavCount: document.getElementById('mesFavCount')?.textContent
  4534.         });
  4535.         
  4536.         // Protection : empêcher la décrémentation du compteur pour les clics de filtre
  4537.         e.stopPropagation();
  4538.         e.preventDefault();
  4539.         
  4540.         // Appeler uniquement la fonction de filtrage
  4541.         if (typeof window.filterContent === 'function') {
  4542.           window.filterContent('favoris');
  4543.         } else {
  4544.           console.error('❌ window.filterContent n\\'est pas disponible');
  4545.         }
  4546.         return; // Sortir de la fonction pour éviter le traitement normal
  4547.       }
  4548.       // Exception pour le bouton photos : ne pas modifier les états actifs
  4549.       if (btn.dataset.filter === 'photos') {
  4550.         // Pour le bouton photos, ne pas toucher aux autres boutons
  4551.         // Juste exécuter l'action sans changer les états
  4552.       } else {
  4553.         // Pour les autres boutons : gérer les états actifs normalement
  4554.         const mtbBtns = document.querySelectorAll('.mtb-btn[data-filter]');
  4555.         for (let i = 0; i < mtbBtns.length; i++) {
  4556.           const b = mtbBtns[i];
  4557.           if (b && b.classList) {
  4558.             if (b === btn) {
  4559.               b.classList.add('active');
  4560.             } else {
  4561.               b.classList.remove('active');
  4562.             }
  4563.           }
  4564.         }
  4565.       }
  4566.       
  4567.       // Déclencher le filtrage du contenu - même logique que stat-pill
  4568.       console.log('mtb-btn click:', filter, 'filterContent type:', typeof window.filterContent);
  4569.       if (typeof window.filterContent === 'function') {
  4570.         window.filterContent(filter);
  4571.       } else {
  4572.         console.error('window.filterContent n\\'est pas une fonction!');
  4573.       }
  4574.     });
  4575.     // Expose un setter global
  4576.     window.setMediaFilter = (filter) => {
  4577.       // Pour le bouton photos : ne pas modifier les états
  4578.       if (filter !== 'photos') {
  4579.         setActive(filter);
  4580.       }
  4581.       applyFilter(filter);
  4582.     };
  4583.     // Mise à jour des compteurs quand les favoris changent
  4584.     window.addEventListener('favorites:updated', updateCounts);
  4585.     
  4586.     // Initialisation
  4587.     setTimeout(() => {
  4588.       updateCounts();
  4589.       setActive('all');
  4590.     }, 100);
  4591.     // Mise à jour périodique des compteurs (sauf favoris qui reste fixe)
  4592.     setInterval(updateCounts, 2000);
  4593.   })();
  4594.   function navigateToDay(index) {
  4595.      if (index >= 0 && index < collapseSections.length) {
  4596.       // Fermer tous les jours
  4597.       collapseSections.forEach(s => {
  4598.         if (s && s.classList) {
  4599.           s.classList.remove('show');
  4600.         }
  4601.       });
  4602.       dateCards.forEach(c => {
  4603.         if (c && c.classList) {
  4604.           c.classList.remove('active');
  4605.         }
  4606.       });
  4607.       // Ouvrir le bon jour
  4608.       const targetCollapse = collapseSections[index];
  4609.       const targetCard = dateCards[index];
  4610.       if (targetCollapse && targetCard) {
  4611.         if (targetCollapse.classList) {
  4612.           targetCollapse.classList.add('show');
  4613.         }
  4614.         if (targetCard.classList) {
  4615.           targetCard.classList.add('active');
  4616.         }
  4617.       }
  4618.     }
  4619.   }
  4620.   prevButtons.forEach(button => {
  4621.     button.addEventListener('click', function () {
  4622.       const targetIndex = parseInt(this.dataset.target, 10);
  4623.       navigateToDay(targetIndex);
  4624.     });
  4625.   });
  4626.   nextButtons.forEach(button => {
  4627.     button.addEventListener('click', function () {
  4628.       const targetIndex = parseInt(this.dataset.target, 10);
  4629.       navigateToDay(targetIndex);
  4630.     });
  4631.   });
  4632. });
  4633. </script>
  4634.   <script>
  4635.     document.addEventListener('DOMContentLoaded', function() {
  4636.   const style = document.createElement('style');
  4637.   style.textContent = `
  4638.     .hidden {
  4639.       display: none !important;
  4640.     }
  4641.   `;
  4642.   document.head.appendChild(style);
  4643. });
  4644.     document.addEventListener('DOMContentLoaded', function() {
  4645.     // Get the gift button
  4646.     const giftButton = document.querySelector('.gift-button');
  4647.     if (giftButton) {
  4648.       // Keep it clickable for the gift functionality
  4649.       giftButton.style.pointerEvents = 'auto';
  4650.       
  4651.       // Add click handler for gift action
  4652.       giftButton.onclick = function(e) {
  4653.         e.preventDefault();
  4654.         e.stopPropagation();
  4655.         return false;
  4656.       };
  4657.       
  4658.       // Make sure hover still works
  4659.       favoriteButton.addEventListener('mouseover', function() {
  4660.         document.getElementById('purchase-alert').style.display = 'block';
  4661.       });
  4662.       
  4663.       // Keep any existing hover functionality
  4664.       if (typeof showSelection === 'function') {
  4665.         favoriteButton.onmouseover = showSelection;
  4666.       }
  4667.     }
  4668.     
  4669.     // Make sure the purchase alert remains interactive
  4670.     const purchaseAlert = document.getElementById('purchase-alert');
  4671.     if (purchaseAlert) {
  4672.       purchaseAlert.style.pointerEvents = 'auto';
  4673.     }
  4674.   });
  4675.     // Sélection des éléments
  4676.     const purchaseAlert = document.getElementById(\"purchase-alert\");
  4677.     const alertContent = document.getElementById(\"purchase-alert-content\");
  4678.     const likeCountLabel = document.getElementById(\"likeCount\");
  4679.     
  4680.     // Fonction pour obtenir le nombre actuel de favoris
  4681.     function getCurrentFavoriteCount() {
  4682.         const likeCountLabel = document.getElementById(\"likeCount\");
  4683.         return parseInt(likeCountLabel?.textContent.trim(), 10) || 0;
  4684.     }
  4685.     // Fonction pour mettre à jour le contenu de l'alerte
  4686.     function updatePurchaseAlert(current) {
  4687.   let remainingForAlbum = Math.max(0, 20 - current);
  4688.   let remainingForPochette = Math.max(0, 12 - current);
  4689.   let remainingForPack = Math.max(0, 12 - current);
  4690.   const progressBar = (count, total, color) => `
  4691.   <div style=\"margin: 5px 0;\">
  4692.     <div style=\"background-color: #e9ecef; border-radius: 5px; overflow: hidden; height: 8px;\">
  4693.       <div style=\"width: \${
  4694.         (count / total) * 100
  4695.       }%; background-color: \${color}; height: 100%;\"></div>
  4696.     </div>
  4697.     <small style=\"font-size: 12px;\">\${count}/\${total} photos</small>
  4698.   </div>
  4699. `;
  4700.   // Use Twig paths here:
  4701.   const products = [
  4702.       {
  4703.       name: \"Pochette photo (12 photos)\",
  4704.       required: 12,
  4705.       remaining: remainingForPochette,
  4706.       image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  4707.       color: \"#2196f3\",
  4708.       link: \"";
  4709.         // line 4344
  4710.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("AjoutPochettePhotos_Favoris", ["nbr" => 12]);
  4711.         yield "\",
  4712.     },
  4713.        {
  4714.       name: \"Pack numérique (20 photos)\",
  4715.       required: 20,
  4716.       remaining: remainingForAlbum,
  4717.       image: \"/images/produit/photoNumerique.jpg\",
  4718.       color: \"#4caf50\",
  4719.       link: \"";
  4720.         // line 4352
  4721.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("PackPhotosNumerique_Favoris", ["nbr" => 20]);
  4722.         yield "\",
  4723.     }
  4724.   
  4725.   
  4726.     
  4727.   ].sort((a, b) => a.remaining - b.remaining);
  4728.   const productList = products
  4729.     .map((product) => {
  4730.       const count = current;
  4731.       const total = product.required;
  4732.       const remaining = product.remaining;
  4733.       return `
  4734.     <li style=\"margin-bottom: 15px;\">
  4735.       <div style=\"display: flex; align-items: center; gap: 10px;\">
  4736.         <img
  4737.           src=\"\${product.image}\"
  4738.           alt=\"\${product.name}\"
  4739.           style=\"width: 65px; height: 65px; border-radius: 5px; margin-top:-19px\"
  4740.         />
  4741.         <div style=\"flex: 1;\">
  4742.           <strong style=\"font-size: 14px;\">\${product.name}</strong>
  4743.           \${progressBar(count, total, product.color)}
  4744.           \${
  4745.             remaining > 0
  4746.               ? `<small style=\"color: \${product.color}; font-size: 12px;\">
  4747.                    Encore \${remaining} photos ❤️ pour compléter \${product.name.toLowerCase()}
  4748.                  </small>`
  4749.               : `<button
  4750.                   style=\"
  4751.                     margin-top: 5px;
  4752.                     padding: 5px 8px;
  4753.                     background-color: \${product.color};
  4754.                     color: white;
  4755.                     border: none;
  4756.                     border-radius: 5px;
  4757.                     font-size: 12px;
  4758.                     cursor: pointer;
  4759.                   \"
  4760.                   onclick=\"window.location.href='\${product.link}'\"
  4761.                 >
  4762.                   Commander
  4763.                 </button>`
  4764.           }
  4765.         </div>
  4766.       </div>
  4767.     </li>
  4768.   `;
  4769.     })
  4770.     .join(\"\");
  4771.   const plusButton = `
  4772.     <li style=\"margin-bottom: 15px; text-align: center;\">
  4773.       <button
  4774.         style=\"
  4775.           padding: 5px 8px;
  4776.           background-color: #F56040;
  4777.           color: white;
  4778.           border: none;
  4779.           border-radius: 5px;
  4780.           font-size: 14px;
  4781.           line-height: 1;
  4782.           width: 150px;
  4783.           height: 40px;
  4784.           cursor: pointer;
  4785.         \"
  4786.         onclick=\"window.location.href='";
  4787.         // line 4419
  4788.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("boutique5sur5");
  4789.         yield "'\"
  4790.       >
  4791.         Aller à la boutique
  4792.       </button>
  4793.     </li>
  4794.   `;
  4795.   if (current === 0) {
  4796.     alertContent.innerHTML = `
  4797.     <p style=\"font-size: 16px; font-weight: bold; color: #333;\">
  4798.       Vous n'avez pas encore de photos favorites !
  4799.     </p>
  4800.     <p style=\"margin-bottom: 20px; color: #555;\">
  4801.       Commencez à ajouter vos moments préférés pour profiter de nos offres.
  4802.     </p>
  4803.     <ul style=\"list-style-type: none; padding: 0;\">\${productList}\${plusButton}</ul>
  4804.   `;
  4805.   } else {
  4806.     alertContent.innerHTML = `
  4807.     <p style=\"font-size: 16px; font-weight: bold; color: #333;\">
  4808.       Vous avez atteint \${current} photos favorites !
  4809.     </p>
  4810.     <p style=\"margin-bottom: 20px; color: #555;\">
  4811.       Profitez de nos offres spéciales :
  4812.     </p>
  4813.     <ul style=\"list-style-type: none; padding: 0;\">\${productList}\${plusButton}</ul>
  4814.   `;
  4815.   }
  4816.   if (purchaseAlert && purchaseAlert.classList) {
  4817.     purchaseAlert.classList.remove(\"hidden\");
  4818.   }
  4819.   clearTimeout(window.purchaseAlertTimeout);
  4820.   window.purchaseAlertTimeout = setTimeout(() => {
  4821.     if (!purchaseAlert.matches(\":hover\")) {
  4822.       closePurchaseAlert();
  4823.     }
  4824.   }, 5000);
  4825. }
  4826.     // Fonction pour fermer l'alerte
  4827.     function closePurchaseAlert() {
  4828.       if (purchaseAlert && purchaseAlert.classList) {
  4829.         purchaseAlert.classList.add(\"hidden\");
  4830.       }
  4831.     }
  4832.     // Événement pour mettre à jour le contenu et afficher la popover dynamiquement au hover
  4833.     document.querySelector(\".gift-button\").addEventListener(\"mouseover\", () => {
  4834.       const currentCount = getCurrentFavoriteCount();
  4835.       updatePurchaseAlert(currentCount);
  4836.       if (purchaseAlert && purchaseAlert.classList) {
  4837.         purchaseAlert.classList.remove(\"cachee\"); // Réaffiche la popover
  4838.       }
  4839.     });
  4840.     // Nouvelles fonctions pour le bouton cadeau
  4841.     function showGiftMessage() {
  4842.       const tooltip = document.getElementById(\"giftTooltip\");
  4843.       if (tooltip) {
  4844.         if (tooltip && tooltip.classList) {
  4845.           tooltip.classList.add(\"show\");
  4846.         }
  4847.       }
  4848.     }
  4849.     function hideGiftMessage() {
  4850.       const tooltip = document.getElementById(\"giftTooltip\");
  4851.       if (tooltip) {
  4852.         if (tooltip && tooltip.classList) {
  4853.           tooltip.classList.remove(\"show\");
  4854.         }
  4855.       }
  4856.     }
  4857.     function showSelection() {
  4858.       document.getElementById(\"purchase-alert\").style.display = \"block\";
  4859.     }
  4860.     function hideSelection() {
  4861.       document.getElementById(\"selectionPopover\").style.display = \"none\";
  4862.     }
  4863.     document.addEventListener(\"DOMContentLoaded\", function () {
  4864.       const container = document.querySelector(\".date-container\");
  4865.       // Vérifie si le conteneur existe pour éviter les erreurs
  4866.       if (container) {
  4867.         container.scrollTo({
  4868.           left: container.scrollWidth, // Scroll directement à la position maximale
  4869.           behavior: \"smooth\", // Défilement fluide
  4870.         });
  4871.       }
  4872.     });
  4873.     document.addEventListener(\"DOMContentLoaded\", function () {
  4874.       const container = document.querySelector(\".date-container\");
  4875.       const leftArrow = document.querySelector(\".scroll-btn.left\");
  4876.       const rightArrow = document.querySelector(\".scroll-btn.right\");
  4877.       // Fonction pour vérifier le débordement et activer/désactiver les flèches
  4878.       function updateArrowsVisibility() {
  4879.         const isOverflowing = container.scrollWidth > container.clientWidth; // Vérifie si débordement
  4880.         leftArrow.style.display = isOverflowing ? \"flex\" : \"none\";
  4881.         rightArrow.style.display = isOverflowing ? \"flex\" : \"none\";
  4882.       }
  4883.       // Fonction pour défiler
  4884.       function scrollContainer(direction) {
  4885.         container.scrollBy({
  4886.           left: direction === \"left\" ? -200 : 200, // Défiler à gauche ou à droite
  4887.           behavior: \"smooth\",
  4888.         });
  4889.       }
  4890.       // Ajout des événements de clic pour les flèches
  4891.       leftArrow.addEventListener(\"click\", () => scrollContainer(\"left\"));
  4892.       rightArrow.addEventListener(\"click\", () => scrollContainer(\"right\"));
  4893.       // ⚡ OPTIMISÉ: Debounce resize pour éviter surcharge
  4894.       let resizeTimeout;
  4895.       const debouncedResize = () => {
  4896.         clearTimeout(resizeTimeout);
  4897.         resizeTimeout = setTimeout(updateArrowsVisibility, 150);
  4898.       };
  4899.       
  4900.       updateArrowsVisibility();
  4901.       window.addEventListener(\"resize\", debouncedResize, { passive: true });
  4902.     });
  4903.     document.addEventListener(\"DOMContentLoaded\", function () {
  4904.       const container = document.querySelector(\".date-container\");
  4905.       const leftBtn = document.querySelector(\".scroll-btn.left\");
  4906.       const rightBtn = document.querySelector(\".scroll-btn.right\");
  4907.       leftBtn.addEventListener(\"click\", () => {
  4908.         container.scrollBy({
  4909.           left: -200, // Défile vers la gauche
  4910.           behavior: \"smooth\",
  4911.         });
  4912.       });
  4913.       rightBtn.addEventListener(\"click\", () => {
  4914.         container.scrollBy({
  4915.           left: 200, // Défile vers la droite
  4916.           behavior: \"smooth\",
  4917.         });
  4918.       });
  4919.     });
  4920.  document.addEventListener(\"DOMContentLoaded\", function () {
  4921.     // Sélectionnez tous les badges de filtre
  4922.     const filterBadges = document.querySelectorAll(\".filter-badge\");
  4923.     // Sélectionnez tous les éléments de la galerie
  4924.     const galleryItems = document.querySelectorAll(\".column\");
  4925.     // Sélectionnez tous les jours
  4926.     const days = document.querySelectorAll(\".collapse\");
  4927.     // Fonction pour réinitialiser les filtres
  4928.     function resetFilters() {
  4929.         // Réinitialisez tous les éléments de la galerie
  4930.         galleryItems.forEach((item) => {
  4931.             item.style.display = \"block\";
  4932.         });
  4933.         // Réinitialisez les états des badges
  4934.         filterBadges.forEach((badge) => {
  4935.           if (badge && badge.classList) {
  4936.             badge.classList.remove(\"active\");
  4937.           }
  4938.         });
  4939.     }
  4940.     // Ajoutez un gestionnaire d'événements pour chaque badge
  4941.     filterBadges.forEach((badge) => {
  4942.         badge.addEventListener(\"click\", function () {
  4943.             const filter = this.getAttribute(\"data-filter\");
  4944.             // Réinitialisez l'état actif pour tous les badges
  4945.             filterBadges.forEach((btn) => {
  4946.               if (btn && btn.classList) {
  4947.                 btn.classList.remove(\"active\");
  4948.               }
  4949.             });
  4950.             // Ajoutez l'état actif au badge cliqué
  4951.             if (this && this.classList) {
  4952.               this.classList.add(\"active\");
  4953.             }
  4954.             // Affichez ou masquez les éléments de la galerie
  4955.             galleryItems.forEach((item) => {
  4956.                 if (filter === \"all\") {
  4957.                     item.style.display = \"block\";
  4958.                 } else if (filter === \"photo\" && item.querySelector(\"img\")) {
  4959.                     item.style.display = \"block\";
  4960.                 } else if (filter === \"video\" && item.querySelector(\"video\")) {
  4961.                     item.style.display = \"block\";
  4962.                 } else if (filter === \"audio\" && item.classList && item.classList.contains(\"audio-message-item\")) {
  4963.                     item.style.display = \"block\";
  4964.                 } else {
  4965.                     item.style.display = \"none\";
  4966.                 }
  4967.             });
  4968.         });
  4969.     });
  4970.     // Réinitialiser les filtres lors du changement de jour
  4971.     days.forEach((day) => {
  4972.         day.addEventListener(\"show.bs.collapse\", function () {
  4973.             resetFilters();
  4974.         });
  4975.     });
  4976. });
  4977.     \$(document).ready(function () {
  4978.       let zoomCounter = 0; // Initialize zoom counter
  4979.       let currentImageSrc = \"\"; // Track current image source
  4980.       let lastClickPosition = { x: 50, y: 50 }; // Default to center of image
  4981.       \$(\".container--gallery\").magnificPopup({
  4982.         delegate: \"a\",
  4983.         type: \"image\",
  4984.         mainClass: \"mfp-with-zoom mfp-img-mobile\",
  4985.         image: {
  4986.           verticalFit: true,
  4987.         },
  4988.         gallery: {
  4989.           enabled: true,
  4990.           tPrev: \"Previous (Left arrow key)\", // Alt text on left arrow
  4991.           tNext: \"Next (Right arrow key)\", // Alt text on right arrow
  4992.           tCounter: \"%curr% of %total%\", // Markup for \"1 of 7\" counter
  4993.         },
  4994.         zoom: {
  4995.           enabled: true,
  4996.           duration: 300,
  4997.           opener: function (element) {
  4998.             return element.find(\"img\");
  4999.           },
  5000.         },
  5001.         callbacks: {
  5002.           open: function () {
  5003.             // Get current image data from the link that was clicked
  5004.             const currentLink = this.currItem.el;
  5005.             const imageId =
  5006.               currentLink
  5007.                 .closest(\".photo-zoom\")
  5008.                 .find(\".heart-icon\")
  5009.                 .data(\"id\") || \"\";
  5010.             const sejourId =
  5011.               currentLink
  5012.                 .closest(\".photo-zoom\")
  5013.                 .find(\".heart-icon\")
  5014.                 .data(\"sejour-id\") || \"\";
  5015.             const imagePath =
  5016.               currentLink
  5017.                 .closest(\".photo-zoom\")
  5018.                 .find(\".heart-icon\")
  5019.                 .data(\"path\") || \"\";
  5020.             const imageDesc =
  5021.               currentLink
  5022.                 .closest(\".photo-zoom\")
  5023.                 .find(\".heart-icon\")
  5024.                 .data(\"description\") || \"\";
  5025.             const isFavorite = currentLink
  5026.               .closest(\".photo-zoom\")
  5027.               .find(\".heart-icon i\")
  5028.               .hasClass(\"bi-heart-fill\");
  5029.             const favoriteIconClass = isFavorite ? \"bi-heart-fill\" : \"bi-heart\";
  5030.             const favoriteIconColor = isFavorite ? \"#f56040\" : \"white\";
  5031.             const favoriteTooltip = isFavorite
  5032.               ? \"Retirer des favoris\"
  5033.               : \"Ajouter aux favoris\";
  5034.             const zoomControls = `
  5035.           <div class=\"mfp-zoom-controls\">
  5036.             <button class=\"zoom-btn zoom-out\" title=\"Zoom Out\"><i class=\"fa fa-search-minus\"></i></button>
  5037.             <button class=\"zoom-btn zoom-in\" title=\"Zoom In\"><i class=\"fa fa-search-plus\"></i></button>
  5038.           </div>
  5039.           <div class=\"mfp-favorite\">
  5040.             <button class=\"favorite-btn\" 
  5041.                     data-id=\"\${imageId}\" 
  5042.                     data-sejour-id=\"\${sejourId}\" 
  5043.                     data-path=\"\${imagePath}\" 
  5044.                     data-description=\"\${imageDesc}\"
  5045.                     title=\"\${favoriteTooltip}\">
  5046.               <i class=\"bi \${favoriteIconClass}\" style=\"color: \${favoriteIconColor}; text-shadow: 0px 0px 3px rgba(0,0,0,0.5);\"></i>
  5047.             </button>
  5048.           </div>
  5049.           <div class=\"mfp-counter\"></div>
  5050.         `;
  5051.             \$(\".mfp-content\").append(zoomControls);
  5052.             initializeZoomControls();
  5053.             initializeFavoriteButton();
  5054.             const intervalId = setInterval(() => {
  5055.               const newImageSrc = \$(\".mfp-img\").attr(\"src\");
  5056.               if (newImageSrc !== currentImageSrc) {
  5057.                 currentImageSrc = newImageSrc;
  5058.                 zoomCounter = 0;
  5059.                 lastClickPosition = { x: 50, y: 50 }; // Reset to center
  5060.                 attachZoomHandler(); // Reattach zoom handler to new image
  5061.                 \$(\".mfp-img\").css({
  5062.                   \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  5063.                   transform: `scale(1)`,
  5064.                 });
  5065.                 // Update favorite button for the new image
  5066.                 updateFavoriteButton();
  5067.                 initializeZoomControls();
  5068.                 updateCounter();
  5069.               }
  5070.             }, 100);
  5071.             this.content.on(\"mfpClose\", function () {
  5072.               clearInterval(intervalId);
  5073.             });
  5074.             attachZoomHandler();
  5075.           },
  5076.           close: function () {
  5077.             \$(\".mfp-zoom-controls\").remove();
  5078.             \$(\".mfp-favorite\").remove();
  5079.             \$(\".mfp-counter\").remove();
  5080.             zoomCounter = 0;
  5081.           },
  5082.         },
  5083.       });
  5084.       function attachZoomHandler() {
  5085.         \$(\".mfp-img\")
  5086.           .off(\"click\")
  5087.           .on(\"click\", function (event) {
  5088.             event.stopPropagation(); // Prevent default navigation behavior
  5089.             // Calculate click coordinates relative to the image
  5090.             const imgOffset = \$(this).offset();
  5091.             const clickX = event.pageX - imgOffset.left;
  5092.             const clickY = event.pageY - imgOffset.top;
  5093.             const imgWidth = \$(this).width();
  5094.             const imgHeight = \$(this).height();
  5095.             // Calculate transform-origin based on click position
  5096.             lastClickPosition = {
  5097.               x: (clickX / imgWidth) * 100,
  5098.               y: (clickY / imgHeight) * 100,
  5099.             };
  5100.             // Cycle through zoom levels: 1x, 1.5x, 2x
  5101.             zoomCounter = (zoomCounter + 1) % 3;
  5102.             const zoomLevels = [1, 1.5, 2];
  5103.             const zoomLevel = zoomLevels[zoomCounter];
  5104.             \$(this).css({
  5105.               \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  5106.               transform: `scale(\${zoomLevel})`,
  5107.             });
  5108.             updateZoomButtonState();
  5109.           });
  5110.       }
  5111.       function initializeZoomControls() {
  5112.         \$(\".mfp-zoom-controls .zoom-in\")
  5113.           .off(\"click\")
  5114.           .on(\"click\", function (event) {
  5115.             event.stopPropagation();
  5116.             zoomCounter = (zoomCounter + 1) % 3;
  5117.             const zoomLevels = [1, 1.5, 2];
  5118.             const zoomLevel = zoomLevels[zoomCounter];
  5119.             \$(\".mfp-img\").css({
  5120.               \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  5121.               transform: `scale(\${zoomLevel})`,
  5122.             });
  5123.             updateZoomButtonState();
  5124.           });
  5125.         \$(\".mfp-zoom-controls .zoom-out\")
  5126.           .off(\"click\")
  5127.           .on(\"click\", function (event) {
  5128.             event.stopPropagation();
  5129.             if (zoomCounter > 0) {
  5130.               zoomCounter -= 1;
  5131.               const zoomLevels = [1, 1.5, 2];
  5132.               const zoomLevel = zoomLevels[zoomCounter];
  5133.               \$(\".mfp-img\").css({
  5134.                 \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  5135.                 transform: `scale(\${zoomLevel})`,
  5136.               });
  5137.               updateZoomButtonState();
  5138.             } else {
  5139.               \$.magnificPopup.close();
  5140.             }
  5141.           });
  5142.       }
  5143.       function initializeFavoriteButton() {
  5144.         \$(\".mfp-favorite .favorite-btn\")
  5145.           .off(\"click\")
  5146.           .on(\"click\", function (event) {
  5147.             event.stopPropagation();
  5148.             const \$this = \$(this);
  5149.             const imageId = \$this.data(\"id\");
  5150.             const sejourId = \$this.data(\"sejour-id\");
  5151.             // Toggle favorite status
  5152.             const isFavorite = \$this.find(\"i\").hasClass(\"bi-heart-fill\");
  5153.             // Update the button appearance
  5154.             if (isFavorite) {
  5155.               \$this
  5156.                 .find(\"i\")
  5157.                 .removeClass(\"bi-heart-fill\")
  5158.                 .addClass(\"bi-heart\")
  5159.                 .css(\"color\", \"white\");
  5160.               \$this.attr(\"title\", \"Ajouter aux favoris\");
  5161.             } else {
  5162.               \$this
  5163.                 .find(\"i\")
  5164.                 .removeClass(\"bi-heart\")
  5165.                 .addClass(\"bi-heart-fill\")
  5166.                 .css(\"color\", \"#f56040\");
  5167.               \$this.attr(\"title\", \"Retirer des favoris\");
  5168.             }
  5169.             // Update the original heart icon in the gallery
  5170.             const originalHeartIcon = \$(
  5171.               `.heart-icon[data-id=\"\${imageId}\"]`
  5172.             ).find(\"i\");
  5173.             if (isFavorite) {
  5174.               originalHeartIcon
  5175.                 .removeClass(\"bi-heart-fill\")
  5176.                 .addClass(\"bi-heart\")
  5177.                 .css(\"color\", \"\");
  5178.             } else {
  5179.               originalHeartIcon
  5180.                 .removeClass(\"bi-heart\")
  5181.                 .addClass(\"bi-heart-fill\")
  5182.                 .css(\"color\", \"#f56040\");
  5183.             }
  5184.             // Make AJAX call to update favorite status in the backend using Parent routes
  5185.             \$.ajax({
  5186.               url: isFavorite ? \"/Parent/aSupprimerFav\" : \"/Parent/ajouterFav\",
  5187.               type: \"POST\",
  5188.               data: {
  5189.                 id: imageId,
  5190.                 idSejour: sejourId,
  5191.               },
  5192.               success: function (response) {
  5193.                 // Optional: Show a success message or handle response
  5194.                 console.log(\"Favorite status updated\", response);
  5195.               },
  5196.               error: function (error) {
  5197.                 console.error(\"Error updating favorite status\", error);
  5198.                 // Revert the icon change on error
  5199.                 if (isFavorite) {
  5200.                   \$this
  5201.                     .find(\"i\")
  5202.                     .removeClass(\"bi-heart\")
  5203.                     .addClass(\"bi-heart-fill\")
  5204.                     .css(\"color\", \"#f56040\");
  5205.                   originalHeartIcon
  5206.                     .removeClass(\"bi-heart\")
  5207.                     .addClass(\"bi-heart-fill\")
  5208.                     .css(\"color\", \"#f56040\");
  5209.                 } else {
  5210.                   \$this
  5211.                     .find(\"i\")
  5212.                     .removeClass(\"bi-heart-fill\")
  5213.                     .addClass(\"bi-heart\")
  5214.                     .css(\"color\", \"white\");
  5215.                   originalHeartIcon
  5216.                     .removeClass(\"bi-heart-fill\")
  5217.                     .addClass(\"bi-heart\")
  5218.                     .css(\"color\", \"\");
  5219.                 }
  5220.               },
  5221.             });
  5222.           });
  5223.       }
  5224.       function updateFavoriteButton() {
  5225.         // Get current image data from the current slide
  5226.         const currentSlide = \$.magnificPopup.instance.currItem.el;
  5227.         const photoZoom = currentSlide.closest(\".photo-zoom\");
  5228.         if (photoZoom.length) {
  5229.           const heartIcon = photoZoom.find(\".heart-icon\");
  5230.           const imageId = heartIcon.data(\"id\") || \"\";
  5231.           const sejourId = heartIcon.data(\"sejour-id\") || \"\";
  5232.           const imagePath = heartIcon.data(\"path\") || \"\";
  5233.           const imageDesc = heartIcon.data(\"description\") || \"\";
  5234.           const isFavorite = heartIcon.find(\"i\").hasClass(\"bi-heart-fill\");
  5235.           const favoriteIconClass = isFavorite ? \"bi-heart-fill\" : \"bi-heart\";
  5236.           const favoriteIconColor = isFavorite ? \"#f56040\" : \"white\";
  5237.           const favoriteTooltip = isFavorite
  5238.             ? \"Retirer des favoris\"
  5239.             : \"Ajouter aux favoris\";
  5240.           // Update the favorite button
  5241.           const \$favoriteBtn = \$(\".mfp-favorite .favorite-btn\");
  5242.           \$favoriteBtn.data(\"id\", imageId);
  5243.           \$favoriteBtn.data(\"sejour-id\", sejourId);
  5244.           \$favoriteBtn.data(\"path\", imagePath);
  5245.           \$favoriteBtn.data(\"description\", imageDesc);
  5246.           \$favoriteBtn.attr(\"title\", favoriteTooltip);
  5247.           \$favoriteBtn
  5248.             .find(\"i\")
  5249.             .removeClass(\"bi-heart bi-heart-fill\")
  5250.             .addClass(favoriteIconClass)
  5251.             .css(\"color\", favoriteIconColor);
  5252.         }
  5253.       }
  5254.       function updateZoomButtonState() {
  5255.         const zoomLevels = [1, 1.5, 2];
  5256.         const currentZoom = zoomLevels[zoomCounter];
  5257.         \$(\".zoom-in\").prop(\"disabled\", currentZoom === 2);
  5258.         \$(\".zoom-out\").prop(\"disabled\", currentZoom === 1);
  5259.       }
  5260.       function updateCounter() {
  5261.         const counterText = \$(\".mfp-counter\")
  5262.           .closest(\".mfp-content\")
  5263.           .find(\".mfp-counter\")
  5264.           .text();
  5265.         const matches = counterText.match(/(\\d+) of (\\d+)/);
  5266.         if (matches) {
  5267.           const currentIndex = matches[1];
  5268.           const totalImages = matches[2];
  5269.           \$(\".mfp-counter\").text(`\${currentIndex} of \${totalImages}`);
  5270.         }
  5271.       }
  5272.       // Add CSS for the favorite button and rounded image corners
  5273.       \$(\"<style>\")
  5274.         .prop(\"type\", \"text/css\")
  5275.         .html(
  5276.           `
  5277.       .mfp-favorite {
  5278.         position: absolute;
  5279.         top: 15px;
  5280.         left: 15px;
  5281.         z-index: 1046;
  5282.       }
  5283.       .favorite-btn {
  5284.         background: transparent;
  5285.         border: none;
  5286.         font-size: 24px;
  5287.         padding: 5px;
  5288.         cursor: pointer;
  5289.         outline: none;
  5290.       }
  5291.       .favorite-btn i {
  5292.         transition: all 0.3s ease;
  5293.       }
  5294.       .favorite-btn:hover i {
  5295.         transform: scale(1.2);
  5296.       }
  5297.       /* Rounded corners for zoomed images */
  5298.       .mfp-img {
  5299.         border-radius: 8px;
  5300.       }
  5301.       /* Make sure the container doesn't clip the rounded corners */
  5302.       .mfp-figure:after {
  5303.         border-radius: 8px;
  5304.       }
  5305.     `
  5306.         )
  5307.         .appendTo(\"head\");
  5308.     });
  5309.   </script>
  5310. <script>
  5311. document.addEventListener('DOMContentLoaded', function () {
  5312.   const openBtn = document.getElementById('openFavoritesBtn');
  5313.   const closeBtn = document.getElementById('closeSidebarBtn');
  5314.   const sidebar = document.getElementById('favoritesSidebar');
  5315.   const tbody = document.querySelector('#favoritesTable tbody');
  5316.   openBtn.addEventListener('click', async () => {
  5317.     try {
  5318.       const response = await fetch('/Parent/mes-favoris', {
  5319.         headers: {
  5320.           'Accept': 'application/json'
  5321.         }
  5322.       });
  5323.       const result = await response.json();
  5324.       if (!result.success || !Array.isArray(result.data)) {
  5325.         alert('Erreur lors du chargement des favoris.');
  5326.         return;
  5327.       }
  5328.       tbody.innerHTML = '';
  5329.       result.data.forEach((fav, index) => {
  5330.         const row = document.createElement('tr');
  5331.         row.innerHTML = `
  5332.           <td>\${index + 1}</td>
  5333.           <td><img src=\"\${fav.path}\" alt=\"favori\"></td>
  5334.           <td>\${fav.descreption || '—'}</td>
  5335.           <td>\${fav.created_at}</td>
  5336.         `;
  5337.         tbody.appendChild(row);
  5338.       });
  5339.       sidebar.classList.add('active');
  5340.     } catch (e) {
  5341.       console.error('Erreur réseau:', e);
  5342.       alert('Impossible de charger les favoris.');
  5343.     }
  5344.   });
  5345.   closeBtn.addEventListener('click', () => {
  5346.     sidebar.classList.remove('active');
  5347.   });
  5348. });
  5349. </script>
  5350.   <script>
  5351.         // Fonction pour vérifier et afficher l'alerte
  5352.         function checkFavoritesAlert() {
  5353.             const currentCount = window.favoriteCount || 0;
  5354.             if (currentCount >= 10) {
  5355.                 const purchaseAlert = document.getElementById('purchase-alert');
  5356.                 if (purchaseAlert) {
  5357.                     purchaseAlert.style.display = 'block'; // Affiche l'alerte
  5358.                 }
  5359.             } else {
  5360.                 purchaseAlert.style.display = 'none'; // Cache l'alerte si le nombre est réduit
  5361.             }
  5362.         }
  5363.     
  5364.         
  5365.         document.addEventListener('DOMContentLoaded', () => {
  5366.     const favoriteCount = ";
  5367.         // line 5064
  5368.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["nblikes"]) || array_key_exists("nblikes"$context) ? $context["nblikes"] : (function () { throw new RuntimeError('Variable "nblikes" does not exist.'5064$this->source); })()), "html"nulltrue);
  5369.         yield ";
  5370.     updateCardContent(favoriteCount);
  5371. });
  5372. function updateCardContent(favoriteCount) {
  5373.     const card = document.getElementById('dynamic-card');
  5374.     const cardContent = document.getElementById('dynamic-card-content');
  5375.     let produits = [];
  5376.     if (favoriteCount >= 20) {
  5377.         produits.push({
  5378.             titre: \"Album débloqué !\",
  5379.             bouton: \"Commander\",
  5380.             image: \"/images/produit/Album5sur5-3.jpg\",
  5381.             lien: \"";
  5382.         // line 5079
  5383.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("EditionAlbum");
  5384.         yield "\"
  5385.         });
  5386.     }
  5387.     if (favoriteCount >= 12) {
  5388.         produits.push({
  5389.             titre: \"Pochette débloquée !\",
  5390.             bouton: \"Commander\",
  5391.             image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  5392.             lien: \"";
  5393.         // line 5087
  5394.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("AjoutPochettePhotos_Favoris", ["nbr" => 12]);
  5395.         yield "\"
  5396.         });
  5397.     }
  5398.     if (favoriteCount >= 5) {
  5399.         produits.push({
  5400.             titre: \"Pack numérique débloqué !\",
  5401.             bouton: \"Commander\",
  5402.             image: \"/images/produit/photoNumerique.jpg\",
  5403.             lien: \"";
  5404.         // line 5095
  5405.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("PackPhotosNumerique_Favoris", ["nbr" => 15]);
  5406.         yield "\"
  5407.         });
  5408.     }
  5409. if (produits.length === 0) {
  5410.   cardContent.innerHTML = `
  5411.     <div style=\"position: relative; width: 100%; height: 140px; border-radius: 15px; overflow: hidden; box-shadow: 0 4px 10px rgba(0,0,0,0.1);\">
  5412.       <div style=\"background-image: url('/images/produit/CoffretCadeau5sur5-2.jpg'); background-size: cover; background-position: center; width: 100%; height: 100%;\">
  5413.         <div style=\"position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.45); display: flex; align-items: center; justify-content: center; padding: 10px;\">
  5414.           <div style=\"
  5415.     margin-top: 35px;
  5416.     color: white;
  5417.     font-size: 15px;
  5418.     font-weight: bold;
  5419.     text-align: center;
  5420.     line-height: 1;
  5421.     text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);\">
  5422.             Ajoutez des favoris ❤️<br><span style=\"font-size: 16px; font-weight: normal;\">pour débloquer un souvenir à offrir 🎁</span>
  5423.           </div>
  5424.         </div>
  5425.       </div>
  5426.     </div>
  5427.   `;
  5428.         return;
  5429.     }
  5430.     cardContent.innerHTML = `
  5431.     <div class=\"splide\" id=\"dynamicSplide\">
  5432.       <div class=\"splide__track\">
  5433.         <ul class=\"splide__list\">
  5434.           \${produits.map(produit => `
  5435.             <li class=\"splide__slide\" style=\"position: relative;\">
  5436.               <img src=\"\${produit.image}\" alt=\"\${produit.titre}\" style=\"width: 100%; height: 150px; object-fit: cover; border-radius: 8px;\">
  5437.               <div style=\"position: absolute; bottom: 0; left: 0; right: 0; background: rgba(0,0,0,0.1); color: white; padding: 10px; text-align: center; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px;\">
  5438.                 <div style=\"font-weight: bold; font-size: 14px;\">\${produit.titre}</div>
  5439.                 <button style=\"margin-top: 5px; padding: 5px 8px; background-color: #F56040; color: white; border: none; border-radius: 4px; font-size: 12px; cursor: pointer;\" onclick=\"window.location.href='\${produit.lien}'\">
  5440.                   \${produit.bouton}
  5441.                 </button>
  5442.               </div>
  5443.             </li>
  5444.           `).join('')}
  5445.         </ul>
  5446.       </div>
  5447.     </div>
  5448.     `;
  5449.     // Monte le carrousel
  5450.     new Splide('#dynamicSplide', {
  5451.         type: 'loop',
  5452.         arrows: true,
  5453.         pagination: false,
  5454.         autoplay: true,
  5455.         interval: 4000,
  5456.         speed: 800,
  5457.     }).mount();
  5458. }
  5459.         function supprimerFavoris(\$id, \$idSejour) {
  5460.             // Vider l'élément coeur pour ce favori
  5461.             const coeurElement = \$('#coeur' + \$id);
  5462.             coeurElement.empty();
  5463.             // Ajout d'une animation sur le bouton cadeau
  5464.             const giftButton = document.querySelector('.gift-button');
  5465.             if (giftButton) {
  5466.                 giftButton.classList.add('active');
  5467.                 // Retirer l'animation après qu'elle soit jouée
  5468.                 setTimeout(() => {
  5469.                     giftButton.classList.remove('active');
  5470.                 }, 600); // La durée doit correspondre à celle de l'animation
  5471.             }
  5472.             // Mise à jour de l'icône coeur
  5473.             const clas = \$('.IconImag6').hasClass('active') ? \"IconDelete IconDeletesix\" : \"IconDelete\";
  5474.             coeurElement.html(
  5475.                 `<i class=\"bi bi-heart \${clas}\" ></i>`
  5476.             );
  5477.             // Mettre à jour le compteur des favoris
  5478.             const likeCountLabel = document.getElementById('likeCount');
  5479.             const likeMesFavLabel = document.getElementById('mesFavCount');
  5480.             
  5481.             let newCount = 0;
  5482.             
  5483.             if (likeCountLabel) {
  5484.                 // Utiliser la fonction utilitaire robuste
  5485.                 let currentCount = window.getFavoriteCount();
  5486.                 newCount = Math.max(0, currentCount - 1); // Empêche le compteur d'aller en dessous de 0
  5487.                 window.setFavoriteCount(newCount);
  5488.             
  5489.                 // Mettre à jour la valeur dans l'input hidden
  5490.                 const nbFavCurrentInput = \$('#nbFavCurrent');
  5491.                 if (nbFavCurrentInput.length) {
  5492.                     nbFavCurrentInput.val(newCount);
  5493.                 }
  5494.             }
  5495.             
  5496.             // Synchroniser mesFavCount avec likeCount
  5497.             if (likeMesFavLabel) {
  5498.                 if (likeCountLabel) {
  5499.                     // Utiliser la valeur de likeCount pour synchroniser
  5500.                     likeMesFavLabel.textContent = newCount;
  5501.                 } else {
  5502.                     // Si likeCount n'existe pas, décrémenter directement mesFavCount
  5503.                     let currentFavCount = parseInt(likeMesFavLabel.textContent.trim(), 10) || 0;
  5504.                     newCount = Math.max(0, currentFavCount - 1);
  5505.                                          likeMesFavLabel.textContent = newCount;
  5506.                  }
  5507.              }
  5508.              
  5509.              // Mettre à jour l'alerte immédiatement
  5510.              setTimeout(() => {
  5511.                  const finalCount = getCurrentFavoriteCount();
  5512.                  if (typeof updatePurchaseAlert === 'function') {
  5513.                      updatePurchaseAlert(finalCount);
  5514.                  }
  5515.              }, 50);
  5516.             // Préparation des données pour l'Ajax
  5517.             const \$_data = { 'id': \$id, 'idSejour': \$idSejour };
  5518.             // Appel Ajax pour supprimer le favori
  5519.             \$.ajax({
  5520.                 type: \"POST\",
  5521.                 url: \"";
  5522.         // line 5220
  5523.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("Supprimer_fav");
  5524.         yield "\",
  5525.                 data: \$_data,
  5526.                 success: function () {
  5527.                     // Réactiver les icônes après succès
  5528.                     \$('.IconDelete').each(function () {
  5529.                         \$(this).css('pointer-events', '');
  5530.                     });
  5531.                     
  5532.                     // Mettre à jour l'alerte avec le nouveau nombre
  5533.                     const finalCount = getCurrentFavoriteCount();
  5534.                     if (typeof updatePurchaseAlert === 'function') {
  5535.                         updatePurchaseAlert(finalCount);
  5536.                     }
  5537.                 },
  5538.                 error: function (xhr, status, error) {
  5539.                     console.error('Erreur lors de la suppression du favori :', error);
  5540.                 }
  5541.             });
  5542.         }
  5543.         function AddFavoris(\$id, \$idSejour, \$urlimg, \$description) {
  5544.             // Update heart icon
  5545.             \$('#coeur' + \$id).empty();
  5546.             var clas = \$('.IconImag6').hasClass('active') ? \"IconDelete IconDeletesix\" : \"IconDelete\";
  5547.             \$('#coeur' + \$id).html(\"<i class=\\\"bi bi-heart-fill favSelect \" + clas + \"\\\" )\\\"></i>\");
  5548.             
  5549.             // Update counters UNIQUEMENT
  5550.             const likeCountLabel = document.getElementById('likeCount');
  5551.             const likeMesFavLabel = document.getElementById('mesFavCount');
  5552.             const  giftCountLabel = document.getElementById('giftCount');
  5553.             
  5554.             if (likeCountLabel) {
  5555.                 // Utiliser la fonction utilitaire robuste
  5556.                 let currentCount = window.getFavoriteCount();
  5557.                 currentCount++;
  5558.                 window.setFavoriteCount(currentCount);
  5559.                
  5560.                 
  5561.                 // Mettre à jour le compteur des favoris dans le titre
  5562.                 if (likeMesFavLabel) {
  5563.                     likeMesFavLabel.textContent = currentCount;
  5564.              
  5565.                 }
  5566.                   if (giftCountLabel) {
  5567.                     giftCountLabel.textContent = currentCount;
  5568.              
  5569.                 }
  5570.                 
  5571.                 // Mettre à jour l'input hidden
  5572.                 const nbFavCurrentInput = document.getElementById('nbFavCurrent');
  5573.                 if (nbFavCurrentInput) {
  5574.                     nbFavCurrentInput.value = currentCount;
  5575.                 }
  5576.             }
  5577.             
  5578.             // Update other counters
  5579.             var \$total = parseInt(\$(\"#totalLike\").html()) + 1;
  5580.             \$(\"#totalLike\").html(\$total);
  5581.             \$(\"#totalLikeTitle\").html(\$total);
  5582.             \$(\"#totalLikeMobile\").html(\$total);
  5583.             
  5584.             // Add gift button animation
  5585.             const giftButton = document.querySelector('.gift-button');
  5586.             if (giftButton) {
  5587.                 giftButton.classList.add('active');
  5588.                 setTimeout(() => {
  5589.                     giftButton.classList.remove('active');
  5590.                 }, 600);
  5591.             }
  5592.             var \$data = { 'id': \$id, 'idSejour': \$idSejour };
  5593.             \$.ajax({
  5594.                 type: \"POST\",
  5595.                 url: \"";
  5596.         // line 5294
  5597.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("Ajouter_fav");
  5598.         yield "\",
  5599.                 data: \$data,
  5600.                 success: function () {
  5601.                     \$('.IconDelete').each(function () {
  5602.                         \$(this).css('pointer-events', '');
  5603.                     });
  5604.                     if (\$description === undefined) {
  5605.                         \$description = ''; // Set it to an empty string
  5606.                     }
  5607.                     \$('.rowMaselection').append(
  5608.                         '<div class=\"column\" id=\"column-' + \$id + '\">'+
  5609.                         '<a style=\"position: relative;\" title=\"Enlever de ma sélection\" onclick=\"supprimerFavoris(' + \$id + ',' + \$idSejour + ')\" class=\"iconeSuppImg\"><i class=\"bi bi-x\" style=\"font-size:17px;cursor:pointer;color:#d30909;float:right;margin-top:-3%;margin-right:2%\"></i></a>'+
  5610.                         '<a class=\"photo-zoom\">'+
  5611.                         '<img data-idAtach=\"'+\$id+'\" id=\"'+\$idSejour+'\" src=\"'+\$urlimg+'\"></a>'+
  5612.                         (\$description ? '<h4 id=\"commint\" class=\"titleHeadPhoto\">'+\$description+'</h4>' : '')+ // Only add the <h4> if \$description is not empty
  5613.                         '</div>'
  5614.                     );
  5615.                     // Directly update nbLikes count in the header
  5616.                     var currentNbLikes = parseInt(\$('#favoris-link-Accueilpayment .nbrpanier').text());
  5617.                     var newNbLikes = currentNbLikes + 1;
  5618.                     \$('#favoris-link-Accueilpayment .nbrpanier').text(newNbLikes);
  5619.                     
  5620.                     // Mettre à jour l'alerte avec le nouveau nombre
  5621.                     const finalCount = getCurrentFavoriteCount();
  5622.                     if (typeof updatePurchaseAlert === 'function') {
  5623.                         updatePurchaseAlert(finalCount);
  5624.                     }
  5625.                 },
  5626.                 error: function (xhr, status, error) {
  5627.                     console.error('Error:', error);
  5628.                 }
  5629.             });
  5630.         }
  5631.         \$(document).on('click', '.bi-heart, .bi-heart-fill', function () {
  5632.         const heartIcon       = \$(this);
  5633.         const heartContainer  = heartIcon.closest('.heart-icon');
  5634.         // Extract data attributes
  5635.         const attachmentId    = heartContainer.data('id');
  5636.         const sejourId        = heartContainer.data('sejour-id');
  5637.         const path            = heartContainer.data('path');
  5638.         const description     = heartContainer.data('description');
  5639.         const isFavorite      = heartIcon.hasClass('bi-heart-fill');
  5640.         if (isFavorite) {
  5641.             // Remove from favorites
  5642.             supprimerFavoris(attachmentId, sejourId);
  5643.         } else {
  5644.             // Add to favorites
  5645.             AddFavoris(attachmentId, sejourId, path, description);
  5646.         }
  5647.         // Update UI components after the action (sans double comptage)
  5648.         setTimeout(function() {
  5649.             const likeCountLabel = document.getElementById('likeCount');
  5650.             
  5651.             if (likeCountLabel) {
  5652.                 const currentCount = parseInt(likeCountLabel.textContent, 10) || 0;
  5653.                 
  5654.                 // Update UI components seulement
  5655.                 updateCardContent(currentCount);
  5656.                 updateFavoritesSidebar();
  5657.                 \$(\"#close-favorites-btn\").click();
  5658.             }
  5659.         }, 50);
  5660.     });
  5661.         // Ajoutez les événements sur les icônes de cœur
  5662.         document.querySelectorAll('.IconDelete').forEach((icon) => {
  5663.             icon.addEventListener('click', (event) => {
  5664.                 const isFavorite = icon && icon.classList && icon.classList.contains('bi-heart-fill');
  5665.                 if (isFavorite) {
  5666.                     removeFavorite();
  5667.                     if (icon.classList) {
  5668.                       icon.classList.remove('bi-heart-fill');
  5669.                       icon.classList.add('bi-heart');
  5670.                     }
  5671.                 } else {
  5672.                     addFavorite();
  5673.                     if (icon.classList) {
  5674.                       icon.classList.remove('bi-heart');
  5675.                       icon.classList.add('bi-heart-fill');
  5676.                     }
  5677.                 }
  5678.             });
  5679.         });
  5680.         // Vérifie l'état initial
  5681.         checkFavoritesAlert();
  5682.         
  5683.         
  5684.         // ⚡ OPTIMISÉ: Réduction du délai d'initialisation
  5685.       
  5686.   </script>
  5687.   <!-- Initialisation -->
  5688.   <script>
  5689.     // ⚡ OPTIMISATION: Différer l'initialisation d'AOS pour ne pas bloquer le chargement
  5690.     setTimeout(function() {
  5691.       AOS.init({
  5692.         duration: 800,
  5693.         easing: \"ease-in-out\"
  5694.       });
  5695.     }, 100);
  5696.     // 🎯 DAY FILTER DROPDOWN LOGIC (Senior UX)
  5697.     document.addEventListener('DOMContentLoaded', function() {
  5698.       initializeDayFilters();
  5699.       
  5700.       // Initialiser le compteur audio avec la valeur correcte
  5701.       setTimeout(function() {
  5702.         updateAudioButtonState('days');
  5703.       }, 500);
  5704.     });
  5705.     function initializeDayFilters() {
  5706.       const dropdowns = document.querySelectorAll('.day-filter-dropdown');
  5707.       
  5708.       dropdowns.forEach(dropdown => {
  5709.         const toggle = dropdown.querySelector('.filter-toggle');
  5710.         const menu = dropdown.querySelector('.filter-dropdown-menu');
  5711.         const options = dropdown.querySelectorAll('.filter-option');
  5712.         const dayIndex = dropdown.dataset.dayIndex;
  5713.         const dayContainer = document.getElementById(`demP\${dayIndex}`);
  5714.         
  5715.         if (!toggle || !menu || !dayContainer) return;
  5716.         
  5717.         // Calculer et mettre à jour les compteurs initiaux
  5718.         updateDayFilterCounts(dropdown, dayContainer);
  5719.         
  5720.         // Toggle dropdown
  5721.         toggle.addEventListener('click', (e) => {
  5722.           e.stopPropagation();
  5723.           const isOpen = dropdown.classList.contains('open');
  5724.           
  5725.           // Fermer tous les autres dropdowns
  5726.           document.querySelectorAll('.day-filter-dropdown.open').forEach(d => {
  5727.             if (d !== dropdown) d.classList.remove('open');
  5728.           });
  5729.           
  5730.           // Toggle le dropdown actuel
  5731.           dropdown.classList.toggle('open', !isOpen);
  5732.         });
  5733.         
  5734.         // Gérer les clics sur les options
  5735.         options.forEach(option => {
  5736.           option.addEventListener('click', (e) => {
  5737.             e.stopPropagation();
  5738.             const filter = option.dataset.filter;
  5739.             
  5740.             // Mettre à jour l'état actif
  5741.             options.forEach(opt => opt.classList.remove('active'));
  5742.             option.classList.add('active');
  5743.             
  5744.             // Appliquer le filtre
  5745.             applyDayFilter(dayContainer, filter);
  5746.             
  5747.             // Fermer le dropdown
  5748.             dropdown.classList.remove('open');
  5749.           });
  5750.         });
  5751.       });
  5752.       
  5753.       // Fermer les dropdowns en cliquant ailleurs
  5754.       document.addEventListener('click', () => {
  5755.         document.querySelectorAll('.day-filter-dropdown.open').forEach(dropdown => {
  5756.           dropdown.classList.remove('open');
  5757.         });
  5758.       });
  5759.     }
  5760.     function updateDayFilterCounts(dropdown, dayContainer) {
  5761.       const photoItems = dayContainer.querySelectorAll('[data-type=\"photo\"]');
  5762.       const videoItems = dayContainer.querySelectorAll('[data-type=\"video\"]');
  5763.       // Compter les messages audio individuels plutôt que les conteneurs
  5764.       const audioMessageItems = dayContainer.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  5765.       const audioContainers = dayContainer.querySelectorAll('.audio-messages-container[data-type=\"audio\"]');
  5766.       const audioRestricted = dayContainer.querySelectorAll('.audio-messages-restricted[data-type=\"audio\"]');
  5767.       
  5768.       const allItems = dayContainer.querySelectorAll('[data-type]');
  5769.       
  5770.       const countAll = dropdown.querySelector('[data-count-all]');
  5771.       const countPhoto = dropdown.querySelector('[data-count-photo]');
  5772.       const countVideo = dropdown.querySelector('[data-count-video]');
  5773.       const countAudio = dropdown.querySelector('[data-count-audio]');
  5774.       
  5775.       // Compter les messages audio individuels + conteneurs + sections restreintes
  5776.       const totalAudio = audioMessageItems.length + audioContainers.length + audioRestricted.length;
  5777.       
  5778.       if (countAll) countAll.textContent = allItems.length;
  5779.       if (countPhoto) countPhoto.textContent = photoItems.length;
  5780.       if (countVideo) countVideo.textContent = videoItems.length;
  5781.       if (countAudio) countAudio.textContent = totalAudio;
  5782.       
  5783.       // Masquer les options sans contenu
  5784.       const photoOption = dropdown.querySelector('[data-filter=\"photo\"]');
  5785.       const videoOption = dropdown.querySelector('[data-filter=\"video\"]');
  5786.       const audioOption = dropdown.querySelector('[data-filter=\"audio\"]');
  5787.       
  5788.       if (photoOption) photoOption.style.display = photoItems.length > 0 ? 'flex' : 'none';
  5789.       if (videoOption) videoOption.style.display = videoItems.length > 0 ? 'flex' : 'none';
  5790.       if (audioOption) audioOption.style.display = totalAudio > 0 ? 'flex' : 'none';
  5791.     }
  5792.     function applyDayFilter(dayContainer, filter) {
  5793.       const items = dayContainer.querySelectorAll('[data-type]');
  5794.       
  5795.       items.forEach(item => {
  5796.         if (filter === 'all' || item.dataset.type === filter) {
  5797.           item.style.display = '';
  5798.           item.classList.remove('filtered-out');
  5799.         } else {
  5800.           item.style.display = 'none';
  5801.           item.classList.add('filtered-out');
  5802.         }
  5803.       });
  5804.       
  5805.       // Animation fluide pour les éléments visibles
  5806.       requestAnimationFrame(() => {
  5807.         const visibleItems = dayContainer.querySelectorAll('[data-type]:not(.filtered-out)');
  5808.         visibleItems.forEach((item, index) => {
  5809.           item.style.animation = `fadeInUp 0.3s ease forwards \${index * 0.05}s`;
  5810.         });
  5811.       });
  5812.     }
  5813.     // Animation CSS pour fadeInUp
  5814.     if (!document.querySelector('#dayFilterAnimations')) {
  5815.       const style = document.createElement('style');
  5816.       style.id = 'dayFilterAnimations';
  5817.       style.textContent = `
  5818.         @keyframes fadeInUp {
  5819.           from {
  5820.             opacity: 0;
  5821.             transform: translateY(20px);
  5822.           }
  5823.           to {
  5824.             opacity: 1;
  5825.             transform: translateY(0);
  5826.           }
  5827.         }
  5828.       `;
  5829.       document.head.appendChild(style);
  5830.     }
  5831.     document.addEventListener(\"DOMContentLoaded\", function () {
  5832.       const dateCards = document.querySelectorAll(\".date-card\");
  5833.       const sections = document.querySelectorAll(\".collapse\");
  5834.       dateCards.forEach((card) => {
  5835.         card.addEventListener(\"click\", function () {
  5836.           // Supprimer les classes actives des autres cartes et sections
  5837.           dateCards.forEach((c) => c.classList.remove(\"active\"));
  5838.           sections.forEach((s) => s.classList.remove(\"show\"));
  5839.           // Ajouter la classe active à la carte cliquée
  5840.           this.classList.add(\"active\");
  5841.           // Récupérer la cible et afficher la bonne section
  5842.           const targetId = this.getAttribute(\"data-bs-target\");
  5843.           const targetSection = document.querySelector(targetId);
  5844.           if (targetSection) {
  5845.             targetSection.classList.add(\"show\");
  5846.           }
  5847.         });
  5848.       });
  5849.     });
  5850.     document.addEventListener(\"DOMContentLoaded\", function () {
  5851.       // Clé localStorage pour tracker la première visite
  5852.       const sejourId = '";
  5853.         // line 5569
  5854.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source, ($context["sejour"] ?? null), "id", [], "any"truetruefalse5569)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'5569$this->source); })()), "id", [], "any"falsefalsefalse5569), "")) : ("")), "html"nulltrue);
  5855.         yield "';
  5856.       const parentId = '";
  5857.         // line 5570
  5858.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, ($context["app"] ?? null), "user", [], "any"falsetruefalse5570), "id", [], "any"truetruefalse5570)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'5570$this->source); })()), "user", [], "any"falsefalsefalse5570), "id", [], "any"falsefalsefalse5570), "")) : ("")), "html"nulltrue);
  5859.         yield "';
  5860.       const sliderKey = `imageSlider_seen_\${parentId}_\${sejourId}`;
  5861.       const isFirstVisit = !localStorage.getItem(sliderKey);
  5862.       
  5863.       const sliderContainer = document.querySelector('.divSliderModern');
  5864.       const imageSlider = document.getElementById('imageSlider');
  5865.       
  5866.       if (!isFirstVisit) {
  5867.         // Pas la première visite : cacher le slider
  5868.         if (sliderContainer) sliderContainer.style.display = 'none';
  5869.         return; // Ne pas initialiser Splide ni l'autoscroll
  5870.       }
  5871.       
  5872.       // Première visite : afficher le slider et initialiser
  5873.       if (sliderContainer) sliderContainer.style.display = 'block';
  5874.       
  5875.       // Initialisation du carrousel Splide
  5876.       var splide = new Splide(\"#imageSlider\", {
  5877.         type: \"loop\",
  5878.         perPage: 1,
  5879.         autoplay: true,
  5880.         interval: 6000,
  5881.         pauseOnHover: false,
  5882.         pauseOnFocus: false,
  5883.         pagination: false,
  5884.         arrows: false,
  5885.       });
  5886.       splide.mount();
  5887.       // Fonction pour faire défiler automatiquement vers la section suivante
  5888.       function scrollToNextSection() {
  5889.         const targetSection = document.getElementById(\"scrollTarget\");
  5890.         if (targetSection) {
  5891.           const targetPosition =
  5892.             targetSection.getBoundingClientRect().top + window.scrollY;
  5893.           const adjustedPosition = targetPosition - 50;
  5894.           window.scrollTo({
  5895.             top: adjustedPosition,
  5896.             behavior: \"smooth\",
  5897.           });
  5898.         }
  5899.       }
  5900.       // Démarrer le timer pour le scroll automatique après 5 secondes (première visite uniquement)
  5901.       setTimeout(scrollToNextSection, 5000);
  5902.       
  5903.       // Marquer comme vu après le premier scroll
  5904.       setTimeout(() => {
  5905.         localStorage.setItem(sliderKey, '1');
  5906.       }, 6000);
  5907.     });
  5908.   </script>
  5909.   <script>
  5910.    
  5911.     const giftButton = document.querySelector('.gift-button');
  5912.     if (giftButton) {
  5913.         giftButton.addEventListener('click', () => {
  5914.         // Ajouter la classe 'active' pour déclencher l'éclat
  5915.             giftButton.classList.add('active');
  5916.         // Retirer l'animation après qu'elle soit jouée
  5917.         setTimeout(() => {
  5918.                 giftButton.classList.remove('active');
  5919.         }, 600); // La durée doit correspondre à celle de l'animation
  5920.             
  5921.             // Optionnel : rediriger vers la page de commande
  5922.             // window.location.href = '/commande';
  5923.     });
  5924.     }
  5925.     
  5926.     //const HeartAddButton = document.querySelector('.IconDelete');
  5927.     \$(\".IconDelete\").on('click', () => {
  5928.         // Ajouter la classe 'active' pour déclencher l'éclat
  5929.         favoriteButton.classList.add('active');
  5930.         // Retirer l'animation après qu'elle soit jouée
  5931.         setTimeout(() => {
  5932.             favoriteButton.classList.remove('active');
  5933.         }, 600); // La durée doit correspondre à celle de l'animation
  5934.     });
  5935.     \$(document).ready(function() {
  5936.         // Attach click event to collapse triggers
  5937.         const lastCard = \$('.date-card.modern-card.active');
  5938.         const lastTargetId = lastCard.attr('data-bs-target');
  5939.         if (lastTargetId) {
  5940.             \$(lastTargetId).collapse('show'); // Expand the last collapse section
  5941.             LoadImagesCloud(\$(lastTargetId)); // Load images for the last day
  5942.         }
  5943.         \$('[data-bs-toggle=\"collapse\"]').on('click', function() {
  5944.             var targetId = \$(this).attr('data-bs-target'); // Get the target ID
  5945.             \$('.date-card.modern-card').removeClass('active'); // Remove 'active' class from all cards
  5946.             \$(this).addClass('active'); // Add 'active' class to the clicked card
  5947.             LoadImagesCloud(\$(targetId)); // Ensure this function works as expected
  5948.                // Hide all other collapses except the one clicked
  5949.                \$('[data-bs-target]').each(function() {
  5950.                 var currentTargetId = \$(this).attr('data-bs-target');
  5951.                 // If the current collapse is not the one clicked, hide it
  5952.                 if (currentTargetId !== targetId) {
  5953.                     \$(currentTargetId).collapse('hide');
  5954.                     //\$('[data-bs-toggle=\"collapse\"]').removeClass('active'); // Remove active class from all cards
  5955.                     //Modifier leurs style en non active aussi
  5956.                 }
  5957.             });
  5958.         });
  5959.     });
  5960.   
  5961.             \$(document).ready(function () {
  5962.               
  5963.                 ";
  5964.         // line 5701
  5965.         if ((($tmp CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'5701$this->source); })()), "session", [], "any"falsefalsefalse5701), "get", ["paymentmoniteco"], "method"falsefalsefalse5701)) && $tmp instanceof Markup ? (string) $tmp $tmp)) {
  5966.             // line 5702
  5967.             yield "                ";
  5968.             if ((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'5702$this->source); })()), "session", [], "any"falsefalsefalse5702), "get", ["paymentmoniteco"], "method"falsefalsefalse5702) == "succses")) {
  5969.                 // line 5703
  5970.                 yield "
  5971.                 Swal.fire({
  5972.                     icon: 'success',
  5973.                     title: ' succès ',
  5974.                     text: 'votre commande est validée'
  5975.                 });
  5976.                 ";
  5977.             }
  5978.             // line 5713
  5979.             yield "                ";
  5980.         }
  5981.         // line 5714
  5982.         yield "
  5983.                 if (\$total1 > 0) {
  5984.                     \$('.iconeFleche').first().click();
  5985.                     //  \$([document.documentElement, document.body]).animate({
  5986.                     //  scrollTop: \$('.iconeFleche').last().offset().top
  5987.                     //  }, );
  5988.                 }
  5989.                 else {
  5990.                     \$(window).scrollTop(0);
  5991.                 }
  5992.                 var slider = \$('.responsive').slick({
  5993.                     infinite: true,
  5994.                     slidesToShow: 1,
  5995.                     slidesToScroll: 1,
  5996.                     autoplay: true,
  5997.                     autoplaySpeed: 4000,
  5998.                     pauseOnFocus: false,
  5999.                     pauseOnHover: false,
  6000.                     draggable: false,
  6001.                     fade: true
  6002.                 });
  6003.                 \$('.responsive').css('display', 'block');
  6004.                 \$('.namePRD').css('display', 'block');
  6005.                 var currSlide = 0;
  6006.                 var nextSlide = 0;
  6007.                 slider.on('afterChange', function (event, slick, currentSlide) {
  6008.                     console.log(typeof (\$('.slick-active .slick-current').find('.imgproduit2')) != \"undefined\");
  6009.                     if (typeof (\$('.slick-active .slick-current').find('.imgproduit2')) != \"undefined\") {
  6010.                         setTimeout(function () {
  6011.                             \$('.slick-active .imgproduit1').removeClass('animated fadeIn');
  6012.                             \$('.slick-active .imgproduit1').addClass('animated fadeOut');
  6013.                             \$('.slick-active .imgproduit1').css('display', 'none');
  6014.                             \$('.slick-active .imgproduit2').css('display', 'block');
  6015.                             \$('.slick-active .imgproduit2').removeClass('animated fadeOut');
  6016.                             \$('.slick-active .imgproduit2').addClass('animated fadeIn');
  6017.                         }, 2000);
  6018.                     }
  6019.                 });
  6020.                 slider.on('beforeChange', function (event, slick, currentSlide, nextSlide) {
  6021.                     currSlide = currentSlide;
  6022.                     \$('.imgproduit2').each(function () {
  6023.                         \$(this).removeClass('animated fadeIn');
  6024.                         \$(this).addClass('animated fadeOut');
  6025.                         \$(this).css('display', 'none');
  6026.                     });
  6027.                     \$('.imgproduit1').each(function () {
  6028.                         \$(this).css('display', 'block');
  6029.                         \$(this).removeClass('animated fadeOut');
  6030.                         \$(this).addClass('animated fadeIn');
  6031.                     });
  6032.                 });
  6033.                 \$('.columnPub').each(function () {
  6034.                     \$(this).slick({
  6035.                         infinite: true,
  6036.                         speed: 50,
  6037.                         fade: true,
  6038.                         slidesToShow: 1,
  6039.                         slidesToScroll: 1,
  6040.                         autoplay: true,
  6041.                         pauseOnFocus: false,
  6042.                         pauseOnHover: false,
  6043.                         draggable: false
  6044.                     });
  6045.                     \$(this).css('display', 'block');
  6046.                 });
  6047.                 \$(\"#offrePack\").click();
  6048.                 ";
  6049.         // line 5788
  6050.         if ((CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["app"]) || array_key_exists("app"$context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.'5788$this->source); })()), "user", [], "any"falsefalsefalse5788), "showpubprod", [], "any"falsefalsefalse5788) != "false")) {
  6051.             // line 5789
  6052.             yield "                \$('#btnPubProd').click();
  6053.                 \$('.modal-backdrop').css('background-color', 'rgba(0, 0, 0, 0.2)');
  6054.                 ";
  6055.         }
  6056.         // line 5792
  6057.         yield "            });
  6058.             \$(\"#closeImage\").click(function () {
  6059.                 \$('#myModalImage').css('display', \"none\");
  6060.             });
  6061.             \$.ajax({
  6062.                 type: \"POST\",
  6063.                 url: \"";
  6064.         // line 5798
  6065.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("delateSession_parent");
  6066.         yield "\",
  6067.                 success: function () { }
  6068.             });
  6069.             function afficheDiv(elem) {
  6070.                 \$('.nav-link').each(function () {
  6071.                     \$(this).removeClass('active');
  6072.                 });
  6073.                 elem.addClass('active');
  6074.                 if (elem.attr('id') === \"esphoto\" || elem.attr('id') === \"esphotoMobile\") {
  6075.                     \$(\"#espacphoto\").show();
  6076.                     \$(\"#espacemessage\").hide();
  6077.                     \$(\"#espaceMa_selection\").hide();
  6078.                     pageMenu = 'MonSejour'
  6079.                     \$(this).addClass('active');
  6080.                    \$('#imageActifphoto').css('display', 'block');
  6081.                      \$('#imagenoActifphoto').css('display', 'none');
  6082.                    \$('#VocalActivee').css('display', 'none');
  6083.                      \$('#noActifVocal').css('display', 'block');
  6084.                 }
  6085.                 if (elem.attr('id') === \"esmessage\" || elem.attr('id') === \"esmessageMobile\") {
  6086.                     \$(\"#espacphoto\").hide();
  6087.                     \$(\"#espaceMa_selection\").hide();
  6088.                     \$(\"#espacemessage\").show();
  6089.                     pageMenu = 'BoiteVocale'
  6090.                     \$(\"#espaceMa_selection\").hide();
  6091.                     \$(this).addClass('active');
  6092.                   \$('#imageActifphoto').css('display', 'none');
  6093.                      \$('#imagenoActifphoto').css('display', 'block');
  6094.                    \$('#VocalActivee').css('display', 'block');
  6095.                      \$('#noActifVocal').css('display', 'none');
  6096.                 }
  6097.                 if (elem.attr('id') === \"esselection\" || elem.attr('id') === \"esselectionMobile\") {
  6098.                     \$(\"#espacphoto\").hide();
  6099.                     \$(\"#espacemessage\").hide();
  6100.                     \$(\"#espaceMa_selection\").show();
  6101.                     \$(homeNavmob).removeClass('bi bi-house-door-fill');
  6102.                     \$(homeNavmob).addClass('bi bi-house-door');
  6103.                     \$(micromob).removeClass('bi bi-mic-fill');
  6104.                     \$(micromob).addClass('bi bi-mic');
  6105.                     \$(selecNavmob).removeClass('bi bi-heart');
  6106.                     \$(selecNavmob).addClass('bi bi-heart-fill');
  6107.                 }
  6108.             }
  6109.             function LoadImagesCloud(\$element) {
  6110.                 \$element.find('.photo-zoom img').each(function (\$this) {
  6111.                     if (\$(this).attr('data-src') != \$(this).attr('src')) {
  6112.                         \$(this).attr('src', \$(this).attr('data-src'));
  6113.                     }
  6114.                 });
  6115.             }
  6116.   </script>
  6117.   <script>
  6118.     // ⚡ OPTIMISATION: Regroupement des initialisations jQuery
  6119.     \$(document).ready(function () {
  6120.       // Modal PubProd
  6121.       \$(\"#PubProd\").on(\"hidden.bs.modal\", function () {
  6122.         \$(document).trigger(\"modalClosed\");
  6123.       });
  6124.       
  6125.       // NoShow checkbox
  6126.       \$(\"#noShow\").on(\"change\", function () {
  6127.         if (\$(this).is(\":checked\")) {
  6128.           \$.ajax({
  6129.             url: \"/Parent/showpub\",
  6130.             type: \"POST\",
  6131.             dataType: \"json\",
  6132.             success: function (response) {
  6133.               if (response.status === \"success\") {
  6134.                 console.log(\"User showpubprod updated successfully.\");
  6135.               } else {
  6136.                 console.log(\"Error:\", response.message);
  6137.               }
  6138.             },
  6139.             error: function (xhr, status, error) {
  6140.               console.log(\"AJAX Error:\", error);
  6141.             },
  6142.           });
  6143.         }
  6144.       });
  6145.     });
  6146.   </script>
  6147. </div>
  6148. <!-- Script pour la sidebar des favoris -->
  6149. <script>
  6150.   // ⚡ OPTIMISATION: Utiliser requestIdleCallback pour ne pas bloquer le thread principal
  6151.  
  6152.   
  6153.     
  6154.     // Charger les favoris
  6155.     function loadFavorites() {
  6156.       \$.ajax({
  6157.         url: \"/Parent/mes-favoris\",
  6158.         type: \"GET\",
  6159.         dataType: \"json\",
  6160.         beforeSend: function() {
  6161.           \$(\"#favorites-grid\").html(\"<div style='text-align:center'>Chargement...</div>\");
  6162.         },
  6163.         success: function(data) {
  6164.           \$(\"#favorites-grid\").empty();
  6165.           
  6166.           if (data.data && data.data.length > 0) {
  6167.             \$(\"#favorites-empty-state\").hide();
  6168.             
  6169.             \$.each(data.data, function(i, fav) {
  6170.               var item = \$(\"<div class='favorite-item'></div>\");
  6171.               var img = \$(\"<img>\").attr(\"src\", fav.path).attr(\"alt\", fav.descreption || \"Photo favorite\");
  6172.               var overlay = \$(\"<div class='favorite-overlay'></div>\");
  6173.         
  6174.               
  6175.               btn.click(function(e) {
  6176.                 e.preventDefault();
  6177.                 e.stopPropagation();
  6178.                 removeFavorite(fav.id);
  6179.               });
  6180.               
  6181.               overlay.append(btn);
  6182.               item.append(img).append(overlay);
  6183.               \$(\"#favorites-grid\").append(item);
  6184.             });
  6185.             
  6186.             \$(\"#favorites-counter\").text(data.data.length);
  6187.             var percentage = (data.data.length / 10) * 100;
  6188.             \$(\"#favorites-progress\").css(\"width\", percentage + \"%\");
  6189.             
  6190.           } else {
  6191.             \$(\"#favorites-empty-state\").show();
  6192.             \$(\"#favorites-counter\").text(\"0\");
  6193.             \$(\"#favorites-progress\").css(\"width\", \"0%\");
  6194.           }
  6195.         },
  6196.         error: function() {
  6197.           \$(\"#favorites-grid\").html(\"<div style='color:red;text-align:center'>Erreur de chargement</div>\");
  6198.         }
  6199.       });
  6200.     }
  6201.     
  6202.     // Supprimer un favori
  6203.     function removeFavorite(id) {
  6204.       \$.ajax({
  6205.         url: \"/Parent/remove-favorite/\" + id,
  6206.         type: \"POST\",
  6207.         success: function() {
  6208.           loadFavorites();
  6209.           
  6210.           // Mettre à jour tous les compteurs de favoris
  6211.           updateAllFavoriteCounters();
  6212.         },
  6213.         error: function() {
  6214.           alert(\"Erreur lors de la suppression du favori\");
  6215.         }
  6216.       });
  6217.     }
  6218.   });
  6219. </script>
  6220. <!-- === E-COMMERCE SIDEBAR JAVASCRIPT === -->
  6221. <script>
  6222. // Configuration UX_VARIANT pour A/B testing
  6223. let UX_VARIANT = 'EMOTION'; // ou 'URGENCY'
  6224. // Variables globales e-commerce
  6225. let sejourEndDate = null; // À définir avec la vraie date de fin du séjour
  6226. // Fonction utilitaire robuste pour gérer les compteurs de favoris
  6227. window.getFavoriteCount = function getFavoriteCount() {
  6228.   const likeCountInput = document.getElementById('likeCount');
  6229.   if (likeCountInput) {
  6230.     // Priorité à la valeur de l'input
  6231.     const value = likeCountInput.value || likeCountInput.textContent || 0;
  6232.     return parseInt(value, 10) || 0;
  6233.   }
  6234.   
  6235.   // Fallback sur giftCount
  6236.   const giftCount = document.getElementById('giftCount');
  6237.   if (giftCount && giftCount.textContent) {
  6238.     return parseInt(giftCount.textContent.trim(), 10) || 0;
  6239.   }
  6240.   
  6241.   return 0;
  6242. };
  6243. window.setFavoriteCount = function setFavoriteCount(count) {
  6244.   const likeCountInput = document.getElementById('likeCount');
  6245.   if (likeCountInput) {
  6246.     // Mettre à jour les deux propriétés pour être sûr
  6247.     likeCountInput.value = count;
  6248.     likeCountInput.textContent = count;
  6249.   }
  6250.   
  6251.   // Mettre à jour les autres compteurs
  6252.   const giftCount = document.getElementById('giftCount');
  6253.   if (giftCount) {
  6254.     giftCount.textContent = count;
  6255.   }
  6256.   
  6257.   const mesFavCount = document.getElementById('mesFavCount');
  6258.   if (mesFavCount) {
  6259.     mesFavCount.textContent = count;
  6260.   }
  6261.   
  6262.   // Mettre à jour l'input hidden
  6263.   const nbFavCurrentInput = document.getElementById('nbFavCurrent');
  6264.   if (nbFavCurrentInput) {
  6265.     nbFavCurrentInput.value = count;
  6266.   }
  6267. };
  6268. // Fonction pour définir la date de fin du séjour
  6269. window.setSejourEndDate = function setSejourEndDate(dateString) {
  6270.   sejourEndDate = dateString;
  6271.   console.log('🎯 Sejour end date set to:', sejourEndDate);
  6272.   
  6273.   // Mettre à jour le countdown si le sidebar est ouvert
  6274.   updateCountdownTimer();
  6275. };
  6276. // Fonctions d'ouverture/fermeture du sidebar
  6277. window.openEcommerceSidebar = function openEcommerceSidebar() {
  6278.   const sidebar = document.getElementById('ecommerce-sidebar');
  6279.   if (!sidebar) {
  6280.     console.error('❌ E-commerce sidebar element not found!');
  6281.     return false;
  6282.   }
  6283.   
  6284.   // Ajouter la classe active
  6285.   sidebar.classList.add('active');
  6286.   
  6287.     // Mettre à jour le contenu avec le nombre actuel de favoris
  6288.     let favoriteCount = window.getFavoriteCount();
  6289.     console.log('🎯 Opening sidebar with favoriteCount:', favoriteCount);
  6290.   
  6291.   // Mettre à jour le contenu du sidebar
  6292.   if (typeof window.updateEcommerceSidebarContent === 'function') {
  6293.     window.updateEcommerceSidebarContent(favoriteCount);
  6294.   }
  6295.   
  6296.   return true;
  6297. };
  6298. window.closeEcommerceSidebar = function closeEcommerceSidebar() {
  6299.   const sidebar = document.getElementById('ecommerce-sidebar');
  6300.   if (sidebar) {
  6301.     sidebar.classList.remove('active');
  6302.     console.log('🎯 E-commerce sidebar closed');
  6303.   } else {
  6304.     console.error('❌ E-commerce sidebar element not found!');
  6305.   }
  6306. };
  6307. // Fonction pour mettre à jour le contenu du sidebar
  6308. window.updateEcommerceSidebarContent = function updateEcommerceSidebarContent(favoriteCount) {
  6309.   const title = document.getElementById('ecommerce-title');
  6310.   const subtitle = document.getElementById('ecommerce-subtitle');
  6311.   const albumCount = document.getElementById('album-count');
  6312.   const digitalCount = document.getElementById('digital-count');
  6313.   const printsCount = document.getElementById('prints-count');
  6314.   const printsCard = document.getElementById('prints-card');
  6315.   const productsContainer = document.getElementById('products-container');
  6316.   
  6317.   // Gérer l'état vide vs rempli
  6318.   const isEmpty = favoriteCount === 0;
  6319.   
  6320.   // Titre émotionnel basé sur le nombre de favoris et la variante UX
  6321.   if (title) {
  6322.     if (UX_VARIANT === 'URGENCY') {
  6323.       // Variante urgence
  6324.       if (isEmpty) {
  6325.         title.innerHTML = `⏳ Commencez par sélectionner vos favoris ❤️`;
  6326.       } else if (favoriteCount < 5) {
  6327.         title.innerHTML = `⏳ \${favoriteCount} souvenirs - Commandez vite !`;
  6328.       } else if (favoriteCount < 12) {
  6329.         title.innerHTML = `⏳ \${favoriteCount} magnifiques souvenirs - Plus que X jours !`;
  6330.       } else {
  6331.         title.innerHTML = `⏳ Superbe collection de \${favoriteCount} photos - Dernière chance !`;
  6332.       }
  6333.     } else {
  6334.       // Variante émotion (par défaut)
  6335.       if (isEmpty) {
  6336.         title.innerHTML = `Commencez par sélectionner vos favoris ❤️`;
  6337.       } else if (favoriteCount < 5) {
  6338.         title.innerHTML = `✨ \${favoriteCount} souvenirs sélectionnés !`;
  6339.       } else if (favoriteCount < 12) {
  6340.         title.innerHTML = `🎉 Vous avez \${favoriteCount} souvenirs favoris`;
  6341.       } else {
  6342.         title.innerHTML = `🎊 Superbe collection de \${favoriteCount} photos !`;
  6343.       }
  6344.     }
  6345.   }
  6346.   
  6347.   // Sous-titre dynamique
  6348.   if (subtitle) {
  6349.     if (isEmpty) {
  6350.       subtitle.innerHTML = `Cliquez sur ❤️ pour ajouter des photos à vos favoris`;
  6351.     } else if (favoriteCount === 1) {
  6352.       subtitle.innerHTML = `1 photo sélectionnée avec amour ❤️`;
  6353.     } else {
  6354.       subtitle.innerHTML = `\${favoriteCount} photos sélectionnées avec amour ❤️`;
  6355.     }
  6356.   }
  6357.   
  6358.   // Mettre à jour les compteurs produits
  6359.   console.log('🔄 Updating sidebar counters:', { favoriteCount, albumCount, digitalCount, printsCount });
  6360.   if (albumCount) {
  6361.     albumCount.textContent = favoriteCount;
  6362.     console.log('✅ Album count updated to:', favoriteCount);
  6363.   }
  6364.   if (digitalCount) {
  6365.     digitalCount.textContent = favoriteCount;
  6366.     console.log('✅ Digital count updated to:', favoriteCount);
  6367.   }
  6368.   
  6369.   // Afficher la pochette tirages seulement si >= 12 favoris
  6370.   if (printsCard) {
  6371.     if (favoriteCount >= 12) {
  6372.       printsCard.style.display = 'block';
  6373.       if (printsCount) printsCount.textContent = Math.min(favoriteCount, 12);
  6374.     } else {
  6375.       printsCard.style.display = 'none';
  6376.     }
  6377.   }
  6378.   
  6379.   // Gérer l'état des CTA produits
  6380.   updateProductCTAs(favoriteCount);
  6381.   
  6382.   // Gérer le countdown si proche de l'expiration
  6383.   updateCountdownTimer();
  6384. }
  6385. // Fonction pour gérer l'état des CTA produits
  6386. window.updateProductCTAs = function updateProductCTAs(favoriteCount) {
  6387.   const isEmpty = favoriteCount === 0;
  6388.   const productCTAs = document.querySelectorAll('.product-cta');
  6389.   const productDescriptions = document.querySelectorAll('.product-description');
  6390.   
  6391.   productCTAs.forEach((cta, index) => {
  6392.     if (isEmpty) {
  6393.       // État désactivé
  6394.       cta.disabled = true;
  6395.       cta.setAttribute('aria-disabled', 'true');
  6396.       cta.style.cursor = 'not-allowed';
  6397.       cta.style.opacity = '0.6';
  6398.       cta.title = 'Ajoutez des favoris pour commander';
  6399.     } else {
  6400.       // État activé
  6401.       cta.disabled = false;
  6402.       cta.removeAttribute('aria-disabled');
  6403.       cta.style.cursor = 'pointer';
  6404.       cta.style.opacity = '1';
  6405.       cta.title = '';
  6406.     }
  6407.   });
  6408.   
  6409.   // Mettre à jour les descriptions des produits
  6410.   productDescriptions.forEach((desc, index) => {
  6411.     if (isEmpty) {
  6412.       // Texte générique sans compteur
  6413.       if (index === 0) { // Album
  6414.         desc.innerHTML = 'Personnalisez votre album avec vos photos favorites. Papier de qualité supérieure, reliure rigide.';
  6415.       } else if (index === 1) { // Pack numérique
  6416.         desc.innerHTML = 'Téléchargement immédiat de vos photos en haute définition. Qualité professionnelle garantie.';
  6417.       } else if (index === 2) { // Tirages
  6418.         desc.innerHTML = 'Tirages photo 10x15cm de vos favoris. Papier brillant professionnel, livraison gratuite.';
  6419.       }
  6420.     } else {
  6421.       // Texte avec compteur dynamique
  6422.       if (index === 0) { // Album
  6423.         desc.innerHTML = `Album photo personnalisé avec vos <strong>\${favoriteCount}</strong> photos favorites. Papier de qualité supérieure, reliure rigide.`;
  6424.       } else if (index === 1) { // Pack numérique
  6425.         desc.innerHTML = `Téléchargement immédiat de vos <strong>\${favoriteCount}</strong> photos en haute définition. Qualité professionnelle garantie.`;
  6426.       } else if (index === 2) { // Tirages
  6427.         const printsCount = Math.min(favoriteCount, 12);
  6428.         desc.innerHTML = `<strong>\${printsCount}</strong> tirages photo 10x15cm de vos favoris. Papier brillant professionnel, envoi sous 48h.`;
  6429.       }
  6430.     }
  6431.   });
  6432.   
  6433.   // Mettre à jour les icônes de favoris dans les produits
  6434.   const albumFavCount = document.getElementById('album-fav-count');
  6435.   const digitalFavCount = document.getElementById('digital-fav-count');
  6436.   const printsFavCount = document.getElementById('prints-fav-count');
  6437.   
  6438.   if (albumFavCount) albumFavCount.textContent = favoriteCount;
  6439.   if (digitalFavCount) digitalFavCount.textContent = favoriteCount;
  6440.   if (printsFavCount) printsFavCount.textContent = Math.min(favoriteCount, 12);
  6441. }
  6442. // Fonction pour gérer le countdown
  6443. window.updateCountdownTimer = function updateCountdownTimer() {
  6444.   const countdownTimer = document.getElementById('countdown-timer');
  6445.   const daysLeftSpan = document.getElementById('days-left');
  6446.   
  6447.   if (!countdownTimer || !daysLeftSpan) return;
  6448.   
  6449.   // Si pas de date définie, utiliser une date par défaut (6 semaines à partir d'aujourd'hui)
  6450.   let expirationDate;
  6451.   if (sejourEndDate) {
  6452.     const endDate = new Date(sejourEndDate);
  6453.     expirationDate = new Date(endDate.getTime() + (6 * 7 * 24 * 60 * 60 * 1000)); // +6 semaines
  6454.   } else {
  6455.     // Date par défaut : 6 semaines à partir d'aujourd'hui
  6456.     expirationDate = new Date();
  6457.     expirationDate.setDate(expirationDate.getDate() + (6 * 7));
  6458.   }
  6459.   
  6460.   const now = new Date();
  6461.   const daysLeft = Math.ceil((expirationDate - now) / (24 * 60 * 60 * 1000));
  6462.   
  6463.   if (daysLeft <= 10 && daysLeft > 0) {
  6464.     countdownTimer.style.display = 'block';
  6465.     daysLeftSpan.textContent = daysLeft;
  6466.     
  6467.     // Mettre à jour les titres avec le countdown si variante URGENCY
  6468.     if (UX_VARIANT === 'URGENCY') {
  6469.       const title = document.getElementById('ecommerce-title');
  6470.       if (title) {
  6471.         const favoriteCount = parseInt(document.getElementById('giftCount')?.textContent || '0');
  6472.         if (favoriteCount > 0) {
  6473.           if (favoriteCount < 5) {
  6474.             title.innerHTML = `⏳ \${favoriteCount} souvenirs - Plus que \${daysLeft} jours !`;
  6475.           } else if (favoriteCount < 12) {
  6476.             title.innerHTML = `⏳ \${favoriteCount} magnifiques souvenirs - Plus que \${daysLeft} jours !`;
  6477.           } else {
  6478.             title.innerHTML = `⏳ Superbe collection de \${favoriteCount} photos - Plus que \${daysLeft} jours !`;
  6479.           }
  6480.         }
  6481.       }
  6482.     }
  6483.   } else {
  6484.     countdownTimer.style.display = 'none';
  6485.   }
  6486. }
  6487. // Fonction pour commander un produit
  6488. window.orderProduct = function orderProduct(productType) {
  6489.   let favoriteCount = 0;
  6490.   
  6491.   // Méthode 1: Fonction getCurrentFavoriteCount
  6492.   try {
  6493.     if (typeof getCurrentFavoriteCount === 'function') {
  6494.       favoriteCount = getCurrentFavoriteCount();
  6495.     }
  6496.   } catch (e) {
  6497.     console.log('⚠️ getCurrentFavoriteCount non disponible:', e);
  6498.   }
  6499.   
  6500.   // Méthode 2: Element giftCount
  6501.   if (favoriteCount === 0) {
  6502.     const giftCount = document.getElementById('giftCount');
  6503.     if (giftCount && giftCount.textContent) {
  6504.       favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  6505.     }
  6506.   }
  6507.   
  6508.   // Méthode 3: Récupérer depuis les éléments qui affichent le nombre de favoris
  6509.   if (favoriteCount === 0) {
  6510.     const albumFavCount = document.getElementById('album-fav-count');
  6511.     const digitalFavCount = document.getElementById('digital-fav-count');
  6512.     
  6513.     if (albumFavCount && albumFavCount.textContent) {
  6514.       favoriteCount = parseInt(albumFavCount.textContent.trim()) || 0;
  6515.     } else if (digitalFavCount && digitalFavCount.textContent) {
  6516.       favoriteCount = parseInt(digitalFavCount.textContent.trim()) || 0;
  6517.     }
  6518.   }
  6519.   
  6520.   // Méthode 4: Variable globale likes
  6521.   if (favoriteCount === 0 && typeof likes !== 'undefined' && likes) {
  6522.     favoriteCount = likes.length || 0;
  6523.   }
  6524.   
  6525.   // Méthode 5: Compter les éléments liked dans le DOM
  6526.   if (favoriteCount === 0) {
  6527.     const likedElements = document.querySelectorAll('.liked, .photo.liked, [data-liked=\"true\"]');
  6528.     favoriteCount = likedElements.length;
  6529.   }
  6530.   
  6531.   // Debug pour voir la valeur récupérée
  6532.   console.log('🔍 Nombre de favoris détecté:', favoriteCount);
  6533.   
  6534.   if (favoriteCount === 0) {
  6535.     // Afficher une notification plus élégante
  6536.     const notification = document.createElement('div');
  6537.     notification.className = 'favorite-notification';
  6538.     notification.innerHTML = `
  6539.       <div class=\"notification-content\">
  6540.         <i class=\"bi bi-heart\" style=\"color: #e91e63; font-size: 1.5rem; margin-right: 10px;\"></i>
  6541.         <span>Veuillez d'abord sélectionner des photos favorites !</span>
  6542.         <button onclick=\"this.parentElement.parentElement.remove()\" style=\"background: none; border: none; color: #666; font-size: 1.2rem; margin-left: 10px;\">&times;</button>
  6543.       </div>
  6544.     `;
  6545.     
  6546.     // Styles pour la notification
  6547.     notification.style.cssText = `
  6548.       position: fixed;
  6549.       top: 20px;
  6550.       right: 20px;
  6551.       background: #fff;
  6552.       border: 2px solid #e91e63;
  6553.       border-radius: 8px;
  6554.       padding: 15px;
  6555.       box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  6556.       z-index: 10000;
  6557.       animation: slideInRight 0.3s ease;
  6558.     `;
  6559.     
  6560.     // Ajouter l'animation CSS si elle n'existe pas
  6561.     if (!document.getElementById('notification-styles')) {
  6562.       const style = document.createElement('style');
  6563.       style.id = 'notification-styles';
  6564.       style.textContent = `
  6565.         @keyframes slideInRight {
  6566.           from { transform: translateX(100%); opacity: 0; }
  6567.           to { transform: translateX(0); opacity: 1; }
  6568.         }
  6569.         .notification-content {
  6570.           display: flex;
  6571.           align-items: center;
  6572.         }
  6573.       `;
  6574.       document.head.appendChild(style);
  6575.     }
  6576.     
  6577.     document.body.appendChild(notification);
  6578.     
  6579.     // Supprimer automatiquement après 5 secondes
  6580.     setTimeout(() => {
  6581.       if (notification.parentElement) {
  6582.         notification.remove();
  6583.       }
  6584.     }, 5000);
  6585.     
  6586.     return;
  6587.   }
  6588.   
  6589.   // Construire l'URL avec les favoris pré-sélectionnés
  6590.   let orderUrl = '';
  6591.   
  6592.   switch (productType) {
  6593.     case 'album':
  6594.       orderUrl = `";
  6595.         // line 6354
  6596.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("EditionAlbum");
  6597.         yield "?favorites=\${favoriteCount}`;
  6598.       break;
  6599.     case 'digital':
  6600.       orderUrl = `";
  6601.         // line 6357
  6602.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("PackPhotosNumerique_Favoris", ["nbr" => 15]);
  6603.         yield "?favorites=\${favoriteCount}`;
  6604.       break;
  6605.     case 'prints':
  6606.       orderUrl = `";
  6607.         // line 6360
  6608.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("AjoutPochettePhotos_Favoris", ["nbr" => 12]);
  6609.         yield "?favorites=\${favoriteCount}`;
  6610.       break;
  6611.     default:
  6612.       console.error('Type de produit non reconnu:', productType);
  6613.       alert('Erreur: Type de produit non reconnu');
  6614.       return;
  6615.   }
  6616.   
  6617.   // Analytics/tracking
  6618.   console.log('Product ordered', { productType, favoriteCount, url: orderUrl });
  6619.   
  6620.   // Redirection vers la commande
  6621.   if (orderUrl) {
  6622.     // Vérifier que l'URL est valide
  6623.     try {
  6624.       new URL(orderUrl, window.location.origin);
  6625.     window.location.href = orderUrl;
  6626.     } catch (error) {
  6627.       console.error('URL invalide générée:', orderUrl, error);
  6628.       alert('Erreur: Impossible de générer le lien de commande');
  6629.     }
  6630.   } else {
  6631.     console.error('Aucune URL générée pour le produit:', productType);
  6632.     alert('Erreur: Impossible de générer le lien de commande');
  6633.   }
  6634. }
  6635. // Fonction pour tester tous les liens de produits
  6636. window.testProductLinks = function() {
  6637.   const products = ['album', 'digital', 'prints'];
  6638.   const favoriteCount = window.getFavoriteCount() || 0;
  6639.   
  6640.   console.log('🧪 Test des liens de produits avec', favoriteCount, 'favoris');
  6641.   
  6642.   products.forEach(productType => {
  6643.     try {
  6644.       let testUrl = '';
  6645.       switch (productType) {
  6646.         case 'album':
  6647.           testUrl = `";
  6648.         // line 6399
  6649.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("EditionAlbum");
  6650.         yield "?favorites=\${favoriteCount}`;
  6651.           break;
  6652.         case 'digital':
  6653.           testUrl = `";
  6654.         // line 6402
  6655.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("PackPhotosNumerique_Favoris", ["nbr" => 15]);
  6656.         yield "?favorites=\${favoriteCount}`;
  6657.           break;
  6658.         case 'prints':
  6659.           testUrl = `";
  6660.         // line 6405
  6661.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("AjoutPochettePhotos_Favoris", ["nbr" => 12]);
  6662.         yield "?favorites=\${favoriteCount}`;
  6663.           break;
  6664.       }
  6665.       
  6666.       // Vérifier que l'URL est valide
  6667.       const url = new URL(testUrl, window.location.origin);
  6668.       console.log(`✅ \${productType}: \${url.href}`);
  6669.     } catch (error) {
  6670.       console.error(`❌ \${productType}: Erreur URL`, error);
  6671.     }
  6672.   });
  6673. };
  6674. // Fonction pour valider les liens au chargement de la page
  6675. window.validateProductLinks = function() {
  6676.   // Vérifier que tous les boutons de produits existent
  6677.   const albumBtn = document.querySelector('button[onclick*=\"orderProduct(\\'album\\')\"]');
  6678.   const digitalBtn = document.querySelector('button[onclick*=\"orderProduct(\\'digital\\')\"]');
  6679.   const printsBtn = document.querySelector('button[onclick*=\"orderProduct(\\'prints\\')\"]');
  6680.   
  6681.   if (!albumBtn) console.warn('⚠️ Bouton album non trouvé');
  6682.   if (!digitalBtn) console.warn('⚠️ Bouton digital non trouvé');
  6683.   if (!printsBtn) console.warn('⚠️ Bouton prints non trouvé');
  6684.   
  6685.   // Tester les liens
  6686.   window.testProductLinks();
  6687. };
  6688. // Améliorer la fonction updateAllFavoriteCounters existante
  6689. const originalUpdateAllFavoriteCounters = window.updateAllFavoriteCounters || function() {};
  6690. window.updateAllFavoriteCounters = function() {
  6691.   // Appeler la fonction originale
  6692.   originalUpdateAllFavoriteCounters();
  6693.   
  6694.   // Animation rebond du compteur favoris
  6695.   const giftCount = document.getElementById('giftCount');
  6696.   if (giftCount) {
  6697.     giftCount.classList.remove('gift-count-bounce');
  6698.     setTimeout(() => giftCount.classList.add('gift-count-bounce'), 10);
  6699.   }
  6700.   
  6701.   // Animation rebond du compteur dans la bulle cadeau
  6702.   const likeCount = document.getElementById('likeCount');
  6703.   if (likeCount) {
  6704.     likeCount.classList.remove('gift-count-bounce');
  6705.     setTimeout(() => likeCount.classList.add('gift-count-bounce'), 10);
  6706.   }
  6707.   
  6708.   // Récupérer le nombre de favoris actuel avec la fonction utilitaire robuste
  6709.   let favoriteCount = window.getFavoriteCount();
  6710.   
  6711.   // Mettre à jour les compteurs dans le sidebar même s'il n'est pas ouvert
  6712.   const albumCount = document.getElementById('album-count');
  6713.   const digitalCount = document.getElementById('digital-count');
  6714.   const printsCount = document.getElementById('prints-count');
  6715.   
  6716.   if (albumCount) albumCount.textContent = favoriteCount;
  6717.   if (digitalCount) digitalCount.textContent = favoriteCount;
  6718.   if (printsCount) printsCount.textContent = Math.min(favoriteCount, 12);
  6719.   
  6720.   // Mettre à jour les icônes de favoris dans les produits
  6721.   const albumFavCount = document.getElementById('album-fav-count');
  6722.   const digitalFavCount = document.getElementById('digital-fav-count');
  6723.   const printsFavCount = document.getElementById('prints-fav-count');
  6724.   
  6725.   if (albumFavCount) albumFavCount.textContent = favoriteCount;
  6726.   if (digitalFavCount) digitalFavCount.textContent = favoriteCount;
  6727.   if (printsFavCount) printsFavCount.textContent = Math.min(favoriteCount, 12);
  6728.   
  6729.   // Mettre à jour le sidebar si ouvert
  6730.   const sidebar = document.getElementById('ecommerce-sidebar');
  6731.   if (sidebar && sidebar.classList.contains('active')) {
  6732.     console.log('🔄 Sidebar is open, updating content with favoriteCount:', favoriteCount);
  6733.     window.updateEcommerceSidebarContent(favoriteCount);
  6734.   } else {
  6735.     console.log('ℹ️ Sidebar is closed, but updating content anyway for consistency');
  6736.     // Mettre à jour le contenu même si le sidebar n'est pas ouvert pour la cohérence
  6737.     window.updateEcommerceSidebarContent(favoriteCount);
  6738.   }
  6739. };
  6740. // Fonction pour retirer un favori de la grille et exécuter supprimerFavoris
  6741. window.removeFavorite = function removeFavorite(itemId) {
  6742.   // Animation simple de disparition puis suppression
  6743.   const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${itemId}\"]`);
  6744.  
  6745.   if (favoriteItem) {
  6746.     favoriteItem.classList.add('fade-out');
  6747.     setTimeout(() => {
  6748.       favoriteItem.remove();
  6749.       // Appeler la fonction métier si présente
  6750.       if (typeof window.supprimerFavoris === 'function') {
  6751.         const heartIcon = document.querySelector(`#coeur\${itemId}`);
  6752.         const sejourId = heartIcon && heartIcon.dataset.sejourId ? heartIcon.dataset.sejourId : '';
  6753.         window.supprimerFavoris(itemId, sejourId);
  6754.       }
  6755.       // Mettre à jour les compteurs
  6756.       updateAllFavoriteCounters();
  6757.     }, 200);
  6758.   }
  6759. };
  6760. // Vérifier que la fonction est bien définie
  6761. console.log('🔍 removeFavorite function defined:', typeof window.removeFavorite);
  6762. // (Nettoyé) Pas de délégation globale ici; les boutons utilisent des onclick simples
  6763. // Fonction pour voir un favori en grand
  6764. window.viewFavorite = function viewFavorite(itemId) {
  6765.   console.log('👁️ Viewing favorite:', itemId);
  6766.   
  6767.   // Essayer d'utiliser la fonction viewImage existante
  6768.   if (typeof window.viewImage === 'function') {
  6769.     window.viewImage(itemId, null);
  6770.   } else {
  6771.     console.log('ℹ️ viewImage function not available, opening in new tab');
  6772.     // Fallback: ouvrir dans un nouvel onglet
  6773.     const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${itemId}\"] img`);
  6774.     if (favoriteItem && favoriteItem.src) {
  6775.       window.open(favoriteItem.src, '_blank');
  6776.     }
  6777.   }
  6778. };
  6779. // Fonction de debug pour tester les compteurs
  6780. window.debugFavoriteCounters = function() {
  6781.   console.log('🔍 Debug Favorite Counters:');
  6782.   console.log('- getFavoriteCount():', window.getFavoriteCount());
  6783.   console.log('- likeCount input value:', document.getElementById('likeCount')?.value);
  6784.   console.log('- likeCount textContent:', document.getElementById('likeCount')?.textContent);
  6785.   console.log('- giftCount textContent:', document.getElementById('giftCount')?.textContent);
  6786.   console.log('- album-count textContent:', document.getElementById('album-count')?.textContent);
  6787.   console.log('- digital-count textContent:', document.getElementById('digital-count')?.textContent);
  6788.   console.log('- prints-count textContent:', document.getElementById('prints-count')?.textContent);
  6789.   console.log('- Sidebar active:', document.getElementById('ecommerce-sidebar')?.classList.contains('active'));
  6790. };
  6791. // Fonction de test pour les boutons de favoris
  6792. window.testFavoriteButtons = function() {
  6793.   console.log('🧪 Testing favorite buttons:');
  6794.   const removeButtons = document.querySelectorAll('.btn-remove-favorite');
  6795.   const viewButtons = document.querySelectorAll('.btn-view-favorite');
  6796.   
  6797.   console.log('- Remove buttons found:', removeButtons.length);
  6798.   console.log('- View buttons found:', viewButtons.length);
  6799.   
  6800.   removeButtons.forEach((btn, index) => {
  6801.     console.log(`- Remove button \${index}:`, {
  6802.       itemId: btn.dataset.itemId,
  6803.       hasClickListener: btn.onclick !== null
  6804.     });
  6805.   });
  6806.   
  6807.   viewButtons.forEach((btn, index) => {
  6808.     console.log(`- View button \${index}:`, {
  6809.       itemId: btn.dataset.itemId,
  6810.       hasClickListener: btn.onclick !== null
  6811.     });
  6812.   });
  6813. };
  6814. // Fermer le sidebar en cliquant en dehors
  6815. document.addEventListener('click', function(e) {
  6816.   const sidebar = document.getElementById('ecommerce-sidebar');
  6817.   const giftButton = document.querySelector('.gift-button');
  6818.   
  6819.   if (sidebar && sidebar.classList.contains('active') && 
  6820.       !sidebar.contains(e.target) && 
  6821.       !giftButton.contains(e.target)) {
  6822.     window.closeEcommerceSidebar();
  6823.   }
  6824. });
  6825. // Fermer avec Escape
  6826. document.addEventListener('keydown', function(e) {
  6827.   if (e.key === 'Escape') {
  6828.     window.closeEcommerceSidebar();
  6829.   }
  6830. });
  6831. // Initialisation au chargement
  6832. document.addEventListener('DOMContentLoaded', function() {
  6833.   // Vérifier que les éléments existent
  6834.   const sidebar = document.getElementById('ecommerce-sidebar');
  6835.   const giftButton = document.getElementById('gift-button-trigger');
  6836.   
  6837.   // Event listener propre pour le bouton cadeau
  6838.   if (giftButton) {
  6839.     giftButton.addEventListener('click', function(e) {
  6840.       e.preventDefault();
  6841.       e.stopPropagation();
  6842.       window.openEcommerceSidebar();
  6843.     });
  6844.   }
  6845.   
  6846.   // Définir la date de fin du séjour si disponible
  6847.   ";
  6848.         // line 6601
  6849.         if (((isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'6601$this->source); })()) && CoreExtension::getAttribute($this->env$this->source, ($context["sejour"] ?? null), "dateFinSejour", [], "any"truetruefalse6601))) {
  6850.             // line 6602
  6851.             yield "    window.setSejourEndDate('";
  6852.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatDate(CoreExtension::getAttribute($this->env$this->source, (isset($context["sejour"]) || array_key_exists("sejour"$context) ? $context["sejour"] : (function () { throw new RuntimeError('Variable "sejour" does not exist.'6602$this->source); })()), "dateFinSejour", [], "any"falsefalsefalse6602), "Y-m-d"), "html"nulltrue);
  6853.             yield "');
  6854.   ";
  6855.         }
  6856.         // line 6604
  6857.         yield "  
  6858.   // Mise à jour initiale du contenu
  6859.   let favoriteCount = 0;
  6860.   try {
  6861.     if (typeof getCurrentFavoriteCount === 'function') {
  6862.       favoriteCount = getCurrentFavoriteCount();
  6863.     } else {
  6864.       // Essayer d'abord l'input likeCount
  6865.       const likeCountInput = document.getElementById('likeCount');
  6866.       if (likeCountInput && likeCountInput.value) {
  6867.         favoriteCount = parseInt(likeCountInput.value, 10) || 0;
  6868.       } else {
  6869.         // Fallback sur giftCount
  6870.         const giftCount = document.getElementById('giftCount');
  6871.         if (giftCount && giftCount.textContent) {
  6872.           favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  6873.         }
  6874.       }
  6875.     }
  6876.   } catch (e) {
  6877.     console.log('⚠️ Fallback pour favoriteCount initial:', e);
  6878.     // Fallback sur likeCount input
  6879.     const likeCountInput = document.getElementById('likeCount');
  6880.     if (likeCountInput && likeCountInput.value) {
  6881.       favoriteCount = parseInt(likeCountInput.value, 10) || 0;
  6882.     } else {
  6883.       const giftCount = document.getElementById('giftCount');
  6884.       if (giftCount && giftCount.textContent) {
  6885.         favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  6886.       }
  6887.     }
  6888.   }
  6889.   
  6890.   window.updateEcommerceSidebarContent(favoriteCount);
  6891.   
  6892. });
  6893. </script>
  6894. <!-- 🎯 DAY FILTER POPOVER (instancié une seule fois) -->
  6895. <div id=\"dayFilterPopover\" class=\"day-popover\" role=\"dialog\" aria-modal=\"true\" aria-hidden=\"true\">
  6896.   <div class=\"dp-arrow\" aria-hidden=\"true\"></div>
  6897.   <div class=\"dp-content\" role=\"group\" aria-label=\"Filtres du jour\">
  6898.     <button class=\"dp-btn\" data-filter=\"all\" title=\"Tout\" aria-pressed=\"true\">
  6899.       <i class=\"bi bi-grid-3x3-gap-fill\"></i><span class=\"dp-count dp-label\">Tout</span>
  6900.     </button>
  6901.     <button class=\"dp-btn\" data-filter=\"photos\" title=\"Photos\" aria-pressed=\"false\">
  6902.       <i class=\"bi bi-images\"></i><span class=\"dp-count\" data-bind=\"photo\">0</span>
  6903.     </button>
  6904.     <button class=\"dp-btn\" data-filter=\"audio\" title=\"Audios\" aria-pressed=\"false\">
  6905.       <i class=\"bi bi-mic-fill\"></i><span class=\"dp-count\" data-bind=\"audio\">0</span>
  6906.     </button>
  6907.     <button class=\"dp-btn\" data-filter=\"videos\" title=\"Vidéos\" aria-pressed=\"false\">
  6908.       <i class=\"bi bi-camera-video-fill\"></i><span class=\"dp-count\" data-bind=\"video\">0</span>
  6909.     </button>
  6910.     <button class=\"dp-btn\" data-filter=\"favoris\" title=\"Favoris\" aria-pressed=\"false\">
  6911.       <i class=\"bi bi-heart-fill\" style=\"color:#f56040\"></i><span class=\"dp-count\" data-bind=\"fav\">0</span>
  6912.     </button>
  6913.     <button class=\"dp-btn dp-close\" title=\"Fermer\" aria-label=\"Fermer\">
  6914.       <i class=\"bi bi-x-lg\"></i>
  6915.     </button>
  6916.   </div>
  6917. </div>
  6918. ";
  6919.         
  6920.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  6921.         
  6922.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  6923.         yield from [];
  6924.     }
  6925.     /**
  6926.      * @codeCoverageIgnore
  6927.      */
  6928.     public function getTemplateName(): string
  6929.     {
  6930.         return "Parent/DetailsSejour.html.twig";
  6931.     }
  6932.     /**
  6933.      * @codeCoverageIgnore
  6934.      */
  6935.     public function isTraitable(): bool
  6936.     {
  6937.         return false;
  6938.     }
  6939.     /**
  6940.      * @codeCoverageIgnore
  6941.      */
  6942.     public function getDebugInfo(): array
  6943.     {
  6944.         return array (  7309 => 6604,  7303 => 6602,  7301 => 6601,  7102 => 6405,  7096 => 6402,  7090 => 6399,  7048 => 6360,  7042 => 6357,  7036 => 6354,  6477 => 5798,  6469 => 5792,  6464 => 5789,  6462 => 5788,  6386 => 5714,  6383 => 5713,  6371 => 5703,  6368 => 5702,  6366 => 5701,  6232 => 5570,  6228 => 5569,  5950 => 5294,  5873 => 5220,  5745 => 5095,  5734 => 5087,  5723 => 5079,  5705 => 5064,  5057 => 4419,  4987 => 4352,  4976 => 4344,  4712 => 4083,  4687 => 4061,  4631 => 4008,  4495 => 3875,  4434 => 3817,  4422 => 3808,  4171 => 3561,  4158 => 3560,  4144 => 3557,  4131 => 3547,  4122 => 3541,  4111 => 3533,  4104 => 3528,  4102 => 3527,  1511 => 938,  1474 => 903,  1471 => 902,  1457 => 901,  1451 => 897,  1447 => 895,  1443 => 893,  1437 => 892,  1433 => 890,  1426 => 886,  1422 => 884,  1420 => 883,  1413 => 879,  1407 => 875,  1404 => 874,  1400 => 873,  1393 => 868,  1391 => 867,  1389 => 866,  1385 => 864,  1379 => 863,  1375 => 861,  1368 => 857,  1364 => 855,  1362 => 854,  1355 => 850,  1349 => 846,  1346 => 845,  1342 => 844,  1339 => 843,  1337 => 842,  1335 => 841,  1331 => 839,  1325 => 838,  1321 => 836,  1314 => 832,  1310 => 830,  1308 => 829,  1301 => 825,  1295 => 821,  1292 => 820,  1288 => 819,  1285 => 818,  1283 => 817,  1281 => 816,  1275 => 813,  1269 => 809,  1267 => 808,  1262 => 805,  1254 => 802,  1250 => 801,  1244 => 799,  1242 => 798,  1234 => 793,  1226 => 788,  1223 => 787,  1221 => 786,  1216 => 783,  1209 => 779,  1203 => 777,  1201 => 776,  1185 => 762,  1182 => 761,  1178 => 760,  1170 => 754,  1166 => 753,  1161 => 751,  1157 => 750,  1153 => 749,  1149 => 748,  1145 => 747,  1135 => 740,  1127 => 737,  1120 => 733,  1117 => 732,  1114 => 731,  1110 => 730,  1093 => 715,  1087 => 714,  1081 => 713,  1079 => 712,  1074 => 711,  1065 => 705,  1057 => 700,  1049 => 695,  1033 => 682,  1013 => 664,  1007 => 661,  1004 => 660,  1002 => 659,  999 => 658,  993 => 655,  990 => 654,  988 => 653,  985 => 652,  979 => 649,  976 => 648,  974 => 647,  963 => 638,  961 => 630,  926 => 600,  922 => 599,  919 => 598,  916 => 597,  913 => 596,  910 => 595,  907 => 594,  904 => 593,  886 => 592,  883 => 591,  881 => 590,  864 => 575,  850 => 574,  844 => 570,  838 => 568,  835 => 567,  830 => 565,  825 => 562,  822 => 561,  816 => 559,  814 => 558,  804 => 550,  798 => 546,  796 => 545,  793 => 544,  791 => 543,  788 => 542,  786 => 539,  782 => 537,  780 => 535,  765 => 528,  763 => 524,  758 => 522,  754 => 521,  750 => 520,  742 => 517,  739 => 516,  736 => 515,  733 => 514,  730 => 513,  713 => 512,  692 => 494,  666 => 471,  653 => 461,  649 => 460,  645 => 459,  634 => 451,  630 => 450,  625 => 448,  621 => 447,  616 => 445,  612 => 444,  601 => 436,  575 => 413,  548 => 389,  517 => 361,  513 => 360,  358 => 208,  354 => 207,  350 => 206,  305 => 164,  298 => 160,  274 => 139,  267 => 135,  226 => 97,  198 => 72,  162 => 38,  160 => 37,  157 => 35,  144 => 33,  112 => 12,  110 => 11,  106 => 10,  102 => 9,  98 => 8,  94 => 7,  90 => 6,  86 => 5,  80 => 2,  57 => 1,  55 => 33,  42 => 1,);
  6945.     }
  6946.     public function getSourceContext(): Source
  6947.     {
  6948.         return new Source("{% extends \"Parent/LayoutParent.html.twig\" %} {% block LinksCss %}
  6949. {{ parent() }}
  6950. <script src=\"https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.js\" defer></script>
  6951. <link rel=\"stylesheet\" href=\"{{ '/css/Parent/css/premiercnx.css' }}\" />
  6952. <link href=\"{{ asset('css/Parent/css/detailsejour.css') }}\" type=\"text/css\" rel=\"stylesheet\" />
  6953. <link rel=\"stylesheet\" href=\"{{ '/css/Accompagnateur/imgzoom.css' }}\" />
  6954. <link rel=\"stylesheet\" href=\"{{ asset('Plugins/css/dropzone.css') }}\" />
  6955. <link rel=\"stylesheet\" href=\"{{ asset('css/splide.min.css') }}\" />
  6956. <link rel=\"stylesheet\" href=\"{{ asset('css/favorites-sidebar.css') }}\" />
  6957. {% set destination = \"detailsejour\" %}
  6958. <style>
  6959. .btn-close {
  6960.   font-size: 1.2rem;
  6961.      border: none;
  6962.     background: transparent;
  6963. }
  6964. .slide img {
  6965.   max-width: 100%;
  6966.   max-height: 100%;
  6967.   object-fit: contain;
  6968.   border-radius: 8px;
  6969.   box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
  6970.   transition: transform 0.3s ease;
  6971.   cursor: pointer;
  6972. }
  6973. .slide img.zoomed {
  6974.   transform: scale(1.5);
  6975.   cursor: zoom-in;
  6976. }
  6977. </style>
  6978. {% endblock %} {% set pageMenu = app.session.get('pageMenu') %} {% block Content
  6979. %}
  6980. {# CRO layers for parent page #}
  6981. {% include 'components/parents/_cro_layers.html.twig' with { sejour: sejour, ctx: ctx|default({}) } %}
  6982. <!-- Alerte pour inciter à acheter -->
  6983. <div id=\"purchase-alert\" class=\"purchase-alert hidden\" style=\"display: none;\">
  6984.   <button class=\"close-btn\" onclick=\"closePurchaseAlert()\">&times;</button>
  6985.   <div id=\"purchase-alert-content\">
  6986.     <!-- Le contenu de l'alerte sera mis à jour dynamiquement en fonction du nombre de favoris -->
  6987.   </div>
  6988. </div>
  6989. <div
  6990.   id=\"verifImg\"
  6991.   class=\"modal fade\"
  6992.   role=\"dialog\"
  6993.   style=\"background-color: rgba(112, 112, 112, 0.56); z-index: 1000000\"
  6994. >
  6995. </div>
  6996. <div class=\"main-content\">
  6997.   <div class=\"row no-margin\">
  6998.     <!-- Bouton cadeau attractif e-commerce -->
  6999.     <div
  7000.       class=\"gift-button\"
  7001.       id=\"gift-button-trigger\"
  7002.       style=\"cursor: pointer;\"
  7003.     >
  7004.       <i id=\"gift-icon-payment\" class=\"bi bi-gift gift-pulse\"></i>
  7005.       <label
  7006.         id=\"giftCount\"
  7007.         class=\"labelGiftCount gift-count-bounce\"
  7008.         style=\"background-color: #f56040\"
  7009.       >
  7010.         {{ likes | length }}
  7011.       </label>
  7012.       <!-- Message flottant attractif -->
  7013.       <div class=\"gift-tooltip\" id=\"giftTooltip\">
  7014.         <div class=\"gift-tooltip-content\">
  7015.           <div class=\"gift-tooltip-header\">
  7016.             <i class=\"bi bi-clock-history\"></i>
  7017.             <strong>Offre limitée !</strong>
  7018.           </div>
  7019.           <p>Commandez vite ! Les photos seront disponibles seulement pendant <strong>6 semaines</strong> après la fin du séjour.</p>
  7020.           <div class=\"gift-tooltip-cta\">
  7021.             <i class=\"bi bi-lightning-charge\"></i>
  7022.             Commander maintenant
  7023.           </div>
  7024.         </div>
  7025.       </div>
  7026.     </div>
  7027.     <!-- Sidebar E-commerce -->
  7028.     <div id=\"ecommerce-sidebar\">
  7029.       <div class=\"ecommerce-header\">
  7030.         <h2 class=\"ecommerce-title\" id=\"ecommerce-title\">
  7031.           🎉 Vos souvenirs favoris sont prêts !
  7032.         </h2>
  7033.         <p class=\"ecommerce-subtitle\" id=\"ecommerce-subtitle\">
  7034.           {{ likes | length }} photos sélectionnées avec amour ❤️
  7035.         </p>
  7036.         <button class=\"ecommerce-close\" onclick=\"closeEcommerceSidebar()\">
  7037.           <i class=\"bi bi-x\"></i>
  7038.         </button>
  7039.       </div>
  7040.       <div class=\"ecommerce-content\">
  7041.         <!-- Bannière d'urgence -->
  7042.         <div class=\"urgency-banner\" id=\"urgency-banner\">
  7043.           <div>
  7044.             <i class=\"bi bi-clock-history\"></i>
  7045.             <strong>⏳ Commandez vite !</strong>
  7046.           </div>
  7047.           <div>Vos photos seront disponibles seulement <strong>6 semaines</strong> après la fin du séjour</div>
  7048.           <div class=\"countdown\" id=\"countdown-timer\" style=\"display: none;\">
  7049.             Plus que <span id=\"days-left\">0</span> jours !
  7050.           </div>
  7051.         </div>
  7052.         <!-- Produits recommandés -->
  7053.         <div id=\"products-container\">
  7054.           <!-- Album Photo -->
  7055.           <div class=\"product-card popular\">
  7056.             <div class=\"product-header\">
  7057.               <div class=\"product-icon\">
  7058.                 <img src=\"/images/produit/Album5sur5-3.jpg\" alt=\"Album Photo Premium\" style=\"width: 100%; height: 100%; object-fit: contain; border-radius: 8px;\">
  7059.               </div>
  7060.               <div class=\"product-info\">
  7061.                 <h4>Album Photo Premium</h4>
  7062.                 <div class=\"product-pricing\">
  7063.                   <span class=\"current-price\">24,90€</span>
  7064.                   <span class=\"original-price\">28,90€</span>
  7065.                   <span class=\"savings\">-14%</span>
  7066.                 </div>
  7067.               </div>
  7068.               <div class=\"product-favorites-indicator\" title=\"Photos favorites sélectionnées\">
  7069.                 <i class=\"bi bi-heart-fill\" style=\"color: #f56040\"></i>
  7070.                 <span id=\"album-fav-count\">{{ likes | length }}</span>
  7071.               </div>
  7072.             </div>
  7073.             <p class=\"product-description\">
  7074.               Album photo personnalisé avec vos <strong id=\"album-count\">{{ likes | length }}</strong> photos favorites. Papier de qualité supérieure, reliure rigide.
  7075.             </p>
  7076.             <button class=\"product-cta\" onclick=\"orderProduct('album')\" 
  7077.                     title=\"Commander l'album photo avec vos photos favorites\">
  7078.               <i class=\"bi bi-cart-plus\"></i>
  7079.               Commander l'album
  7080.             </button>
  7081.           </div>
  7082.           <!-- Pack Numérique -->
  7083.           <div class=\"product-card\">
  7084.             <div class=\"product-header\">
  7085.               <div class=\"product-icon\">
  7086.                 <img src=\"/images/produit/photoNumerique.jpg\" alt=\"Pack Numérique HD\" style=\"width: 100%; height: 100%; object-fit: contain; border-radius: 8px;\">
  7087.               </div>
  7088.               <div class=\"product-info\">
  7089.                 <h4>Pack Numérique HD</h4>
  7090.                 <p class=\"price\">À partir de 3,90€</p>
  7091.               </div>
  7092.                 <div class=\"product-favorites-indicator\" title=\"Photos favorites sélectionnées\">
  7093.                   <i class=\"bi bi-heart-fill\" style=\"color: #f56040\"></i>
  7094.                   <span id=\"digital-fav-count\">{{ likes | length }}</span>
  7095.                 </div>
  7096.             </div>
  7097.             <p class=\"product-description\">
  7098.               Téléchargement immédiat de vos <strong id=\"digital-count\">{{ likes | length }}</strong> photos en haute définition. Qualité professionnelle garantie.
  7099.             </p>
  7100.             <button class=\"product-cta\" onclick=\"orderProduct('digital')\" 
  7101.                     title=\"Télécharger vos photos en haute définition\">
  7102.               <i class=\"bi bi-download\"></i>
  7103.               Télécharger HD
  7104.             </button>
  7105.           </div>
  7106.           <!-- Pochette Tirages -->
  7107.           <div class=\"product-card\" id=\"prints-card\" style=\"display: none;\">
  7108.             <div class=\"product-header\">
  7109.               <div class=\"product-icon\">
  7110.                 <i class=\"bi bi-images\"></i>
  7111.               </div>
  7112.               <div class=\"product-info\">
  7113.                 <h4>Pochette Tirages</h4>
  7114.                 <p class=\"price\">À partir de 9,90€</p>
  7115.               </div>
  7116.             </div>
  7117.             <p class=\"product-description\">
  7118.               <strong id=\"prints-count\">12</strong> tirages photo 10x15cm de vos favoris. Papier brillant professionnel, envoi sous 48h.
  7119.             </p>
  7120.             <button class=\"product-cta\" onclick=\"orderProduct('prints')\" 
  7121.                     title=\"Commander des tirages photo de vos favoris\">
  7122.               <i class=\"bi bi-printer\"></i>
  7123.               Commander les tirages
  7124.             </button>
  7125.           </div>
  7126.         </div>
  7127.         <!-- Réassurance -->
  7128.         <div class=\"reassurance\">
  7129.           <i class=\"bi bi-shield-check\" style=\"color: #10b981; margin-right: 8px;\"></i>
  7130.           <strong>Imprimé par l'équipe 5sur5 – satisfaction garantie ✅</strong>
  7131.         </div>
  7132.         
  7133.       </div>
  7134.     </div>
  7135.     <div class=\"selection-popover\" id=\"selectionPopover\">
  7136.       <h4>Votre sélection</h4>
  7137.       <p>Tirages : {{ likes | length }} / 12</p>
  7138.       <p>Numériques : {{ likes | length }} / 15</p>
  7139.       <p>Album : {{ likes | length }} / 20</p>
  7140.       <button class=\"finalize-button\" onclick=\"openEcommerceSidebar()\" 
  7141.               title=\"Voir les produits disponibles avec vos favoris\">
  7142.         <i class=\"bi bi-gift\"></i>
  7143.         Finaliser ma commande
  7144.       </button>
  7145.     </div>
  7146.     
  7147.     <style>
  7148.       /* Amélioration des boutons de produits */
  7149.       .product-cta {
  7150.         background: #3a8d95;
  7151.         border: none;
  7152.         border-radius: 25px;
  7153.         color: white;
  7154.         padding: 12px 24px;
  7155.         font-weight: 600;
  7156.         cursor: pointer;
  7157.         transition: all 0.3s ease;
  7158.         display: flex;
  7159.         align-items: center;
  7160.         gap: 8px;
  7161.         width: 100%;
  7162.         justify-content: center;
  7163.         margin-top: 10px;
  7164.       }
  7165.       
  7166.       .product-cta:hover {
  7167.         transform: translateY(-2px);
  7168.         box-shadow: 0 5px 15px rgba(58, 141, 149, 0.4);
  7169.         background: #2f7a82;
  7170.       }
  7171.       
  7172.       .product-cta:active {
  7173.         transform: translateY(0);
  7174.       }
  7175.       
  7176.       .product-cta:disabled {
  7177.         background: #ccc;
  7178.         cursor: not-allowed;
  7179.         transform: none;
  7180.         box-shadow: none;
  7181.       }
  7182.       
  7183.       .finalize-button {
  7184.         background: linear-gradient(135deg, #e91e63 0%, #ad1457 100%);
  7185.         border: none;
  7186.         border-radius: 25px;
  7187.         color: white;
  7188.         padding: 12px 24px;
  7189.         font-weight: 600;
  7190.         cursor: pointer;
  7191.         transition: all 0.3s ease;
  7192.         display: flex;
  7193.         align-items: center;
  7194.         gap: 8px;
  7195.         width: 100%;
  7196.         justify-content: center;
  7197.         margin-top: 15px;
  7198.       }
  7199.       
  7200.       .finalize-button:hover {
  7201.         transform: translateY(-2px);
  7202.         box-shadow: 0 5px 15px rgba(233, 30, 99, 0.4);
  7203.         background: linear-gradient(135deg, #d81b60 0%, #9c1450 100%);
  7204.       }
  7205.       
  7206.       /* Amélioration des cartes de produits */
  7207.       .product-card {
  7208.         border-radius: 12px;
  7209.         box-shadow: 0 4px 15px rgba(0,0,0,0.1);
  7210.         transition: all 0.3s ease;
  7211.         margin-bottom: 20px;
  7212.         overflow: hidden;
  7213.       }
  7214.       
  7215.       .product-card:hover {
  7216.         transform: translateY(-5px);
  7217.         box-shadow: 0 8px 25px rgba(0,0,0,0.15);
  7218.       }
  7219.       
  7220.       .product-header {
  7221.         display: flex;
  7222.         align-items: center;
  7223.         gap: 15px;
  7224.         padding: 20px;
  7225.         background: #f8f9fa;
  7226.       }
  7227.       
  7228.       .product-icon {
  7229.         width: 60px;
  7230.         height: 60px;
  7231.         border-radius: 8px;
  7232.         overflow: hidden;
  7233.         flex-shrink: 0;
  7234.       }
  7235.       
  7236.       .product-info h4 {
  7237.         margin: 0 0 5px 0;
  7238.         color: #333;
  7239.         font-weight: 600;
  7240.       }
  7241.       
  7242.       .product-pricing {
  7243.         display: flex;
  7244.         align-items: center;
  7245.         gap: 10px;
  7246.         margin: 5px 0;
  7247.       }
  7248.       
  7249.       .current-price {
  7250.         font-size: 1.2rem;
  7251.         font-weight: 700;
  7252.         color: #e91e63;
  7253.       }
  7254.       
  7255.       .original-price {
  7256.         text-decoration: line-through;
  7257.         color: #666;
  7258.         font-size: 0.9rem;
  7259.       }
  7260.       
  7261.       .savings {
  7262.         background: #4caf50;
  7263.         color: white;
  7264.         padding: 2px 8px;
  7265.         border-radius: 12px;
  7266.         font-size: 0.8rem;
  7267.         font-weight: 600;
  7268.       }
  7269.       
  7270.       .product-description {
  7271.         padding: 0 20px 20px 20px;
  7272.         color: #666;
  7273.         line-height: 1.5;
  7274.       }
  7275.       
  7276.       .product-favorites-indicator {
  7277.         display: flex;
  7278.         align-items: center;
  7279.         gap: 5px;
  7280.         background: rgba(245, 96, 64, 0.1);
  7281.         padding: 5px 10px;
  7282.         border-radius: 15px;
  7283.         font-size: 0.9rem;
  7284.         color: #f56040;
  7285.         font-weight: 600;
  7286.       }
  7287.     </style>
  7288.   </div>
  7289.   <div class=\"divSliderModern\">
  7290.     <input type=\"hidden\" id=\"nbFavCurrent\" value=\"{{ nblikes }}\" />
  7291.    <input  id=\"likeCount\" type=\"hidden\" value=\"{{ nblikes }}\" />
  7292.     <div
  7293.       class=\"splide no-padding no-margin\"
  7294.       id=\"imageSlider\"
  7295.       style=\"max-height: 200px\"
  7296.     >
  7297.       <div class=\"splide__track\">
  7298.         <ul class=\"splide__list\">
  7299.           <!-- Slide 1 -->
  7300.           <li class=\"splide__slide\">
  7301.             <div class=\"slider-content\" style=\"background: white\">
  7302.               <div class=\"namePRD\" style=\"display: block\">
  7303.                 <h4
  7304.                   class=\"titleProdbienvenu titleProdbienvenu1\"
  7305.                   style=\"color: #41a2aa\"
  7306.                 >
  7307.                   Ajoutez vos favoris dès maintenant
  7308.                 </h4>
  7309.                 <h4
  7310.                   class=\"titleProdbienvenu titleProdbienvenu2\"
  7311.                   style=\"color: #f09e7a\"
  7312.                 >
  7313.                   et profitez de nos produits souvenirs personnalisés !
  7314.                 </h4>
  7315.               </div>
  7316.               <img
  7317.                 src=\"{{ asset('/images/imgSliderEmpty2.png') }}\"
  7318.                 class=\"imgslider\"
  7319.                 alt=\"Image 1\"
  7320.               />
  7321.             </div>
  7322.           </li>
  7323.           <!-- Slide 2 -->
  7324.           <li class=\"splide__slide\">
  7325.             <div class=\"slider-content\" style=\"background: white\">
  7326.               <div class=\"namePRD\" style=\"display: block\">
  7327.                 <h4
  7328.                   class=\"titleProdbienvenu titleProdbienvenu1\"
  7329.                   style=\"color: #f09e7a\"
  7330.                 >
  7331.                   Pensez à commander le livre du séjour
  7332.                 </h4>
  7333.                 <h4
  7334.                   class=\"titleProdbienvenu titleProdbienvenu2\"
  7335.                   style=\"color: #41a2aa\"
  7336.                 >
  7337.                   et offrez lui le plus beau des cadeaux !
  7338.                 </h4>
  7339.               </div>
  7340.               <img
  7341.                 src=\"{{ asset('/images/imgSliderEmpty1.png') }}\"
  7342.                 class=\"imgslider\"
  7343.                 alt=\"Image 2\"
  7344.               />
  7345.             </div>
  7346.           </li>
  7347.         </ul>
  7348.       </div>
  7349.     </div>
  7350.   </div>
  7351.   <!-- Section de contenu à atteindre après le scroll -->
  7352.   <div
  7353.     class=\"no-margin\"
  7354.     id=\"scrollTarget\"
  7355.     style=\"width: 100%; background: #f9f9f9; padding-top: 30px\"
  7356.   >
  7357.     <div class=\"no-margin\" id=\"scrollTarget\" style=\"width: 100%\">
  7358.       <!-- Header compact 2 bandes -->
  7359.       <div class=\"header-restructured\">
  7360.         <!-- Ligne 1: Icône + Titre + Stats (alignés) -->
  7361.         <div class=\"header-line-1\">
  7362.           <div class=\"header-content\">
  7363.             <img src=\"/Accueil/imagesAccueil/sejour.png\" alt=\"Icône séjour\" width=\"40\" height=\"40\">
  7364.             <h1 class=\"titreDetailSej\" style=\"display:flex; align-items:center; gap:10px;\">Séjour {{ sejour.themSejour }}
  7365.               <button id=\"croTestAll\" class=\"btn btn-sm btn-outline-secondary d-none\">
  7366.                 Tester CRO
  7367.               </button>
  7368.             </h1>
  7369.             <nav class=\"header-pills\" aria-label=\"Statistiques du séjour\">
  7370.              
  7371.                
  7372.               <button id=\"filtre_photos_voir\" class=\"pill stat-pill\" data-filter=\"photos\" aria-label=\"Voir {{ attachementsCount }} photos et vidéos partagées\">
  7373.                 <i class=\"bi bi-images\"></i> {{ attachementsCount }}
  7374.               </button>
  7375.               <button class=\"pill stat-pill\" data-filter=\"audios\" aria-label=\"Voir {{ nbmessages }} messages audio enregistrés\">
  7376.                 <i class=\"bi bi-mic-fill\"></i> {{ nbmessages }}
  7377.               </button>
  7378.               <button class=\"pill stat-pill\" data-filter=\"favoris\" aria-label=\"Voir {{ nblikes }} contenus marqués en favoris\">
  7379.                 <i class=\"bi bi-heart-fill\"></i> {{ nblikes }}
  7380.               </button>
  7381.             </nav>
  7382.           </div>
  7383.         </div>
  7384.         <!-- Ligne 2: Dates (gris clair) -->
  7385.         <div class=\"header-line-2\">
  7386.           du {{ sejour.dateDebutSejour|date(\"d M Y\")|replace({\"Jan\": \"janv.\", \"Feb\": \"févr.\", \"Mar\": \"mars\", \"Apr\": \"avr.\", \"May\": \"mai\", \"Jun\": \"juin\", \"Jul\": \"juil.\", \"Aug\": \"août\", \"Sep\": \"sept.\", \"Oct.\": \"oct.\", \"Nov.\": \"nov.\", \"Dec.\": \"déc.\"}) }}
  7387.           au {{ sejour.dateFinSejour|date(\"d M Y\")|replace({\"Jan\": \"janv.\", \"Feb\": \"févr.\", \"Mar\": \"mars\", \"Apr\": \"avr.\", \"May\": \"mai\", \"Jun\": \"juin\", \"Jul\": \"juil.\", \"Aug\": \"août\", \"Sep\": \"sept.\", \"Oct.\": \"oct.\", \"Nov.\": \"nov.\", \"Dec.\": \"déc.\"}) }}
  7388.           · Code&nbsp;: {{sejour.codeSejour}}
  7389.         </div>
  7390.         <!-- 🎯 MEDIA TOOLBAR CAPSULE (Senior UX) -->
  7391.         <nav class=\"media-toolbar\" aria-label=\"Filtres médias\">
  7392.           <div class=\"mtb-inner\" role=\"group\">
  7393.             <!-- Tout -->
  7394.             <button class=\"mtb-btn active\" data-filter=\"all\" title=\"Tout\">
  7395.               <i class=\"bi bi-grid-3x3-gap-fill\" aria-hidden=\"true\"></i>
  7396.               <span class=\"mtb-count\">Tout {{ attachementsCount }}</span>
  7397.             </button>
  7398.         
  7399.             <!-- Audios -->
  7400.             <button class=\"mtb-btn\" data-filter=\"audio\" title=\"Audios\">
  7401.              
  7402.        
  7403. <span class=\"icon-telephone-voicemail\" >
  7404.   <i class=\"bi bi-telephone-fill tel text-secandary\" style=\"color:#ffd700\"></i>
  7405.   <i class=\"bi bi-voicemail vm text-secandary\" style=\"color:#ffd700\"></i>
  7406. </span>
  7407.               <span class=\"mtb-count\" data-bind=\"audio\">0</span>
  7408.             </button>
  7409.           
  7410.    
  7411.             <!-- Favoris -->
  7412.             <button class=\"mtb-btn\" data-filter=\"favoris\" title=\"Favoris\">
  7413.               <i class=\"bi bi-heart-fill\" style=\"color:#f56040\" aria-hidden=\"true\"></i>
  7414.               <span class=\"mtb-count\" data-bind=\"fav\" id=\"mesFavCount\">{{ nblikes }}</span>
  7415.             </button>
  7416.                <!-- Photos -->
  7417.             <button class=\"mtb-btn\" data-filter=\"photos\" aria-pressed=\"false\" title=\"Voir toutes les photos\">
  7418.               <i class=\"bi bi-eye-fill\" aria-hidden=\"true\"></i>
  7419.           
  7420.             </button>
  7421.           </div>
  7422.         </nav>
  7423.         <!-- Navigation par jours -->
  7424.         <div class=\"section-days\">
  7425.           <div class=\"date-navigation\">
  7426.           
  7427.      
  7428.             <div class=\"date-container\">
  7429.               {% for x, groupAttach in listeattach %}
  7430.                 {% set xDate = date(x) %}
  7431.                 {% set finDate = date(sejour.dateFinSejour) %}
  7432.                 {% if xDate <= finDate %}
  7433.                   <div
  7434.                     class=\"date-card modern-card {% if loop.last and xDate <= finDate %} active {% endif %}\"
  7435.                     data-aos=\"fade-up\"
  7436.                     data-bs-toggle=\"collapse\"
  7437.                     data-day-id=\"{{ xDate|date('Y-m-d') }}\"
  7438.                     data-bs-target=\"#demP{{ loop.index }}\"
  7439.                     id=\"iconedemoP{{ loop.index }}\"
  7440.                     role=\"button\"
  7441.                     aria-label=\"Contenu du {{ xDate|date(\"d F Y\")|replace({
  7442.                       \"Jan\": \"janvier\", \"Feb\": \"février\", \"Mar\": \"mars\", \"Apr\": \"avril\",
  7443.                       \"May\": \"mai\", \"Jun\": \"juin\", \"Jul\": \"juillet\", \"Aug\": \"août\",
  7444.                       \"Sep\": \"septembre\", \"Oct\": \"octobre\", \"Nov\": \"novembre\", \"Dec\": \"décembre\"
  7445.                     }) }} : {{ groupAttach.countPhotos }} photos, {{ groupAttach.countAudio }} audios, {{ groupAttach.countVideos }} vidéos\"
  7446.                     tabindex=\"0\"
  7447.                   >
  7448.                     <div class=\"card-content\">
  7449.                       <span class=\"title-line\">
  7450.                       
  7451.                           <span class=\"full-date\">
  7452.                             {{ xDate|date(\"D\")|replace({
  7453.                                 \"Mon\": \"lun.\",\"Tue\": \"mar.\",\"Wed\": \"mer.\",\"Thu\": \"jeu.\",\"Fri\": \"ven.\",\"Sat\": \"sam.\",\"Sun\": \"dim.\"
  7454.                           }) }}
  7455.                         
  7456.                             {{ xDate|date(\"d M\")|replace({
  7457.                               \"Jan\": \"janv.\",\"Feb\": \"févr.\",\"Mar\": \"mars\",\"Apr\": \"avr.\",\"May\": \"mai\",\"Jun\": \"juin\",
  7458.                               \"Jul\": \"juil.\",\"Aug\": \"août\",\"Sep\": \"sept.\",\"Oct.\": \"oct.\",\"Nov.\": \"nov.\",\"Dec.\": \"déc.\"
  7459.                             }) }}
  7460.                              {% if groupAttach.isFirstDay == \"yes\" %}
  7461.                               <span class=\"day-badge first\">Début</span>
  7462.                             {% elseif groupAttach.isLastDay == \"yes\" %}
  7463.                               <span class=\"day-badge last\">Dernier</span>
  7464.                      
  7465.                          
  7466.                         {% endif %}
  7467.                       </span>
  7468.                       
  7469.                      
  7470.                           <span class=\"badge-new d-none\" aria-label=\"Nouveau contenu\"></span>
  7471.                     
  7472.                       </span>
  7473.                       <ul class=\"media-list-horizontal\">
  7474.                         {% if groupAttach.countPhotos > 0 %}
  7475.                         <li><i class=\"bi bi-images\"></i>{{ groupAttach.countPhotos }}</li>
  7476.                         {% endif %}
  7477.                         {% if groupAttach.countAudio > 0 %}
  7478.                         <li><span class=\"icon-telephone-voicemail\">
  7479.   <i class=\"bi bi-telephone-fill tel text-secandary\" style=\"color:#ffd700!important\"></i>
  7480.   <i class=\"bi bi-voicemail vm text-secandary\" style=\"color:#ffd700!important;  transform: translate(-8%, -46%);font-size:0.4rem!important\"></i>
  7481. </span>{{ groupAttach.countAudio }}</li>
  7482.                         {% endif %}
  7483.                         {% if groupAttach.countVideos > 0 %}
  7484.                         <li><i class=\"bi bi-camera-video-fill\"></i>{{ groupAttach.countVideos }}</li>
  7485.                         {% endif %}
  7486.                       </ul>
  7487.                     </div>
  7488.                   </div>
  7489.                 {% endif %}
  7490.               {% endfor %}
  7491.       </div>
  7492.     </div>
  7493.             </div>
  7494.           </div>
  7495.         </div>
  7496.     <!-- Carte produit flottante -->
  7497.     <div id=\"dynamic-card\" class=\"dynamic-card\" style=\"display:none\">
  7498.       <div id=\"dynamic-card-content\" class=\"dynamic-card-content\" >
  7499.         <!-- Le contenu dynamique (album, pochette, montage vidéo) sera injecté ici -->
  7500.       </div>
  7501.     </div>
  7502.     <!-- Descriptions and Attachments -->
  7503.     <div class=\"container--gallery modern\">
  7504.       {% set lastValidIndex = 0 %}
  7505.       {% set hasAttachments = false %}
  7506.       {% for x, groupAttach in listeattach %}
  7507.       {% set xDate = date(x) %}
  7508.       {% set finDate = date(sejour.dateFinSejour) %}
  7509.       {% if xDate <= finDate %}
  7510.       {% set lastValidIndex = loop.index %}
  7511.       {% set hasAttachments = true %}
  7512.       <div
  7513.         id=\"demP{{ loop.index }}\"
  7514.         class=\"collapse {% if loop.last and xDate <= finDate %}show{% endif %}\"
  7515.         style=\"padding: 2%; padding-top: 0%\"
  7516.       >
  7517.         <div class=\"journal-entry\">
  7518.         <div class=\"entry-header\" style=\"
  7519.     display: none;
  7520.     align-items: center;
  7521.     justify-content: space-between;
  7522.     background: #ffffff;
  7523.     padding: 8px 15px;
  7524.     border-radius: 10px;
  7525.     margin-bottom: 20px;
  7526.     box-shadow: 0 2px 8px rgba(0,0,0,0.05);
  7527.     border-bottom: 1px solid #eee;
  7528.     flex-wrap: wrap;
  7529. \">
  7530.  
  7531.  
  7532.   <!-- Centre : Date + Médias -->
  7533.   <div style=\"
  7534.       flex-grow: 1;
  7535.       display: flex;
  7536.       align-items: center;
  7537.       justify-content: center;
  7538.       flex-wrap: wrap;
  7539.       gap: 12px;
  7540.   \">
  7541.     <!-- Date -->
  7542.     <div style=\"font-weight: bold; font-size: 16px; color: #333;\">
  7543.       {{ x|date(\"l d F Y\")|replace({
  7544.           \"Monday\": \"Lundi\", \"Tuesday\": \"Mardi\", \"Wednesday\": \"Mercredi\",
  7545.           \"Thursday\": \"Jeudi\", \"Friday\": \"Vendredi\", \"Saturday\": \"Samedi\",
  7546.           \"Sunday\": \"Dimanche\",
  7547.           \"January\": \"Janvier\", \"February\": \"Février\", \"March\": \"Mars\",
  7548.           \"April\": \"Avril\", \"May\": \"Mai\", \"June\": \"Juin\",
  7549.           \"July\": \"Juillet\", \"August\": \"Août\", \"September\": \"Septembre\",
  7550.           \"October\": \"Octobre\", \"November\": \"Novembre\", \"December\": \"Décembre\"
  7551.       }) }}
  7552.     </div>
  7553.   <!-- Filtres Médias -->
  7554. <div class=\"filter-icons\" style=\"display: flex; gap: 8px; flex-wrap: wrap;\">
  7555.     <span class=\"filter-badge active\" data-filter=\"all\" title=\"Afficher tout\">
  7556.         <i class=\"bi bi-grid-3x3-gap-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> Tout
  7557.     </span>
  7558.     {% if groupAttach.countPhotos > 0 %}
  7559.     <span class=\"filter-badge\" data-filter=\"photo\" title=\"Filtrer les photos\">
  7560.         <i class=\"bi bi-image\" style=\"margin-right: 5px; font-size: 14px;\"></i> {{ groupAttach.countPhotos }}
  7561.     </span>
  7562.     {% endif %}
  7563.     {% if groupAttach.countVideos > 0 %}
  7564.     <span class=\"filter-badge\" data-filter=\"video\" title=\"Filtrer les vidéos\">
  7565.         <i class=\"bi bi-camera-video-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> {{ groupAttach.countVideos }}
  7566.     </span>
  7567.     {% endif %}
  7568.     {% if groupAttach.countAudio > 0 %}
  7569.     <span class=\"filter-badge\" data-filter=\"audio\" title=\"Filtrer les messages audio\">
  7570.         <i class=\"bi bi-mic-fill\" style=\"margin-right: 5px; font-size: 14px;\"></i> {{ groupAttach.countAudio }}
  7571.     </span>
  7572.     {% endif %}
  7573. </div>
  7574.   </div>
  7575.    
  7576.    
  7577.         </div>
  7578.   <!-- Bouton Jour Suivant -->
  7579.         <!-- Contenu -->
  7580.         <div class=\"entry-content\" id=\"TourContent\">
  7581.           <!-- Dropdown de filtrage par jour -->
  7582.           <div class=\"day-filter-dropdown\" data-day-index=\"{{ loop.index }}\">
  7583.             <button class=\"filter-toggle\" type=\"button\" aria-label=\"Options de filtrage\">
  7584.               <i class=\"bi bi-three-dots\"></i>
  7585.             </button>
  7586.             <div class=\"filter-dropdown-menu\">
  7587.               <div class=\"filter-option active\" data-filter=\"all\">
  7588.                 <i class=\"bi bi-grid-3x3-gap-fill\"></i>
  7589.                 <span>Tout</span>
  7590.                 <span class=\"count\" data-count-all>0</span>
  7591.               </div>
  7592.               <div class=\"filter-option\" data-filter=\"photo\">
  7593.                 <i class=\"bi bi-image\"></i>
  7594.                 <span>Photos</span>
  7595.                 <span class=\"count\" data-count-photo>{{ groupAttach.countPhotos|default(0) }}</span>
  7596.               </div>
  7597.               <div class=\"filter-option\" data-filter=\"video\">
  7598.                 <i class=\"bi bi-camera-video-fill\"></i>
  7599.                 <span>Vidéos</span>
  7600.                 <span class=\"count\" data-count-video>{{ groupAttach.countVideos|default(0) }}</span>
  7601.               </div>
  7602.               <div class=\"filter-option\" data-filter=\"audio\">
  7603.                 <i class=\"bi bi-mic-fill\"></i>
  7604.                 <span>Messages</span>
  7605.                 <span class=\"count\" data-count-audio>{{ groupAttach.countAudio|default(0) }}</span>
  7606.               </div>
  7607.             </div>
  7608.           </div>
  7609.       
  7610.           <p class=\"description\" style=\"margin-left:2%;width:95%;margin-top:1%;margin-bottom:1%;text-align:left\">
  7611.             {% for description in sejour.jourdescripdate %} {% if
  7612.             description.datejourphoto|date(\"m/d/Y\") == x|date(\"m/d/Y\") %}
  7613.             {{ description.description | nl2br }}
  7614.             {% endif %} {% endfor %}
  7615.           </p>
  7616.  
  7617.           <!-- Conteneur des photos et vidéos -->
  7618.           <div
  7619.             class=\"rowimag no-margin\"
  7620.             style=\"
  7621.               width: 100%;
  7622.               display: flex;
  7623.               flex-wrap: wrap;
  7624.               margin: 0;
  7625.               box-sizing: border-box;
  7626.             \"
  7627.           >
  7628.             <!-- Afficher les Photos et Vidéos -->
  7629.             {% for attach in groupAttach.attachments %}
  7630.               {% if attach.libiller == 'photo' %}
  7631.            
  7632.             <div class=\"column\" data-type=\"{{ attach.libiller }}\">
  7633.             
  7634.               <div class=\"photo-zoom photo-item\">
  7635.                 <!-- Image sans lien -->
  7636.                 <img src=\"{{ attach.path }}\" alt=\"{{ attach.descreption }}\" loading=\"lazy\" decoding=\"async\" />
  7637.                 <!-- Icône \"voir\" pour ouvrir le slider -->
  7638.                 <div class=\"view-icon\" onclick=\"viewImage('{{ attach.id_attchment }}', this)\" title=\"Voir en plein écran\">
  7639.                   <i class=\"bi bi-eye-fill\"></i>
  7640.                 </div>
  7641.                 <!-- Icône du cœur avec logique existante -->
  7642.                 <div
  7643.                   class=\"heart-icon\"
  7644.                   id=\"coeur{{ attach.id_attchment }}\"
  7645.                   data-id=\"{{ attach.id_attchment }}\"
  7646.                   data-sejour-id=\"{{ sejour.id }}\"
  7647.                   data-path=\"{{ attach.path }}\"
  7648.                   data-description=\"{{ attach.descreption }}\"
  7649.                 >
  7650.                   {% if app.user %} {% if attach.is_favorite %}
  7651.                   <i
  7652.                     class=\"bi bi-heart-fill\"
  7653.                     title=\"Sélectionnée\"
  7654.                     style=\"color: #f56040\"
  7655.                   ></i>
  7656.                   {% else %}
  7657.                   <i class=\"bi bi-heart\" title=\"Ajouter à ma sélection\"></i>
  7658.                   {% endif %} {% endif %}
  7659.                 </div>
  7660.                 <div class=\"photo-actions\" style=\"display: none\">
  7661.                   <button class=\"menu-btn\">⋮</button>
  7662.                   <div class=\"menu-options\">
  7663.                     <button onclick=\"addToPack('tirage')\">
  7664.                       🖨️ Ajouter au tirage
  7665.                     </button>
  7666.                     <button onclick=\"addToPack('numerique')\">
  7667.                       💾 Ajouter au numérique
  7668.                     </button>
  7669.                   </div>
  7670.                 </div>
  7671.               
  7672.               </div>
  7673.               {% if attach.descreption != \"\" %}
  7674.               <h4 class=\"description\">{{ attach.descreption }}</h4>
  7675.               {% endif %}
  7676.             </div>
  7677.             {% endif %} 
  7678.              {% if attach.libiller == 'video' %}
  7679.            
  7680.             <div class=\"column\" data-type=\"{{ attach.libiller }}\">
  7681.                  
  7682.             
  7683.                  <div class=\"video-container\" style=\"position: relative; display: inline-block; width: 100%; border-radius: 8px; overflow: hidden;\">
  7684.                         <video class=\"photo-zoom\" controls controlslist=\"nodownload noplaybackrate\" style=\"width: 100%;\">
  7685.                           <source src=\"{{ attach.path }}\" type=\"video/mp4\" />
  7686.                           Votre navigateur ne supporte pas la lecture vidéo.
  7687.                         </video>
  7688.                       
  7689.                       </div>
  7690.               {% if attach.descreption != \"\" %}
  7691.               <h4 class=\"description\">{{ attach.descreption }}</h4>
  7692.               {% endif %}
  7693.             </div>
  7694.             {% endif %} 
  7695.             
  7696.             {% endfor %}
  7697.           </div>
  7698.           <!-- Section séparée pour les messages audio -->
  7699.           {% if groupAttach.countAudio > 0 %}
  7700.           <div class=\"audio-messages-section\" style=\"margin-top:15px; border-top: 1px solid #eee; padding: 30px;\">
  7701.             <h4 style=\"margin-bottom: 15px; color: #555\">
  7702.             
  7703.               <i class=\"bi bi-mic-fill\" style=\"margin-right: 8px; color: #ffa500\"></i>
  7704.               Messages vocaux ({{ groupAttach.countAudio }})
  7705.             </h4>
  7706.             
  7707.             {% if sejour.codeSejour|slice(0, 2) == 'PF' %}
  7708.               {# Les séjours commençant par PF ont toujours accès #}
  7709.               <div class=\"audio-messages-container\" data-type=\"audio\" style=\"display: flex; flex-wrap: wrap; gap: 15px\">
  7710.                 {% for attach in groupAttach.attachments %}
  7711.                   {% if attach.libiller == 'message' %}
  7712.                     <div class=\"audio-message-item\" data-type=\"audio\" style=\"background: #f9f9f9; border-radius: 8px; padding: 12px; display: flex; flex-direction: column; width: calc(33.33% - 10px); min-width: 250px; flex-grow: 1;\">
  7713.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  7714.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  7715.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\">
  7716.                           <source src=\"{{ attach.path }}\" type=\"audio/mp3\" />
  7717.                           Votre navigateur ne supporte pas la lecture audio.
  7718.                         </audio>
  7719.                       </div>
  7720.                       {% if attach.descreption != \"\" %}
  7721.                         <div class=\"audio-description\" style=\"padding-left: 30px\">
  7722.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  7723.                             {{ attach.descreption }}
  7724.                           </p>
  7725.                         </div>
  7726.                       {% endif %}
  7727.                     </div>
  7728.                   {% endif %}
  7729.                 {% endfor %}
  7730.               </div>
  7731.             
  7732.             {% elseif sejour.codeSejour|slice(0, 2) == 'PP' and parentsejour.payment  == 1 or sejour.codeSejour|slice(0, 2) == 'EF' and parentsejour.payment  == 1 %}
  7733.               {# PP ou EF avec paiement effectué #}
  7734.               <div class=\"audio-messages-container\" data-type=\"audio\" style=\"display: flex; flex-wrap: wrap; gap: 15px\">
  7735.                 {% for attach in groupAttach.attachments %}
  7736.                   {% if attach.libiller == 'message' %}
  7737.                     <div class=\"audio-message-item\" data-type=\"audio\" style=\"background: #f9f9f9; border-radius: 8px; padding: 12px; display: flex; flex-direction: column; width: calc(33.33% - 10px); min-width: 250px; flex-grow: 1;\">
  7738.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  7739.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  7740.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\">
  7741.                           <source src=\"{{ attach.path }}\" type=\"audio/mp3\" />
  7742.                           Votre navigateur ne supporte pas la lecture audio.
  7743.                         </audio>
  7744.                       </div>
  7745.                       {% if attach.descreption != \"\" %}
  7746.                         <div class=\"audio-description\" style=\"padding-left: 30px\">
  7747.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  7748.                             {{ attach.descreption }}
  7749.                           </p>
  7750.                         </div>
  7751.                       {% endif %}
  7752.                     </div>
  7753.                   {% endif %}
  7754.                 {% endfor %}
  7755.               </div>
  7756.             
  7757.             {% elseif sejour.codeSejour|slice(0, 2) == 'PP' and parentsejour.payment == 0 or sejour.codeSejour|slice(0, 2) == 'EF' and parentsejour.payment == 0 %}
  7758.               {# PP ou EF sans paiement - message d'accès limité et audio désactivés #}
  7759.               <div class=\"audio-messages-container\" style=\"display: flex; flex-wrap: wrap; gap: 15px; opacity: 0.5; pointer-events: none; filter: grayscale(100%);\">
  7760.                 <div class=\"audio-messages-restricted\" data-type=\"audio\" style=\"padding: 20px; background: #f0f0f0; border-radius: 8px; text-align: center; margin-bottom: 15px; width: 100%;\">
  7761.                   <i class=\"bi bi-lock-fill\" style=\"font-size: 24px; color: #808080; margin-bottom: 10px;\"></i>
  7762.                   <p style=\"margin: 0; color: #555;\">📢 Les messages vocaux sont disponibles via la boîte vocale premium. Un paiement est requis pour l’activer et y accéder.</p>
  7763.                 </div>
  7764.                 {% for attach in groupAttach.attachments %}
  7765.                   {% if attach.libiller == 'message' %}
  7766.                     <div class=\"audio-message-item\" data-type=\"audio\" style=\"background: #f9f9f9; border-radius: 8px; padding: 12px; display: flex; flex-direction: column; width: calc(33.33% - 10px); min-width: 250px; flex-grow: 1;\">
  7767.                       <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 10px;\">
  7768.                         <i class=\"bi bi-mic-fill\" style=\"font-size: 20px; margin-right: 10px; color: #ffa500\"></i>
  7769.                         <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1\" disabled>
  7770.                           <source src=\"{{ attach.path }}\" type=\"audio/mp3\" />
  7771.                           Votre navigateur ne supporte pas la lecture audio.
  7772.                         </audio>
  7773.                       </div>
  7774.                       {% if attach.descreption != \"\" %}
  7775.                         <div class=\"audio-description\" style=\"padding-left: 30px\">
  7776.                           <p style=\"margin: 0; font-size: 14px; color: #555; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;\">
  7777.                             {{ attach.descreption }}
  7778.                           </p>
  7779.                         </div>
  7780.                       {% endif %}
  7781.                     </div>
  7782.                   {% endif %}
  7783.                 {% endfor %}
  7784.               </div>
  7785.             {% endif %}
  7786.           </div>
  7787.         {% endif %}
  7788.         </div>
  7789.       </div>
  7790.     </div>
  7791.     {% endif %}
  7792.     {% endfor %}
  7793.     {% if not hasAttachments %}
  7794.     <div class=\"welcome-message\" style=\"padding: 50px 20px; text-align: center; background: #f9f9f9; border-radius: 15px; margin: 30px auto; max-width: 800px; box-shadow: 0 5px 15px rgba(0,0,0,0.05);\">
  7795.       <img src=\"/images/welcome-icon.svg\" alt=\"Bienvenue\" style=\"width: 80px; margin-bottom: 20px;\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" onerror=\"this.src='/images/Accompagnateur/Picto5sur5.svg'; this.style.width='120px';\">
  7796.       
  7797.       <h2 style=\"color: #41a2aa; margin-bottom: 20px; font-size: 24px;\">Bienvenue sur votre espace séjour !</h2>
  7798.       
  7799.       <p style=\"font-size: 18px; color: #555; margin-bottom: 15px;\">
  7800.         Aucun contenu n'a encore été partagé pour ce séjour.
  7801.       </p>
  7802.       
  7803.       <p style=\"font-size: 16px; color: #666; margin-bottom: 25px;\">
  7804.         L'accompagnateur partagera bientôt des photos, vidéos et messages vocaux.
  7805.         <br>Revenez consulter cette page régulièrement pour suivre les aventures du séjour !
  7806.       </p>
  7807.       
  7808.       <div style=\"display: flex; justify-content: center; gap: 15px; flex-wrap: wrap;\">
  7809.         <div style=\"display: flex; align-items: center; background: #fff; padding: 15px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);\">
  7810.           <i class=\"bi bi-images\" style=\"font-size: 24px; color: #3a8d95; margin-right: 10px;\"></i>
  7811.           <span>Photos du séjour</span>
  7812.         </div>
  7813.         
  7814.         <div style=\"display: flex; align-items: center; background: #fff; padding: 15px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);\">
  7815.           <i class=\"bi bi-camera-video-fill\" style=\"font-size: 24px; color: #41a2aa; margin-right: 10px;\"></i>
  7816.           <span>Vidéos des activités</span>
  7817.         </div>
  7818.         
  7819.         <div style=\"display: flex; align-items: center; background: #fff; padding: 15px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);\">
  7820.           <i class=\"bi bi-mic-fill\" style=\"font-size: 24px; color: #ffa500; margin-right: 10px;\"></i>
  7821.           <span>Messages vocaux</span>
  7822.         </div>
  7823.       </div>
  7824.     </div>
  7825.     
  7826.     <!-- Espace supplémentaire pour déplacer le footer vers le bas -->
  7827.     <div style=\"height: 300px;\"></div>
  7828.     {% endif %}
  7829.     
  7830.     <!-- JavaScript pour les pills et la gestion du nouveau contenu -->
  7831.     <script>
  7832.       document.addEventListener('DOMContentLoaded', function() {
  7833.         // Valider les liens de produits au chargement
  7834.         setTimeout(() => {
  7835.           if (typeof window.validateProductLinks === 'function') {
  7836.             window.validateProductLinks();
  7837.           }
  7838.         }, 1000);
  7839.         
  7840.         // ⚡ OPTIMISATION: Event delegation avec throttling pour éviter les clics multiples
  7841.         let clickThrottleTimeout = null;
  7842.         document.addEventListener('click', function(e) {
  7843.           // Throttling pour éviter les clics multiples rapides
  7844.           if (clickThrottleTimeout) return;
  7845.           
  7846.           const pill = e.target.closest('.stat-pill');
  7847.           if (pill) {
  7848.             clickThrottleTimeout = setTimeout(() => {
  7849.               clickThrottleTimeout = null;
  7850.             }, 100);
  7851.             
  7852.             // ⚡ OPTIMISÉ: Une seule boucle pour gérer les états actifs
  7853.             const statPills = document.querySelectorAll('.stat-pill');
  7854.             for (let i = 0; i < statPills.length; i++) {
  7855.               const p = statPills[i];
  7856.               if (p && p.classList) {
  7857.                 if (p === pill) {
  7858.                   p.classList.add('active');
  7859.                 } else {
  7860.                   p.classList.remove('active');
  7861.                 }
  7862.               }
  7863.             }
  7864.             
  7865.             // Déclencher le filtrage du contenu
  7866.             const filter = pill.getAttribute('data-filter');
  7867.             if (typeof window.filterContent === 'function') {
  7868.               window.filterContent(filter);
  7869.             }
  7870.           }
  7871.         });
  7872.         // Fonction de filtrage du contenu - globale
  7873.         window.filterContent = function(filter) {
  7874.           // ⚡ OPTIMISÉ: Suppression des console.log en production
  7875.           if (window.location.hostname === 'localhost' || window.location.hostname.includes('dev')) {
  7876.             console.log('Filtrage par:', filter);
  7877.           }
  7878.           
  7879.           const dateNavigation = document.querySelector('.date-navigation');
  7880.           const sectionDays = document.querySelector('.section-days');
  7881.           
  7882.           if (filter === 'favoris') {
  7883.             // Afficher la vue des favoris
  7884.             showFavoritesView();
  7885.           } else if (filter === 'audio') {
  7886.             // Afficher la vue des messages audio
  7887.             showAudiosView();
  7888.           } else if (filter === 'photos') {
  7889.             // Ouvrir le carrousel du jour actif ou du dernier jour
  7890.             openCurrentDayCarousel();
  7891.           } else {
  7892.             // Restaurer la vue normale des jours
  7893.             showDaysView();
  7894.           }
  7895.         }
  7896.         // Fonction pour afficher la vue des favoris - globale
  7897.         window.showFavoritesView = function() {
  7898.           const sectionDays = document.querySelector('.section-days');
  7899.           const containerGallery = document.querySelector('.container--gallery');
  7900.           
  7901.           // Masquer le container gallery
  7902.           if (containerGallery) {
  7903.             containerGallery.style.display = 'none';
  7904.           }
  7905.           
  7906.           // Mettre à jour l'état des boutons
  7907.           updatePhotosButtonState('favorites');
  7908.           updateAudioButtonState('favorites');
  7909.           updateFavoritesButtonState('favorites');
  7910.           
  7911.           const favoriteCount = getCurrentFavoriteCount();
  7912.           
  7913.           // sla vue des favoris avec e-commerce
  7914.           const favoritesHTML = `
  7915.             <div class=\"favorites-ecommerce-view\">
  7916.               <!-- Header avec progression -->
  7917.               <div class=\"favorites-header\">
  7918.                 <div class=\"favorites-title\">
  7919.                   <h3>Vos souvenirs sélectionnés</h3>
  7920.                   <span class=\"favorites-count\" id=\"favorites-count\">\${favoriteCount} photos</span>
  7921.                 </div>
  7922.                 <button class=\"btn-back-to-days\" onclick=\"window.showDaysView()\">
  7923.                   <i class=\"bi bi-arrow-left\"></i>
  7924.                   Retour aux jours
  7925.                 </button>
  7926.               </div>
  7927.             
  7928.               <!-- Grille des favoris -->
  7929.               <div class=\"favorites-content\">
  7930.                 <div class=\"favorites-grid\" id=\"favoritesGrid\">
  7931.                   \${generateFavoritesGrid()}
  7932.                 </div>
  7933.                 
  7934.                 <!-- Propositions de produits -->
  7935.                 <div class=\"product-suggestions\">
  7936.                   \${generateProductSuggestions(favoriteCount)}
  7937.                 </div>
  7938.               </div>
  7939.             </div>
  7940.           `;
  7941.           
  7942.           sectionDays.innerHTML = favoritesHTML;
  7943.         }
  7944.         // Fonction pour afficher la vue des messages audio - globale
  7945.         window.showAudiosView = function() {
  7946.           const sectionDays = document.querySelector('.section-days');
  7947.           const containerGallery = document.querySelector('.container--gallery');
  7948.           
  7949.           // Masquer le container gallery
  7950.           if (containerGallery) {
  7951.             containerGallery.style.display = 'none';
  7952.           }
  7953.           
  7954.           // Mettre à jour l'état des boutons
  7955.           updatePhotosButtonState('audios');
  7956.           updateAudioButtonState('audios');
  7957.           updateFavoritesButtonState('audios');
  7958.           
  7959.           // Collecter tous les messages audio de tous les jours
  7960.           const allAudioMessages = [];
  7961.           const audioItems = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  7962.           
  7963.           audioItems.forEach(item => {
  7964.             const audio = item.querySelector('audio source');
  7965.             const description = item.querySelector('.audio-description p');
  7966.             const dayContainer = item.closest('[id^=\"demP\"]');
  7967.             let dayTitle = 'Jour inconnu';
  7968.             
  7969.             if (dayContainer) {
  7970.               // Trouver le titre du jour
  7971.               const dayIndex = dayContainer.id.replace('demP', '');
  7972.               const dayCard = document.querySelector(`[data-target=\"#demP\${dayIndex}\"]`);
  7973.               if (dayCard) {
  7974.                 dayTitle = dayCard.textContent.trim();
  7975.               } else {
  7976.                 // Essayer de trouver dans les cartes de date
  7977.                 const dateCard = document.querySelector(`.date-card[data-bs-target=\"#demP\${dayIndex}\"], .date-card[data-target=\"#demP\${dayIndex}\"]`);
  7978.                 if (dateCard) {
  7979.                   const dateText = dateCard.querySelector('.date-text, .card-title, h5, .title-line');
  7980.                   if (dateText) {
  7981.                     dayTitle = dateText.textContent.trim();
  7982.                   }
  7983.                 }
  7984.               }
  7985.             }
  7986.             
  7987.             if (audio) {
  7988.               allAudioMessages.push({
  7989.                 src: audio.src,
  7990.                 description: description ? description.textContent.trim() : '',
  7991.                 day: dayTitle,
  7992.                 isRestricted: item.closest('.audio-messages-container[style*=\"opacity: 0.5\"]') !== null
  7993.               });
  7994.             }
  7995.           });
  7996.           
  7997.           // Créer la vue des messages audio
  7998.           const audiosHTML = `
  7999.             <div class=\"audios-view\">
  8000.               <!-- Header -->
  8001.               <div class=\"audios-header\" style=\"display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; padding: 20px; background: #f8f9fa; border-radius: 10px;\">
  8002.                 <div class=\"audios-title\">
  8003.                   <h3><span class=\"icon-telephone-voicemail\">
  8004.   <i class=\"bi bi-telephone-fill tel\"  style=\"color: #ffd700;font-size:1.5em\"></i>
  8005.   <i class=\"bi bi-voicemail vm\" style=\"color: #ffd700;font-size: 0.9rem;
  8006.     transform: translate(-40%, -46%);\"></i>
  8007. </span>
  8008.                   <span class=\"audios-count\">\${allAudioMessages.length} messages</span>
  8009.                 </div>
  8010.                 <button class=\"btn-back-to-days\" onclick=\"window.showDaysView()\" style=\"background: #6c757d; color: white; border: none; padding: 8px 16px; border-radius: 5px; cursor: pointer;\">
  8011.                   <i class=\"bi bi-arrow-left\"></i>
  8012.                   Retour aux jours
  8013.                 </button>
  8014.               </div>
  8015.               <!-- Grille des messages audio -->
  8016.               <div class=\"audios-content\" style=\"display: flex; flex-wrap: wrap; gap: 20px;\">
  8017.                 \${allAudioMessages.map(msg => `
  8018.                   <div class=\"audio-message-card\" style=\"background: #f9f9f9; border-radius: 12px; padding: 20px; width: calc(50% - 10px); min-width: 300px; \${msg.isRestricted ? 'opacity: 0.5; filter: grayscale(100%);' : ''}\">
  8019.                     \${msg.day && msg.day !== 'Jour inconnu' ? `
  8020.                       <div class=\"audio-day-tag\" style=\"background: #e9ecef; color: #495057; padding: 4px 8px; border-radius: 15px; font-size: 12px; margin-bottom: 12px; display: inline-block;\">
  8021.                         \${msg.day}
  8022.                       </div>
  8023.                     ` : ''}
  8024.                     <div class=\"audio-player-container\" style=\"display: flex; align-items: center; margin-bottom: 12px;\">
  8025.                       <i class=\"bi bi-mic-fill\" style=\"font-size: 24px; margin-right: 15px; color: #ffa500;\"></i>
  8026.                       <audio controls controlslist=\"nodownload noplaybackrate\" style=\"flex: 1; border-radius: 5px;\" \${msg.isRestricted ? 'disabled' : ''}>
  8027.                         <source src=\"\${msg.src}\" type=\"audio/mp3\" />
  8028.                         Votre navigateur ne supporte pas la lecture audio.
  8029.                       </audio>
  8030.                     </div>
  8031.                     \${msg.description ? `
  8032.                       <div class=\"audio-description\" style=\"padding-left: 39px;\">
  8033.                         <p style=\"margin: 0; font-size: 14px; color: #666; line-height: 1.4;\">\${msg.description}</p>
  8034.                       </div>
  8035.                     ` : ''}
  8036.                     \${msg.isRestricted ? `
  8037.                       <div class=\"audio-restricted-notice\" style=\"text-align: center; margin-top: 10px; padding: 8px; background: #fff3cd; border-radius: 5px; border: 1px solid #ffeaa7;\">
  8038.                         <i class=\"bi bi-lock-fill\" style=\"color: #856404; margin-right: 5px;\"></i>
  8039.                         <small style=\"color: #856404;\">Accès premium requis</small>
  8040.                       </div>
  8041.                     ` : ''}
  8042.                   </div>
  8043.                 `).join('')}
  8044.               </div>
  8045.               
  8046.               \${allAudioMessages.length === 0 ? `
  8047.                 <div class=\"no-audios\" style=\"text-align: center; padding: 60px 20px; color: #6c757d;\">
  8048.                   <i class=\"bi bi-mic\" style=\"font-size: 4rem; margin-bottom: 20px; opacity: 0.3;\"></i>
  8049.                   <h4>Aucun message vocal</h4>
  8050.                   <p>Il n'y a pas encore de messages vocaux dans ce séjour.</p>
  8051.                 </div>
  8052.               ` : ''}
  8053.             </div>
  8054.           `;
  8055.           
  8056.           sectionDays.innerHTML = audiosHTML;
  8057.         }
  8058.         
  8059.         // Variables pour sauvegarder le contenu original
  8060.         let originalDaysContent = null;
  8061.         
  8062.         // Sauvegarder le contenu original au chargement
  8063.         document.addEventListener('DOMContentLoaded', function() {
  8064.           setTimeout(() => {
  8065.             const containerGallery = document.querySelector('.container--gallery');
  8066.             if (containerGallery) {
  8067.               originalDaysContent = containerGallery.outerHTML;
  8068.             }
  8069.           }, 1000);
  8070.         });
  8071.         
  8072.       
  8073.         // Fonction pour ouvrir le carrousel contextuel - globale
  8074.         window.openCurrentDayCarousel = function() {
  8075.           // Détecter la vue active
  8076.           const currentView = detectCurrentView();
  8077.           
  8078.           switch (currentView) {
  8079.             case 'favorites':
  8080.               openFavoritesCarousel();
  8081.               break;
  8082.             case 'audios':
  8083.               // Dans la vue audios, pas de carrousel photos pertinent
  8084.               console.log('Carrousel photos non disponible dans la vue audios');
  8085.               return;
  8086.             case 'days':
  8087.             default:
  8088.               openActiveDayCarousel();
  8089.               break;
  8090.           }
  8091.         }
  8092.         
  8093.         // Fonction pour mettre à jour l'état du bouton photos selon le contexte
  8094.         function updatePhotosButtonState(currentView) {
  8095.           const photosBtn = document.querySelector('.mtb-btn[data-filter=\"photos\"]');
  8096.           if (!photosBtn) return;
  8097.           
  8098.           const btnIcon = photosBtn.querySelector('i');
  8099.           const btnCount = photosBtn.querySelector('.mtb-count');
  8100.           
  8101.           switch (currentView) {
  8102.             case 'favorites':
  8103.               // Dans les favoris : bouton actif, ouvre le carrousel des favoris
  8104.               photosBtn.style.opacity = '1';
  8105.               photosBtn.style.pointerEvents = 'auto';
  8106.               photosBtn.title = 'Voir le carrousel des favoris';
  8107.               if (btnIcon) btnIcon.style.color = '#007bff';
  8108.               if (btnCount) btnCount.style.display = 'none'; // Cacher le compteur
  8109.               break;
  8110.               
  8111.             case 'audios':
  8112.               // Dans les audios : bouton désactivé
  8113.               photosBtn.style.opacity = '0.4';
  8114.               photosBtn.style.pointerEvents = 'none';
  8115.               photosBtn.title = 'Carrousel non disponible dans la vue audios';
  8116.               if (btnIcon) btnIcon.style.color = '#6c757d';
  8117.               if (btnCount) btnCount.style.display = 'none';
  8118.               break;
  8119.               
  8120.             case 'days':
  8121.             default:
  8122.               // Vue normale : utiliser la logique existante du carrousel
  8123.               photosBtn.style.opacity = '1';
  8124.               photosBtn.style.pointerEvents = 'auto';
  8125.               photosBtn.title = 'Voir les photos du jour actif';
  8126.               if (btnIcon) btnIcon.style.color = '';
  8127.               if (btnCount) btnCount.style.display = 'none'; // Cacher le compteur pour éviter la confusion
  8128.               break;
  8129.           }
  8130.         }
  8131.         
  8132.         // Fonction pour mettre à jour l'état du bouton audio selon le contexte
  8133.         window.updateAudioButtonState = function updateAudioButtonState(currentView) {
  8134.           const audioBtn = document.querySelector('.mtb-btn[data-filter=\"audio\"]');
  8135.           if (!audioBtn) return;
  8136.           
  8137.           const btnCount = audioBtn.querySelector('.mtb-count');
  8138.           
  8139.           switch (currentView) {
  8140.             case 'favorites':
  8141.               // Dans les favoris : pas d'action sur le compteur audio
  8142.               break;
  8143.               
  8144.             case 'audios':
  8145.               // Dans les audios : afficher le nombre total calculé par le frontend
  8146.               const totalAudioCount = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]').length;
  8147.               if (btnCount) {
  8148.                 btnCount.textContent = totalAudioCount;
  8149.               }
  8150.               break;
  8151.               
  8152.             case 'days':
  8153.             default:
  8154.               // Vue normale : compter les audios du jour actif
  8155.               const activeDayAudioCount = countActiveDayAudios();
  8156.               if (btnCount) {
  8157.                 btnCount.textContent = activeDayAudioCount;
  8158.               }
  8159.               break;
  8160.           }
  8161.         }
  8162.         
  8163.         // Fonction pour mettre à jour l'état du bouton favoris selon le contexte
  8164.         window.updateFavoritesButtonState = function updateFavoritesButtonState(currentView) {
  8165.           const favoritesBtn = document.querySelector('.mtb-btn[data-filter=\"favoris\"]');
  8166.           if (!favoritesBtn) return;
  8167.           
  8168.           const btnIcon = favoritesBtn.querySelector('i');
  8169.           const btnCount = favoritesBtn.querySelector('.mtb-count');
  8170.           
  8171.           switch (currentView) {
  8172.             case 'favorites':
  8173.               // Dans les favoris : bouton actif
  8174.               favoritesBtn.style.opacity = '1';
  8175.               favoritesBtn.style.pointerEvents = 'auto';
  8176.               favoritesBtn.title = 'Vous êtes dans la vue favoris';
  8177.               if (btnIcon) btnIcon.style.color = '#f56040';
  8178.               if (btnCount) btnCount.style.display = 'inline';
  8179.               favoritesBtn.classList.add('active');
  8180.               break;
  8181.               
  8182.             case 'audios':
  8183.               // Dans les audios : bouton désactivé
  8184.               favoritesBtn.style.opacity = '0.4';
  8185.               favoritesBtn.style.pointerEvents = 'none';
  8186.               favoritesBtn.title = 'Favoris non disponibles dans la vue audios';
  8187.               if (btnIcon) btnIcon.style.color = '#6c757d';
  8188.               if (btnCount) btnCount.style.display = 'none';
  8189.               favoritesBtn.classList.remove('active');
  8190.               break;
  8191.               
  8192.             case 'days':
  8193.             default:
  8194.               // Vue normale : bouton normal
  8195.               favoritesBtn.style.opacity = '1';
  8196.               favoritesBtn.style.pointerEvents = 'auto';
  8197.               favoritesBtn.title = 'Voir les favoris';
  8198.               if (btnIcon) btnIcon.style.color = '#f56040';
  8199.               if (btnCount) btnCount.style.display = 'inline';
  8200.               favoritesBtn.classList.remove('active');
  8201.               break;
  8202.           }
  8203.         }
  8204.         
  8205.         // Fonction pour compter les audios du jour actif (réutilise la même logique)
  8206.         // ⚡ OPTIMISÉ: Cache des éléments DOM pour éviter les requêtes répétitives
  8207.         let cachedActiveDay = null;
  8208.         let cachedAudioCount = 0;
  8209.         let lastCacheTime = 0;
  8210.         const CACHE_DURATION = 1000; // 1 seconde
  8211.         
  8212.         function countActiveDayAudios() {
  8213.           const now = Date.now();
  8214.           
  8215.           // Utiliser le cache si récent
  8216.           if (cachedActiveDay && (now - lastCacheTime) < CACHE_DURATION) {
  8217.             return cachedAudioCount;
  8218.           }
  8219.           
  8220.           // Trouver le jour actuellement ouvert
  8221.           let activeDay = document.querySelector('.collapse.show[id^=\"demP\"]');
  8222.           
  8223.           // Si aucun jour ouvert, prendre le dernier jour
  8224.           if (!activeDay) {
  8225.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  8226.             activeDay = allDays[allDays.length - 1];
  8227.           }
  8228.           
  8229.           if (!activeDay) {
  8230.             cachedActiveDay = null;
  8231.             cachedAudioCount = 0;
  8232.             lastCacheTime = now;
  8233.             return 0;
  8234.           }
  8235.           
  8236.           // Compter les messages audio dans ce jour
  8237.           const audiosInDay = activeDay.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  8238.           const count = audiosInDay.length;
  8239.           
  8240.           // Mettre à jour le cache
  8241.           cachedActiveDay = activeDay;
  8242.           cachedAudioCount = count;
  8243.           lastCacheTime = now;
  8244.           
  8245.           return count;
  8246.         }
  8247.         
  8248.         // Fonction pour détecter la vue active
  8249.         // ⚡ OPTIMISÉ: Cache de la vue active pour éviter les requêtes DOM répétitives
  8250.         let cachedCurrentView = null;
  8251.         let lastViewCheck = 0;
  8252.         const VIEW_CACHE_DURATION = 500; // 500ms
  8253.         
  8254.         function detectCurrentView() {
  8255.           const now = Date.now();
  8256.           
  8257.           // Utiliser le cache si récent
  8258.           if (cachedCurrentView && (now - lastViewCheck) < VIEW_CACHE_DURATION) {
  8259.             return cachedCurrentView;
  8260.           }
  8261.           
  8262.           let view = 'days';
  8263.           if (document.querySelector('.favorites-ecommerce-view')) {
  8264.             view = 'favorites';
  8265.           } else if (document.querySelector('.audios-view')) {
  8266.             view = 'audios';
  8267.           }
  8268.           
  8269.           // Mettre à jour le cache
  8270.           cachedCurrentView = view;
  8271.           lastViewCheck = now;
  8272.           
  8273.           return view;
  8274.         }
  8275.         
  8276.         // ⚡ OPTIMISÉ: Cache global des éléments DOM fréquemment utilisés
  8277.         const domCache = {
  8278.           favoritesGrid: null,
  8279.           lastFavoritesUpdate: 0,
  8280.           CACHE_DURATION: 2000 // 2 secondes
  8281.         };
  8282.         
  8283.         function getCachedFavorites() {
  8284.           const now = Date.now();
  8285.           if (!domCache.favoritesGrid || (now - domCache.lastFavoritesUpdate) > domCache.CACHE_DURATION) {
  8286.             domCache.favoritesGrid = document.querySelector('.favorites-grid');
  8287.             domCache.lastFavoritesUpdate = now;
  8288.           }
  8289.           return domCache.favoritesGrid;
  8290.         }
  8291.         
  8292.         // Fonction pour ouvrir le carrousel des favoris
  8293.         function openFavoritesCarousel() {
  8294.           const favoritesGrid = getCachedFavorites();
  8295.           const favoriteItems = favoritesGrid ? favoritesGrid.querySelectorAll('.favorite-item') : [];
  8296.           if (favoriteItems.length > 0) {
  8297.             // Trouver le premier favori avec une action de vue
  8298.             const firstFavorite = favoriteItems[0];
  8299.             const viewBtn = firstFavorite.querySelector('.btn-view-favorite');
  8300.             if (viewBtn && viewBtn.onclick) {
  8301.               viewBtn.click();
  8302.             } else {
  8303.               // Fallback : extraire l'ID du data-id et utiliser viewImage
  8304.               const favoriteId = firstFavorite.dataset.id;
  8305.               if (favoriteId && typeof window.viewImage === 'function') {
  8306.                 window.viewImage(favoriteId, firstFavorite);
  8307.               }
  8308.             }
  8309.           } else {
  8310.             console.log('Aucun favori trouvé pour ouvrir le carrousel');
  8311.           }
  8312.         }
  8313.         
  8314.         // Fonction pour ouvrir le carrousel du jour actif
  8315.         function openActiveDayCarousel() {
  8316.           // Trouver le jour actuellement ouvert (avec classe 'show')
  8317.           let activeDay = document.querySelector('.collapse.show[id^=\"demP\"]');
  8318.           
  8319.           // Si aucun jour n'est ouvert, prendre le dernier jour
  8320.           if (!activeDay) {
  8321.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  8322.             activeDay = allDays[allDays.length - 1]; // Dernier jour
  8323.           }
  8324.           
  8325.           if (!activeDay) {
  8326.             console.warn('Aucun jour trouvé pour ouvrir le carrousel');
  8327.             return;
  8328.           }
  8329.           
  8330.           // Trouver la première photo de ce jour
  8331.           const viewIcon = activeDay.querySelector('.view-icon[onclick*=\"viewImage\"]');
  8332.           if (viewIcon) {
  8333.             // Extraire l'ID de la photo du onclick
  8334.             const onclickAttr = viewIcon.getAttribute('onclick');
  8335.             const match = onclickAttr.match(/viewImage\\('(\\d+)'/);
  8336.             if (match) {
  8337.               const imageId = match[1];
  8338.               // Ouvrir le slider avec cette image
  8339.               if (typeof window.viewImage === 'function') {
  8340.                 window.viewImage(imageId, viewIcon);
  8341.               }
  8342.             }
  8343.           } else {
  8344.             // Fallback : chercher dans tous les jours
  8345.             const allDays = document.querySelectorAll('.collapse[id^=\"demP\"]');
  8346.             for (let day of allDays) {
  8347.               const photoInDay = day.querySelector('.view-icon[onclick*=\"viewImage\"]');
  8348.               if (photoInDay) {
  8349.                 photoInDay.click();
  8350.                 break;
  8351.               }
  8352.             }
  8353.           }
  8354.         }
  8355.         // Fonction pour afficher la vue normale des jours - globale
  8356.         window.showDaysView = function() {
  8357.           const sectionDays = document.querySelector('.section-days');
  8358.           const containerGallery = document.querySelector('.container--gallery');
  8359.           
  8360.           // Si la section days contient des vues spéciales (favoris/audios), les supprimer
  8361.           if (sectionDays && (sectionDays.innerHTML.includes('favorites-ecommerce-view') || sectionDays.innerHTML.includes('audios-view'))) {
  8362.             // Restaurer le contenu original si disponible
  8363.             if (originalDaysContent) {
  8364.               sectionDays.innerHTML = originalDaysContent;
  8365.             } else {
  8366.               // Fallback : recharger la page si pas de sauvegarde
  8367.               location.reload();
  8368.               return;
  8369.             }
  8370.           }
  8371.           
  8372.           // Restaurer la visibilité du container gallery
  8373.           if (containerGallery) {
  8374.             containerGallery.style.display = 'block';
  8375.           }
  8376.           
  8377.           // Appeler le filtre \"all\" pour restaurer l'affichage complet
  8378.           if (typeof window.filterContent === 'function') {
  8379.             window.filterContent('toutVoir');
  8380.           }
  8381.           
  8382.           // Mettre à jour l'état des boutons
  8383.           updatePhotosButtonState('days');
  8384.           updateAudioButtonState('days');
  8385.           updateFavoritesButtonState('days');
  8386.         }
  8387.         // Fonction pour générer les cartes de jours (alternative simple)
  8388.         function generateDaysCards() {
  8389.           // Cette fonction pourrait régénérer les cartes, mais pour simplifier
  8390.           // on recharge la page dans showDaysView()
  8391.           return '';
  8392.         }
  8393.         // Fonction pour revenir à la vue des jours
  8394.      
  8395.         // Fonction pour générer la grille des favoris
  8396.         function generateFavoritesGrid() {
  8397.           const favorites = getFavoriteItems();
  8398.           
  8399.           if (favorites.length === 0) {
  8400.             return `
  8401.               <div class=\"no-favorites\">
  8402.                 <i class=\"bi bi-heart\" style=\"font-size: 3rem; color: #ccc; margin-bottom: 1rem;\"></i>
  8403.                 <h4>Aucun favori sélectionné</h4>
  8404.                 <p>Cliquez sur <i class=\"bi bi-heart\" style=\"color: #e91e63;\"></i> sur vos photos préférées pour les ajouter ici.</p>
  8405.               </div>
  8406.             `;
  8407.           }
  8408.           
  8409.           return favorites.map(item => `
  8410.             <div class=\"favorite-item\" data-id=\"\${item.id}\">
  8411.               \${item.type === 'image' ? 
  8412.                 `<img src=\"\${item.url}\" alt=\"Photo favorite\" loading=\"lazy\">` :
  8413.                 item.type === 'video' ? 
  8414.                 `<video src=\"\${item.url}\" poster=\"\${item.thumbnail}\"></video>
  8415.                  <div class=\"video-overlay\"><i class=\"bi bi-play-circle\"></i></div>` :
  8416.                 `<div class=\"audio-item\">
  8417.                    <i class=\"bi bi-mic-fill\"></i>
  8418.                    <span>Audio \${item.duration || '00:00'}</span>
  8419.                  </div>`
  8420.               }
  8421.               <!-- Actions overlay -->
  8422.               <div class=\"favorite-actions\">
  8423.                 <button class=\"btn-view-favorite\" onclick=\"viewFavorite('\${item.id}')\" title=\"Voir en grand\">
  8424.                   <i class=\"bi bi-eye\"></i>
  8425.                   <span>Voir</span>
  8426.                 </button>
  8427.                 <button class=\"btn-remove-favorite\" onclick=\"removeFavorite('\${item.id}')\" title=\"Retirer des favoris\">
  8428.                   <i class=\"bi bi-heart-fill\"></i>
  8429.                   <span>Retirer</span>
  8430.                 </button>
  8431.               </div>
  8432.             </div>
  8433.           `).join('');
  8434.         }
  8435.         // Fonction pour réorganiser la grille des favoris
  8436.         function reorganizeFavoritesGrid() {
  8437.           const favoritesGrid = document.getElementById('favoritesGrid');
  8438.           if (!favoritesGrid) return;
  8439.           
  8440.           const remainingItems = favoritesGrid.querySelectorAll('.favorite-item');
  8441.           if (remainingItems.length === 0) {
  8442.             // Afficher le message \"Aucun favori\"
  8443.             favoritesGrid.innerHTML = `
  8444.               <div class=\"no-favorites\">
  8445.                 <i class=\"bi bi-heart\" style=\"font-size: 3rem; color: #ccc; margin-bottom: 1rem;\"></i>
  8446.                 <h4>Aucun favori sélectionné</h4>
  8447.                 <p>Cliquez sur <i class=\"bi bi-heart\" style=\"color: #e91e63;\"></i> sur vos photos préférées pour les ajouter ici.</p>
  8448.               </div>
  8449.             `;
  8450.           } else {
  8451.             // Réorganiser les éléments restants avec une animation douce
  8452.             remainingItems.forEach((item, index) => {
  8453.               item.style.transition = 'all 0.3s ease';
  8454.               item.style.order = index;
  8455.             });
  8456.           }
  8457.         }
  8458.         // Fonction pour récupérer les éléments favoris
  8459.         function getFavoriteItems() {
  8460.           const favorites = [];
  8461.           
  8462.           // ⚡ OPTIMISÉ: Cache et parcours plus efficace des favoris
  8463.           const heartIcons = document.querySelectorAll('.heart-icon');
  8464.           for (let i = 0; i < heartIcons.length; i++) {
  8465.             const heartIcon = heartIcons[i];
  8466.             const heartFill = heartIcon.querySelector('.bi-heart-fill');
  8467.             if (heartFill) {
  8468.               const id = heartIcon.getAttribute('data-id');
  8469.               const path = heartIcon.getAttribute('data-path');
  8470.               const description = heartIcon.getAttribute('data-description');
  8471.               
  8472.               if (id && path) {
  8473.                 // Déterminer le type de média
  8474.                 let type = 'image';
  8475.                 let url = path;
  8476.                 let thumbnail = path;
  8477.                 
  8478.                 if (path.includes('.mp4') || path.includes('.mov') || path.includes('.avi')) {
  8479.                   type = 'video';
  8480.                   thumbnail = path.replace(/\\.(mp4|mov|avi)\$/i, '_thumb.jpg');
  8481.                 } else if (path.includes('.mp3') || path.includes('.wav') || path.includes('.m4a')) {
  8482.                   type = 'audio';
  8483.                   url = path;
  8484.                 }
  8485.                 
  8486.                 // Récupérer la date depuis le conteneur parent
  8487.                 const dateCard = heartIcon.closest('[id^=\"demP\"]');
  8488.                 let date = 'Date inconnue';
  8489.                 if (dateCard) {
  8490.                   const dateElement = dateCard.querySelector('.full-date, .day-title');
  8491.                   if (dateElement) {
  8492.                     date = dateElement.textContent.trim();
  8493.                   }
  8494.                 }
  8495.                 
  8496.                 favorites.push({
  8497.                   id: id,
  8498.                   url: url,
  8499.                   thumbnail: thumbnail,
  8500.                   type: type,
  8501.                   date: date,
  8502.                   description: description || ''
  8503.                 });
  8504.               }
  8505.             }
  8506.           }
  8507.           
  8508.           // ⚡ OPTIMISÉ: Log conditionnel pour réduire l'impact performance
  8509.           if (favorites.length > 0) {
  8510.             console.log('Favoris trouvés:', favorites.length);
  8511.           }
  8512.           return favorites;
  8513.         }
  8514.         // Rendre les fonctions accessibles globalement
  8515.         window.viewFavorite = viewFavorite;
  8516.         window.removeFavorite = removeFavorite;
  8517.         window.getFavoriteItems = getFavoriteItems;
  8518.         // Fonction pour supprimer un favori
  8519.         function removeFavorite(id) {
  8520.          
  8521.           const heartIcon = document.querySelector(`[data-id=\"\${id}\"]`);
  8522.          
  8523.           if (heartIcon) {
  8524.             const heartFill = heartIcon.querySelector('.bi-heart-fill');
  8525.             if (heartFill && heartFill.classList) {
  8526.               heartFill.classList.remove('bi-heart-fill');
  8527.               heartFill.classList.add('bi-heart');
  8528.               heartFill.style.color = '';
  8529.             }
  8530.           }
  8531.           const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${id}\"]`);
  8532.         
  8533.           if (favoriteItem) {
  8534.             // Animation de disparition puis suppression complète
  8535.             favoriteItem.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
  8536.             favoriteItem.style.opacity = '0';
  8537.             favoriteItem.style.transform = 'scale(0.8)';
  8538.             
  8539.             setTimeout(() => {
  8540.               favoriteItem.remove();
  8541.               
  8542.               // Appeler la fonction métier si présente
  8543.               const heartIcon = document.querySelector(`#coeur\${id}`);
  8544.               const sejourId = heartIcon && heartIcon.dataset.sejourId ? heartIcon.dataset.sejourId : '';
  8545.               supprimerFavoris(id, sejourId);
  8546.               
  8547.               // Mettre à jour les compteurs
  8548.               updateAllFavoriteCounters();
  8549.               
  8550.               // Réorganiser la grille si nécessaire
  8551.               reorganizeFavoritesGrid();
  8552.             }, 300);
  8553.       
  8554.      
  8555.    
  8556.   }
  8557.           
  8558.         }
  8559.         // Slider plein écran pour les favoris
  8560.         class FavoritesSlider {
  8561.           constructor() {
  8562.             this.currentIndex = 0;
  8563.             this.favorites = [];
  8564.             this.isOpen = false;
  8565.             this.touchStartX = 0;
  8566.             this.touchEndX = 0;
  8567.           }
  8568.           open(favoriteId) {
  8569.             console.log('Ouverture du slider pour:', favoriteId);
  8570.             
  8571.             // Récupérer tous les favoris images
  8572.             this.favorites = getFavoriteItems().filter(item => item.type === 'image');
  8573.             
  8574.             if (this.favorites.length === 0) {
  8575.               console.error('Aucun favori image trouvé');
  8576.               return;
  8577.             }
  8578.             // Trouver l'index de l'image courante
  8579.             this.currentIndex = this.favorites.findIndex(fav => fav.id === favoriteId);
  8580.             if (this.currentIndex === -1) this.currentIndex = 0;
  8581.             console.log('Index courant:', this.currentIndex, 'Total:', this.favorites.length);
  8582.             this.createSlider();
  8583.             this.showSlide(this.currentIndex);
  8584.             this.attachEvents();
  8585.             this.isOpen = true;
  8586.             // Animation d'ouverture immédiate pour favoris avec diagnostic
  8587.             setTimeout(() => {
  8588.               if (window.diagnoseSliderDisplay) {
  8589.                 window.diagnoseSliderDisplay('#favoritesSlider');
  8590.               }
  8591.             }, 50);
  8592.           }
  8593.           createSlider() {
  8594.             // ⚡ OPTIMISATION: Créer le slider seulement quand nécessaire
  8595.             if (document.querySelector('#favoritesSlider')) {
  8596.               return; // Déjà créé, ne pas recréer
  8597.             }
  8598.             
  8599.             // Structure HTML minimale et optimisée
  8600.             const sliderHTML = `
  8601.               <div class=\"favorites-slider\" id=\"favoritesSlider\" style=\"
  8602.                 position: fixed !important; 
  8603.                 top: 0 !important; 
  8604.                 left: 0 !important; 
  8605.                 width: 100% !important; 
  8606.                 height: 100% !important; 
  8607.                 background: rgba(0,0,0,0.95) !important; 
  8608.                 z-index: 9999 !important; 
  8609.                 display: flex !important; 
  8610.                 align-items: center !important; 
  8611.                 justify-content: center !important; 
  8612.                 opacity: 1 !important; 
  8613.                 visibility: visible !important;
  8614.               \">
  8615.                 <div class=\"slider-overlay\"></div>
  8616.                 
  8617.                 <!-- Header avec contrôles -->
  8618.                 <div class=\"slider-header\">
  8619.                   <div class=\"slider-controls\">
  8620.                     <button class=\"slider-btn favorite-btn\" title=\"Retirer des favoris\">
  8621.                       <i class=\"bi bi-heart-fill\"></i>
  8622.                     </button>
  8623.                     <button class=\"slider-btn zoom-btn\" title=\"Zoom\">
  8624.                       <i class=\"bi bi-zoom-in\"></i>
  8625.                     </button>
  8626.                     <button class=\"slider-btn close-btn\" title=\"Fermer\">
  8627.                       <i class=\"bi bi-x-lg\"></i>
  8628.                     </button>
  8629.                   </div>
  8630.                 </div>
  8631.                 <!-- Navigation -->
  8632.                 <button class=\"slider-nav prev-btn\" title=\"Précédent\">
  8633.                   <i class=\"bi bi-arrow-left-circle-fill\"></i>
  8634.                 </button>
  8635.                 <button class=\"slider-nav next-btn\" title=\"Suivant\">
  8636.                   <i class=\"bi bi-arrow-right-circle-fill\"></i>
  8637.                 </button>
  8638.                 <!-- Container des slides -->
  8639.                 <div class=\"slider-container\">
  8640.                   <div class=\"slider-track\" id=\"sliderTrack\">
  8641.                     \${this.favorites.map((fav, index) => `
  8642.                       <div class=\"slide\" data-index=\"\${index}\">
  8643.                         <div class=\"slide-content\">
  8644.                           <img src=\"\${fav.url}\" alt=\"\${fav.description || 'Photo favorite'}\" 
  8645.                                loading=\"\${index <= 2 ? 'eager' : 'lazy'}\"
  8646.                                draggable=\"false\">
  8647.                         </div>
  8648.                         <div class=\"slide-info\">
  8649.                           <h4>\${fav.description || 'Photo favorite'}</h4>
  8650.                           <p>\${fav.date || 'Date inconnue'}</p>
  8651.                         </div>
  8652.                       </div>
  8653.                     `).join('')}
  8654.                   </div>
  8655.                 </div>
  8656.                 <!-- Thumbnails -->
  8657.                 <div class=\"slider-thumbnails\">
  8658.                   \${this.favorites.map((fav, index) => `
  8659.                     <div class=\"thumbnail \${index === this.currentIndex ? 'active' : ''}\" 
  8660.                          data-index=\"\${index}\">
  8661.                       <img src=\"\${fav.url}\" alt=\"Thumbnail \${index + 1}\">
  8662.                     </div>
  8663.                   `).join('')}
  8664.                 </div>
  8665.               </div>
  8666.             `;
  8667.             // Injecter dans le DOM
  8668.             document.body.insertAdjacentHTML('beforeend', sliderHTML);
  8669.           }
  8670.           showSlide(index) {
  8671.             if (index < 0 || index >= this.favorites.length) return;
  8672.             this.currentIndex = index;
  8673.             const track = document.getElementById('sliderTrack');
  8674.             const translateX = -index * 100;
  8675.             
  8676.             track.style.transform = `translateX(\${translateX}%)`;
  8677.             // ⚡ OPTIMISÉ: Éviter forEach sur querySelectorAll (mémoire)
  8678.             const thumbnails = document.querySelectorAll('.thumbnail');
  8679.             for (let i = 0; i < thumbnails.length; i++) {
  8680.               const thumb = thumbnails[i];
  8681.               if (thumb?.classList) {
  8682.                 thumb.classList.toggle('active', i === index);
  8683.               }
  8684.             }
  8685.             // Mettre à jour le bouton favori
  8686.             const currentFav = this.favorites[index];
  8687.             const favoriteBtn = document.querySelector('.slider-controls .favorite-btn');
  8688.             if (favoriteBtn && currentFav) {
  8689.               favoriteBtn.setAttribute('data-id', currentFav.id);
  8690.             }
  8691.           }
  8692.           nextSlide() {
  8693.             const nextIndex = (this.currentIndex + 1) % this.favorites.length;
  8694.             this.showSlide(nextIndex);
  8695.           }
  8696.           prevSlide() {
  8697.             const prevIndex = (this.currentIndex - 1 + this.favorites.length) % this.favorites.length;
  8698.             this.showSlide(prevIndex);
  8699.           }
  8700.           close() {
  8701.             if (!this.isOpen) return;
  8702.             const slider = document.querySelector('.favorites-slider');
  8703.             if (slider && slider.classList) {
  8704.               slider.classList.remove('active');
  8705.               
  8706.               setTimeout(() => {
  8707.                 slider.remove();
  8708.                 this.isOpen = false;
  8709.               }, 300);
  8710.             }
  8711.           }
  8712.           attachEvents() {
  8713.             const slider = document.getElementById('favoritesSlider');
  8714.             
  8715.             // Bouton fermer
  8716.             slider.querySelector('.close-btn').addEventListener('click', () => this.close());
  8717.             
  8718.             // Navigation
  8719.             slider.querySelector('.prev-btn').addEventListener('click', () => this.prevSlide());
  8720.             slider.querySelector('.next-btn').addEventListener('click', () => this.nextSlide());
  8721.             
  8722.             // ⚡ OPTIMISÉ: Event delegation au lieu de listeners multiples
  8723.             const thumbContainer = slider.querySelector('.thumbnails-container') || slider;
  8724.             if (thumbContainer && !thumbContainer.hasAttribute('data-thumb-delegated')) {
  8725.               thumbContainer.addEventListener('click', (e) => {
  8726.                 const thumb = e.target.closest('.thumbnail');
  8727.                 if (thumb) {
  8728.                   const thumbnails = slider.querySelectorAll('.thumbnail');
  8729.                   const index = Array.from(thumbnails).indexOf(thumb);
  8730.                   if (index !== -1) this.showSlide(index);
  8731.                 }
  8732.               });
  8733.               thumbContainer.setAttribute('data-thumb-delegated', 'true');
  8734.             }
  8735.             // Bouton favori
  8736.             slider.querySelector('.favorite-btn').addEventListener('click', (e) => {
  8737.               const favoriteId = e.currentTarget.getAttribute('data-id');
  8738.               if (favoriteId) {
  8739.                 removeFavorite(favoriteId);
  8740.                 // Recharger le slider avec les favoris mis à jour
  8741.                 setTimeout(() => {
  8742.                   this.close();
  8743.                   if (getFavoriteItems().filter(item => item.type === 'image').length > 0) {
  8744.                     this.open(this.favorites[0]?.id);
  8745.                   }
  8746.                 }, 100);
  8747.               }
  8748.             });
  8749.             // Clavier
  8750.             document.addEventListener('keydown', this.handleKeyboard.bind(this));
  8751.             
  8752.             // Clic sur overlay pour fermer
  8753.             slider.querySelector('.slider-overlay').addEventListener('click', () => this.close());
  8754.             // Touch/swipe sur mobile
  8755.             const track = slider.querySelector('.slider-track');
  8756.             track.addEventListener('touchstart', this.handleTouchStart.bind(this), { passive: true });
  8757.             track.addEventListener('touchend', this.handleTouchEnd.bind(this), { passive: true });
  8758.             // Zoom sur clic simple (5 niveaux) + double-clic (legacy)
  8759.             slider.querySelectorAll('.slide img').forEach(img => {
  8760.               let zoomLevel = 1;
  8761.               let isDragging = false;
  8762.               let startX, startY, translateX = 0, translateY = 0;
  8763.               
  8764.               // Zoom sur clic simple (nouveau système 5 niveaux)
  8765.               img.addEventListener('click', (e) => {
  8766.                 e.preventDefault();
  8767.                 e.stopPropagation();
  8768.                 
  8769.                 // Cycle à travers 5 niveaux de zoom
  8770.                 switch(zoomLevel) {
  8771.                   case 1: zoomLevel = 1.5; break;  // 1x → 1.5x
  8772.                   case 1.5: zoomLevel = 2; break;  // 1.5x → 2x
  8773.                   case 2: zoomLevel = 3; break;    // 2x → 3x
  8774.                   case 3: zoomLevel = 4; break;    // 3x → 4x
  8775.                   case 4: zoomLevel = 5; break;    // 4x → 5x
  8776.                   case 5: 
  8777.                     zoomLevel = 1;                 // 5x → 1x (reset)
  8778.                     translateX = 0;
  8779.                     translateY = 0;
  8780.                     break;
  8781.                 }
  8782.                 console.log('FavoritesSlider - Zoom niveau:', zoomLevel);
  8783.                 img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  8784.                 
  8785.                 // Curseur selon le niveau
  8786.                 if (zoomLevel === 1) {
  8787.                   img.style.cursor = 'zoom-in';
  8788.                   img.removeAttribute('data-zoomed');
  8789.                 } else if (zoomLevel === 5) {
  8790.                   img.style.cursor = 'zoom-out';
  8791.                   img.setAttribute('data-zoomed', zoomLevel);
  8792.                 } else {
  8793.                   img.style.cursor = 'zoom-in';
  8794.                   img.setAttribute('data-zoomed', zoomLevel);
  8795.                 }
  8796.               });
  8797.               
  8798.               // Drag pour déplacer l'image zoomée
  8799.               img.addEventListener('mousedown', (e) => {
  8800.                 if (zoomLevel > 1) {
  8801.                   isDragging = true;
  8802.                   startX = e.clientX - translateX;
  8803.                   startY = e.clientY - translateY;
  8804.                   img.style.cursor = 'grabbing';
  8805.                   e.preventDefault();
  8806.                   e.stopPropagation();
  8807.                 }
  8808.               });
  8809.               const handleMouseMove = (e) => {
  8810.                 if (isDragging && zoomLevel > 1) {
  8811.                   translateX = e.clientX - startX;
  8812.                   translateY = e.clientY - startY;
  8813.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  8814.                 }
  8815.               };
  8816.               const handleMouseUp = () => {
  8817.                 if (isDragging) {
  8818.                   isDragging = false;
  8819.                   if (zoomLevel === 1) {
  8820.                     img.style.cursor = 'zoom-in';
  8821.                   } else if (zoomLevel === 5) {
  8822.                     img.style.cursor = 'zoom-out';
  8823.                   } else {
  8824.                     img.style.cursor = 'zoom-in';
  8825.                   }
  8826.                 }
  8827.               };
  8828.               document.addEventListener('mousemove', handleMouseMove);
  8829.               document.addEventListener('mouseup', handleMouseUp);
  8830.               // Support tactile pour mobile
  8831.               img.addEventListener('touchstart', (e) => {
  8832.                 if (zoomLevel > 1 && e.touches.length === 1) {
  8833.                   isDragging = true;
  8834.                   const touch = e.touches[0];
  8835.                   startX = touch.clientX - translateX;
  8836.                   startY = touch.clientY - translateY;
  8837.                   e.preventDefault();
  8838.                 }
  8839.               });
  8840.               img.addEventListener('touchmove', (e) => {
  8841.                 if (isDragging && zoomLevel > 1 && e.touches.length === 1) {
  8842.                   const touch = e.touches[0];
  8843.                   translateX = touch.clientX - startX;
  8844.                   translateY = touch.clientY - startY;
  8845.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  8846.                   e.preventDefault();
  8847.                 }
  8848.               });
  8849.               img.addEventListener('touchend', () => {
  8850.                 isDragging = false;
  8851.               });
  8852.               // Initialiser le curseur
  8853.               img.style.cursor = 'zoom-in';
  8854.               
  8855.               // Garder aussi le double-clic pour compatibilité (legacy)
  8856.               img.addEventListener('dblclick', this.handleZoom.bind(this));
  8857.             });
  8858.           }
  8859.           handleKeyboard(e) {
  8860.             if (!this.isOpen) return;
  8861.             
  8862.             switch(e.key) {
  8863.               case 'Escape':
  8864.                 this.close();
  8865.                 break;
  8866.               case 'ArrowLeft':
  8867.                 e.preventDefault();
  8868.                 this.prevSlide();
  8869.                 break;
  8870.               case 'ArrowRight':
  8871.                 e.preventDefault();
  8872.                 this.nextSlide();
  8873.                 break;
  8874.             }
  8875.           }
  8876.           handleTouchStart(e) {
  8877.             this.touchStartX = e.changedTouches[0].screenX;
  8878.           }
  8879.           handleTouchEnd(e) {
  8880.             this.touchEndX = e.changedTouches[0].screenX;
  8881.             this.handleSwipe();
  8882.           }
  8883.           handleSwipe() {
  8884.             const swipeThreshold = 50;
  8885.             const diff = this.touchStartX - this.touchEndX;
  8886.             if (Math.abs(diff) > swipeThreshold) {
  8887.               if (diff > 0) {
  8888.                 this.nextSlide(); // Swipe left -> next
  8889.               } else {
  8890.                 this.prevSlide(); // Swipe right -> prev
  8891.               }
  8892.             }
  8893.           }
  8894.           handleZoom(e) {
  8895.             const img = e.target;
  8896.             
  8897.             // Vérifier que l'élément et ses propriétés existent
  8898.             if (!img || !img.classList) {
  8899.               console.warn('Élément image invalide pour le zoom');
  8900.               return;
  8901.             }
  8902.             
  8903.             // Gérer les différents niveaux de zoom
  8904.             if (img.classList.contains('zoom-4x')) {
  8905.               // Retour à la taille normale
  8906.               img.classList.remove('zoom-4x', 'zoom-3x', 'zoom-2x', 'zoomed');
  8907.               img.style.cursor = 'pointer';
  8908.               img.style.transform = 'scale(1)'; // Réinitialiser la position
  8909.             } else if (img.classList.contains('zoom-3x')) {
  8910.               // Passer au zoom 4x
  8911.               img.classList.remove('zoom-3x');
  8912.               img.classList.add('zoom-4x');
  8913.               img.style.cursor = 'zoom-out';
  8914.               img.style.transform = 'scale(4)'; // Réinitialiser la position
  8915.             } else if (img.classList.contains('zoom-2x')) {
  8916.               // Passer au zoom 3x
  8917.               img.classList.remove('zoom-2x');
  8918.               img.classList.add('zoom-3x');
  8919.               img.style.cursor = 'zoom-in';
  8920.               img.style.transform = 'scale(3)'; // Réinitialiser la position
  8921.             } else if (img.classList.contains('zoomed')) {
  8922.               // Passer au zoom 2x
  8923.               img.classList.remove('zoomed');
  8924.               img.classList.add('zoom-2x');
  8925.               img.style.cursor = 'zoom-in';
  8926.               img.style.transform = 'scale(2)'; // Réinitialiser la position
  8927.             } else {
  8928.               // Premier zoom (1.5x)
  8929.               img.classList.add('zoomed');
  8930.               img.style.cursor = 'zoom-in';
  8931.               img.style.transform = 'scale(1.5)'; // Réinitialiser la position
  8932.             }
  8933.           }
  8934.         }
  8935.         // Slider universel pour toutes les images (favoris + galerie normale)
  8936.         class UniversalImageSlider {
  8937.           constructor() {
  8938.             this.currentIndex = 0;
  8939.             this.images = [];
  8940.             this.isOpen = false;
  8941.             this.touchStartX = 0;
  8942.             this.touchEndX = 0;
  8943.           }
  8944.           // Ouvrir avec une image spécifique depuis les favoris
  8945.           openFromFavorites(favoriteId) {
  8946.             console.log('Ouverture du slider depuis favoris:', favoriteId);
  8947.             
  8948.             // Récupérer tous les favoris images
  8949.             this.images = getFavoriteItems().filter(item => item.type === 'image');
  8950.             
  8951.             if (this.images.length === 0) {
  8952.               console.error('Aucun favori image trouvé');
  8953.               return;
  8954.             }
  8955.             // Trouver l'index de l'image courante
  8956.             this.currentIndex = this.images.findIndex(img => img.id === favoriteId);
  8957.             if (this.currentIndex === -1) this.currentIndex = 0;
  8958.             this.openSlider();
  8959.           }
  8960.           // Ouvrir avec une image spécifique depuis la galerie normale
  8961.           openFromGallery(imageId, dayContainer) {
  8962.             console.log('Ouverture du slider depuis galerie:', imageId, dayContainer);
  8963.             
  8964.             // Récupérer toutes les images du jour courant
  8965.             const dayImages = [];
  8966.             
  8967.             // Chercher dans le container du jour (peut être .dynamic-card ou autre)
  8968.             let photoItems;
  8969.             if (dayContainer) {
  8970.               photoItems = dayContainer.querySelectorAll('.photo-item');
  8971.             } else {
  8972.               // Fallback: chercher dans tout le document
  8973.               photoItems = document.querySelectorAll('.photo-item');
  8974.             }
  8975.             
  8976.             console.log('Photo items trouvés:', photoItems.length);
  8977.             
  8978.             photoItems.forEach(item => {
  8979.               const img = item.querySelector('img');
  8980.               const heartIcon = item.querySelector('.heart-icon');
  8981.               
  8982.               console.log('Processing item:', {
  8983.                 img: !!img,
  8984.                 heartIcon: !!heartIcon,
  8985.                 imgSrc: img ? img.src : null,
  8986.                 heartIconId: heartIcon ? heartIcon.getAttribute('data-id') : null
  8987.               });
  8988.               
  8989.               if (img && heartIcon) {
  8990.                 dayImages.push({
  8991.                   id: heartIcon.getAttribute('data-id'),
  8992.                   url: heartIcon.getAttribute('data-path') || img.src,
  8993.                   description: heartIcon.getAttribute('data-description') || img.alt || 'Photo',
  8994.                   date: '', // Pas de date spécifique pour les images de galerie
  8995.                   type: 'image'
  8996.                 });
  8997.               }
  8998.             });
  8999.             console.log('Images trouvées:', dayImages);
  9000.             this.images = dayImages;
  9001.             
  9002.             if (this.images.length === 0) {
  9003.               console.error('Aucune image trouvée dans ce jour');
  9004.               // Essayer de créer au moins l'image courante
  9005.               const currentHeartIcon = document.querySelector(`[data-id=\"\${imageId}\"]`);
  9006.               if (currentHeartIcon) {
  9007.                 const currentImg = currentHeartIcon.closest('.photo-item').querySelector('img');
  9008.                 if (currentImg) {
  9009.                   this.images = [{
  9010.                     id: imageId,
  9011.                     url: currentHeartIcon.getAttribute('data-path') || currentImg.src,
  9012.                     description: currentHeartIcon.getAttribute('data-description') || currentImg.alt || 'Photo',
  9013.                     date: '',
  9014.                     type: 'image'
  9015.                   }];
  9016.                   console.log('Image de fallback créée:', this.images);
  9017.                 }
  9018.               }
  9019.               
  9020.               if (this.images.length === 0) {
  9021.                 return;
  9022.               }
  9023.             }
  9024.             // Trouver l'index de l'image courante
  9025.             this.currentIndex = this.images.findIndex(img => img.id === imageId);
  9026.             if (this.currentIndex === -1) this.currentIndex = 0;
  9027.             console.log('Index trouvé:', this.currentIndex);
  9028.             this.openSlider();
  9029.           }
  9030.           openSlider() {
  9031.             console.log('=== openSlider appelée ===');
  9032.             console.log('Index courant:', this.currentIndex, 'Total:', this.images.length);
  9033.             console.log('Images à afficher:', this.images);
  9034.             // Supprimer tout slider existant
  9035.             const existingSlider = document.querySelector('.universal-slider');
  9036.             if (existingSlider) {
  9037.               console.log('Suppression du slider existant');
  9038.               existingSlider.remove();
  9039.             }
  9040.             this.createSlider();
  9041.             this.showSlide(this.currentIndex);
  9042.             this.attachEvents();
  9043.             this.isOpen = true;
  9044.               // Animation d'ouverture immédiate et garantie avec diagnostic
  9045.               setTimeout(() => {
  9046.                 if (window.diagnoseSliderDisplay) {
  9047.                   window.diagnoseSliderDisplay('#universalSlider');
  9048.                 }
  9049.               }, 50);
  9050.           }
  9051.           createSlider() {
  9052.             // ⚡ OPTIMISATION: Créer seulement si nécessaire
  9053.             if (document.querySelector('#universalSlider')) {
  9054.               return; // Déjà créé
  9055.             }
  9056.             
  9057.             console.log('Création slider pour', this.images.length, 'images');
  9058.             
  9059.             // HTML optimisé et minimal
  9060.             const sliderHTML = `
  9061.               <div class=\"universal-slider\" id=\"universalSlider\" style=\"
  9062.                 position: fixed !important; 
  9063.                 top: 0 !important; 
  9064.                 left: 0 !important; 
  9065.                 width: 100% !important; 
  9066.                 height: 100% !important; 
  9067.                 background: rgba(0,0,0,0.95) !important; 
  9068.                 z-index: 9999 !important; 
  9069.                 display: flex !important; 
  9070.                 align-items: center !important; 
  9071.                 justify-content: center !important; 
  9072.                 opacity: 1 !important; 
  9073.                 visibility: visible !important;
  9074.               \">
  9075.                 <div class=\"slider-overlay\" style=\"position: absolute; top: 0; left: 0; width: 100%; height: 100%; cursor: pointer;\"></div>
  9076.                 
  9077.                 <!-- Header avec contrôles -->
  9078.                 <div class=\"slider-header\" style=\"
  9079.                   position: absolute; 
  9080.                   top: 20px; 
  9081.                   right: 20px; 
  9082.                   display: flex; 
  9083.                   align-items: center; 
  9084.                   gap: 15px; 
  9085.                   z-index: 10001;
  9086.                 \">
  9087.                   <button class=\"slider-btn close-btn\" title=\"Fermer\" style=\"
  9088.                     background: rgba(255,255,255,0.2); 
  9089.                     border: none; 
  9090.                     color: white; 
  9091.                     width: 40px; 
  9092.                     height: 40px; 
  9093.                     border-radius: 50%; 
  9094.                     cursor: pointer; 
  9095.                     display: flex; 
  9096.                     align-items: center; 
  9097.                     justify-content: center;
  9098.                     transition: background 0.2s ease;
  9099.                   \">
  9100.                     <i class=\"bi bi-x-lg\"></i>
  9101.                   </button>
  9102.                 </div>
  9103.                 <!-- Navigation -->
  9104.                 <button class=\"slider-nav prev-btn\" title=\"Précédent\" style=\"
  9105.                   position: absolute; 
  9106.                   left: 20px; 
  9107.                   top: 50%; 
  9108.                   transform: translateY(-50%); 
  9109.                   background: rgba(255,255,255,0.2); 
  9110.                   border: none; 
  9111.                   color: white; 
  9112.                   width: 50px; 
  9113.                   height: 50px; 
  9114.                   border-radius: 50%; 
  9115.                   cursor: pointer; 
  9116.                   display: \${this.images.length > 1 ? 'flex' : 'none'}; 
  9117.                   align-items: center; 
  9118.                   justify-content: center; 
  9119.                   z-index: 10001;
  9120.                   transition: background 0.2s ease;
  9121.                 \">
  9122.                   <i class=\"bi bi-arrow-left-circle-fill\" style=\"font-size: 20px;\"></i>
  9123.                 </button>
  9124.                 <button class=\"slider-nav next-btn\" title=\"Suivant\" style=\"
  9125.                   position: absolute; 
  9126.                   right: 20px; 
  9127.                   top: 50%; 
  9128.                   transform: translateY(-50%); 
  9129.                   background: rgba(255,255,255,0.2); 
  9130.                   border: none; 
  9131.                   color: white; 
  9132.                   width: 50px; 
  9133.                   height: 50px; 
  9134.                   border-radius: 50%; 
  9135.                   cursor: pointer; 
  9136.                   display: \${this.images.length > 1 ? 'flex' : 'none'}; 
  9137.                   align-items: center; 
  9138.                   justify-content: center; 
  9139.                   z-index: 10001;
  9140.                   transition: background 0.2s ease;
  9141.                 \">
  9142.                   <i class=\"bi bi-arrow-right-circle-fill\" style=\"font-size: 20px;\"></i>
  9143.                 </button>
  9144.                 <!-- Container des slides -->
  9145.                 <div class=\"slider-container\" style=\"
  9146.                   position: relative; 
  9147.                   width: 90%; 
  9148.                   height: 90%; 
  9149.                   display: flex; 
  9150.                   align-items: center; 
  9151.                   justify-content: center; 
  9152.                   z-index: 10000;
  9153.                 \">
  9154.                   <div class=\"slider-track\" id=\"universalSliderTrack\" style=\"
  9155.                     position: relative; 
  9156.                     width: 100%; 
  9157.                     height: 100%; 
  9158.                     display: flex; 
  9159.                     align-items: center; 
  9160.                     justify-content: center;
  9161.                     overflow: hidden;
  9162.                   \">
  9163.                     \${this.images.map((img, index) => `
  9164.                       <div class=\"slide\" data-index=\"\${index}\" style=\"
  9165.                         position: absolute; 
  9166.                         width: 100%; 
  9167.                         height: 100%; 
  9168.                         display: \${index === 0 ? 'flex' : 'none'}; 
  9169.                         align-items: center; 
  9170.                         justify-content: center; 
  9171.                         flex-direction: column;
  9172.                       \">
  9173.                         <div class=\"slide-content\" style=\"
  9174.                           position: relative; 
  9175.                           max-width: 100%; 
  9176.                           max-height: 90%; 
  9177.                           display: flex; 
  9178.                           align-items: center; 
  9179.                           justify-content: center;
  9180.                         \">
  9181.                           <img src=\"\${img.url}\" alt=\"\${img.description || 'Photo'}\" 
  9182.                                loading=\"\${index <= 2 ? 'eager' : 'lazy'}\"
  9183.                                draggable=\"false\"
  9184.                                style=\"
  9185.                                  max-width: 100%; 
  9186.                                  max-height: 100%; 
  9187.                                  object-fit: contain; 
  9188.                                  cursor: zoom-in;
  9189.                                  transition: transform 0.3s ease;
  9190.                                  user-select: none;
  9191.                                \">
  9192.                         </div>
  9193.                         \${img.description ? `
  9194.                         <div class=\"slide-info\" style=\"
  9195.                           position: absolute; 
  9196.                           bottom: 60px; 
  9197.                           left: 50%; 
  9198.                           transform: translateX(-50%); 
  9199.                           text-align: center; 
  9200.                           color: white; 
  9201.                           background: rgba(0,0,0,0.6); 
  9202.                           padding: 8px 16px; 
  9203.                           border-radius: 20px; 
  9204.                           max-width: 80%;
  9205.                           font-size: 14px;
  9206.                         \">
  9207.                           \${img.description}
  9208.                         </div>
  9209.                         ` : ''}
  9210.                       </div>
  9211.                     `).join('')}
  9212.                   </div>
  9213.                 </div>
  9214.                 <!-- Galerie de thumbnails révolutionnaire -->
  9215.                 <div class=\"cinema-gallery\" style=\"
  9216.                   position: absolute; 
  9217.                   bottom: 0; 
  9218.                   left: 0; 
  9219.                   right: 0;
  9220.                   height: 180px;
  9221.                   background: linear-gradient(0deg, rgba(0,0,0,0.95) 0%, rgba(0,0,0,0.7) 50%, transparent 100%);
  9222.                   z-index: 10001;
  9223.                   display: flex;
  9224.                   flex-direction: column;
  9225.                   justify-content: flex-end;
  9226.                   padding: 0 20px 20px;
  9227.                 \">
  9228.                   
  9229.                   <!-- Info header avec compteur élégant -->
  9230.                   <div class=\"gallery-header\" style=\"
  9231.                     display: flex;
  9232.                     justify-content: space-between;
  9233.                     align-items: center;
  9234.                     margin-bottom: 15px;
  9235.                   \">
  9236.                     <div class=\"photo-counter\" style=\"
  9237.                       color: white;
  9238.                       font-size: 16px;
  9239.                       font-weight: 600;
  9240.                       display: flex;
  9241.                       align-items: center;
  9242.                       gap: 8px;
  9243.                     \">
  9244.                       <div style=\"
  9245.                         width: 8px;
  9246.                         height: 8px;
  9247.                         background: #10b981;
  9248.                         border-radius: 50%;
  9249.                         animation: pulse 2s infinite;
  9250.                       \"></div>
  9251.                       <span>\${(this.currentIndex || 0) + 1}</span>
  9252.                       <span style=\"opacity: 0.6;\">sur</span>
  9253.                       <span>\${this.images.length}</span>
  9254.                     </div>
  9255.                     <div class=\"gallery-controls\" style=\"
  9256.                       display: flex;
  9257.                       gap: 12px;
  9258.                       align-items: center;
  9259.                     \">
  9260.                       <div style=\"color: rgba(255,255,255,0.7); font-size: 12px;\">
  9261.                         Clic = Zoom 5x • Drag = Déplacer
  9262.                       </div>
  9263.                     </div>
  9264.                   </div>
  9265.                   
  9266.                   <!-- Carrousel de thumbnails cinématographique -->
  9267.                   <div class=\"cinema-carousel\" style=\"
  9268.                     position: relative;
  9269.                     height: 80px;
  9270.                     overflow: hidden;
  9271.                   \">
  9272.                     <!-- Container scrollable -->
  9273.                     <div class=\"carousel-track\" id=\"carouselTrack\" style=\"
  9274.                       display: flex;
  9275.                       gap: 12px;
  9276.                       height: 100%;
  9277.                       overflow-x: auto;
  9278.                       overflow-y: hidden;
  9279.                       scroll-behavior: smooth;
  9280.                       scrollbar-width: none;
  9281.                       -ms-overflow-style: none;
  9282.                       padding: 0 50px;
  9283.                     \">
  9284.                       \${this.images.map((img, index) => `
  9285.                         <div class=\"cinema-thumb \${index === 0 ? 'active' : ''}\" 
  9286.                              data-index=\"\${index}\" 
  9287.                              style=\"
  9288.                                flex: 0 0 auto;
  9289.                                width: \${index === 0 ? '100px' : '70px'};
  9290.                                height: 70px;
  9291.                                border-radius: 8px;
  9292.                                overflow: hidden;
  9293.                                cursor: pointer;
  9294.                                position: relative;
  9295.                                transition: transform 0.2s ease, opacity 0.2s ease;
  9296.                                transform: \${index === 0 ? 'translateY(-4px)' : 'translateY(0)'};
  9297.                                opacity: \${index === 0 ? '1' : '0.7'};
  9298.                                border: \${index === 0 ? '2px solid #10b981' : '1px solid rgba(255,255,255,0.3)'};
  9299.                              \"
  9300.                              onmouseenter=\"
  9301.                                if (\${index} !== (window.universalSlider?.currentIndex || 0)) {
  9302.                                  this.style.opacity = '0.9';
  9303.                                }
  9304.                              \"
  9305.                              onmouseleave=\"
  9306.                                if (\${index} !== (window.universalSlider?.currentIndex || 0)) {
  9307.                                  this.style.opacity = '0.7';
  9308.                                }
  9309.                              \">
  9310.                           
  9311.                           <!-- Image principale -->
  9312.                           <img src=\"\${img.url}\" 
  9313.                                alt=\"\${img.description || 'Photo'}\" 
  9314.                                loading=\"lazy\" 
  9315.                                decoding=\"async\"
  9316.                                style=\"
  9317.                                  width: 100%; 
  9318.                                  height: 100%; 
  9319.                                  object-fit: cover;
  9320.                                \">
  9321.                           
  9322.                           <!-- Numéro simplifié -->
  9323.                           <div class=\"thumb-number\" style=\"
  9324.                             position: absolute;
  9325.                             top: 4px;
  9326.                             right: 4px;
  9327.                             background: \${index === 0 ? '#10b981' : 'rgba(0,0,0,0.8)'};
  9328.                             color: white;
  9329.                             font-size: 10px;
  9330.                             font-weight: 500;
  9331.                             padding: 2px 5px;
  9332.                             border-radius: 4px;
  9333.                             min-width: 16px;
  9334.                             text-align: center;
  9335.                           \">
  9336.                             \${index + 1}
  9337.                           </div>
  9338.                           
  9339.                           <!-- Indicateur actif simplifié -->
  9340.                           \${index === 0 ? `
  9341.                           <div class=\"active-indicator\" style=\"
  9342.                             position: absolute;
  9343.                             bottom: -1px;
  9344.                             left: 50%;
  9345.                             transform: translateX(-50%);
  9346.                             width: 16px;
  9347.                             height: 2px;
  9348.                             background: #10b981;
  9349.                             border-radius: 1px;
  9350.                           \"></div>
  9351.                           ` : ''}
  9352.                           
  9353.                           <!-- Preview au hover pour les non-actifs -->
  9354.                           \${index !== 0 ? `
  9355.                           <div class=\"hover-preview\" style=\"
  9356.                             position: absolute;
  9357.                             bottom: -40px;
  9358.                             left: 50%;
  9359.                             transform: translateX(-50%);
  9360.                             background: rgba(0,0,0,0.9);
  9361.                             color: white;
  9362.                             font-size: 11px;
  9363.                             padding: 4px 8px;
  9364.                             border-radius: 6px;
  9365.                             opacity: 0;
  9366.                             pointer-events: none;
  9367.                             transition: all 0.3s ease;
  9368.                             white-space: nowrap;
  9369.                             z-index: 1000;
  9370.                           \">
  9371.                             Photo \${index + 1}
  9372.                           </div>
  9373.                           ` : ''}
  9374.                         </div>
  9375.                       `).join('')}
  9376.                     </div>
  9377.                     
  9378.                     <!-- Gradients de fade sur les côtés -->
  9379.                     <div style=\"
  9380.                       position: absolute;
  9381.                       left: 0;
  9382.                       top: 0;
  9383.                       bottom: 0;
  9384.                       width: 50px;
  9385.                       background: linear-gradient(90deg, rgba(0,0,0,0.8), transparent);
  9386.                       pointer-events: none;
  9387.                       z-index: 1;
  9388.                     \"></div>
  9389.                     <div style=\"
  9390.                       position: absolute;
  9391.                       right: 0;
  9392.                       top: 0;
  9393.                       bottom: 0;
  9394.                       width: 50px;
  9395.                       background: linear-gradient(-90deg, rgba(0,0,0,0.8), transparent);
  9396.                       pointer-events: none;
  9397.                       z-index: 1;
  9398.                     \"></div>
  9399.                   </div>
  9400.                 </div>
  9401.                 <!-- Animations CSS Optimisées -->
  9402.                 <style>
  9403.                   /* Optimisation: animations réduites et ciblées */
  9404.                   @keyframes pulse {
  9405.                     0%, 100% { opacity: 1; }
  9406.                     50% { opacity: 0.7; }
  9407.                   }
  9408.                   
  9409.                   /* Suppression du glow coûteux - remplacé par border simple */
  9410.                   .cinema-thumb.active .active-indicator {
  9411.                     background: #10b981;
  9412.                     animation: none; /* Suppression de l'animation glow */
  9413.                   }
  9414.                   
  9415.                   /* Hover optimisé - moins d'effets */
  9416.                   .cinema-thumb:hover .hover-preview {
  9417.                     opacity: 1 !important;
  9418.                     bottom: -35px !important;
  9419.                   }
  9420.                   
  9421.                   /* Masquer scrollbar */
  9422.                   .carousel-track::-webkit-scrollbar {
  9423.                     display: none;
  9424.                   }
  9425.                   
  9426.                   /* Optimisation: will-change pour les éléments animés */
  9427.                   .cinema-thumb {
  9428.                     will-change: transform, filter;
  9429.                   }
  9430.                   
  9431.                   .progress-bar {
  9432.                     will-change: width;
  9433.                   }
  9434.                 </style>
  9435.               </div>
  9436.             `;
  9437.             // Injecter dans le DOM
  9438.             console.log('Ajout du slider au DOM');
  9439.             document.body.insertAdjacentHTML('beforeend', sliderHTML);
  9440.             
  9441.             // Vérifier que le slider a été ajouté
  9442.             const addedSlider = document.querySelector('#universalSlider');
  9443.             console.log('Slider ajouté:', !!addedSlider);
  9444.             if (addedSlider) {
  9445.               console.log('Slider trouvé dans le DOM');
  9446.               console.log('Styles du slider:', {
  9447.                 display: addedSlider.style.display,
  9448.                 opacity: addedSlider.style.opacity,
  9449.                 visibility: addedSlider.style.visibility,
  9450.                 zIndex: addedSlider.style.zIndex,
  9451.                 position: addedSlider.style.position
  9452.               });
  9453.               console.log('Slider dans viewport:', addedSlider.getBoundingClientRect());
  9454.             } else {
  9455.               console.error('Erreur: slider non trouvé après ajout');
  9456.             }
  9457.           }
  9458.           showSlide(index) {
  9459.             console.log('=== showSlide appelée ===', 'index:', index, 'total:', this.images.length);
  9460.             if (index < 0 || index >= this.images.length) {
  9461.               console.log('Index invalide, arrêt');
  9462.               return;
  9463.             }
  9464.             this.currentIndex = index;
  9465.             // Masquer toutes les slides et afficher seulement la courante
  9466.             const slides = document.querySelectorAll('#universalSlider .slide');
  9467.             console.log('Slides trouvées:', slides.length);
  9468.             slides.forEach((slide, i) => {
  9469.               slide.style.display = i === index ? 'flex' : 'none';
  9470.               console.log(`Slide \${i}:`, i === index ? 'visible' : 'cachée');
  9471.             });
  9472.             // Mettre à jour le compteur
  9473.             const currentSlideSpan = document.querySelector('#universalSlider .current-slide');
  9474.             if (currentSlideSpan) {
  9475.               currentSlideSpan.textContent = index + 1;
  9476.               console.log('Compteur mis à jour:', index + 1);
  9477.             }
  9478.             // Mettre à jour les boutons de navigation
  9479.             const prevBtn = document.querySelector('#universalSlider .prev-btn');
  9480.             const nextBtn = document.querySelector('#universalSlider .next-btn');
  9481.             
  9482.             if (prevBtn) {
  9483.               prevBtn.style.opacity = index > 0 ? '1' : '0.5';
  9484.             }
  9485.             if (nextBtn) {
  9486.               nextBtn.style.opacity = index < this.images.length - 1 ? '1' : '0.5';
  9487.             }
  9488.             // Mettre à jour la galerie cinématographique
  9489.             this.updateCinemaGallery(index);
  9490.             // Mettre à jour le bouton favori
  9491.             this.updateFavoriteButton();
  9492.           }
  9493.           updateCinemaGallery(activeIndex) {
  9494.             // Mettre à jour la progress bar (optimisé)
  9495.             const progressBar = document.querySelector('.progress-bar');
  9496.             if (progressBar) {
  9497.               progressBar.style.width = `\${(activeIndex + 1) / this.images.length * 100}%`;
  9498.             }
  9499.             // Mettre à jour le compteur (optimisé)
  9500.             const counter = document.querySelector('.photo-counter span');
  9501.             if (counter) {
  9502.               counter.textContent = activeIndex + 1;
  9503.             }
  9504.             // Mettre à jour les thumbnails - optimisé avec moins de calculs
  9505.             const cinemaThumbs = document.querySelectorAll('.cinema-thumb');
  9506.             cinemaThumbs.forEach((thumb, i) => {
  9507.               const isActive = i === activeIndex;
  9508.               
  9509.               // Optimisation: changements minimaux
  9510.               if (isActive) {
  9511.                 thumb.style.width = '100px';
  9512.                 thumb.style.transform = 'translateY(-4px)';
  9513.                 thumb.style.opacity = '1';
  9514.                 thumb.style.borderColor = '#10b981';
  9515.                 thumb.style.borderWidth = '2px';
  9516.                 
  9517.                 // Numéro actif - simplifié
  9518.                 const number = thumb.querySelector('.thumb-number');
  9519.                 if (number) {
  9520.                   number.style.background = '#10b981';
  9521.                 }
  9522.               } else {
  9523.                 thumb.style.width = '70px';
  9524.                 thumb.style.transform = 'translateY(0)';
  9525.                 thumb.style.opacity = '0.7';
  9526.                 thumb.style.borderColor = 'rgba(255,255,255,0.3)';
  9527.                 thumb.style.borderWidth = '1px';
  9528.                 
  9529.                 // Numéro inactif - simplifié
  9530.                 const number = thumb.querySelector('.thumb-number');
  9531.                 if (number) {
  9532.                   number.style.background = 'rgba(0,0,0,0.8)';
  9533.                 }
  9534.               }
  9535.             });
  9536.             // Auto-scroll optimisé avec throttling
  9537.             if (!this.scrollTimeout) {
  9538.               this.scrollTimeout = setTimeout(() => {
  9539.                 const track = document.getElementById('carouselTrack');
  9540.                 const activeThumb = document.querySelector(`.cinema-thumb[data-index=\"\${activeIndex}\"]`);
  9541.                 if (track && activeThumb) {
  9542.                   const scrollLeft = activeThumb.offsetLeft - (track.clientWidth / 2) + (activeThumb.clientWidth / 2);
  9543.                   track.scrollTo({
  9544.                     left: scrollLeft,
  9545.                     behavior: 'smooth'
  9546.                   });
  9547.                 }
  9548.                 this.scrollTimeout = null;
  9549.               }, 50); // Throttle à 50ms
  9550.             }
  9551.           }
  9552.           updateFavoriteButton() {
  9553.             const currentImage = this.images[this.currentIndex];
  9554.             const favoriteBtn = document.querySelector('.slider-controls .favorite-btn');
  9555.             
  9556.             if (favoriteBtn && currentImage) {
  9557.               favoriteBtn.setAttribute('data-id', currentImage.id);
  9558.               
  9559.               // Vérifier si l'image est déjà en favoris
  9560.               const heartIcon = document.querySelector(`[data-id=\"\${currentImage.id}\"]`);
  9561.               const isFavorite = heartIcon && heartIcon.querySelector('i.bi-heart-fill');
  9562.               
  9563.               const icon = favoriteBtn.querySelector('i');
  9564.               if (isFavorite) {
  9565.                 icon.className = 'bi bi-heart-fill';
  9566.                 favoriteBtn.style.color = '#e91e63';
  9567.               } else {
  9568.                 icon.className = 'bi bi-heart';
  9569.                 favoriteBtn.style.color = 'white';
  9570.               }
  9571.             }
  9572.           }
  9573.           nextSlide() {
  9574.             const nextIndex = (this.currentIndex + 1) % this.images.length;
  9575.             this.showSlide(nextIndex);
  9576.           }
  9577.           prevSlide() {
  9578.             const prevIndex = (this.currentIndex - 1 + this.images.length) % this.images.length;
  9579.             this.showSlide(prevIndex);
  9580.           }
  9581.           close() {
  9582.             if (!this.isOpen) return;
  9583.             const slider = document.querySelector('.universal-slider');
  9584.             if (slider) {
  9585.               slider.classList.remove('active');
  9586.               
  9587.               setTimeout(() => {
  9588.                 slider.remove();
  9589.                 this.isOpen = false;
  9590.               }, 300);
  9591.             }
  9592.           }
  9593.           attachEvents() {
  9594.             console.log('=== attachEvents appelée ===');
  9595.             const slider = document.getElementById('universalSlider');
  9596.             if (!slider) {
  9597.               console.error('Slider non trouvé pour attachEvents');
  9598.               return;
  9599.             }
  9600.             console.log('Slider trouvé pour attachEvents');
  9601.             
  9602.             // Bouton fermer
  9603.             const closeBtn = slider.querySelector('.close-btn');
  9604.             if (closeBtn) {
  9605.               console.log('Bouton fermer trouvé');
  9606.               closeBtn.addEventListener('click', () => {
  9607.                 console.log('Clic fermer');
  9608.                 this.close();
  9609.               });
  9610.             }
  9611.             
  9612.             // Navigation
  9613.             const prevBtn = slider.querySelector('.prev-btn');
  9614.             const nextBtn = slider.querySelector('.next-btn');
  9615.             if (prevBtn) {
  9616.               console.log('Bouton précédent trouvé');
  9617.               prevBtn.addEventListener('click', () => {
  9618.                 console.log('Clic précédent');
  9619.                 this.prevSlide();
  9620.               });
  9621.             }
  9622.             if (nextBtn) {
  9623.               console.log('Bouton suivant trouvé');
  9624.               nextBtn.addEventListener('click', () => {
  9625.                 console.log('Clic suivant');
  9626.                 this.nextSlide();
  9627.               });
  9628.             }
  9629.             // Navigation cinématographique des thumbnails
  9630.             const cinemaThumbs = slider.querySelectorAll('.cinema-thumb');
  9631.             cinemaThumbs.forEach((thumb, index) => {
  9632.               thumb.addEventListener('click', () => {
  9633.                 console.log('Clic cinema thumbnail:', index);
  9634.                 this.showSlide(index);
  9635.                 this.updateCinemaGallery(index);
  9636.               });
  9637.             });
  9638.             console.log('Cinema thumbnails cliquables:', cinemaThumbs.length);
  9639.             // Clic sur overlay pour fermer
  9640.             const overlay = slider.querySelector('.slider-overlay');
  9641.             if (overlay) {
  9642.               overlay.addEventListener('click', () => {
  9643.                 console.log('Clic overlay');
  9644.                 this.close();
  9645.               });
  9646.             }
  9647.             // Clavier
  9648.             this.keyboardHandler = this.handleKeyboard.bind(this);
  9649.             document.addEventListener('keydown', this.keyboardHandler);
  9650.             console.log('Événements clavier attachés');
  9651.             // Zoom sur les images
  9652.             this.attachZoomEvents(slider);
  9653.             console.log('Événements zoom attachés');
  9654.             console.log('Événements attachés avec succès');
  9655.           }
  9656.           close() {
  9657.             console.log('=== close appelée ===');
  9658.             const slider = document.querySelector('.universal-slider');
  9659.             if (slider) {
  9660.               console.log('Fermeture du slider');
  9661.               // Animation de fermeture
  9662.               slider.style.opacity = '0';
  9663.               
  9664.               setTimeout(() => {
  9665.                 slider.remove();
  9666.                 console.log('Slider supprimé du DOM');
  9667.                 
  9668.                 // Nettoyer les événements
  9669.                 if (this.keyboardHandler) {
  9670.                   document.removeEventListener('keydown', this.keyboardHandler);
  9671.                   this.keyboardHandler = null;
  9672.                 }
  9673.                 
  9674.                 this.isOpen = false;
  9675.               }, 300);
  9676.             }
  9677.           }
  9678.           nextSlide() {
  9679.             if (this.currentIndex < this.images.length - 1) {
  9680.               this.showSlide(this.currentIndex + 1);
  9681.             }
  9682.           }
  9683.           prevSlide() {
  9684.             if (this.currentIndex > 0) {
  9685.               this.showSlide(this.currentIndex - 1);
  9686.             }
  9687.           }
  9688.           handleKeyboard(e) {
  9689.             if (!this.isOpen) return;
  9690.             
  9691.             switch (e.key) {
  9692.               case 'Escape':
  9693.                 this.close();
  9694.                 break;
  9695.               case 'ArrowLeft':
  9696.                 this.prevSlide();
  9697.                 break;
  9698.               case 'ArrowRight':
  9699.                 this.nextSlide();
  9700.                 break;
  9701.             }
  9702.           }
  9703.           attachZoomEvents(slider) {
  9704.             // Fonctionnalité de zoom à 5 niveaux pour les images
  9705.             const images = slider.querySelectorAll('.slide img');
  9706.             images.forEach(img => {
  9707.               let zoomLevel = 1; // 1x, 1.5x, 2x, 3x, 4x, 5x
  9708.               let isDragging = false;
  9709.               let startX = 0;
  9710.               let startY = 0;
  9711.               let translateX = 0;
  9712.               let translateY = 0;
  9713.               // Clic simple pour zoom progressif (5 niveaux)
  9714.               img.addEventListener('click', (e) => {
  9715.                 e.preventDefault();
  9716.                 e.stopPropagation();
  9717.                 
  9718.                 // Cycle à travers 5 niveaux de zoom
  9719.                 switch(zoomLevel) {
  9720.                   case 1: zoomLevel = 1.5; break;  // 1x → 1.5x
  9721.                   case 1.5: zoomLevel = 2; break;  // 1.5x → 2x
  9722.                   case 2: zoomLevel = 3; break;    // 2x → 3x
  9723.                   case 3: zoomLevel = 4; break;    // 3x → 4x
  9724.                   case 4: zoomLevel = 5; break;    // 4x → 5x
  9725.                   case 5: 
  9726.                     zoomLevel = 1;                 // 5x → 1x (reset)
  9727.                     translateX = 0;
  9728.                     translateY = 0;
  9729.                     break;
  9730.                 }
  9731.                 console.log('Zoom niveau:', zoomLevel);
  9732.                 img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  9733.                 
  9734.                 // Curseur selon le niveau
  9735.                 if (zoomLevel === 1) {
  9736.                   img.style.cursor = 'zoom-in';
  9737.                   img.removeAttribute('data-zoomed');
  9738.                 } else if (zoomLevel === 5) {
  9739.                   img.style.cursor = 'zoom-out';
  9740.                   img.setAttribute('data-zoomed', zoomLevel);
  9741.                 } else {
  9742.                   img.style.cursor = 'zoom-in';
  9743.                   img.setAttribute('data-zoomed', zoomLevel);
  9744.                 }
  9745.               });
  9746.               // Drag pour déplacer l'image zoomée
  9747.               img.addEventListener('mousedown', (e) => {
  9748.                 if (zoomLevel > 1) {
  9749.                   isDragging = true;
  9750.                   startX = e.clientX - translateX;
  9751.                   startY = e.clientY - translateY;
  9752.                   img.style.cursor = 'grabbing';
  9753.                   e.preventDefault();
  9754.                   e.stopPropagation();
  9755.                 }
  9756.               });
  9757.               // Mousemove global pour le drag
  9758.               const handleMouseMove = (e) => {
  9759.                 if (isDragging && zoomLevel > 1) {
  9760.                   translateX = e.clientX - startX;
  9761.                   translateY = e.clientY - startY;
  9762.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  9763.                 }
  9764.               };
  9765.               // Mouseup global pour arrêter le drag
  9766.               const handleMouseUp = () => {
  9767.                 if (isDragging) {
  9768.                   isDragging = false;
  9769.                   if (zoomLevel === 1) {
  9770.                     img.style.cursor = 'zoom-in';
  9771.                   } else if (zoomLevel === 5) {
  9772.                     img.style.cursor = 'zoom-out';
  9773.                   } else {
  9774.                     img.style.cursor = 'zoom-in';
  9775.                   }
  9776.                 }
  9777.               };
  9778.               document.addEventListener('mousemove', handleMouseMove);
  9779.               document.addEventListener('mouseup', handleMouseUp);
  9780.               // Touch support pour mobile
  9781.               img.addEventListener('touchstart', (e) => {
  9782.                 if (zoomLevel > 1 && e.touches.length === 1) {
  9783.                   isDragging = true;
  9784.                   const touch = e.touches[0];
  9785.                   startX = touch.clientX - translateX;
  9786.                   startY = touch.clientY - translateY;
  9787.                   e.preventDefault();
  9788.                 }
  9789.               });
  9790.               img.addEventListener('touchmove', (e) => {
  9791.                 if (isDragging && zoomLevel > 1 && e.touches.length === 1) {
  9792.                   const touch = e.touches[0];
  9793.                   translateX = touch.clientX - startX;
  9794.                   translateY = touch.clientY - startY;
  9795.                   img.style.transform = `scale(\${zoomLevel}) translate(\${translateX}px, \${translateY}px)`;
  9796.                   e.preventDefault();
  9797.                 }
  9798.               });
  9799.               img.addEventListener('touchend', () => {
  9800.                 isDragging = false;
  9801.               });
  9802.               // Initialiser le curseur
  9803.               img.style.cursor = 'zoom-in';
  9804.             });
  9805.           }
  9806.         }
  9807.         // ⚡ OPTIMISATION MAJEURE: Sliders lazy (créés seulement quand utilisés)
  9808.         let favoritesSlider = null;
  9809.         let universalSlider = null;
  9810.         
  9811.         // Fonctions pour créer les sliders à la demande
  9812.         function getFavoritesSlider() {
  9813.           if (!favoritesSlider) {
  9814.             favoritesSlider = new FavoritesSlider();
  9815.           }
  9816.           return favoritesSlider;
  9817.         }
  9818.         
  9819.         function getUniversalSlider() {
  9820.           if (!universalSlider) {
  9821.             universalSlider = new UniversalImageSlider();
  9822.           }
  9823.           return universalSlider;
  9824.         }
  9825.         // Fonction pour voir un favori avec le slider plein écran
  9826.         function viewFavorite(id) {
  9827.           console.log('Ouverture du slider pour favori:', id);
  9828.           // ⚡ OPTIMISÉ: Utiliser le slider lazy
  9829.           const slider = getUniversalSlider();
  9830.           if (slider && slider.openFromFavorites) {
  9831.             slider.openFromFavorites(id);
  9832.           } else {
  9833.             console.error('Erreur slider favoris');
  9834.           }
  9835.         }
  9836.         // Fonction pour voir une image depuis la galerie normale
  9837.         function viewImage(imageId, clickedElement) {
  9838.           console.log('=== viewImage appelée ===');
  9839.           console.log('imageId:', imageId);
  9840.           console.log('clickedElement:', clickedElement);
  9841.           
  9842.           // Trouver le container du jour - peut être plusieurs niveaux au-dessus
  9843.           let dayContainer = clickedElement;
  9844.           
  9845.           // Remonter jusqu'à trouver un container approprié
  9846.           while (dayContainer && dayContainer !== document.body) {
  9847.             console.log('Checking element:', dayContainer.tagName, dayContainer.className, dayContainer.id);
  9848.             if (dayContainer && dayContainer.classList && (
  9849.                 dayContainer.classList.contains('dynamic-card') || 
  9850.                 dayContainer.classList.contains('collapse') ||
  9851.                 dayContainer.id && dayContainer.id.startsWith('demP')
  9852.             )) {
  9853.               break;
  9854.             }
  9855.             dayContainer = dayContainer.parentElement;
  9856.           }
  9857.           
  9858.           // ⚡ OPTIMISÉ: Logs réduits pour performance
  9859.           
  9860.           // ⚡ OPTIMISÉ: Utiliser le slider lazy
  9861.           const slider = getUniversalSlider();
  9862.           if (slider && slider.openFromGallery) {
  9863.             slider.openFromGallery(imageId, dayContainer);
  9864.           } else {
  9865.             console.error('Erreur slider galerie');
  9866.           }
  9867.         }
  9868.         // ⚡ OPTIMISÉ: Fonctions globales avec sliders lazy
  9869.         window.viewImage = viewImage;
  9870.         window.viewFavorite = viewFavorite;
  9871.         window.getUniversalSlider = getUniversalSlider; // Fonction lazy au lieu de l'instance
  9872.         // Variables globales pour éviter les ReferenceError
  9873.         if (typeof favoriteCount === 'undefined') {
  9874.           window.favoriteCount = 0;
  9875.         }
  9876.         if (typeof favButton === 'undefined') {
  9877.           window.favButton = null;
  9878.         }
  9879.         if (typeof favoriteButton === 'undefined') {
  9880.           window.favoriteButton = null;
  9881.         }
  9882.         if (typeof purchaseAlertTimeout === 'undefined') {
  9883.           window.purchaseAlertTimeout = null;
  9884.         }
  9885.         
  9886.         // Définir favoriteCount globalement pour éviter les ReferenceError
  9887.         let favoriteCount = window.favoriteCount || 0;
  9888.         // Fonction de sécurité pour vérifier les éléments DOM
  9889.         function safeAddEventListener(selector, event, callback) {
  9890.           const element = document.querySelector(selector);
  9891.           if (element) {
  9892.             element.addEventListener(event, callback);
  9893.           } else {
  9894.             console.warn(`Élément non trouvé: \${selector}`);
  9895.           }
  9896.         }
  9897.         // Fonction utilitaire pour manipuler classList de manière sécurisée
  9898.         function safeClassList(element, action, ...classes) {
  9899.           if (!element || !element.classList) {
  9900.             console.warn('Élément ou classList invalide:', element);
  9901.             return false;
  9902.           }
  9903.           
  9904.           try {
  9905.             switch(action) {
  9906.               case 'add':
  9907.                 element.classList.add(...classes);
  9908.                 break;
  9909.               case 'remove':
  9910.                 element.classList.remove(...classes);
  9911.                 break;
  9912.               case 'toggle':
  9913.                 return element.classList.toggle(classes[0], classes[1]);
  9914.               case 'contains':
  9915.                 return element.classList.contains(classes[0]);
  9916.               default:
  9917.                 console.warn('Action classList inconnue:', action);
  9918.                 return false;
  9919.             }
  9920.             return true;
  9921.           } catch (error) {
  9922.             console.warn('Erreur lors de la manipulation de classList:', error);
  9923.             return false;
  9924.           }
  9925.         }
  9926.         // Rendre la fonction utilitaire globale
  9927.         window.safeClassList = safeClassList;
  9928.         // Fonction pour sécuriser automatiquement tous les accès à classList
  9929.         function secureClassListAccess() {
  9930.           // Intercepter les erreurs classList globalement
  9931.           window.addEventListener('error', function(e) {
  9932.             if (e.message && (e.message.includes('classList') || e.message.includes('Cannot read properties of null'))) {
  9933.               console.warn('Erreur DOM interceptée et corrigée:', e.message, 'Ligne:', e.lineno, 'Fichier:', e.filename);
  9934.               e.preventDefault(); // Empêcher l'erreur de se propager
  9935.               return true;
  9936.             }
  9937.           });
  9938.           
  9939.           // Intercepter les erreurs non catchées
  9940.           window.addEventListener('unhandledrejection', function(e) {
  9941.             if (e.reason && e.reason.message && e.reason.message.includes('classList')) {
  9942.               console.warn('Promise rejection classList interceptée:', e.reason.message);
  9943.               e.preventDefault();
  9944.               return true;
  9945.             }
  9946.           });
  9947.           
  9948.           console.log('Système de sécurisation DOM/classList activé');
  9949.         }
  9950.         // Activer la sécurisation
  9951.         secureClassListAccess();
  9952.         // Fonction de diagnostic pour vérifier l'affichage du slider
  9953.         function diagnoseSliderDisplay(sliderId) {
  9954.           const slider = document.querySelector(sliderId);
  9955.           if (!slider) {
  9956.             console.error('Diagnostic: Slider non trouvé -', sliderId);
  9957.             return false;
  9958.           }
  9959.           
  9960.           const styles = window.getComputedStyle(slider);
  9961.           const rect = slider.getBoundingClientRect();
  9962.           
  9963.           console.log('=== DIAGNOSTIC SLIDER ===', sliderId);
  9964.           console.log('Élément présent:', !!slider);
  9965.           console.log('Styles calculés:', {
  9966.             display: styles.display,
  9967.             opacity: styles.opacity,
  9968.             visibility: styles.visibility,
  9969.             zIndex: styles.zIndex,
  9970.             position: styles.position
  9971.           });
  9972.           console.log('Position/Taille:', rect);
  9973.           console.log('Dans le viewport:', rect.width > 0 && rect.height > 0);
  9974.           console.log('Parent:', slider.parentElement?.tagName);
  9975.           
  9976.           // Vérifier les règles CSS qui pourraient masquer le slider
  9977.           const hiddenReasons = [];
  9978.           if (styles.display === 'none') hiddenReasons.push('display: none');
  9979.           if (styles.opacity === '0') hiddenReasons.push('opacity: 0');
  9980.           if (styles.visibility === 'hidden') hiddenReasons.push('visibility: hidden');
  9981.           if (parseInt(styles.zIndex) < 0) hiddenReasons.push('z-index négatif');
  9982.           
  9983.           if (hiddenReasons.length > 0) {
  9984.             console.warn('Raisons du masquage:', hiddenReasons);
  9985.             
  9986.             // Forcer l'affichage
  9987.             console.log('Forçage de l\\'affichage...');
  9988.             slider.style.display = 'flex';
  9989.             slider.style.opacity = '1';
  9990.             slider.style.visibility = 'visible';
  9991.             slider.style.zIndex = '9999';
  9992.             slider.style.position = 'fixed';
  9993.             slider.style.top = '0';
  9994.             slider.style.left = '0';
  9995.             slider.style.width = '100%';
  9996.             slider.style.height = '100%';
  9997.             
  9998.             console.log('Slider forcé visible');
  9999.           } else {
  10000.             console.log('✅ Slider devrait être visible');
  10001.           }
  10002.           
  10003.           return true;
  10004.         }
  10005.         // Rendre la fonction globale
  10006.         window.diagnoseSliderDisplay = diagnoseSliderDisplay;
  10007.         // Fonction de sécurité pour checkFavorites
  10008.         function checkFavorites() {
  10009.           try {
  10010.             let count = 0;
  10011.             if (typeof getFavoriteItems === 'function') {
  10012.               count = getFavoriteItems().length;
  10013.             } else {
  10014.               // Fallback : compter depuis le DOM
  10015.               const giftCount = document.getElementById('giftCount');
  10016.               if (giftCount && giftCount.textContent) {
  10017.                 count = parseInt(giftCount.textContent.trim()) || 0;
  10018.               }
  10019.             }
  10020.             
  10021.             // Mettre à jour les variables globales
  10022.             window.favoriteCount = count;
  10023.             favoriteCount = count;
  10024.             
  10025.             console.log('Favoris vérifiés:', count);
  10026.             return count;
  10027.           } catch (error) {
  10028.             console.warn('Erreur lors de la vérification des favoris:', error);
  10029.             return 0;
  10030.           }
  10031.         }
  10032.         // Rendre checkFavorites globale si elle n'existe pas
  10033.         if (typeof window.checkFavorites === 'undefined') {
  10034.           window.checkFavorites = checkFavorites;
  10035.         }
  10036.         // Initialisation sécurisée après chargement du DOM
  10037.         document.addEventListener('DOMContentLoaded', function() {
  10038.           console.log('=== DOM chargé, initialisation des sliders ===');
  10039.           console.log('viewImage disponible:', typeof window.viewImage);
  10040.           console.log('viewFavorite disponible:', typeof window.viewFavorite);
  10041.           console.log('universalSlider disponible:', typeof window.universalSlider);
  10042.           
  10043.           // Vérifier que les éléments critiques existent
  10044.           const criticalElements = [
  10045.             'filtre_photos_voir',
  10046.             // Ajoutez d'autres IDs critiques ici si nécessaire
  10047.           ];
  10048.           
  10049.           criticalElements.forEach(id => {
  10050.             const element = document.getElementById(id);
  10051.             if (element) {
  10052.               console.log(`✓ Élément trouvé: \${id}`);
  10053.             } else {
  10054.               console.warn(`⚠ Élément manquant: \${id}`);
  10055.             }
  10056.           });
  10057.           
  10058.           // Initialiser checkFavorites si la fonction existe
  10059.           if (typeof window.checkFavorites === 'function') {
  10060.             window.checkFavorites();
  10061.           }
  10062.         });
  10063.       
  10064.         // Fonction pour obtenir l'image d'un produit selon son type
  10065.         function getProductImage(productId) {
  10066.           const productImages = {
  10067.             'album': '/images/produit/Album5sur5-3.jpg',
  10068.             'digital': '/images/produit/photoNumerique.jpg', 
  10069.             'prints': '/images/produit/PochettePhoto5sur5-2.jpg',
  10070.             'calendrier': '/images/produit/Calendrier5sur5-1.jpg',
  10071.             'livre': '/images/produit/LivreSouvenir5sur5-1.jpg',
  10072.             'coffret': '/images/produit/CoffretCadeau5sur5-2.jpg',
  10073.             'retro': '/images/produit/PochetteRetro5sur5-1.jpg'
  10074.           };
  10075.           
  10076.           return productImages[productId] || '/images/produit/albumm.PNG';
  10077.         }
  10078.         
  10079.         // Fonction pour générer les suggestions de produits (synchronisées avec ecommerce-sidebar)
  10080.         function generateProductSuggestions(favoriteCount) {
  10081.           if (favoriteCount === 0) {
  10082.             return `
  10083.               <div class=\"no-favorites-cta\">
  10084.                 <div class=\"cta-content\">
  10085.                   <i class=\"bi bi-heart\" style=\"font-size: 4rem; color: #e91e63; margin-bottom: 1rem;\"></i>
  10086.                   <h3>Commencez par sélectionner vos photos préférées</h3>
  10087.                   <p>Cliquez sur <i class=\"bi bi-heart\" style=\"color: #e91e63;\"></i> sur vos plus beaux souvenirs pour débloquer nos produits personnalisés.</p>
  10088.                   <button class=\"btn-start-selection\" onclick=\"window.showDaysView()\">
  10089.                     <i class=\"bi bi-images\"></i>
  10090.                     Parcourir les photos
  10091.                   </button>
  10092.                 </div>
  10093.               </div>
  10094.             `;
  10095.           }
  10096.           let suggestionsHTML = '<div class=\"suggestions-header\"><h4><i class=\"bi bi-gift\"></i> Produits recommandés pour vous</h4></div>';
  10097.           
  10098.           // Utiliser les mêmes produits que dans ecommerce-sidebar
  10099.           const products = [];
  10100.           
  10101.           // Album Photo Premium (toujours disponible)
  10102.           products.push({
  10103.             id: 'album',
  10104.             name: 'Album Photo Premium',
  10105.             description: `Album photo personnalisé avec vos \${favoriteCount} photos favorites. Papier de qualité supérieure, reliure rigide.`,
  10106.             currentPrice: '24,90€',
  10107.             originalPrice: '28,90€',
  10108.             savings: '-14%',
  10109.             badge: 'Populaire',
  10110.             available: favoriteCount > 0,
  10111.             disabled: favoriteCount === 0
  10112.           });
  10113.           // Pack Numérique HD (toujours disponible)
  10114.           products.push({
  10115.             id: 'digital',
  10116.             name: 'Pack Numérique HD',
  10117.             description: `Téléchargement immédiat de vos photos en haute définition. Qualité professionnelle garantie.`,
  10118.             currentPrice: '3,90€',
  10119.             originalPrice: '',
  10120.             savings: '',
  10121.             badge: 'Nouveau',
  10122.             available: favoriteCount > 0,
  10123.             disabled: favoriteCount === 0
  10124.           });
  10125.           // Tirages Premium (disponible si >= 12 favoris)
  10126.          
  10127.             products.push({
  10128.               id: 'prints',
  10129.               name: 'Tirages Premium',
  10130.               description: `\${Math.min(favoriteCount, 12)} tirages photo 10x15cm de vos favoris. Papier brillant professionnel, livraison gratuite.`,
  10131.               currentPrice: '9.9€',
  10132.               originalPrice: '',
  10133.               savings: '',
  10134.               badge: 'Débloqué !',
  10135.               available: true,
  10136.               disabled: false
  10137.             });
  10138.           
  10139.           suggestionsHTML += '<div class=\"products-grid\">';
  10140.           
  10141.           products.forEach(product => {
  10142.             suggestionsHTML += `
  10143.               <div class=\"product-card \${product.disabled ? 'disabled' : ''}\" data-product=\"\${product.id}\">
  10144.                 <div class=\"product-badge \${product.disabled ? 'disabled' : ''}\">\${product.badge}</div>
  10145.                 <div class=\"product-image\">
  10146.                   <img src=\"\${getProductImage(product.id)}\" alt=\"\${product.name}\" onerror=\"this.src='/images/produit/albumm.PNG'\">
  10147.                 </div>
  10148.                 <div class=\"product-info\">
  10149.                   <h5>\${product.name}</h5>
  10150.                   <p>\${product.description}</p>
  10151.                   <div class=\"product-pricing\">
  10152.                     <span class=\"current-price\">\${product.currentPrice}</span>
  10153.                     \${product.originalPrice ? `<span class=\"original-price\">\${product.originalPrice}</span>` : ''}
  10154.                     \${product.savings ? `<span class=\"savings\">\${product.savings}</span>` : ''}
  10155.                   </div>
  10156.                   <button class=\"btn-add-to-cart \${product.disabled ? 'disabled' : ''}\" 
  10157.                           onclick=\"orderProduct('\${product.id}')\" 
  10158.                           \${product.disabled ? 'disabled title=\"Ajoutez des favoris pour commander\"' : ''}>
  10159.                     <i class=\"bi bi-cart-plus\"></i>
  10160.                     \${product.disabled ? 'Ajoutez des favoris' : 'Commander'}
  10161.                   </button>
  10162.                 </div>
  10163.               </div>
  10164.             `;
  10165.           });
  10166.           
  10167.           suggestionsHTML += '</div>';
  10168.           // Message d'encouragement
  10169.           if (favoriteCount < 12) {
  10170.             const remaining = 12 - favoriteCount;
  10171.             suggestionsHTML += `
  10172.               <div class=\"encouragement-card\">
  10173.                 <div class=\"encouragement-content\">
  10174.                   <div class=\"encouragement-icon\">🎯</div>
  10175.                   <div class=\"encouragement-text\">
  10176.                     <h5>Encore \${remaining} photo\${remaining > 1 ? 's' : ''} pour débloquer les Tirages Premium !</h5>
  10177.                     <p>Sélectionnez \${remaining} photo\${remaining > 1 ? 's' : ''} supplémentaire\${remaining > 1 ? 's' : ''} pour accéder à tous nos produits</p>
  10178.                   </div>
  10179.                 </div>
  10180.               </div>
  10181.             `;
  10182.           }
  10183.           return suggestionsHTML;
  10184.         }
  10185.         // Fonction pour ajouter au panier
  10186.         function addToCart(productId) {
  10187.           // Animation du bouton cadeau
  10188.           const giftButton = document.querySelector('.gift-button');
  10189.           if (giftButton) {
  10190.             if (giftButton.classList) {
  10191.               giftButton.classList.add('active');
  10192.               setTimeout(() => {
  10193.                 if (giftButton.classList) {
  10194.                   giftButton.classList.remove('active');
  10195.                 }
  10196.               }, 600);
  10197.             }
  10198.           }
  10199.           // Afficher une notification
  10200.           showNotification(`Produit ajouté au panier !`, 'success');
  10201.           
  10202.           // Ici vous pourriez ajouter la logique d'ajout au panier réel
  10203.           console.log('Ajout au panier:', productId);
  10204.         }
  10205.         // Fonction pour afficher une notification
  10206.         function showNotification(message, type = 'info') {
  10207.           const notification = document.createElement('div');
  10208.           notification.className = `notification \${type}`;
  10209.           notification.innerHTML = `
  10210.             <i class=\"bi bi-check-circle\"></i>
  10211.             <span>\${message}</span>
  10212.           `;
  10213.           
  10214.           document.body.appendChild(notification);
  10215.           
  10216.           setTimeout(() => {
  10217.             if (notification && notification.classList) {
  10218.               notification.classList.add('show');
  10219.             }
  10220.           }, 100);
  10221.           
  10222.           setTimeout(() => {
  10223.             if (notification && notification.classList) {
  10224.               notification.classList.remove('show');
  10225.               setTimeout(() => {
  10226.                 if (document.body.contains(notification)) {
  10227.                   document.body.removeChild(notification);
  10228.                 }
  10229.               }, 300);
  10230.             }
  10231.           }, 3000);
  10232.         }
  10233.         // Fonction pour obtenir le nombre actuel de favoris
  10234.         function getCurrentFavoriteCount() {
  10235.           return getFavoriteItems().length;
  10236.         }
  10237.         // Gestion du localStorage pour l'indicateur \"nouveau contenu\"
  10238.         const lastVisitKey = 'lastVisitISO';
  10239.         const currentVisit = new Date().toISOString();
  10240.         
  10241.         // Sauvegarder la visite actuelle
  10242.         localStorage.setItem(lastVisitKey, currentVisit);
  10243.         
  10244.         // Vérifier et marquer les jours avec nouveau contenu
  10245.         const dateCards = document.querySelectorAll('.date-card.modern-card');
  10246.         dateCards.forEach(card => {
  10247.           // Ici vous devriez comparer avec updatedAt du backend
  10248.           // Pour l'instant, on simule avec un attribut data-updated
  10249.           const updatedAt = card.getAttribute('data-updated');
  10250.           if (updatedAt) {
  10251.             const lastVisit = localStorage.getItem(lastVisitKey);
  10252.             if (new Date(updatedAt) > new Date(lastVisit)) {
  10253.               if (card && card.classList) {
  10254.                 card.classList.add('has-new-content');
  10255.               }
  10256.               // Ajouter le badge \"nouveau\" si pas déjà présent
  10257.               if (!card.querySelector('.badge-new')) {
  10258.                 const badge = document.createElement('span');
  10259.                 badge.className = 'badge-new';
  10260.                 badge.setAttribute('aria-label', 'Nouveau contenu');
  10261.                 card.querySelector('.title-line').appendChild(badge);
  10262.               }
  10263.             }
  10264.           }
  10265.         });
  10266.         // Gestion des aria-label dynamiques pour les cartes de jours
  10267.         dateCards.forEach(card => {
  10268.           const dayText = card.querySelector('.day').textContent.trim();
  10269.           const dateText = card.querySelector('.full-date').textContent.trim();
  10270.           const photos = card.querySelector('.media-list-horizontal li:nth-child(1)')?.textContent.trim() || '0';
  10271.           const audios = card.querySelector('.media-list-horizontal li:nth-child(2)')?.textContent.trim() || '0';
  10272.           const videos = card.querySelector('.media-list-horizontal li:nth-child(3)')?.textContent.trim() || '0';
  10273.           
  10274.           const ariaLabel = `Contenu du \${dateText} : \${photos} photos, \${audios} audios, \${videos} vidéos`;
  10275.           card.setAttribute('aria-label', ariaLabel);
  10276.         });
  10277.       });
  10278.     </script>
  10279.     
  10280.     <!-- Make sure we're showing the right content by default if no valid content is marked 'show' -->
  10281.     {% if lastValidIndex > 0 %}
  10282.     <script>
  10283.       document.addEventListener('DOMContentLoaded', function() {
  10284.         // Check if no content is showing
  10285.         if (document.querySelectorAll('.container--gallery .collapse.show').length === 0) {
  10286.           // Show the content for the last valid date
  10287.           var lastValidContent = document.getElementById('demP{{ lastValidIndex }}');
  10288.           if (lastValidContent) {
  10289.             if (lastValidContent.classList) {
  10290.               lastValidContent.classList.add('show');
  10291.             }
  10292.             
  10293.             // Also mark the corresponding date card as active
  10294.             var dateCards = document.querySelectorAll('.date-card');
  10295.             if (dateCards.length >= {{ lastValidIndex }}) {
  10296.               dateCards.forEach(card => {
  10297.                 if (card && card.classList) {
  10298.                   card.classList.remove('active');
  10299.                 }
  10300.               });
  10301.               const targetCard = dateCards[{{ lastValidIndex - 1 }}];
  10302.               if (targetCard && targetCard.classList) {
  10303.                 targetCard.classList.add('active');
  10304.               }
  10305.             }
  10306.           }
  10307.         }
  10308.       });
  10309.     </script>
  10310.     {% endif %}
  10311.   </div>
  10312. </div>
  10313.   {% endblock %} {% block Javascript %}
  10314.   {{ parent() }}
  10315.   <script>// Gestion de la sidebar des favoris
  10316. document.addEventListener('DOMContentLoaded', function() {
  10317.     const sidebar = document.getElementById('favorites-sidebar');
  10318.     const openBtn = document.getElementById('openFavoritesSidebar');
  10319.     const closeBtn = document.querySelector('.favorites-close');
  10320.     const giftButton = document.querySelector('.gift-button');
  10321.     function openSidebar() {
  10322.         if (sidebar && sidebar.classList) {
  10323.           sidebar.classList.add('active');
  10324.           updateFavoritesSidebar();
  10325.         }
  10326.     }
  10327.     function closeSidebar() {
  10328.         if (sidebar && sidebar.classList) {
  10329.           sidebar.classList.remove('active');
  10330.         }
  10331.     }
  10332.     function updateFavoritesSidebar() {
  10333.         const grid = document.getElementById('favorites-grid');
  10334.         const counter = document.getElementById('favorites-counter');
  10335.         const emptyState = document.getElementById('favorites-empty-state');
  10336.         const progress = document.getElementById('favorites-progress');
  10337.         
  10338.         const count = parseInt(document.getElementById('likeCount').textContent);
  10339.         counter.textContent = count +1;
  10340.         
  10341.         if (count === 0) {
  10342.             emptyState.style.display = 'flex';
  10343.             grid.style.display = 'none';
  10344.         } else {
  10345.             emptyState.style.display = 'none';
  10346.             grid.style.display = 'grid';
  10347.             const percentage = (count / 20) * 100;
  10348.             progress.style.width = `\${percentage}%`;
  10349.         }
  10350.     }
  10351.     if (openBtn) {
  10352.         openBtn.addEventListener('click', openSidebar);
  10353.     }
  10354.     if (favButton) {
  10355.         favButton.addEventListener('click', openSidebar);
  10356.     }
  10357.     if (closeBtn) {
  10358.         closeBtn.addEventListener('click', closeSidebar);
  10359.     }
  10360.     document.addEventListener('click', (e) => {
  10361.         if (sidebar && sidebar.classList && sidebar.classList.contains('active') && 
  10362.             !sidebar.contains(e.target) && 
  10363.             (!favButton || !favButton.contains(e.target)) && 
  10364.             (!openBtn || !openBtn.contains(e.target))) {
  10365.             closeSidebar();
  10366.         }
  10367.     });
  10368. });
  10369. // Modification des fonctions existantes
  10370. const originalAddFavoris = window.AddFavoris;
  10371. window.AddFavoris = function(\$id, \$idSejour, \$urlimg, \$description) {
  10372.     if (originalAddFavoris) {
  10373.         originalAddFavoris(\$id, \$idSejour, \$urlimg, \$description);
  10374.     }
  10375.     
  10376.   
  10377.     
  10378.     // Vérifier si la sidebar est ouverte - noter que nous vérifions la valeur CSS right: 0
  10379.     if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  10380.         // Recharger les favoris
  10381.         loadFavorites();
  10382.     }
  10383. };
  10384. const originalSupprimerFavoris = window.supprimerFavoris;
  10385. window.supprimerFavoris = function(\$id, \$idSejour) {
  10386.     if (originalSupprimerFavoris) {
  10387.         originalSupprimerFavoris(\$id, \$idSejour);
  10388.     }
  10389.     
  10390.     // Mettre à jour tous les compteurs de favoris
  10391.     updateAllFavoriteCounters();
  10392.     
  10393.     // Vérifier si la sidebar est ouverte
  10394.     if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  10395.         // Recharger les favoris
  10396.         loadFavorites();
  10397.     }
  10398. };
  10399. // Variables globales
  10400. let selectedFavorites = [];
  10401. let allFavorites = [];
  10402. // Fonction pour mettre à jour la sidebar
  10403. function loadFavorites() {
  10404.     \$(\"#favorites-grid\").html(\"<div style='text-align:center;padding:20px;'>Chargement...</div>\");
  10405.     
  10406.     \$.ajax({
  10407.         url: \"/Parent/mes-favoris\",
  10408.         type: \"GET\",
  10409.         dataType: \"json\",
  10410.         success: function(data) {
  10411.             \$(\"#favorites-grid\").empty();
  10412.             allFavorites = data.data || [];
  10413.             
  10414.             if (allFavorites.length > 0) {
  10415.                 \$(\"#favorites-empty-state\").hide();
  10416.                 
  10417.                 \$.each(allFavorites, function(i, fav) {
  10418.                     var isSelected = selectedFavorites.includes(fav.id);
  10419.                     
  10420.                     var item = \$(\"<div class='favorite-item' style='position:relative;border-radius:8px;overflow:hidden;aspect-ratio:1;cursor:pointer;'></div>\");
  10421.                     var img = \$(\"<img style='width:100%;height:100%;object-fit:cover;transition:transform 0.3s ease;'>\").attr(\"src\", fav.path).attr(\"alt\", fav.descreption || \"Photo favorite\");
  10422.                     
  10423.                     // Overlay de sélection
  10424.                     var selectionOverlay = \$(\"<div class='selection-overlay' style='position:absolute;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.3);display:flex;align-items:center;justify-content:center;'></div>\");
  10425.                     
  10426.                     // Icône de sélection
  10427.                     var checkIcon = \$(\"<div style='width:25px;height:25px;border-radius:50%;border:2px solid white;display:flex;align-items:center;justify-content:center;background:\" + (isSelected ? \"#F56040\" : \"transparent\") + \";transition:background 0.2s;'></div>\");
  10428.                     if (isSelected) {
  10429.                         checkIcon.append(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  10430.                     }
  10431.                     
  10432.                     selectionOverlay.append(checkIcon);
  10433.                     
  10434.                     // Overlay d'action (bouton supprimer)
  10435.                     var actionOverlay = \$(\"<div class='action-overlay' style='position:absolute;top:5px;right:5px;opacity:0;transition:opacity 0.2s;'></div>\");
  10436.                   
  10437.                     actionOverlay.append(deleteBtn);
  10438.                     
  10439.                     // Ajouter les événements
  10440.                     item.hover(
  10441.                         function() { \$(this).find(\".action-overlay\").css(\"opacity\", \"1\"); },
  10442.                         function() { \$(this).find(\".action-overlay\").css(\"opacity\", \"0\"); }
  10443.                     );
  10444.                     
  10445.                     item.click(function() {
  10446.                         toggleSelection(fav.id, \$(this).find(\".selection-overlay > div\"));
  10447.                     });
  10448.                     
  10449.                     item.append(img).append(selectionOverlay).append(actionOverlay);
  10450.                     \$(\"#favorites-grid\").append(item);
  10451.                 });
  10452.                 
  10453.                 \$(\"#favorites-counter\").text(allFavorites.length);
  10454.                 
  10455.                 // Mettre à jour le compteur sur le bouton également
  10456.                 \$(\"#openFavoritesSidebar span\").text(allFavorites.length);
  10457.                 
  10458.                 // Mettre à jour l'interface produits
  10459.                 updateProductsView();
  10460.                 
  10461.             } else {
  10462.                 \$(\"#favorites-empty-state\").show();
  10463.                 \$(\"#favorites-counter\").text(\"0\");
  10464.                 \$(\"#openFavoritesSidebar span\").text(\"0\");
  10465.                 \$(\"#selection-count\").text(\"0\");
  10466.                 updateProductsView();
  10467.             }
  10468.         },
  10469.         error: function() {
  10470.             \$(\"#favorites-grid\").html(\"<div style='color:red;text-align:center;padding:20px;'>Erreur de chargement</div>\");
  10471.         }
  10472.     });
  10473. }
  10474. // Fonction pour supprimer un favori
  10475. function removeFavorite(id) {
  10476.     \$.ajax({
  10477.         url: \"/Parent/remove-favorite/\" + id,
  10478.         type: \"POST\",
  10479.         success: function() {
  10480.             // Retirer de la sélection si présent
  10481.             selectedFavorites = selectedFavorites.filter(favId => favId != id);
  10482.             
  10483.             // Mettre à jour le compteur de sélection
  10484.             \$(\"#selection-count\").text(selectedFavorites.length);
  10485.             
  10486.             // Recharger les favoris
  10487.             loadFavorites();
  10488.             
  10489.             // Mettre à jour tous les compteurs de favoris
  10490.             updateAllFavoriteCounters();
  10491.             
  10492.             // Mettre à jour l'interface produits
  10493.             updateProductsView();
  10494.         },
  10495.         error: function() {
  10496.             alert(\"Erreur lors de la suppression du favori\");
  10497.         }
  10498.     });
  10499. }
  10500. // Fonction pour basculer la sélection d'une photo
  10501. function toggleSelection(id, checkElement) {
  10502.     const index = selectedFavorites.indexOf(id);
  10503.     
  10504.     if (index === -1) {
  10505.         // Ajouter à la sélection
  10506.         selectedFavorites.push(id);
  10507.         checkElement.css(\"background\", \"#F56040\");
  10508.         checkElement.html(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  10509.     } else {
  10510.         // Retirer de la sélection
  10511.         selectedFavorites.splice(index, 1);
  10512.         checkElement.css(\"background\", \"transparent\");
  10513.         checkElement.html(\"\");
  10514.     }
  10515.     
  10516.     // Mettre à jour le compteur
  10517.     \$(\"#selection-count\").text(selectedFavorites.length);
  10518.     
  10519.     // Mettre à jour l'interface produits
  10520.     updateProductsView();
  10521. }
  10522. // Fonction pour mettre à jour la vue des produits
  10523. function updateProductsView() {
  10524.     const current = selectedFavorites.length;
  10525.     \$(\"#product-photo-count\").text(current);
  10526.     
  10527.     let remainingForAlbum = Math.max(0, 20 - current);
  10528.     let remainingForPochette = Math.max(0, 12 - current);
  10529.     let remainingForPack = Math.max(0, 12 - current);
  10530.     const progressBar = (count, total, color) => `
  10531.         <div style=\"margin: 5px 0;\">
  10532.             <div style=\"background-color: #e9ecef; border-radius: 5px; overflow: hidden; height: 8px;\">
  10533.                 <div style=\"width: \${(count / total) * 100}%; background-color: \${color}; height: 100%;\"></div>
  10534.             </div>
  10535.             <small style=\"font-size: 12px;\">\${count}/\${total} photos</small>
  10536.         </div>
  10537.     `;
  10538.     // Liste des produits
  10539.     const products = [
  10540.         {
  10541.             name: \"Pack numérique (20 photos)\",
  10542.             required: 20,
  10543.             remaining: Math.max(0, 20 - current),
  10544.             image: \"/images/produit/photoNumerique.jpg\",
  10545.             color: \"#4caf50\",
  10546.             link: \"{{ path('PackPhotosNumerique_Favoris', {'nbr':20}) }}\",
  10547.         },
  10548.        +
  10549.         {
  10550.             name: \"Pochette photo (12 photos)\",
  10551.             required: 12,
  10552.             remaining: Math.max(0, 12 - current),
  10553.             image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  10554.             color: \"#2196f3\",
  10555.             link: \"{{ path('AjoutPochettePhotos_Favoris', {'nbr': 12}) }}\",
  10556.         },
  10557.     ].sort((a, b) => a.remaining - b.remaining);
  10558.     const productList = products
  10559.         .map((product) => {
  10560.             const count = current;
  10561.             const total = product.required;
  10562.             const remaining = product.remaining;
  10563.             return `
  10564.                 <li style=\"margin-bottom: 20px;\">
  10565.                     <div style=\"display: flex; align-items: center; gap: 10px;\">
  10566.                         <img src=\"\${product.image}\" alt=\"\${product.name}\" style=\"width: 70px; height: 70px; border-radius: 5px; object-fit: cover;\" />
  10567.                         <div style=\"flex: 1;\">
  10568.                             <strong style=\"font-size: 14px;\">\${product.name}</strong>
  10569.                             \${progressBar(count, total, product.color)}
  10570.                             \${
  10571.                                 `<small style=\"color: \${product.color}; font-size: 12px;\">
  10572.                                     Encore \${remaining} photos pour compléter \${product.name.toLowerCase()}
  10573.                                 </small>
  10574.                                 <button
  10575.                                     style=\"
  10576.                                         margin-top: 5px;
  10577.                                         padding: 6px 12px;
  10578.                                         background-color: \${product.color};
  10579.                                         color: white;
  10580.                                         border: none;
  10581.                                         border-radius: 5px;
  10582.                                         font-size: 13px;
  10583.                                         cursor: pointer;
  10584.                                     \"
  10585.                                     onclick=\"window.location.href='\${product.link}'\"
  10586.                                 >
  10587.                                     Commander
  10588.                                 </button>`
  10589.                             }
  10590.                         </div>
  10591.                     </div>
  10592.                 </li>
  10593.             `;
  10594.         })
  10595.         .join(\"\");
  10596.     const boutiqueButton = `
  10597.         <li style=\"margin-top: 25px; text-align: center;\">
  10598.             <button
  10599.                 style=\"
  10600.                     padding: 8px 15px;
  10601.                     background-color: #F56040;
  10602.                     color: white;
  10603.                     border: none;
  10604.                     border-radius: 5px;
  10605.                     font-size: 14px;
  10606.                     width: 170px;
  10607.                     height: 40px;
  10608.                     cursor: pointer;
  10609.                 \"
  10610.                 onclick=\"window.location.href='{{ path('boutique5sur5') }}'\"
  10611.             >
  10612.                 Voir toute la boutique
  10613.             </button>
  10614.         </li>
  10615.     `;
  10616.     \$(\"#product-list\").html(productList + boutiqueButton);
  10617. }
  10618. // Modifications au script existant
  10619. \$(document).ready(function() {
  10620.     // Fonctions pour ouvrir/fermer la sidebar
  10621.     \$(\"#openFavoritesSidebar\").click(function() {
  10622.         \$(\"#favorites-sidebar\").css(\"right\", \"0\");
  10623.         loadFavorites();
  10624.     });
  10625.     
  10626.     \$(\"#close-favorites-btn\").click(function() {
  10627.         closeFavoritesSidebar();
  10628.     });
  10629.     
  10630.     // Fonction pour fermer la sidebar
  10631.     window.closeFavoritesSidebar = function() {
  10632.         \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  10633.     };
  10634.     
  10635.     // Tout sélectionner / Tout désélectionner
  10636.     \$(\"#select-all-btn\").click(function() {
  10637.         if (selectedFavorites.length === allFavorites.length) {
  10638.             // Tout désélectionner
  10639.             selectedFavorites = [];
  10640.             \$(\".selection-overlay > div\").css(\"background\", \"transparent\").html(\"\");
  10641.             \$(this).text(\"Tout sélectionner\");
  10642.         } else {
  10643.             // Tout sélectionner
  10644.             selectedFavorites = allFavorites.map(fav => fav.id);
  10645.             \$(\".selection-overlay > div\").css(\"background\", \"#F56040\").html(\"<i class='bi bi-check' style='color:white;font-size:16px;'></i>\");
  10646.             \$(this).text(\"Tout désélectionner\");
  10647.         }
  10648.         
  10649.         // Mettre à jour le compteur
  10650.         \$(\"#selection-count\").text(selectedFavorites.length);
  10651.         
  10652.         // Mettre à jour l'interface produits
  10653.         updateProductsView();
  10654.     });
  10655.     
  10656.     // Gestion des onglets
  10657.     \$(\".sidebar-tab\").click(function() {
  10658.         \$(\".sidebar-tab\").removeClass(\"active\").css({
  10659.             \"color\": \"#666\",
  10660.             \"border-bottom\": \"none\"
  10661.         });
  10662.         \$(this).addClass(\"active\").css({
  10663.             \"color\": \"#F56040\",
  10664.             \"border-bottom\": \"2px solid #F56040\"
  10665.         });
  10666.         
  10667.         const tabId = \$(this).attr(\"id\");
  10668.         \$(\".tab-content\").hide();
  10669.         
  10670.         if (tabId === \"tab-photos\") {
  10671.             \$(\"#photos-content\").show();
  10672.         } else if (tabId === \"tab-products\") {
  10673.             \$(\"#products-content\").show();
  10674.         }
  10675.     });
  10676.     
  10677.     // Modifier les fonctions existantes pour intercepter l'ajout/suppression de favoris
  10678.     const originalAddFavoris = window.AddFavoris;
  10679.     window.AddFavoris = function(\$id, \$idSejour, \$urlimg, \$description) {
  10680.         if (originalAddFavoris) {
  10681.             originalAddFavoris(\$id, \$idSejour, \$urlimg, \$description);
  10682.         }
  10683.         
  10684.         // Mettre à jour tous les compteurs de favoris
  10685.         updateAllFavoriteCounters();
  10686.         
  10687.         // Recharger les favoris si la sidebar est ouverte
  10688.         if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  10689.             loadFavorites();
  10690.         }
  10691.     };
  10692.     const originalSupprimerFavoris = window.supprimerFavoris;
  10693.     window.supprimerFavoris = function(\$id, \$idSejour) {
  10694.         if (originalSupprimerFavoris) {
  10695.             originalSupprimerFavoris(\$id, \$idSejour);
  10696.         }
  10697.         
  10698.         // Mettre à jour tous les compteurs de favoris
  10699.         updateAllFavoriteCounters();
  10700.         
  10701.         // Recharger les favoris si la sidebar est ouverte
  10702.         if (\$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  10703.             // Retirer de la sélection si présent
  10704.             selectedFavorites = selectedFavorites.filter(favId => favId != \$id);
  10705.             loadFavorites();
  10706.         }
  10707.     };
  10708.     
  10709.     // Fermer en cliquant en dehors
  10710.     \$(document).click(function(event) {
  10711.         if (!\$(event.target).closest(\"#favorites-sidebar\").length && 
  10712.             !\$(event.target).closest(\"#openFavoritesSidebar\").length && 
  10713.             \$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  10714.             closeFavoritesSidebar();
  10715.         }
  10716.     });
  10717. });
  10718. // Initialisation de la sidebar
  10719. \$(document).ready(function() {
  10720.     // Fonctions pour ouvrir/fermer la sidebar
  10721.     \$(\"#openFavoritesSidebar\").click(function() {
  10722.         \$(\"#favorites-sidebar\").css(\"right\", \"0\");
  10723.         loadFavorites();
  10724.     });
  10725.     
  10726.     \$(\"#close-favorites-btn\").click(function() {
  10727.         \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  10728.     });
  10729.     
  10730.     // Fermer en cliquant en dehors
  10731.     \$(document).click(function(event) {
  10732.         if (!\$(event.target).closest(\"#favorites-sidebar\").length && 
  10733.             !\$(event.target).closest(\"#openFavoritesSidebar\").length && 
  10734.             \$(\"#favorites-sidebar\").css(\"right\") === \"0px\") {
  10735.             \$(\"#favorites-sidebar\").css(\"right\", \"-500px\");
  10736.         }
  10737.     });
  10738. });
  10739.   </script>
  10740.   <script src=\"{{ asset('js/splide.min.js') }}\" defer></script>
  10741.    
  10742. <script>
  10743.   document.addEventListener('DOMContentLoaded', function () {
  10744.     const openBtn = document.getElementById('openFavoritesSidebar');
  10745.     const sidebar = document.getElementById('favorites-sidebar');
  10746.     const closeBtn = document.getElementById('favorites-close');
  10747.     if (openBtn && sidebar) {
  10748.       openBtn.addEventListener('click', () => {
  10749.         if (sidebar && sidebar.classList) {
  10750.           sidebar.classList.add('active');
  10751.         }
  10752.       });
  10753.     }
  10754.     if (closeBtn && sidebar) {
  10755.       closeBtn.addEventListener('click', () => {
  10756.         if (sidebar && sidebar.classList) {
  10757.           sidebar.classList.remove('active');
  10758.         }
  10759.       });
  10760.     }
  10761.   });
  10762. </script>
  10763.  
  10764. <script>
  10765. document.addEventListener('DOMContentLoaded', function() {
  10766.   const filterBadges = document.querySelectorAll('.filter-badge');
  10767.   filterBadges.forEach(badge => {
  10768.     badge.addEventListener('click', function() {
  10769.       // Désactiver tous les badges
  10770.       filterBadges.forEach(b => {
  10771.         if (b && b.classList) {
  10772.           b.classList.remove('active');
  10773.         }
  10774.       });
  10775.       // Activer le badge cliqué
  10776.       if (this && this.classList) {
  10777.         this.classList.add('active');
  10778.       }
  10779.     });
  10780.   });
  10781. });
  10782. </script>
  10783.   <script
  10784.     type=\"text/javascript\"
  10785.     src=\"{{ asset('Accueil/js/jquery.magnific-popup.min.js') }}\"
  10786.   ></script>
  10787.   <script>
  10788. document.addEventListener('DOMContentLoaded', function () {
  10789.   const prevButtons = document.querySelectorAll('.btn-prev-day');
  10790.   const nextButtons = document.querySelectorAll('.btn-next-day');
  10791.   const dateCards = document.querySelectorAll('.date-card.modern-card');
  10792.   const collapseSections = document.querySelectorAll('.collapse');
  10793.   // 🎯 MEDIA TOOLBAR CAPSULE - État global et logique (Senior UX)
  10794.   (() => {
  10795.     // État global de filtre
  10796.     const MediaFilter = { current: 'all' };
  10797.     // Compteurs dynamiques
  10798.     const counters = { photo: 0, audio: 0, video: 0, fav: 0 };
  10799.     
  10800.     const updateCounts = () => {
  10801.       // Compter les médias dans le DOM
  10802.       counters.photo = document.querySelectorAll('.photo-item, [data-media-type=\"photo\"]').length;
  10803.       counters.video = document.querySelectorAll('[data-media-type=\"video\"]').length;
  10804.       counters.audio = document.querySelectorAll('.audio-message-item[data-type=\"audio\"]').length;
  10805.       // NE PAS recalculer seulement les favoris - ils utilisent {{ nblikes }}
  10806.       
  10807.       // Mettre à jour l'affichage (sauf favoris)
  10808.       Object.entries(counters).forEach(([k, v]) => {
  10809.         if (k !== 'fav') { // Garder seulement le compteur favoris intact
  10810.           document.querySelectorAll(`.mtb-count[data-bind=\"\${k}\"]`).forEach(el => el.textContent = v);
  10811.         }
  10812.       });
  10813.     };
  10814.     // Simple fonction pour le filtre actuel
  10815.     function setActive(filter) {
  10816.       MediaFilter.current = filter;
  10817.       
  10818.       // Exception : ne pas ajouter de classe active au bouton photos
  10819.       if (filter === 'photos') {
  10820.         const photosBtn = document.querySelector('.mtb-btn[data-filter=\"photos\"]');
  10821.         if (photosBtn) {
  10822.           photosBtn.classList.remove('active', 'is-active');
  10823.         }
  10824.       }
  10825.     }
  10826.     // Fonction simplifiée qui mappe et appelle filterContent
  10827.     function applyFilter(filter) {
  10828.       // Mapper les filtres de la capsule vers les filtres existants si nécessaire
  10829.       const filterMap = {
  10830.         'all': 'toutVoir',
  10831.         'photos': 'photos', 
  10832.         'audio': 'audio',
  10833.         'videos': 'videos',
  10834.         'favoris': 'favoris'
  10835.       };
  10836.       
  10837.       const mappedFilter = filterMap[filter] || filter;
  10838.       
  10839.       // Pour le filtre \"all\", s'assurer que la vue des jours est restaurée
  10840.       if (filter === 'all') {
  10841.         const containerGallery = document.querySelector('.container--gallery');
  10842.         if (containerGallery) {
  10843.           containerGallery.style.display = 'block';
  10844.         }
  10845.       }
  10846.       
  10847.       if (typeof window.filterContent === 'function') {
  10848.         window.filterContent(mappedFilter);
  10849.       } else {
  10850.         console.error('window.filterContent n\\'est pas disponible');
  10851.       }
  10852.     }
  10853.     // Click handlers - exactement la même logique que stat-pill
  10854.     document.addEventListener('click', (e) => {
  10855.       const btn = e.target.closest('.mtb-btn');
  10856.       if (!btn) return;
  10857.       // Bouton fermer
  10858.       if (btn.classList.contains('mtb-close')) {
  10859.         document.querySelector('.media-toolbar')?.remove();
  10860.         return;
  10861.       }
  10862.       const filter = btn.dataset.filter;
  10863.       if (!filter) return;
  10864.       // Debug spécifique pour le bouton favoris
  10865.       if (filter === 'favoris') {
  10866.         console.log('🔍 Bouton favoris cliqué - Debug:', {
  10867.           btn: btn,
  10868.           filter: filter,
  10869.           hasFilterContent: typeof window.filterContent === 'function',
  10870.           mesFavCount: document.getElementById('mesFavCount')?.textContent
  10871.         });
  10872.         
  10873.         // Protection : empêcher la décrémentation du compteur pour les clics de filtre
  10874.         e.stopPropagation();
  10875.         e.preventDefault();
  10876.         
  10877.         // Appeler uniquement la fonction de filtrage
  10878.         if (typeof window.filterContent === 'function') {
  10879.           window.filterContent('favoris');
  10880.         } else {
  10881.           console.error('❌ window.filterContent n\\'est pas disponible');
  10882.         }
  10883.         return; // Sortir de la fonction pour éviter le traitement normal
  10884.       }
  10885.       // Exception pour le bouton photos : ne pas modifier les états actifs
  10886.       if (btn.dataset.filter === 'photos') {
  10887.         // Pour le bouton photos, ne pas toucher aux autres boutons
  10888.         // Juste exécuter l'action sans changer les états
  10889.       } else {
  10890.         // Pour les autres boutons : gérer les états actifs normalement
  10891.         const mtbBtns = document.querySelectorAll('.mtb-btn[data-filter]');
  10892.         for (let i = 0; i < mtbBtns.length; i++) {
  10893.           const b = mtbBtns[i];
  10894.           if (b && b.classList) {
  10895.             if (b === btn) {
  10896.               b.classList.add('active');
  10897.             } else {
  10898.               b.classList.remove('active');
  10899.             }
  10900.           }
  10901.         }
  10902.       }
  10903.       
  10904.       // Déclencher le filtrage du contenu - même logique que stat-pill
  10905.       console.log('mtb-btn click:', filter, 'filterContent type:', typeof window.filterContent);
  10906.       if (typeof window.filterContent === 'function') {
  10907.         window.filterContent(filter);
  10908.       } else {
  10909.         console.error('window.filterContent n\\'est pas une fonction!');
  10910.       }
  10911.     });
  10912.     // Expose un setter global
  10913.     window.setMediaFilter = (filter) => {
  10914.       // Pour le bouton photos : ne pas modifier les états
  10915.       if (filter !== 'photos') {
  10916.         setActive(filter);
  10917.       }
  10918.       applyFilter(filter);
  10919.     };
  10920.     // Mise à jour des compteurs quand les favoris changent
  10921.     window.addEventListener('favorites:updated', updateCounts);
  10922.     
  10923.     // Initialisation
  10924.     setTimeout(() => {
  10925.       updateCounts();
  10926.       setActive('all');
  10927.     }, 100);
  10928.     // Mise à jour périodique des compteurs (sauf favoris qui reste fixe)
  10929.     setInterval(updateCounts, 2000);
  10930.   })();
  10931.   function navigateToDay(index) {
  10932.      if (index >= 0 && index < collapseSections.length) {
  10933.       // Fermer tous les jours
  10934.       collapseSections.forEach(s => {
  10935.         if (s && s.classList) {
  10936.           s.classList.remove('show');
  10937.         }
  10938.       });
  10939.       dateCards.forEach(c => {
  10940.         if (c && c.classList) {
  10941.           c.classList.remove('active');
  10942.         }
  10943.       });
  10944.       // Ouvrir le bon jour
  10945.       const targetCollapse = collapseSections[index];
  10946.       const targetCard = dateCards[index];
  10947.       if (targetCollapse && targetCard) {
  10948.         if (targetCollapse.classList) {
  10949.           targetCollapse.classList.add('show');
  10950.         }
  10951.         if (targetCard.classList) {
  10952.           targetCard.classList.add('active');
  10953.         }
  10954.       }
  10955.     }
  10956.   }
  10957.   prevButtons.forEach(button => {
  10958.     button.addEventListener('click', function () {
  10959.       const targetIndex = parseInt(this.dataset.target, 10);
  10960.       navigateToDay(targetIndex);
  10961.     });
  10962.   });
  10963.   nextButtons.forEach(button => {
  10964.     button.addEventListener('click', function () {
  10965.       const targetIndex = parseInt(this.dataset.target, 10);
  10966.       navigateToDay(targetIndex);
  10967.     });
  10968.   });
  10969. });
  10970. </script>
  10971.   <script>
  10972.     document.addEventListener('DOMContentLoaded', function() {
  10973.   const style = document.createElement('style');
  10974.   style.textContent = `
  10975.     .hidden {
  10976.       display: none !important;
  10977.     }
  10978.   `;
  10979.   document.head.appendChild(style);
  10980. });
  10981.     document.addEventListener('DOMContentLoaded', function() {
  10982.     // Get the gift button
  10983.     const giftButton = document.querySelector('.gift-button');
  10984.     if (giftButton) {
  10985.       // Keep it clickable for the gift functionality
  10986.       giftButton.style.pointerEvents = 'auto';
  10987.       
  10988.       // Add click handler for gift action
  10989.       giftButton.onclick = function(e) {
  10990.         e.preventDefault();
  10991.         e.stopPropagation();
  10992.         return false;
  10993.       };
  10994.       
  10995.       // Make sure hover still works
  10996.       favoriteButton.addEventListener('mouseover', function() {
  10997.         document.getElementById('purchase-alert').style.display = 'block';
  10998.       });
  10999.       
  11000.       // Keep any existing hover functionality
  11001.       if (typeof showSelection === 'function') {
  11002.         favoriteButton.onmouseover = showSelection;
  11003.       }
  11004.     }
  11005.     
  11006.     // Make sure the purchase alert remains interactive
  11007.     const purchaseAlert = document.getElementById('purchase-alert');
  11008.     if (purchaseAlert) {
  11009.       purchaseAlert.style.pointerEvents = 'auto';
  11010.     }
  11011.   });
  11012.     // Sélection des éléments
  11013.     const purchaseAlert = document.getElementById(\"purchase-alert\");
  11014.     const alertContent = document.getElementById(\"purchase-alert-content\");
  11015.     const likeCountLabel = document.getElementById(\"likeCount\");
  11016.     
  11017.     // Fonction pour obtenir le nombre actuel de favoris
  11018.     function getCurrentFavoriteCount() {
  11019.         const likeCountLabel = document.getElementById(\"likeCount\");
  11020.         return parseInt(likeCountLabel?.textContent.trim(), 10) || 0;
  11021.     }
  11022.     // Fonction pour mettre à jour le contenu de l'alerte
  11023.     function updatePurchaseAlert(current) {
  11024.   let remainingForAlbum = Math.max(0, 20 - current);
  11025.   let remainingForPochette = Math.max(0, 12 - current);
  11026.   let remainingForPack = Math.max(0, 12 - current);
  11027.   const progressBar = (count, total, color) => `
  11028.   <div style=\"margin: 5px 0;\">
  11029.     <div style=\"background-color: #e9ecef; border-radius: 5px; overflow: hidden; height: 8px;\">
  11030.       <div style=\"width: \${
  11031.         (count / total) * 100
  11032.       }%; background-color: \${color}; height: 100%;\"></div>
  11033.     </div>
  11034.     <small style=\"font-size: 12px;\">\${count}/\${total} photos</small>
  11035.   </div>
  11036. `;
  11037.   // Use Twig paths here:
  11038.   const products = [
  11039.       {
  11040.       name: \"Pochette photo (12 photos)\",
  11041.       required: 12,
  11042.       remaining: remainingForPochette,
  11043.       image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  11044.       color: \"#2196f3\",
  11045.       link: \"{{ path('AjoutPochettePhotos_Favoris', {'nbr': 12}) }}\",
  11046.     },
  11047.        {
  11048.       name: \"Pack numérique (20 photos)\",
  11049.       required: 20,
  11050.       remaining: remainingForAlbum,
  11051.       image: \"/images/produit/photoNumerique.jpg\",
  11052.       color: \"#4caf50\",
  11053.       link: \"{{ path('PackPhotosNumerique_Favoris', {'nbr': 20}) }}\",
  11054.     }
  11055.   
  11056.   
  11057.     
  11058.   ].sort((a, b) => a.remaining - b.remaining);
  11059.   const productList = products
  11060.     .map((product) => {
  11061.       const count = current;
  11062.       const total = product.required;
  11063.       const remaining = product.remaining;
  11064.       return `
  11065.     <li style=\"margin-bottom: 15px;\">
  11066.       <div style=\"display: flex; align-items: center; gap: 10px;\">
  11067.         <img
  11068.           src=\"\${product.image}\"
  11069.           alt=\"\${product.name}\"
  11070.           style=\"width: 65px; height: 65px; border-radius: 5px; margin-top:-19px\"
  11071.         />
  11072.         <div style=\"flex: 1;\">
  11073.           <strong style=\"font-size: 14px;\">\${product.name}</strong>
  11074.           \${progressBar(count, total, product.color)}
  11075.           \${
  11076.             remaining > 0
  11077.               ? `<small style=\"color: \${product.color}; font-size: 12px;\">
  11078.                    Encore \${remaining} photos ❤️ pour compléter \${product.name.toLowerCase()}
  11079.                  </small>`
  11080.               : `<button
  11081.                   style=\"
  11082.                     margin-top: 5px;
  11083.                     padding: 5px 8px;
  11084.                     background-color: \${product.color};
  11085.                     color: white;
  11086.                     border: none;
  11087.                     border-radius: 5px;
  11088.                     font-size: 12px;
  11089.                     cursor: pointer;
  11090.                   \"
  11091.                   onclick=\"window.location.href='\${product.link}'\"
  11092.                 >
  11093.                   Commander
  11094.                 </button>`
  11095.           }
  11096.         </div>
  11097.       </div>
  11098.     </li>
  11099.   `;
  11100.     })
  11101.     .join(\"\");
  11102.   const plusButton = `
  11103.     <li style=\"margin-bottom: 15px; text-align: center;\">
  11104.       <button
  11105.         style=\"
  11106.           padding: 5px 8px;
  11107.           background-color: #F56040;
  11108.           color: white;
  11109.           border: none;
  11110.           border-radius: 5px;
  11111.           font-size: 14px;
  11112.           line-height: 1;
  11113.           width: 150px;
  11114.           height: 40px;
  11115.           cursor: pointer;
  11116.         \"
  11117.         onclick=\"window.location.href='{{ path('boutique5sur5') }}'\"
  11118.       >
  11119.         Aller à la boutique
  11120.       </button>
  11121.     </li>
  11122.   `;
  11123.   if (current === 0) {
  11124.     alertContent.innerHTML = `
  11125.     <p style=\"font-size: 16px; font-weight: bold; color: #333;\">
  11126.       Vous n'avez pas encore de photos favorites !
  11127.     </p>
  11128.     <p style=\"margin-bottom: 20px; color: #555;\">
  11129.       Commencez à ajouter vos moments préférés pour profiter de nos offres.
  11130.     </p>
  11131.     <ul style=\"list-style-type: none; padding: 0;\">\${productList}\${plusButton}</ul>
  11132.   `;
  11133.   } else {
  11134.     alertContent.innerHTML = `
  11135.     <p style=\"font-size: 16px; font-weight: bold; color: #333;\">
  11136.       Vous avez atteint \${current} photos favorites !
  11137.     </p>
  11138.     <p style=\"margin-bottom: 20px; color: #555;\">
  11139.       Profitez de nos offres spéciales :
  11140.     </p>
  11141.     <ul style=\"list-style-type: none; padding: 0;\">\${productList}\${plusButton}</ul>
  11142.   `;
  11143.   }
  11144.   if (purchaseAlert && purchaseAlert.classList) {
  11145.     purchaseAlert.classList.remove(\"hidden\");
  11146.   }
  11147.   clearTimeout(window.purchaseAlertTimeout);
  11148.   window.purchaseAlertTimeout = setTimeout(() => {
  11149.     if (!purchaseAlert.matches(\":hover\")) {
  11150.       closePurchaseAlert();
  11151.     }
  11152.   }, 5000);
  11153. }
  11154.     // Fonction pour fermer l'alerte
  11155.     function closePurchaseAlert() {
  11156.       if (purchaseAlert && purchaseAlert.classList) {
  11157.         purchaseAlert.classList.add(\"hidden\");
  11158.       }
  11159.     }
  11160.     // Événement pour mettre à jour le contenu et afficher la popover dynamiquement au hover
  11161.     document.querySelector(\".gift-button\").addEventListener(\"mouseover\", () => {
  11162.       const currentCount = getCurrentFavoriteCount();
  11163.       updatePurchaseAlert(currentCount);
  11164.       if (purchaseAlert && purchaseAlert.classList) {
  11165.         purchaseAlert.classList.remove(\"cachee\"); // Réaffiche la popover
  11166.       }
  11167.     });
  11168.     // Nouvelles fonctions pour le bouton cadeau
  11169.     function showGiftMessage() {
  11170.       const tooltip = document.getElementById(\"giftTooltip\");
  11171.       if (tooltip) {
  11172.         if (tooltip && tooltip.classList) {
  11173.           tooltip.classList.add(\"show\");
  11174.         }
  11175.       }
  11176.     }
  11177.     function hideGiftMessage() {
  11178.       const tooltip = document.getElementById(\"giftTooltip\");
  11179.       if (tooltip) {
  11180.         if (tooltip && tooltip.classList) {
  11181.           tooltip.classList.remove(\"show\");
  11182.         }
  11183.       }
  11184.     }
  11185.     function showSelection() {
  11186.       document.getElementById(\"purchase-alert\").style.display = \"block\";
  11187.     }
  11188.     function hideSelection() {
  11189.       document.getElementById(\"selectionPopover\").style.display = \"none\";
  11190.     }
  11191.     document.addEventListener(\"DOMContentLoaded\", function () {
  11192.       const container = document.querySelector(\".date-container\");
  11193.       // Vérifie si le conteneur existe pour éviter les erreurs
  11194.       if (container) {
  11195.         container.scrollTo({
  11196.           left: container.scrollWidth, // Scroll directement à la position maximale
  11197.           behavior: \"smooth\", // Défilement fluide
  11198.         });
  11199.       }
  11200.     });
  11201.     document.addEventListener(\"DOMContentLoaded\", function () {
  11202.       const container = document.querySelector(\".date-container\");
  11203.       const leftArrow = document.querySelector(\".scroll-btn.left\");
  11204.       const rightArrow = document.querySelector(\".scroll-btn.right\");
  11205.       // Fonction pour vérifier le débordement et activer/désactiver les flèches
  11206.       function updateArrowsVisibility() {
  11207.         const isOverflowing = container.scrollWidth > container.clientWidth; // Vérifie si débordement
  11208.         leftArrow.style.display = isOverflowing ? \"flex\" : \"none\";
  11209.         rightArrow.style.display = isOverflowing ? \"flex\" : \"none\";
  11210.       }
  11211.       // Fonction pour défiler
  11212.       function scrollContainer(direction) {
  11213.         container.scrollBy({
  11214.           left: direction === \"left\" ? -200 : 200, // Défiler à gauche ou à droite
  11215.           behavior: \"smooth\",
  11216.         });
  11217.       }
  11218.       // Ajout des événements de clic pour les flèches
  11219.       leftArrow.addEventListener(\"click\", () => scrollContainer(\"left\"));
  11220.       rightArrow.addEventListener(\"click\", () => scrollContainer(\"right\"));
  11221.       // ⚡ OPTIMISÉ: Debounce resize pour éviter surcharge
  11222.       let resizeTimeout;
  11223.       const debouncedResize = () => {
  11224.         clearTimeout(resizeTimeout);
  11225.         resizeTimeout = setTimeout(updateArrowsVisibility, 150);
  11226.       };
  11227.       
  11228.       updateArrowsVisibility();
  11229.       window.addEventListener(\"resize\", debouncedResize, { passive: true });
  11230.     });
  11231.     document.addEventListener(\"DOMContentLoaded\", function () {
  11232.       const container = document.querySelector(\".date-container\");
  11233.       const leftBtn = document.querySelector(\".scroll-btn.left\");
  11234.       const rightBtn = document.querySelector(\".scroll-btn.right\");
  11235.       leftBtn.addEventListener(\"click\", () => {
  11236.         container.scrollBy({
  11237.           left: -200, // Défile vers la gauche
  11238.           behavior: \"smooth\",
  11239.         });
  11240.       });
  11241.       rightBtn.addEventListener(\"click\", () => {
  11242.         container.scrollBy({
  11243.           left: 200, // Défile vers la droite
  11244.           behavior: \"smooth\",
  11245.         });
  11246.       });
  11247.     });
  11248.  document.addEventListener(\"DOMContentLoaded\", function () {
  11249.     // Sélectionnez tous les badges de filtre
  11250.     const filterBadges = document.querySelectorAll(\".filter-badge\");
  11251.     // Sélectionnez tous les éléments de la galerie
  11252.     const galleryItems = document.querySelectorAll(\".column\");
  11253.     // Sélectionnez tous les jours
  11254.     const days = document.querySelectorAll(\".collapse\");
  11255.     // Fonction pour réinitialiser les filtres
  11256.     function resetFilters() {
  11257.         // Réinitialisez tous les éléments de la galerie
  11258.         galleryItems.forEach((item) => {
  11259.             item.style.display = \"block\";
  11260.         });
  11261.         // Réinitialisez les états des badges
  11262.         filterBadges.forEach((badge) => {
  11263.           if (badge && badge.classList) {
  11264.             badge.classList.remove(\"active\");
  11265.           }
  11266.         });
  11267.     }
  11268.     // Ajoutez un gestionnaire d'événements pour chaque badge
  11269.     filterBadges.forEach((badge) => {
  11270.         badge.addEventListener(\"click\", function () {
  11271.             const filter = this.getAttribute(\"data-filter\");
  11272.             // Réinitialisez l'état actif pour tous les badges
  11273.             filterBadges.forEach((btn) => {
  11274.               if (btn && btn.classList) {
  11275.                 btn.classList.remove(\"active\");
  11276.               }
  11277.             });
  11278.             // Ajoutez l'état actif au badge cliqué
  11279.             if (this && this.classList) {
  11280.               this.classList.add(\"active\");
  11281.             }
  11282.             // Affichez ou masquez les éléments de la galerie
  11283.             galleryItems.forEach((item) => {
  11284.                 if (filter === \"all\") {
  11285.                     item.style.display = \"block\";
  11286.                 } else if (filter === \"photo\" && item.querySelector(\"img\")) {
  11287.                     item.style.display = \"block\";
  11288.                 } else if (filter === \"video\" && item.querySelector(\"video\")) {
  11289.                     item.style.display = \"block\";
  11290.                 } else if (filter === \"audio\" && item.classList && item.classList.contains(\"audio-message-item\")) {
  11291.                     item.style.display = \"block\";
  11292.                 } else {
  11293.                     item.style.display = \"none\";
  11294.                 }
  11295.             });
  11296.         });
  11297.     });
  11298.     // Réinitialiser les filtres lors du changement de jour
  11299.     days.forEach((day) => {
  11300.         day.addEventListener(\"show.bs.collapse\", function () {
  11301.             resetFilters();
  11302.         });
  11303.     });
  11304. });
  11305.     \$(document).ready(function () {
  11306.       let zoomCounter = 0; // Initialize zoom counter
  11307.       let currentImageSrc = \"\"; // Track current image source
  11308.       let lastClickPosition = { x: 50, y: 50 }; // Default to center of image
  11309.       \$(\".container--gallery\").magnificPopup({
  11310.         delegate: \"a\",
  11311.         type: \"image\",
  11312.         mainClass: \"mfp-with-zoom mfp-img-mobile\",
  11313.         image: {
  11314.           verticalFit: true,
  11315.         },
  11316.         gallery: {
  11317.           enabled: true,
  11318.           tPrev: \"Previous (Left arrow key)\", // Alt text on left arrow
  11319.           tNext: \"Next (Right arrow key)\", // Alt text on right arrow
  11320.           tCounter: \"%curr% of %total%\", // Markup for \"1 of 7\" counter
  11321.         },
  11322.         zoom: {
  11323.           enabled: true,
  11324.           duration: 300,
  11325.           opener: function (element) {
  11326.             return element.find(\"img\");
  11327.           },
  11328.         },
  11329.         callbacks: {
  11330.           open: function () {
  11331.             // Get current image data from the link that was clicked
  11332.             const currentLink = this.currItem.el;
  11333.             const imageId =
  11334.               currentLink
  11335.                 .closest(\".photo-zoom\")
  11336.                 .find(\".heart-icon\")
  11337.                 .data(\"id\") || \"\";
  11338.             const sejourId =
  11339.               currentLink
  11340.                 .closest(\".photo-zoom\")
  11341.                 .find(\".heart-icon\")
  11342.                 .data(\"sejour-id\") || \"\";
  11343.             const imagePath =
  11344.               currentLink
  11345.                 .closest(\".photo-zoom\")
  11346.                 .find(\".heart-icon\")
  11347.                 .data(\"path\") || \"\";
  11348.             const imageDesc =
  11349.               currentLink
  11350.                 .closest(\".photo-zoom\")
  11351.                 .find(\".heart-icon\")
  11352.                 .data(\"description\") || \"\";
  11353.             const isFavorite = currentLink
  11354.               .closest(\".photo-zoom\")
  11355.               .find(\".heart-icon i\")
  11356.               .hasClass(\"bi-heart-fill\");
  11357.             const favoriteIconClass = isFavorite ? \"bi-heart-fill\" : \"bi-heart\";
  11358.             const favoriteIconColor = isFavorite ? \"#f56040\" : \"white\";
  11359.             const favoriteTooltip = isFavorite
  11360.               ? \"Retirer des favoris\"
  11361.               : \"Ajouter aux favoris\";
  11362.             const zoomControls = `
  11363.           <div class=\"mfp-zoom-controls\">
  11364.             <button class=\"zoom-btn zoom-out\" title=\"Zoom Out\"><i class=\"fa fa-search-minus\"></i></button>
  11365.             <button class=\"zoom-btn zoom-in\" title=\"Zoom In\"><i class=\"fa fa-search-plus\"></i></button>
  11366.           </div>
  11367.           <div class=\"mfp-favorite\">
  11368.             <button class=\"favorite-btn\" 
  11369.                     data-id=\"\${imageId}\" 
  11370.                     data-sejour-id=\"\${sejourId}\" 
  11371.                     data-path=\"\${imagePath}\" 
  11372.                     data-description=\"\${imageDesc}\"
  11373.                     title=\"\${favoriteTooltip}\">
  11374.               <i class=\"bi \${favoriteIconClass}\" style=\"color: \${favoriteIconColor}; text-shadow: 0px 0px 3px rgba(0,0,0,0.5);\"></i>
  11375.             </button>
  11376.           </div>
  11377.           <div class=\"mfp-counter\"></div>
  11378.         `;
  11379.             \$(\".mfp-content\").append(zoomControls);
  11380.             initializeZoomControls();
  11381.             initializeFavoriteButton();
  11382.             const intervalId = setInterval(() => {
  11383.               const newImageSrc = \$(\".mfp-img\").attr(\"src\");
  11384.               if (newImageSrc !== currentImageSrc) {
  11385.                 currentImageSrc = newImageSrc;
  11386.                 zoomCounter = 0;
  11387.                 lastClickPosition = { x: 50, y: 50 }; // Reset to center
  11388.                 attachZoomHandler(); // Reattach zoom handler to new image
  11389.                 \$(\".mfp-img\").css({
  11390.                   \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  11391.                   transform: `scale(1)`,
  11392.                 });
  11393.                 // Update favorite button for the new image
  11394.                 updateFavoriteButton();
  11395.                 initializeZoomControls();
  11396.                 updateCounter();
  11397.               }
  11398.             }, 100);
  11399.             this.content.on(\"mfpClose\", function () {
  11400.               clearInterval(intervalId);
  11401.             });
  11402.             attachZoomHandler();
  11403.           },
  11404.           close: function () {
  11405.             \$(\".mfp-zoom-controls\").remove();
  11406.             \$(\".mfp-favorite\").remove();
  11407.             \$(\".mfp-counter\").remove();
  11408.             zoomCounter = 0;
  11409.           },
  11410.         },
  11411.       });
  11412.       function attachZoomHandler() {
  11413.         \$(\".mfp-img\")
  11414.           .off(\"click\")
  11415.           .on(\"click\", function (event) {
  11416.             event.stopPropagation(); // Prevent default navigation behavior
  11417.             // Calculate click coordinates relative to the image
  11418.             const imgOffset = \$(this).offset();
  11419.             const clickX = event.pageX - imgOffset.left;
  11420.             const clickY = event.pageY - imgOffset.top;
  11421.             const imgWidth = \$(this).width();
  11422.             const imgHeight = \$(this).height();
  11423.             // Calculate transform-origin based on click position
  11424.             lastClickPosition = {
  11425.               x: (clickX / imgWidth) * 100,
  11426.               y: (clickY / imgHeight) * 100,
  11427.             };
  11428.             // Cycle through zoom levels: 1x, 1.5x, 2x
  11429.             zoomCounter = (zoomCounter + 1) % 3;
  11430.             const zoomLevels = [1, 1.5, 2];
  11431.             const zoomLevel = zoomLevels[zoomCounter];
  11432.             \$(this).css({
  11433.               \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  11434.               transform: `scale(\${zoomLevel})`,
  11435.             });
  11436.             updateZoomButtonState();
  11437.           });
  11438.       }
  11439.       function initializeZoomControls() {
  11440.         \$(\".mfp-zoom-controls .zoom-in\")
  11441.           .off(\"click\")
  11442.           .on(\"click\", function (event) {
  11443.             event.stopPropagation();
  11444.             zoomCounter = (zoomCounter + 1) % 3;
  11445.             const zoomLevels = [1, 1.5, 2];
  11446.             const zoomLevel = zoomLevels[zoomCounter];
  11447.             \$(\".mfp-img\").css({
  11448.               \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  11449.               transform: `scale(\${zoomLevel})`,
  11450.             });
  11451.             updateZoomButtonState();
  11452.           });
  11453.         \$(\".mfp-zoom-controls .zoom-out\")
  11454.           .off(\"click\")
  11455.           .on(\"click\", function (event) {
  11456.             event.stopPropagation();
  11457.             if (zoomCounter > 0) {
  11458.               zoomCounter -= 1;
  11459.               const zoomLevels = [1, 1.5, 2];
  11460.               const zoomLevel = zoomLevels[zoomCounter];
  11461.               \$(\".mfp-img\").css({
  11462.                 \"transform-origin\": `\${lastClickPosition.x}% \${lastClickPosition.y}%`,
  11463.                 transform: `scale(\${zoomLevel})`,
  11464.               });
  11465.               updateZoomButtonState();
  11466.             } else {
  11467.               \$.magnificPopup.close();
  11468.             }
  11469.           });
  11470.       }
  11471.       function initializeFavoriteButton() {
  11472.         \$(\".mfp-favorite .favorite-btn\")
  11473.           .off(\"click\")
  11474.           .on(\"click\", function (event) {
  11475.             event.stopPropagation();
  11476.             const \$this = \$(this);
  11477.             const imageId = \$this.data(\"id\");
  11478.             const sejourId = \$this.data(\"sejour-id\");
  11479.             // Toggle favorite status
  11480.             const isFavorite = \$this.find(\"i\").hasClass(\"bi-heart-fill\");
  11481.             // Update the button appearance
  11482.             if (isFavorite) {
  11483.               \$this
  11484.                 .find(\"i\")
  11485.                 .removeClass(\"bi-heart-fill\")
  11486.                 .addClass(\"bi-heart\")
  11487.                 .css(\"color\", \"white\");
  11488.               \$this.attr(\"title\", \"Ajouter aux favoris\");
  11489.             } else {
  11490.               \$this
  11491.                 .find(\"i\")
  11492.                 .removeClass(\"bi-heart\")
  11493.                 .addClass(\"bi-heart-fill\")
  11494.                 .css(\"color\", \"#f56040\");
  11495.               \$this.attr(\"title\", \"Retirer des favoris\");
  11496.             }
  11497.             // Update the original heart icon in the gallery
  11498.             const originalHeartIcon = \$(
  11499.               `.heart-icon[data-id=\"\${imageId}\"]`
  11500.             ).find(\"i\");
  11501.             if (isFavorite) {
  11502.               originalHeartIcon
  11503.                 .removeClass(\"bi-heart-fill\")
  11504.                 .addClass(\"bi-heart\")
  11505.                 .css(\"color\", \"\");
  11506.             } else {
  11507.               originalHeartIcon
  11508.                 .removeClass(\"bi-heart\")
  11509.                 .addClass(\"bi-heart-fill\")
  11510.                 .css(\"color\", \"#f56040\");
  11511.             }
  11512.             // Make AJAX call to update favorite status in the backend using Parent routes
  11513.             \$.ajax({
  11514.               url: isFavorite ? \"/Parent/aSupprimerFav\" : \"/Parent/ajouterFav\",
  11515.               type: \"POST\",
  11516.               data: {
  11517.                 id: imageId,
  11518.                 idSejour: sejourId,
  11519.               },
  11520.               success: function (response) {
  11521.                 // Optional: Show a success message or handle response
  11522.                 console.log(\"Favorite status updated\", response);
  11523.               },
  11524.               error: function (error) {
  11525.                 console.error(\"Error updating favorite status\", error);
  11526.                 // Revert the icon change on error
  11527.                 if (isFavorite) {
  11528.                   \$this
  11529.                     .find(\"i\")
  11530.                     .removeClass(\"bi-heart\")
  11531.                     .addClass(\"bi-heart-fill\")
  11532.                     .css(\"color\", \"#f56040\");
  11533.                   originalHeartIcon
  11534.                     .removeClass(\"bi-heart\")
  11535.                     .addClass(\"bi-heart-fill\")
  11536.                     .css(\"color\", \"#f56040\");
  11537.                 } else {
  11538.                   \$this
  11539.                     .find(\"i\")
  11540.                     .removeClass(\"bi-heart-fill\")
  11541.                     .addClass(\"bi-heart\")
  11542.                     .css(\"color\", \"white\");
  11543.                   originalHeartIcon
  11544.                     .removeClass(\"bi-heart-fill\")
  11545.                     .addClass(\"bi-heart\")
  11546.                     .css(\"color\", \"\");
  11547.                 }
  11548.               },
  11549.             });
  11550.           });
  11551.       }
  11552.       function updateFavoriteButton() {
  11553.         // Get current image data from the current slide
  11554.         const currentSlide = \$.magnificPopup.instance.currItem.el;
  11555.         const photoZoom = currentSlide.closest(\".photo-zoom\");
  11556.         if (photoZoom.length) {
  11557.           const heartIcon = photoZoom.find(\".heart-icon\");
  11558.           const imageId = heartIcon.data(\"id\") || \"\";
  11559.           const sejourId = heartIcon.data(\"sejour-id\") || \"\";
  11560.           const imagePath = heartIcon.data(\"path\") || \"\";
  11561.           const imageDesc = heartIcon.data(\"description\") || \"\";
  11562.           const isFavorite = heartIcon.find(\"i\").hasClass(\"bi-heart-fill\");
  11563.           const favoriteIconClass = isFavorite ? \"bi-heart-fill\" : \"bi-heart\";
  11564.           const favoriteIconColor = isFavorite ? \"#f56040\" : \"white\";
  11565.           const favoriteTooltip = isFavorite
  11566.             ? \"Retirer des favoris\"
  11567.             : \"Ajouter aux favoris\";
  11568.           // Update the favorite button
  11569.           const \$favoriteBtn = \$(\".mfp-favorite .favorite-btn\");
  11570.           \$favoriteBtn.data(\"id\", imageId);
  11571.           \$favoriteBtn.data(\"sejour-id\", sejourId);
  11572.           \$favoriteBtn.data(\"path\", imagePath);
  11573.           \$favoriteBtn.data(\"description\", imageDesc);
  11574.           \$favoriteBtn.attr(\"title\", favoriteTooltip);
  11575.           \$favoriteBtn
  11576.             .find(\"i\")
  11577.             .removeClass(\"bi-heart bi-heart-fill\")
  11578.             .addClass(favoriteIconClass)
  11579.             .css(\"color\", favoriteIconColor);
  11580.         }
  11581.       }
  11582.       function updateZoomButtonState() {
  11583.         const zoomLevels = [1, 1.5, 2];
  11584.         const currentZoom = zoomLevels[zoomCounter];
  11585.         \$(\".zoom-in\").prop(\"disabled\", currentZoom === 2);
  11586.         \$(\".zoom-out\").prop(\"disabled\", currentZoom === 1);
  11587.       }
  11588.       function updateCounter() {
  11589.         const counterText = \$(\".mfp-counter\")
  11590.           .closest(\".mfp-content\")
  11591.           .find(\".mfp-counter\")
  11592.           .text();
  11593.         const matches = counterText.match(/(\\d+) of (\\d+)/);
  11594.         if (matches) {
  11595.           const currentIndex = matches[1];
  11596.           const totalImages = matches[2];
  11597.           \$(\".mfp-counter\").text(`\${currentIndex} of \${totalImages}`);
  11598.         }
  11599.       }
  11600.       // Add CSS for the favorite button and rounded image corners
  11601.       \$(\"<style>\")
  11602.         .prop(\"type\", \"text/css\")
  11603.         .html(
  11604.           `
  11605.       .mfp-favorite {
  11606.         position: absolute;
  11607.         top: 15px;
  11608.         left: 15px;
  11609.         z-index: 1046;
  11610.       }
  11611.       .favorite-btn {
  11612.         background: transparent;
  11613.         border: none;
  11614.         font-size: 24px;
  11615.         padding: 5px;
  11616.         cursor: pointer;
  11617.         outline: none;
  11618.       }
  11619.       .favorite-btn i {
  11620.         transition: all 0.3s ease;
  11621.       }
  11622.       .favorite-btn:hover i {
  11623.         transform: scale(1.2);
  11624.       }
  11625.       /* Rounded corners for zoomed images */
  11626.       .mfp-img {
  11627.         border-radius: 8px;
  11628.       }
  11629.       /* Make sure the container doesn't clip the rounded corners */
  11630.       .mfp-figure:after {
  11631.         border-radius: 8px;
  11632.       }
  11633.     `
  11634.         )
  11635.         .appendTo(\"head\");
  11636.     });
  11637.   </script>
  11638. <script>
  11639. document.addEventListener('DOMContentLoaded', function () {
  11640.   const openBtn = document.getElementById('openFavoritesBtn');
  11641.   const closeBtn = document.getElementById('closeSidebarBtn');
  11642.   const sidebar = document.getElementById('favoritesSidebar');
  11643.   const tbody = document.querySelector('#favoritesTable tbody');
  11644.   openBtn.addEventListener('click', async () => {
  11645.     try {
  11646.       const response = await fetch('/Parent/mes-favoris', {
  11647.         headers: {
  11648.           'Accept': 'application/json'
  11649.         }
  11650.       });
  11651.       const result = await response.json();
  11652.       if (!result.success || !Array.isArray(result.data)) {
  11653.         alert('Erreur lors du chargement des favoris.');
  11654.         return;
  11655.       }
  11656.       tbody.innerHTML = '';
  11657.       result.data.forEach((fav, index) => {
  11658.         const row = document.createElement('tr');
  11659.         row.innerHTML = `
  11660.           <td>\${index + 1}</td>
  11661.           <td><img src=\"\${fav.path}\" alt=\"favori\"></td>
  11662.           <td>\${fav.descreption || '—'}</td>
  11663.           <td>\${fav.created_at}</td>
  11664.         `;
  11665.         tbody.appendChild(row);
  11666.       });
  11667.       sidebar.classList.add('active');
  11668.     } catch (e) {
  11669.       console.error('Erreur réseau:', e);
  11670.       alert('Impossible de charger les favoris.');
  11671.     }
  11672.   });
  11673.   closeBtn.addEventListener('click', () => {
  11674.     sidebar.classList.remove('active');
  11675.   });
  11676. });
  11677. </script>
  11678.   <script>
  11679.         // Fonction pour vérifier et afficher l'alerte
  11680.         function checkFavoritesAlert() {
  11681.             const currentCount = window.favoriteCount || 0;
  11682.             if (currentCount >= 10) {
  11683.                 const purchaseAlert = document.getElementById('purchase-alert');
  11684.                 if (purchaseAlert) {
  11685.                     purchaseAlert.style.display = 'block'; // Affiche l'alerte
  11686.                 }
  11687.             } else {
  11688.                 purchaseAlert.style.display = 'none'; // Cache l'alerte si le nombre est réduit
  11689.             }
  11690.         }
  11691.     
  11692.         
  11693.         document.addEventListener('DOMContentLoaded', () => {
  11694.     const favoriteCount = {{ nblikes }};
  11695.     updateCardContent(favoriteCount);
  11696. });
  11697. function updateCardContent(favoriteCount) {
  11698.     const card = document.getElementById('dynamic-card');
  11699.     const cardContent = document.getElementById('dynamic-card-content');
  11700.     let produits = [];
  11701.     if (favoriteCount >= 20) {
  11702.         produits.push({
  11703.             titre: \"Album débloqué !\",
  11704.             bouton: \"Commander\",
  11705.             image: \"/images/produit/Album5sur5-3.jpg\",
  11706.             lien: \"{{ path('EditionAlbum') }}\"
  11707.         });
  11708.     }
  11709.     if (favoriteCount >= 12) {
  11710.         produits.push({
  11711.             titre: \"Pochette débloquée !\",
  11712.             bouton: \"Commander\",
  11713.             image: \"/images/produit/PochettePhoto5sur5-2.jpg\",
  11714.             lien: \"{{ path('AjoutPochettePhotos_Favoris', {'nbr': 12}) }}\"
  11715.         });
  11716.     }
  11717.     if (favoriteCount >= 5) {
  11718.         produits.push({
  11719.             titre: \"Pack numérique débloqué !\",
  11720.             bouton: \"Commander\",
  11721.             image: \"/images/produit/photoNumerique.jpg\",
  11722.             lien: \"{{ path('PackPhotosNumerique_Favoris', {'nbr': 15}) }}\"
  11723.         });
  11724.     }
  11725. if (produits.length === 0) {
  11726.   cardContent.innerHTML = `
  11727.     <div style=\"position: relative; width: 100%; height: 140px; border-radius: 15px; overflow: hidden; box-shadow: 0 4px 10px rgba(0,0,0,0.1);\">
  11728.       <div style=\"background-image: url('/images/produit/CoffretCadeau5sur5-2.jpg'); background-size: cover; background-position: center; width: 100%; height: 100%;\">
  11729.         <div style=\"position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.45); display: flex; align-items: center; justify-content: center; padding: 10px;\">
  11730.           <div style=\"
  11731.     margin-top: 35px;
  11732.     color: white;
  11733.     font-size: 15px;
  11734.     font-weight: bold;
  11735.     text-align: center;
  11736.     line-height: 1;
  11737.     text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);\">
  11738.             Ajoutez des favoris ❤️<br><span style=\"font-size: 16px; font-weight: normal;\">pour débloquer un souvenir à offrir 🎁</span>
  11739.           </div>
  11740.         </div>
  11741.       </div>
  11742.     </div>
  11743.   `;
  11744.         return;
  11745.     }
  11746.     cardContent.innerHTML = `
  11747.     <div class=\"splide\" id=\"dynamicSplide\">
  11748.       <div class=\"splide__track\">
  11749.         <ul class=\"splide__list\">
  11750.           \${produits.map(produit => `
  11751.             <li class=\"splide__slide\" style=\"position: relative;\">
  11752.               <img src=\"\${produit.image}\" alt=\"\${produit.titre}\" style=\"width: 100%; height: 150px; object-fit: cover; border-radius: 8px;\">
  11753.               <div style=\"position: absolute; bottom: 0; left: 0; right: 0; background: rgba(0,0,0,0.1); color: white; padding: 10px; text-align: center; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px;\">
  11754.                 <div style=\"font-weight: bold; font-size: 14px;\">\${produit.titre}</div>
  11755.                 <button style=\"margin-top: 5px; padding: 5px 8px; background-color: #F56040; color: white; border: none; border-radius: 4px; font-size: 12px; cursor: pointer;\" onclick=\"window.location.href='\${produit.lien}'\">
  11756.                   \${produit.bouton}
  11757.                 </button>
  11758.               </div>
  11759.             </li>
  11760.           `).join('')}
  11761.         </ul>
  11762.       </div>
  11763.     </div>
  11764.     `;
  11765.     // Monte le carrousel
  11766.     new Splide('#dynamicSplide', {
  11767.         type: 'loop',
  11768.         arrows: true,
  11769.         pagination: false,
  11770.         autoplay: true,
  11771.         interval: 4000,
  11772.         speed: 800,
  11773.     }).mount();
  11774. }
  11775.         function supprimerFavoris(\$id, \$idSejour) {
  11776.             // Vider l'élément coeur pour ce favori
  11777.             const coeurElement = \$('#coeur' + \$id);
  11778.             coeurElement.empty();
  11779.             // Ajout d'une animation sur le bouton cadeau
  11780.             const giftButton = document.querySelector('.gift-button');
  11781.             if (giftButton) {
  11782.                 giftButton.classList.add('active');
  11783.                 // Retirer l'animation après qu'elle soit jouée
  11784.                 setTimeout(() => {
  11785.                     giftButton.classList.remove('active');
  11786.                 }, 600); // La durée doit correspondre à celle de l'animation
  11787.             }
  11788.             // Mise à jour de l'icône coeur
  11789.             const clas = \$('.IconImag6').hasClass('active') ? \"IconDelete IconDeletesix\" : \"IconDelete\";
  11790.             coeurElement.html(
  11791.                 `<i class=\"bi bi-heart \${clas}\" ></i>`
  11792.             );
  11793.             // Mettre à jour le compteur des favoris
  11794.             const likeCountLabel = document.getElementById('likeCount');
  11795.             const likeMesFavLabel = document.getElementById('mesFavCount');
  11796.             
  11797.             let newCount = 0;
  11798.             
  11799.             if (likeCountLabel) {
  11800.                 // Utiliser la fonction utilitaire robuste
  11801.                 let currentCount = window.getFavoriteCount();
  11802.                 newCount = Math.max(0, currentCount - 1); // Empêche le compteur d'aller en dessous de 0
  11803.                 window.setFavoriteCount(newCount);
  11804.             
  11805.                 // Mettre à jour la valeur dans l'input hidden
  11806.                 const nbFavCurrentInput = \$('#nbFavCurrent');
  11807.                 if (nbFavCurrentInput.length) {
  11808.                     nbFavCurrentInput.val(newCount);
  11809.                 }
  11810.             }
  11811.             
  11812.             // Synchroniser mesFavCount avec likeCount
  11813.             if (likeMesFavLabel) {
  11814.                 if (likeCountLabel) {
  11815.                     // Utiliser la valeur de likeCount pour synchroniser
  11816.                     likeMesFavLabel.textContent = newCount;
  11817.                 } else {
  11818.                     // Si likeCount n'existe pas, décrémenter directement mesFavCount
  11819.                     let currentFavCount = parseInt(likeMesFavLabel.textContent.trim(), 10) || 0;
  11820.                     newCount = Math.max(0, currentFavCount - 1);
  11821.                                          likeMesFavLabel.textContent = newCount;
  11822.                  }
  11823.              }
  11824.              
  11825.              // Mettre à jour l'alerte immédiatement
  11826.              setTimeout(() => {
  11827.                  const finalCount = getCurrentFavoriteCount();
  11828.                  if (typeof updatePurchaseAlert === 'function') {
  11829.                      updatePurchaseAlert(finalCount);
  11830.                  }
  11831.              }, 50);
  11832.             // Préparation des données pour l'Ajax
  11833.             const \$_data = { 'id': \$id, 'idSejour': \$idSejour };
  11834.             // Appel Ajax pour supprimer le favori
  11835.             \$.ajax({
  11836.                 type: \"POST\",
  11837.                 url: \"{{ path('Supprimer_fav') }}\",
  11838.                 data: \$_data,
  11839.                 success: function () {
  11840.                     // Réactiver les icônes après succès
  11841.                     \$('.IconDelete').each(function () {
  11842.                         \$(this).css('pointer-events', '');
  11843.                     });
  11844.                     
  11845.                     // Mettre à jour l'alerte avec le nouveau nombre
  11846.                     const finalCount = getCurrentFavoriteCount();
  11847.                     if (typeof updatePurchaseAlert === 'function') {
  11848.                         updatePurchaseAlert(finalCount);
  11849.                     }
  11850.                 },
  11851.                 error: function (xhr, status, error) {
  11852.                     console.error('Erreur lors de la suppression du favori :', error);
  11853.                 }
  11854.             });
  11855.         }
  11856.         function AddFavoris(\$id, \$idSejour, \$urlimg, \$description) {
  11857.             // Update heart icon
  11858.             \$('#coeur' + \$id).empty();
  11859.             var clas = \$('.IconImag6').hasClass('active') ? \"IconDelete IconDeletesix\" : \"IconDelete\";
  11860.             \$('#coeur' + \$id).html(\"<i class=\\\"bi bi-heart-fill favSelect \" + clas + \"\\\" )\\\"></i>\");
  11861.             
  11862.             // Update counters UNIQUEMENT
  11863.             const likeCountLabel = document.getElementById('likeCount');
  11864.             const likeMesFavLabel = document.getElementById('mesFavCount');
  11865.             const  giftCountLabel = document.getElementById('giftCount');
  11866.             
  11867.             if (likeCountLabel) {
  11868.                 // Utiliser la fonction utilitaire robuste
  11869.                 let currentCount = window.getFavoriteCount();
  11870.                 currentCount++;
  11871.                 window.setFavoriteCount(currentCount);
  11872.                
  11873.                 
  11874.                 // Mettre à jour le compteur des favoris dans le titre
  11875.                 if (likeMesFavLabel) {
  11876.                     likeMesFavLabel.textContent = currentCount;
  11877.              
  11878.                 }
  11879.                   if (giftCountLabel) {
  11880.                     giftCountLabel.textContent = currentCount;
  11881.              
  11882.                 }
  11883.                 
  11884.                 // Mettre à jour l'input hidden
  11885.                 const nbFavCurrentInput = document.getElementById('nbFavCurrent');
  11886.                 if (nbFavCurrentInput) {
  11887.                     nbFavCurrentInput.value = currentCount;
  11888.                 }
  11889.             }
  11890.             
  11891.             // Update other counters
  11892.             var \$total = parseInt(\$(\"#totalLike\").html()) + 1;
  11893.             \$(\"#totalLike\").html(\$total);
  11894.             \$(\"#totalLikeTitle\").html(\$total);
  11895.             \$(\"#totalLikeMobile\").html(\$total);
  11896.             
  11897.             // Add gift button animation
  11898.             const giftButton = document.querySelector('.gift-button');
  11899.             if (giftButton) {
  11900.                 giftButton.classList.add('active');
  11901.                 setTimeout(() => {
  11902.                     giftButton.classList.remove('active');
  11903.                 }, 600);
  11904.             }
  11905.             var \$data = { 'id': \$id, 'idSejour': \$idSejour };
  11906.             \$.ajax({
  11907.                 type: \"POST\",
  11908.                 url: \"{{ path('Ajouter_fav') }}\",
  11909.                 data: \$data,
  11910.                 success: function () {
  11911.                     \$('.IconDelete').each(function () {
  11912.                         \$(this).css('pointer-events', '');
  11913.                     });
  11914.                     if (\$description === undefined) {
  11915.                         \$description = ''; // Set it to an empty string
  11916.                     }
  11917.                     \$('.rowMaselection').append(
  11918.                         '<div class=\"column\" id=\"column-' + \$id + '\">'+
  11919.                         '<a style=\"position: relative;\" title=\"Enlever de ma sélection\" onclick=\"supprimerFavoris(' + \$id + ',' + \$idSejour + ')\" class=\"iconeSuppImg\"><i class=\"bi bi-x\" style=\"font-size:17px;cursor:pointer;color:#d30909;float:right;margin-top:-3%;margin-right:2%\"></i></a>'+
  11920.                         '<a class=\"photo-zoom\">'+
  11921.                         '<img data-idAtach=\"'+\$id+'\" id=\"'+\$idSejour+'\" src=\"'+\$urlimg+'\"></a>'+
  11922.                         (\$description ? '<h4 id=\"commint\" class=\"titleHeadPhoto\">'+\$description+'</h4>' : '')+ // Only add the <h4> if \$description is not empty
  11923.                         '</div>'
  11924.                     );
  11925.                     // Directly update nbLikes count in the header
  11926.                     var currentNbLikes = parseInt(\$('#favoris-link-Accueilpayment .nbrpanier').text());
  11927.                     var newNbLikes = currentNbLikes + 1;
  11928.                     \$('#favoris-link-Accueilpayment .nbrpanier').text(newNbLikes);
  11929.                     
  11930.                     // Mettre à jour l'alerte avec le nouveau nombre
  11931.                     const finalCount = getCurrentFavoriteCount();
  11932.                     if (typeof updatePurchaseAlert === 'function') {
  11933.                         updatePurchaseAlert(finalCount);
  11934.                     }
  11935.                 },
  11936.                 error: function (xhr, status, error) {
  11937.                     console.error('Error:', error);
  11938.                 }
  11939.             });
  11940.         }
  11941.         \$(document).on('click', '.bi-heart, .bi-heart-fill', function () {
  11942.         const heartIcon       = \$(this);
  11943.         const heartContainer  = heartIcon.closest('.heart-icon');
  11944.         // Extract data attributes
  11945.         const attachmentId    = heartContainer.data('id');
  11946.         const sejourId        = heartContainer.data('sejour-id');
  11947.         const path            = heartContainer.data('path');
  11948.         const description     = heartContainer.data('description');
  11949.         const isFavorite      = heartIcon.hasClass('bi-heart-fill');
  11950.         if (isFavorite) {
  11951.             // Remove from favorites
  11952.             supprimerFavoris(attachmentId, sejourId);
  11953.         } else {
  11954.             // Add to favorites
  11955.             AddFavoris(attachmentId, sejourId, path, description);
  11956.         }
  11957.         // Update UI components after the action (sans double comptage)
  11958.         setTimeout(function() {
  11959.             const likeCountLabel = document.getElementById('likeCount');
  11960.             
  11961.             if (likeCountLabel) {
  11962.                 const currentCount = parseInt(likeCountLabel.textContent, 10) || 0;
  11963.                 
  11964.                 // Update UI components seulement
  11965.                 updateCardContent(currentCount);
  11966.                 updateFavoritesSidebar();
  11967.                 \$(\"#close-favorites-btn\").click();
  11968.             }
  11969.         }, 50);
  11970.     });
  11971.         // Ajoutez les événements sur les icônes de cœur
  11972.         document.querySelectorAll('.IconDelete').forEach((icon) => {
  11973.             icon.addEventListener('click', (event) => {
  11974.                 const isFavorite = icon && icon.classList && icon.classList.contains('bi-heart-fill');
  11975.                 if (isFavorite) {
  11976.                     removeFavorite();
  11977.                     if (icon.classList) {
  11978.                       icon.classList.remove('bi-heart-fill');
  11979.                       icon.classList.add('bi-heart');
  11980.                     }
  11981.                 } else {
  11982.                     addFavorite();
  11983.                     if (icon.classList) {
  11984.                       icon.classList.remove('bi-heart');
  11985.                       icon.classList.add('bi-heart-fill');
  11986.                     }
  11987.                 }
  11988.             });
  11989.         });
  11990.         // Vérifie l'état initial
  11991.         checkFavoritesAlert();
  11992.         
  11993.         
  11994.         // ⚡ OPTIMISÉ: Réduction du délai d'initialisation
  11995.       
  11996.   </script>
  11997.   <!-- Initialisation -->
  11998.   <script>
  11999.     // ⚡ OPTIMISATION: Différer l'initialisation d'AOS pour ne pas bloquer le chargement
  12000.     setTimeout(function() {
  12001.       AOS.init({
  12002.         duration: 800,
  12003.         easing: \"ease-in-out\"
  12004.       });
  12005.     }, 100);
  12006.     // 🎯 DAY FILTER DROPDOWN LOGIC (Senior UX)
  12007.     document.addEventListener('DOMContentLoaded', function() {
  12008.       initializeDayFilters();
  12009.       
  12010.       // Initialiser le compteur audio avec la valeur correcte
  12011.       setTimeout(function() {
  12012.         updateAudioButtonState('days');
  12013.       }, 500);
  12014.     });
  12015.     function initializeDayFilters() {
  12016.       const dropdowns = document.querySelectorAll('.day-filter-dropdown');
  12017.       
  12018.       dropdowns.forEach(dropdown => {
  12019.         const toggle = dropdown.querySelector('.filter-toggle');
  12020.         const menu = dropdown.querySelector('.filter-dropdown-menu');
  12021.         const options = dropdown.querySelectorAll('.filter-option');
  12022.         const dayIndex = dropdown.dataset.dayIndex;
  12023.         const dayContainer = document.getElementById(`demP\${dayIndex}`);
  12024.         
  12025.         if (!toggle || !menu || !dayContainer) return;
  12026.         
  12027.         // Calculer et mettre à jour les compteurs initiaux
  12028.         updateDayFilterCounts(dropdown, dayContainer);
  12029.         
  12030.         // Toggle dropdown
  12031.         toggle.addEventListener('click', (e) => {
  12032.           e.stopPropagation();
  12033.           const isOpen = dropdown.classList.contains('open');
  12034.           
  12035.           // Fermer tous les autres dropdowns
  12036.           document.querySelectorAll('.day-filter-dropdown.open').forEach(d => {
  12037.             if (d !== dropdown) d.classList.remove('open');
  12038.           });
  12039.           
  12040.           // Toggle le dropdown actuel
  12041.           dropdown.classList.toggle('open', !isOpen);
  12042.         });
  12043.         
  12044.         // Gérer les clics sur les options
  12045.         options.forEach(option => {
  12046.           option.addEventListener('click', (e) => {
  12047.             e.stopPropagation();
  12048.             const filter = option.dataset.filter;
  12049.             
  12050.             // Mettre à jour l'état actif
  12051.             options.forEach(opt => opt.classList.remove('active'));
  12052.             option.classList.add('active');
  12053.             
  12054.             // Appliquer le filtre
  12055.             applyDayFilter(dayContainer, filter);
  12056.             
  12057.             // Fermer le dropdown
  12058.             dropdown.classList.remove('open');
  12059.           });
  12060.         });
  12061.       });
  12062.       
  12063.       // Fermer les dropdowns en cliquant ailleurs
  12064.       document.addEventListener('click', () => {
  12065.         document.querySelectorAll('.day-filter-dropdown.open').forEach(dropdown => {
  12066.           dropdown.classList.remove('open');
  12067.         });
  12068.       });
  12069.     }
  12070.     function updateDayFilterCounts(dropdown, dayContainer) {
  12071.       const photoItems = dayContainer.querySelectorAll('[data-type=\"photo\"]');
  12072.       const videoItems = dayContainer.querySelectorAll('[data-type=\"video\"]');
  12073.       // Compter les messages audio individuels plutôt que les conteneurs
  12074.       const audioMessageItems = dayContainer.querySelectorAll('.audio-message-item[data-type=\"audio\"]');
  12075.       const audioContainers = dayContainer.querySelectorAll('.audio-messages-container[data-type=\"audio\"]');
  12076.       const audioRestricted = dayContainer.querySelectorAll('.audio-messages-restricted[data-type=\"audio\"]');
  12077.       
  12078.       const allItems = dayContainer.querySelectorAll('[data-type]');
  12079.       
  12080.       const countAll = dropdown.querySelector('[data-count-all]');
  12081.       const countPhoto = dropdown.querySelector('[data-count-photo]');
  12082.       const countVideo = dropdown.querySelector('[data-count-video]');
  12083.       const countAudio = dropdown.querySelector('[data-count-audio]');
  12084.       
  12085.       // Compter les messages audio individuels + conteneurs + sections restreintes
  12086.       const totalAudio = audioMessageItems.length + audioContainers.length + audioRestricted.length;
  12087.       
  12088.       if (countAll) countAll.textContent = allItems.length;
  12089.       if (countPhoto) countPhoto.textContent = photoItems.length;
  12090.       if (countVideo) countVideo.textContent = videoItems.length;
  12091.       if (countAudio) countAudio.textContent = totalAudio;
  12092.       
  12093.       // Masquer les options sans contenu
  12094.       const photoOption = dropdown.querySelector('[data-filter=\"photo\"]');
  12095.       const videoOption = dropdown.querySelector('[data-filter=\"video\"]');
  12096.       const audioOption = dropdown.querySelector('[data-filter=\"audio\"]');
  12097.       
  12098.       if (photoOption) photoOption.style.display = photoItems.length > 0 ? 'flex' : 'none';
  12099.       if (videoOption) videoOption.style.display = videoItems.length > 0 ? 'flex' : 'none';
  12100.       if (audioOption) audioOption.style.display = totalAudio > 0 ? 'flex' : 'none';
  12101.     }
  12102.     function applyDayFilter(dayContainer, filter) {
  12103.       const items = dayContainer.querySelectorAll('[data-type]');
  12104.       
  12105.       items.forEach(item => {
  12106.         if (filter === 'all' || item.dataset.type === filter) {
  12107.           item.style.display = '';
  12108.           item.classList.remove('filtered-out');
  12109.         } else {
  12110.           item.style.display = 'none';
  12111.           item.classList.add('filtered-out');
  12112.         }
  12113.       });
  12114.       
  12115.       // Animation fluide pour les éléments visibles
  12116.       requestAnimationFrame(() => {
  12117.         const visibleItems = dayContainer.querySelectorAll('[data-type]:not(.filtered-out)');
  12118.         visibleItems.forEach((item, index) => {
  12119.           item.style.animation = `fadeInUp 0.3s ease forwards \${index * 0.05}s`;
  12120.         });
  12121.       });
  12122.     }
  12123.     // Animation CSS pour fadeInUp
  12124.     if (!document.querySelector('#dayFilterAnimations')) {
  12125.       const style = document.createElement('style');
  12126.       style.id = 'dayFilterAnimations';
  12127.       style.textContent = `
  12128.         @keyframes fadeInUp {
  12129.           from {
  12130.             opacity: 0;
  12131.             transform: translateY(20px);
  12132.           }
  12133.           to {
  12134.             opacity: 1;
  12135.             transform: translateY(0);
  12136.           }
  12137.         }
  12138.       `;
  12139.       document.head.appendChild(style);
  12140.     }
  12141.     document.addEventListener(\"DOMContentLoaded\", function () {
  12142.       const dateCards = document.querySelectorAll(\".date-card\");
  12143.       const sections = document.querySelectorAll(\".collapse\");
  12144.       dateCards.forEach((card) => {
  12145.         card.addEventListener(\"click\", function () {
  12146.           // Supprimer les classes actives des autres cartes et sections
  12147.           dateCards.forEach((c) => c.classList.remove(\"active\"));
  12148.           sections.forEach((s) => s.classList.remove(\"show\"));
  12149.           // Ajouter la classe active à la carte cliquée
  12150.           this.classList.add(\"active\");
  12151.           // Récupérer la cible et afficher la bonne section
  12152.           const targetId = this.getAttribute(\"data-bs-target\");
  12153.           const targetSection = document.querySelector(targetId);
  12154.           if (targetSection) {
  12155.             targetSection.classList.add(\"show\");
  12156.           }
  12157.         });
  12158.       });
  12159.     });
  12160.     document.addEventListener(\"DOMContentLoaded\", function () {
  12161.       // Clé localStorage pour tracker la première visite
  12162.       const sejourId = '{{ sejour.id|default(\"\") }}';
  12163.       const parentId = '{{ app.user.id|default(\"\") }}';
  12164.       const sliderKey = `imageSlider_seen_\${parentId}_\${sejourId}`;
  12165.       const isFirstVisit = !localStorage.getItem(sliderKey);
  12166.       
  12167.       const sliderContainer = document.querySelector('.divSliderModern');
  12168.       const imageSlider = document.getElementById('imageSlider');
  12169.       
  12170.       if (!isFirstVisit) {
  12171.         // Pas la première visite : cacher le slider
  12172.         if (sliderContainer) sliderContainer.style.display = 'none';
  12173.         return; // Ne pas initialiser Splide ni l'autoscroll
  12174.       }
  12175.       
  12176.       // Première visite : afficher le slider et initialiser
  12177.       if (sliderContainer) sliderContainer.style.display = 'block';
  12178.       
  12179.       // Initialisation du carrousel Splide
  12180.       var splide = new Splide(\"#imageSlider\", {
  12181.         type: \"loop\",
  12182.         perPage: 1,
  12183.         autoplay: true,
  12184.         interval: 6000,
  12185.         pauseOnHover: false,
  12186.         pauseOnFocus: false,
  12187.         pagination: false,
  12188.         arrows: false,
  12189.       });
  12190.       splide.mount();
  12191.       // Fonction pour faire défiler automatiquement vers la section suivante
  12192.       function scrollToNextSection() {
  12193.         const targetSection = document.getElementById(\"scrollTarget\");
  12194.         if (targetSection) {
  12195.           const targetPosition =
  12196.             targetSection.getBoundingClientRect().top + window.scrollY;
  12197.           const adjustedPosition = targetPosition - 50;
  12198.           window.scrollTo({
  12199.             top: adjustedPosition,
  12200.             behavior: \"smooth\",
  12201.           });
  12202.         }
  12203.       }
  12204.       // Démarrer le timer pour le scroll automatique après 5 secondes (première visite uniquement)
  12205.       setTimeout(scrollToNextSection, 5000);
  12206.       
  12207.       // Marquer comme vu après le premier scroll
  12208.       setTimeout(() => {
  12209.         localStorage.setItem(sliderKey, '1');
  12210.       }, 6000);
  12211.     });
  12212.   </script>
  12213.   <script>
  12214.    
  12215.     const giftButton = document.querySelector('.gift-button');
  12216.     if (giftButton) {
  12217.         giftButton.addEventListener('click', () => {
  12218.         // Ajouter la classe 'active' pour déclencher l'éclat
  12219.             giftButton.classList.add('active');
  12220.         // Retirer l'animation après qu'elle soit jouée
  12221.         setTimeout(() => {
  12222.                 giftButton.classList.remove('active');
  12223.         }, 600); // La durée doit correspondre à celle de l'animation
  12224.             
  12225.             // Optionnel : rediriger vers la page de commande
  12226.             // window.location.href = '/commande';
  12227.     });
  12228.     }
  12229.     
  12230.     //const HeartAddButton = document.querySelector('.IconDelete');
  12231.     \$(\".IconDelete\").on('click', () => {
  12232.         // Ajouter la classe 'active' pour déclencher l'éclat
  12233.         favoriteButton.classList.add('active');
  12234.         // Retirer l'animation après qu'elle soit jouée
  12235.         setTimeout(() => {
  12236.             favoriteButton.classList.remove('active');
  12237.         }, 600); // La durée doit correspondre à celle de l'animation
  12238.     });
  12239.     \$(document).ready(function() {
  12240.         // Attach click event to collapse triggers
  12241.         const lastCard = \$('.date-card.modern-card.active');
  12242.         const lastTargetId = lastCard.attr('data-bs-target');
  12243.         if (lastTargetId) {
  12244.             \$(lastTargetId).collapse('show'); // Expand the last collapse section
  12245.             LoadImagesCloud(\$(lastTargetId)); // Load images for the last day
  12246.         }
  12247.         \$('[data-bs-toggle=\"collapse\"]').on('click', function() {
  12248.             var targetId = \$(this).attr('data-bs-target'); // Get the target ID
  12249.             \$('.date-card.modern-card').removeClass('active'); // Remove 'active' class from all cards
  12250.             \$(this).addClass('active'); // Add 'active' class to the clicked card
  12251.             LoadImagesCloud(\$(targetId)); // Ensure this function works as expected
  12252.                // Hide all other collapses except the one clicked
  12253.                \$('[data-bs-target]').each(function() {
  12254.                 var currentTargetId = \$(this).attr('data-bs-target');
  12255.                 // If the current collapse is not the one clicked, hide it
  12256.                 if (currentTargetId !== targetId) {
  12257.                     \$(currentTargetId).collapse('hide');
  12258.                     //\$('[data-bs-toggle=\"collapse\"]').removeClass('active'); // Remove active class from all cards
  12259.                     //Modifier leurs style en non active aussi
  12260.                 }
  12261.             });
  12262.         });
  12263.     });
  12264.   
  12265.             \$(document).ready(function () {
  12266.               
  12267.                 {% if app.session.get(\"paymentmoniteco\") %}
  12268.                 {% if app.session.get(\"paymentmoniteco\") == \"succses\" %}
  12269.                 Swal.fire({
  12270.                     icon: 'success',
  12271.                     title: ' succès ',
  12272.                     text: 'votre commande est validée'
  12273.                 });
  12274.                 {% endif %}
  12275.                 {% endif %}
  12276.                 if (\$total1 > 0) {
  12277.                     \$('.iconeFleche').first().click();
  12278.                     //  \$([document.documentElement, document.body]).animate({
  12279.                     //  scrollTop: \$('.iconeFleche').last().offset().top
  12280.                     //  }, );
  12281.                 }
  12282.                 else {
  12283.                     \$(window).scrollTop(0);
  12284.                 }
  12285.                 var slider = \$('.responsive').slick({
  12286.                     infinite: true,
  12287.                     slidesToShow: 1,
  12288.                     slidesToScroll: 1,
  12289.                     autoplay: true,
  12290.                     autoplaySpeed: 4000,
  12291.                     pauseOnFocus: false,
  12292.                     pauseOnHover: false,
  12293.                     draggable: false,
  12294.                     fade: true
  12295.                 });
  12296.                 \$('.responsive').css('display', 'block');
  12297.                 \$('.namePRD').css('display', 'block');
  12298.                 var currSlide = 0;
  12299.                 var nextSlide = 0;
  12300.                 slider.on('afterChange', function (event, slick, currentSlide) {
  12301.                     console.log(typeof (\$('.slick-active .slick-current').find('.imgproduit2')) != \"undefined\");
  12302.                     if (typeof (\$('.slick-active .slick-current').find('.imgproduit2')) != \"undefined\") {
  12303.                         setTimeout(function () {
  12304.                             \$('.slick-active .imgproduit1').removeClass('animated fadeIn');
  12305.                             \$('.slick-active .imgproduit1').addClass('animated fadeOut');
  12306.                             \$('.slick-active .imgproduit1').css('display', 'none');
  12307.                             \$('.slick-active .imgproduit2').css('display', 'block');
  12308.                             \$('.slick-active .imgproduit2').removeClass('animated fadeOut');
  12309.                             \$('.slick-active .imgproduit2').addClass('animated fadeIn');
  12310.                         }, 2000);
  12311.                     }
  12312.                 });
  12313.                 slider.on('beforeChange', function (event, slick, currentSlide, nextSlide) {
  12314.                     currSlide = currentSlide;
  12315.                     \$('.imgproduit2').each(function () {
  12316.                         \$(this).removeClass('animated fadeIn');
  12317.                         \$(this).addClass('animated fadeOut');
  12318.                         \$(this).css('display', 'none');
  12319.                     });
  12320.                     \$('.imgproduit1').each(function () {
  12321.                         \$(this).css('display', 'block');
  12322.                         \$(this).removeClass('animated fadeOut');
  12323.                         \$(this).addClass('animated fadeIn');
  12324.                     });
  12325.                 });
  12326.                 \$('.columnPub').each(function () {
  12327.                     \$(this).slick({
  12328.                         infinite: true,
  12329.                         speed: 50,
  12330.                         fade: true,
  12331.                         slidesToShow: 1,
  12332.                         slidesToScroll: 1,
  12333.                         autoplay: true,
  12334.                         pauseOnFocus: false,
  12335.                         pauseOnHover: false,
  12336.                         draggable: false
  12337.                     });
  12338.                     \$(this).css('display', 'block');
  12339.                 });
  12340.                 \$(\"#offrePack\").click();
  12341.                 {%if app.user.showpubprod != 'false' %}
  12342.                 \$('#btnPubProd').click();
  12343.                 \$('.modal-backdrop').css('background-color', 'rgba(0, 0, 0, 0.2)');
  12344.                 {% endif %}
  12345.             });
  12346.             \$(\"#closeImage\").click(function () {
  12347.                 \$('#myModalImage').css('display', \"none\");
  12348.             });
  12349.             \$.ajax({
  12350.                 type: \"POST\",
  12351.                 url: \"{{ path(\"delateSession_parent\") }}\",
  12352.                 success: function () { }
  12353.             });
  12354.             function afficheDiv(elem) {
  12355.                 \$('.nav-link').each(function () {
  12356.                     \$(this).removeClass('active');
  12357.                 });
  12358.                 elem.addClass('active');
  12359.                 if (elem.attr('id') === \"esphoto\" || elem.attr('id') === \"esphotoMobile\") {
  12360.                     \$(\"#espacphoto\").show();
  12361.                     \$(\"#espacemessage\").hide();
  12362.                     \$(\"#espaceMa_selection\").hide();
  12363.                     pageMenu = 'MonSejour'
  12364.                     \$(this).addClass('active');
  12365.                    \$('#imageActifphoto').css('display', 'block');
  12366.                      \$('#imagenoActifphoto').css('display', 'none');
  12367.                    \$('#VocalActivee').css('display', 'none');
  12368.                      \$('#noActifVocal').css('display', 'block');
  12369.                 }
  12370.                 if (elem.attr('id') === \"esmessage\" || elem.attr('id') === \"esmessageMobile\") {
  12371.                     \$(\"#espacphoto\").hide();
  12372.                     \$(\"#espaceMa_selection\").hide();
  12373.                     \$(\"#espacemessage\").show();
  12374.                     pageMenu = 'BoiteVocale'
  12375.                     \$(\"#espaceMa_selection\").hide();
  12376.                     \$(this).addClass('active');
  12377.                   \$('#imageActifphoto').css('display', 'none');
  12378.                      \$('#imagenoActifphoto').css('display', 'block');
  12379.                    \$('#VocalActivee').css('display', 'block');
  12380.                      \$('#noActifVocal').css('display', 'none');
  12381.                 }
  12382.                 if (elem.attr('id') === \"esselection\" || elem.attr('id') === \"esselectionMobile\") {
  12383.                     \$(\"#espacphoto\").hide();
  12384.                     \$(\"#espacemessage\").hide();
  12385.                     \$(\"#espaceMa_selection\").show();
  12386.                     \$(homeNavmob).removeClass('bi bi-house-door-fill');
  12387.                     \$(homeNavmob).addClass('bi bi-house-door');
  12388.                     \$(micromob).removeClass('bi bi-mic-fill');
  12389.                     \$(micromob).addClass('bi bi-mic');
  12390.                     \$(selecNavmob).removeClass('bi bi-heart');
  12391.                     \$(selecNavmob).addClass('bi bi-heart-fill');
  12392.                 }
  12393.             }
  12394.             function LoadImagesCloud(\$element) {
  12395.                 \$element.find('.photo-zoom img').each(function (\$this) {
  12396.                     if (\$(this).attr('data-src') != \$(this).attr('src')) {
  12397.                         \$(this).attr('src', \$(this).attr('data-src'));
  12398.                     }
  12399.                 });
  12400.             }
  12401.   </script>
  12402.   <script>
  12403.     // ⚡ OPTIMISATION: Regroupement des initialisations jQuery
  12404.     \$(document).ready(function () {
  12405.       // Modal PubProd
  12406.       \$(\"#PubProd\").on(\"hidden.bs.modal\", function () {
  12407.         \$(document).trigger(\"modalClosed\");
  12408.       });
  12409.       
  12410.       // NoShow checkbox
  12411.       \$(\"#noShow\").on(\"change\", function () {
  12412.         if (\$(this).is(\":checked\")) {
  12413.           \$.ajax({
  12414.             url: \"/Parent/showpub\",
  12415.             type: \"POST\",
  12416.             dataType: \"json\",
  12417.             success: function (response) {
  12418.               if (response.status === \"success\") {
  12419.                 console.log(\"User showpubprod updated successfully.\");
  12420.               } else {
  12421.                 console.log(\"Error:\", response.message);
  12422.               }
  12423.             },
  12424.             error: function (xhr, status, error) {
  12425.               console.log(\"AJAX Error:\", error);
  12426.             },
  12427.           });
  12428.         }
  12429.       });
  12430.     });
  12431.   </script>
  12432. </div>
  12433. <!-- Script pour la sidebar des favoris -->
  12434. <script>
  12435.   // ⚡ OPTIMISATION: Utiliser requestIdleCallback pour ne pas bloquer le thread principal
  12436.  
  12437.   
  12438.     
  12439.     // Charger les favoris
  12440.     function loadFavorites() {
  12441.       \$.ajax({
  12442.         url: \"/Parent/mes-favoris\",
  12443.         type: \"GET\",
  12444.         dataType: \"json\",
  12445.         beforeSend: function() {
  12446.           \$(\"#favorites-grid\").html(\"<div style='text-align:center'>Chargement...</div>\");
  12447.         },
  12448.         success: function(data) {
  12449.           \$(\"#favorites-grid\").empty();
  12450.           
  12451.           if (data.data && data.data.length > 0) {
  12452.             \$(\"#favorites-empty-state\").hide();
  12453.             
  12454.             \$.each(data.data, function(i, fav) {
  12455.               var item = \$(\"<div class='favorite-item'></div>\");
  12456.               var img = \$(\"<img>\").attr(\"src\", fav.path).attr(\"alt\", fav.descreption || \"Photo favorite\");
  12457.               var overlay = \$(\"<div class='favorite-overlay'></div>\");
  12458.         
  12459.               
  12460.               btn.click(function(e) {
  12461.                 e.preventDefault();
  12462.                 e.stopPropagation();
  12463.                 removeFavorite(fav.id);
  12464.               });
  12465.               
  12466.               overlay.append(btn);
  12467.               item.append(img).append(overlay);
  12468.               \$(\"#favorites-grid\").append(item);
  12469.             });
  12470.             
  12471.             \$(\"#favorites-counter\").text(data.data.length);
  12472.             var percentage = (data.data.length / 10) * 100;
  12473.             \$(\"#favorites-progress\").css(\"width\", percentage + \"%\");
  12474.             
  12475.           } else {
  12476.             \$(\"#favorites-empty-state\").show();
  12477.             \$(\"#favorites-counter\").text(\"0\");
  12478.             \$(\"#favorites-progress\").css(\"width\", \"0%\");
  12479.           }
  12480.         },
  12481.         error: function() {
  12482.           \$(\"#favorites-grid\").html(\"<div style='color:red;text-align:center'>Erreur de chargement</div>\");
  12483.         }
  12484.       });
  12485.     }
  12486.     
  12487.     // Supprimer un favori
  12488.     function removeFavorite(id) {
  12489.       \$.ajax({
  12490.         url: \"/Parent/remove-favorite/\" + id,
  12491.         type: \"POST\",
  12492.         success: function() {
  12493.           loadFavorites();
  12494.           
  12495.           // Mettre à jour tous les compteurs de favoris
  12496.           updateAllFavoriteCounters();
  12497.         },
  12498.         error: function() {
  12499.           alert(\"Erreur lors de la suppression du favori\");
  12500.         }
  12501.       });
  12502.     }
  12503.   });
  12504. </script>
  12505. <!-- === E-COMMERCE SIDEBAR JAVASCRIPT === -->
  12506. <script>
  12507. // Configuration UX_VARIANT pour A/B testing
  12508. let UX_VARIANT = 'EMOTION'; // ou 'URGENCY'
  12509. // Variables globales e-commerce
  12510. let sejourEndDate = null; // À définir avec la vraie date de fin du séjour
  12511. // Fonction utilitaire robuste pour gérer les compteurs de favoris
  12512. window.getFavoriteCount = function getFavoriteCount() {
  12513.   const likeCountInput = document.getElementById('likeCount');
  12514.   if (likeCountInput) {
  12515.     // Priorité à la valeur de l'input
  12516.     const value = likeCountInput.value || likeCountInput.textContent || 0;
  12517.     return parseInt(value, 10) || 0;
  12518.   }
  12519.   
  12520.   // Fallback sur giftCount
  12521.   const giftCount = document.getElementById('giftCount');
  12522.   if (giftCount && giftCount.textContent) {
  12523.     return parseInt(giftCount.textContent.trim(), 10) || 0;
  12524.   }
  12525.   
  12526.   return 0;
  12527. };
  12528. window.setFavoriteCount = function setFavoriteCount(count) {
  12529.   const likeCountInput = document.getElementById('likeCount');
  12530.   if (likeCountInput) {
  12531.     // Mettre à jour les deux propriétés pour être sûr
  12532.     likeCountInput.value = count;
  12533.     likeCountInput.textContent = count;
  12534.   }
  12535.   
  12536.   // Mettre à jour les autres compteurs
  12537.   const giftCount = document.getElementById('giftCount');
  12538.   if (giftCount) {
  12539.     giftCount.textContent = count;
  12540.   }
  12541.   
  12542.   const mesFavCount = document.getElementById('mesFavCount');
  12543.   if (mesFavCount) {
  12544.     mesFavCount.textContent = count;
  12545.   }
  12546.   
  12547.   // Mettre à jour l'input hidden
  12548.   const nbFavCurrentInput = document.getElementById('nbFavCurrent');
  12549.   if (nbFavCurrentInput) {
  12550.     nbFavCurrentInput.value = count;
  12551.   }
  12552. };
  12553. // Fonction pour définir la date de fin du séjour
  12554. window.setSejourEndDate = function setSejourEndDate(dateString) {
  12555.   sejourEndDate = dateString;
  12556.   console.log('🎯 Sejour end date set to:', sejourEndDate);
  12557.   
  12558.   // Mettre à jour le countdown si le sidebar est ouvert
  12559.   updateCountdownTimer();
  12560. };
  12561. // Fonctions d'ouverture/fermeture du sidebar
  12562. window.openEcommerceSidebar = function openEcommerceSidebar() {
  12563.   const sidebar = document.getElementById('ecommerce-sidebar');
  12564.   if (!sidebar) {
  12565.     console.error('❌ E-commerce sidebar element not found!');
  12566.     return false;
  12567.   }
  12568.   
  12569.   // Ajouter la classe active
  12570.   sidebar.classList.add('active');
  12571.   
  12572.     // Mettre à jour le contenu avec le nombre actuel de favoris
  12573.     let favoriteCount = window.getFavoriteCount();
  12574.     console.log('🎯 Opening sidebar with favoriteCount:', favoriteCount);
  12575.   
  12576.   // Mettre à jour le contenu du sidebar
  12577.   if (typeof window.updateEcommerceSidebarContent === 'function') {
  12578.     window.updateEcommerceSidebarContent(favoriteCount);
  12579.   }
  12580.   
  12581.   return true;
  12582. };
  12583. window.closeEcommerceSidebar = function closeEcommerceSidebar() {
  12584.   const sidebar = document.getElementById('ecommerce-sidebar');
  12585.   if (sidebar) {
  12586.     sidebar.classList.remove('active');
  12587.     console.log('🎯 E-commerce sidebar closed');
  12588.   } else {
  12589.     console.error('❌ E-commerce sidebar element not found!');
  12590.   }
  12591. };
  12592. // Fonction pour mettre à jour le contenu du sidebar
  12593. window.updateEcommerceSidebarContent = function updateEcommerceSidebarContent(favoriteCount) {
  12594.   const title = document.getElementById('ecommerce-title');
  12595.   const subtitle = document.getElementById('ecommerce-subtitle');
  12596.   const albumCount = document.getElementById('album-count');
  12597.   const digitalCount = document.getElementById('digital-count');
  12598.   const printsCount = document.getElementById('prints-count');
  12599.   const printsCard = document.getElementById('prints-card');
  12600.   const productsContainer = document.getElementById('products-container');
  12601.   
  12602.   // Gérer l'état vide vs rempli
  12603.   const isEmpty = favoriteCount === 0;
  12604.   
  12605.   // Titre émotionnel basé sur le nombre de favoris et la variante UX
  12606.   if (title) {
  12607.     if (UX_VARIANT === 'URGENCY') {
  12608.       // Variante urgence
  12609.       if (isEmpty) {
  12610.         title.innerHTML = `⏳ Commencez par sélectionner vos favoris ❤️`;
  12611.       } else if (favoriteCount < 5) {
  12612.         title.innerHTML = `⏳ \${favoriteCount} souvenirs - Commandez vite !`;
  12613.       } else if (favoriteCount < 12) {
  12614.         title.innerHTML = `⏳ \${favoriteCount} magnifiques souvenirs - Plus que X jours !`;
  12615.       } else {
  12616.         title.innerHTML = `⏳ Superbe collection de \${favoriteCount} photos - Dernière chance !`;
  12617.       }
  12618.     } else {
  12619.       // Variante émotion (par défaut)
  12620.       if (isEmpty) {
  12621.         title.innerHTML = `Commencez par sélectionner vos favoris ❤️`;
  12622.       } else if (favoriteCount < 5) {
  12623.         title.innerHTML = `✨ \${favoriteCount} souvenirs sélectionnés !`;
  12624.       } else if (favoriteCount < 12) {
  12625.         title.innerHTML = `🎉 Vous avez \${favoriteCount} souvenirs favoris`;
  12626.       } else {
  12627.         title.innerHTML = `🎊 Superbe collection de \${favoriteCount} photos !`;
  12628.       }
  12629.     }
  12630.   }
  12631.   
  12632.   // Sous-titre dynamique
  12633.   if (subtitle) {
  12634.     if (isEmpty) {
  12635.       subtitle.innerHTML = `Cliquez sur ❤️ pour ajouter des photos à vos favoris`;
  12636.     } else if (favoriteCount === 1) {
  12637.       subtitle.innerHTML = `1 photo sélectionnée avec amour ❤️`;
  12638.     } else {
  12639.       subtitle.innerHTML = `\${favoriteCount} photos sélectionnées avec amour ❤️`;
  12640.     }
  12641.   }
  12642.   
  12643.   // Mettre à jour les compteurs produits
  12644.   console.log('🔄 Updating sidebar counters:', { favoriteCount, albumCount, digitalCount, printsCount });
  12645.   if (albumCount) {
  12646.     albumCount.textContent = favoriteCount;
  12647.     console.log('✅ Album count updated to:', favoriteCount);
  12648.   }
  12649.   if (digitalCount) {
  12650.     digitalCount.textContent = favoriteCount;
  12651.     console.log('✅ Digital count updated to:', favoriteCount);
  12652.   }
  12653.   
  12654.   // Afficher la pochette tirages seulement si >= 12 favoris
  12655.   if (printsCard) {
  12656.     if (favoriteCount >= 12) {
  12657.       printsCard.style.display = 'block';
  12658.       if (printsCount) printsCount.textContent = Math.min(favoriteCount, 12);
  12659.     } else {
  12660.       printsCard.style.display = 'none';
  12661.     }
  12662.   }
  12663.   
  12664.   // Gérer l'état des CTA produits
  12665.   updateProductCTAs(favoriteCount);
  12666.   
  12667.   // Gérer le countdown si proche de l'expiration
  12668.   updateCountdownTimer();
  12669. }
  12670. // Fonction pour gérer l'état des CTA produits
  12671. window.updateProductCTAs = function updateProductCTAs(favoriteCount) {
  12672.   const isEmpty = favoriteCount === 0;
  12673.   const productCTAs = document.querySelectorAll('.product-cta');
  12674.   const productDescriptions = document.querySelectorAll('.product-description');
  12675.   
  12676.   productCTAs.forEach((cta, index) => {
  12677.     if (isEmpty) {
  12678.       // État désactivé
  12679.       cta.disabled = true;
  12680.       cta.setAttribute('aria-disabled', 'true');
  12681.       cta.style.cursor = 'not-allowed';
  12682.       cta.style.opacity = '0.6';
  12683.       cta.title = 'Ajoutez des favoris pour commander';
  12684.     } else {
  12685.       // État activé
  12686.       cta.disabled = false;
  12687.       cta.removeAttribute('aria-disabled');
  12688.       cta.style.cursor = 'pointer';
  12689.       cta.style.opacity = '1';
  12690.       cta.title = '';
  12691.     }
  12692.   });
  12693.   
  12694.   // Mettre à jour les descriptions des produits
  12695.   productDescriptions.forEach((desc, index) => {
  12696.     if (isEmpty) {
  12697.       // Texte générique sans compteur
  12698.       if (index === 0) { // Album
  12699.         desc.innerHTML = 'Personnalisez votre album avec vos photos favorites. Papier de qualité supérieure, reliure rigide.';
  12700.       } else if (index === 1) { // Pack numérique
  12701.         desc.innerHTML = 'Téléchargement immédiat de vos photos en haute définition. Qualité professionnelle garantie.';
  12702.       } else if (index === 2) { // Tirages
  12703.         desc.innerHTML = 'Tirages photo 10x15cm de vos favoris. Papier brillant professionnel, livraison gratuite.';
  12704.       }
  12705.     } else {
  12706.       // Texte avec compteur dynamique
  12707.       if (index === 0) { // Album
  12708.         desc.innerHTML = `Album photo personnalisé avec vos <strong>\${favoriteCount}</strong> photos favorites. Papier de qualité supérieure, reliure rigide.`;
  12709.       } else if (index === 1) { // Pack numérique
  12710.         desc.innerHTML = `Téléchargement immédiat de vos <strong>\${favoriteCount}</strong> photos en haute définition. Qualité professionnelle garantie.`;
  12711.       } else if (index === 2) { // Tirages
  12712.         const printsCount = Math.min(favoriteCount, 12);
  12713.         desc.innerHTML = `<strong>\${printsCount}</strong> tirages photo 10x15cm de vos favoris. Papier brillant professionnel, envoi sous 48h.`;
  12714.       }
  12715.     }
  12716.   });
  12717.   
  12718.   // Mettre à jour les icônes de favoris dans les produits
  12719.   const albumFavCount = document.getElementById('album-fav-count');
  12720.   const digitalFavCount = document.getElementById('digital-fav-count');
  12721.   const printsFavCount = document.getElementById('prints-fav-count');
  12722.   
  12723.   if (albumFavCount) albumFavCount.textContent = favoriteCount;
  12724.   if (digitalFavCount) digitalFavCount.textContent = favoriteCount;
  12725.   if (printsFavCount) printsFavCount.textContent = Math.min(favoriteCount, 12);
  12726. }
  12727. // Fonction pour gérer le countdown
  12728. window.updateCountdownTimer = function updateCountdownTimer() {
  12729.   const countdownTimer = document.getElementById('countdown-timer');
  12730.   const daysLeftSpan = document.getElementById('days-left');
  12731.   
  12732.   if (!countdownTimer || !daysLeftSpan) return;
  12733.   
  12734.   // Si pas de date définie, utiliser une date par défaut (6 semaines à partir d'aujourd'hui)
  12735.   let expirationDate;
  12736.   if (sejourEndDate) {
  12737.     const endDate = new Date(sejourEndDate);
  12738.     expirationDate = new Date(endDate.getTime() + (6 * 7 * 24 * 60 * 60 * 1000)); // +6 semaines
  12739.   } else {
  12740.     // Date par défaut : 6 semaines à partir d'aujourd'hui
  12741.     expirationDate = new Date();
  12742.     expirationDate.setDate(expirationDate.getDate() + (6 * 7));
  12743.   }
  12744.   
  12745.   const now = new Date();
  12746.   const daysLeft = Math.ceil((expirationDate - now) / (24 * 60 * 60 * 1000));
  12747.   
  12748.   if (daysLeft <= 10 && daysLeft > 0) {
  12749.     countdownTimer.style.display = 'block';
  12750.     daysLeftSpan.textContent = daysLeft;
  12751.     
  12752.     // Mettre à jour les titres avec le countdown si variante URGENCY
  12753.     if (UX_VARIANT === 'URGENCY') {
  12754.       const title = document.getElementById('ecommerce-title');
  12755.       if (title) {
  12756.         const favoriteCount = parseInt(document.getElementById('giftCount')?.textContent || '0');
  12757.         if (favoriteCount > 0) {
  12758.           if (favoriteCount < 5) {
  12759.             title.innerHTML = `⏳ \${favoriteCount} souvenirs - Plus que \${daysLeft} jours !`;
  12760.           } else if (favoriteCount < 12) {
  12761.             title.innerHTML = `⏳ \${favoriteCount} magnifiques souvenirs - Plus que \${daysLeft} jours !`;
  12762.           } else {
  12763.             title.innerHTML = `⏳ Superbe collection de \${favoriteCount} photos - Plus que \${daysLeft} jours !`;
  12764.           }
  12765.         }
  12766.       }
  12767.     }
  12768.   } else {
  12769.     countdownTimer.style.display = 'none';
  12770.   }
  12771. }
  12772. // Fonction pour commander un produit
  12773. window.orderProduct = function orderProduct(productType) {
  12774.   let favoriteCount = 0;
  12775.   
  12776.   // Méthode 1: Fonction getCurrentFavoriteCount
  12777.   try {
  12778.     if (typeof getCurrentFavoriteCount === 'function') {
  12779.       favoriteCount = getCurrentFavoriteCount();
  12780.     }
  12781.   } catch (e) {
  12782.     console.log('⚠️ getCurrentFavoriteCount non disponible:', e);
  12783.   }
  12784.   
  12785.   // Méthode 2: Element giftCount
  12786.   if (favoriteCount === 0) {
  12787.     const giftCount = document.getElementById('giftCount');
  12788.     if (giftCount && giftCount.textContent) {
  12789.       favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  12790.     }
  12791.   }
  12792.   
  12793.   // Méthode 3: Récupérer depuis les éléments qui affichent le nombre de favoris
  12794.   if (favoriteCount === 0) {
  12795.     const albumFavCount = document.getElementById('album-fav-count');
  12796.     const digitalFavCount = document.getElementById('digital-fav-count');
  12797.     
  12798.     if (albumFavCount && albumFavCount.textContent) {
  12799.       favoriteCount = parseInt(albumFavCount.textContent.trim()) || 0;
  12800.     } else if (digitalFavCount && digitalFavCount.textContent) {
  12801.       favoriteCount = parseInt(digitalFavCount.textContent.trim()) || 0;
  12802.     }
  12803.   }
  12804.   
  12805.   // Méthode 4: Variable globale likes
  12806.   if (favoriteCount === 0 && typeof likes !== 'undefined' && likes) {
  12807.     favoriteCount = likes.length || 0;
  12808.   }
  12809.   
  12810.   // Méthode 5: Compter les éléments liked dans le DOM
  12811.   if (favoriteCount === 0) {
  12812.     const likedElements = document.querySelectorAll('.liked, .photo.liked, [data-liked=\"true\"]');
  12813.     favoriteCount = likedElements.length;
  12814.   }
  12815.   
  12816.   // Debug pour voir la valeur récupérée
  12817.   console.log('🔍 Nombre de favoris détecté:', favoriteCount);
  12818.   
  12819.   if (favoriteCount === 0) {
  12820.     // Afficher une notification plus élégante
  12821.     const notification = document.createElement('div');
  12822.     notification.className = 'favorite-notification';
  12823.     notification.innerHTML = `
  12824.       <div class=\"notification-content\">
  12825.         <i class=\"bi bi-heart\" style=\"color: #e91e63; font-size: 1.5rem; margin-right: 10px;\"></i>
  12826.         <span>Veuillez d'abord sélectionner des photos favorites !</span>
  12827.         <button onclick=\"this.parentElement.parentElement.remove()\" style=\"background: none; border: none; color: #666; font-size: 1.2rem; margin-left: 10px;\">&times;</button>
  12828.       </div>
  12829.     `;
  12830.     
  12831.     // Styles pour la notification
  12832.     notification.style.cssText = `
  12833.       position: fixed;
  12834.       top: 20px;
  12835.       right: 20px;
  12836.       background: #fff;
  12837.       border: 2px solid #e91e63;
  12838.       border-radius: 8px;
  12839.       padding: 15px;
  12840.       box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  12841.       z-index: 10000;
  12842.       animation: slideInRight 0.3s ease;
  12843.     `;
  12844.     
  12845.     // Ajouter l'animation CSS si elle n'existe pas
  12846.     if (!document.getElementById('notification-styles')) {
  12847.       const style = document.createElement('style');
  12848.       style.id = 'notification-styles';
  12849.       style.textContent = `
  12850.         @keyframes slideInRight {
  12851.           from { transform: translateX(100%); opacity: 0; }
  12852.           to { transform: translateX(0); opacity: 1; }
  12853.         }
  12854.         .notification-content {
  12855.           display: flex;
  12856.           align-items: center;
  12857.         }
  12858.       `;
  12859.       document.head.appendChild(style);
  12860.     }
  12861.     
  12862.     document.body.appendChild(notification);
  12863.     
  12864.     // Supprimer automatiquement après 5 secondes
  12865.     setTimeout(() => {
  12866.       if (notification.parentElement) {
  12867.         notification.remove();
  12868.       }
  12869.     }, 5000);
  12870.     
  12871.     return;
  12872.   }
  12873.   
  12874.   // Construire l'URL avec les favoris pré-sélectionnés
  12875.   let orderUrl = '';
  12876.   
  12877.   switch (productType) {
  12878.     case 'album':
  12879.       orderUrl = `{{ path('EditionAlbum') }}?favorites=\${favoriteCount}`;
  12880.       break;
  12881.     case 'digital':
  12882.       orderUrl = `{{ path('PackPhotosNumerique_Favoris', {'nbr': 15}) }}?favorites=\${favoriteCount}`;
  12883.       break;
  12884.     case 'prints':
  12885.       orderUrl = `{{ path('AjoutPochettePhotos_Favoris', {'nbr': 12}) }}?favorites=\${favoriteCount}`;
  12886.       break;
  12887.     default:
  12888.       console.error('Type de produit non reconnu:', productType);
  12889.       alert('Erreur: Type de produit non reconnu');
  12890.       return;
  12891.   }
  12892.   
  12893.   // Analytics/tracking
  12894.   console.log('Product ordered', { productType, favoriteCount, url: orderUrl });
  12895.   
  12896.   // Redirection vers la commande
  12897.   if (orderUrl) {
  12898.     // Vérifier que l'URL est valide
  12899.     try {
  12900.       new URL(orderUrl, window.location.origin);
  12901.     window.location.href = orderUrl;
  12902.     } catch (error) {
  12903.       console.error('URL invalide générée:', orderUrl, error);
  12904.       alert('Erreur: Impossible de générer le lien de commande');
  12905.     }
  12906.   } else {
  12907.     console.error('Aucune URL générée pour le produit:', productType);
  12908.     alert('Erreur: Impossible de générer le lien de commande');
  12909.   }
  12910. }
  12911. // Fonction pour tester tous les liens de produits
  12912. window.testProductLinks = function() {
  12913.   const products = ['album', 'digital', 'prints'];
  12914.   const favoriteCount = window.getFavoriteCount() || 0;
  12915.   
  12916.   console.log('🧪 Test des liens de produits avec', favoriteCount, 'favoris');
  12917.   
  12918.   products.forEach(productType => {
  12919.     try {
  12920.       let testUrl = '';
  12921.       switch (productType) {
  12922.         case 'album':
  12923.           testUrl = `{{ path('EditionAlbum') }}?favorites=\${favoriteCount}`;
  12924.           break;
  12925.         case 'digital':
  12926.           testUrl = `{{ path('PackPhotosNumerique_Favoris', {'nbr': 15}) }}?favorites=\${favoriteCount}`;
  12927.           break;
  12928.         case 'prints':
  12929.           testUrl = `{{ path('AjoutPochettePhotos_Favoris', {'nbr': 12}) }}?favorites=\${favoriteCount}`;
  12930.           break;
  12931.       }
  12932.       
  12933.       // Vérifier que l'URL est valide
  12934.       const url = new URL(testUrl, window.location.origin);
  12935.       console.log(`✅ \${productType}: \${url.href}`);
  12936.     } catch (error) {
  12937.       console.error(`❌ \${productType}: Erreur URL`, error);
  12938.     }
  12939.   });
  12940. };
  12941. // Fonction pour valider les liens au chargement de la page
  12942. window.validateProductLinks = function() {
  12943.   // Vérifier que tous les boutons de produits existent
  12944.   const albumBtn = document.querySelector('button[onclick*=\"orderProduct(\\'album\\')\"]');
  12945.   const digitalBtn = document.querySelector('button[onclick*=\"orderProduct(\\'digital\\')\"]');
  12946.   const printsBtn = document.querySelector('button[onclick*=\"orderProduct(\\'prints\\')\"]');
  12947.   
  12948.   if (!albumBtn) console.warn('⚠️ Bouton album non trouvé');
  12949.   if (!digitalBtn) console.warn('⚠️ Bouton digital non trouvé');
  12950.   if (!printsBtn) console.warn('⚠️ Bouton prints non trouvé');
  12951.   
  12952.   // Tester les liens
  12953.   window.testProductLinks();
  12954. };
  12955. // Améliorer la fonction updateAllFavoriteCounters existante
  12956. const originalUpdateAllFavoriteCounters = window.updateAllFavoriteCounters || function() {};
  12957. window.updateAllFavoriteCounters = function() {
  12958.   // Appeler la fonction originale
  12959.   originalUpdateAllFavoriteCounters();
  12960.   
  12961.   // Animation rebond du compteur favoris
  12962.   const giftCount = document.getElementById('giftCount');
  12963.   if (giftCount) {
  12964.     giftCount.classList.remove('gift-count-bounce');
  12965.     setTimeout(() => giftCount.classList.add('gift-count-bounce'), 10);
  12966.   }
  12967.   
  12968.   // Animation rebond du compteur dans la bulle cadeau
  12969.   const likeCount = document.getElementById('likeCount');
  12970.   if (likeCount) {
  12971.     likeCount.classList.remove('gift-count-bounce');
  12972.     setTimeout(() => likeCount.classList.add('gift-count-bounce'), 10);
  12973.   }
  12974.   
  12975.   // Récupérer le nombre de favoris actuel avec la fonction utilitaire robuste
  12976.   let favoriteCount = window.getFavoriteCount();
  12977.   
  12978.   // Mettre à jour les compteurs dans le sidebar même s'il n'est pas ouvert
  12979.   const albumCount = document.getElementById('album-count');
  12980.   const digitalCount = document.getElementById('digital-count');
  12981.   const printsCount = document.getElementById('prints-count');
  12982.   
  12983.   if (albumCount) albumCount.textContent = favoriteCount;
  12984.   if (digitalCount) digitalCount.textContent = favoriteCount;
  12985.   if (printsCount) printsCount.textContent = Math.min(favoriteCount, 12);
  12986.   
  12987.   // Mettre à jour les icônes de favoris dans les produits
  12988.   const albumFavCount = document.getElementById('album-fav-count');
  12989.   const digitalFavCount = document.getElementById('digital-fav-count');
  12990.   const printsFavCount = document.getElementById('prints-fav-count');
  12991.   
  12992.   if (albumFavCount) albumFavCount.textContent = favoriteCount;
  12993.   if (digitalFavCount) digitalFavCount.textContent = favoriteCount;
  12994.   if (printsFavCount) printsFavCount.textContent = Math.min(favoriteCount, 12);
  12995.   
  12996.   // Mettre à jour le sidebar si ouvert
  12997.   const sidebar = document.getElementById('ecommerce-sidebar');
  12998.   if (sidebar && sidebar.classList.contains('active')) {
  12999.     console.log('🔄 Sidebar is open, updating content with favoriteCount:', favoriteCount);
  13000.     window.updateEcommerceSidebarContent(favoriteCount);
  13001.   } else {
  13002.     console.log('ℹ️ Sidebar is closed, but updating content anyway for consistency');
  13003.     // Mettre à jour le contenu même si le sidebar n'est pas ouvert pour la cohérence
  13004.     window.updateEcommerceSidebarContent(favoriteCount);
  13005.   }
  13006. };
  13007. // Fonction pour retirer un favori de la grille et exécuter supprimerFavoris
  13008. window.removeFavorite = function removeFavorite(itemId) {
  13009.   // Animation simple de disparition puis suppression
  13010.   const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${itemId}\"]`);
  13011.  
  13012.   if (favoriteItem) {
  13013.     favoriteItem.classList.add('fade-out');
  13014.     setTimeout(() => {
  13015.       favoriteItem.remove();
  13016.       // Appeler la fonction métier si présente
  13017.       if (typeof window.supprimerFavoris === 'function') {
  13018.         const heartIcon = document.querySelector(`#coeur\${itemId}`);
  13019.         const sejourId = heartIcon && heartIcon.dataset.sejourId ? heartIcon.dataset.sejourId : '';
  13020.         window.supprimerFavoris(itemId, sejourId);
  13021.       }
  13022.       // Mettre à jour les compteurs
  13023.       updateAllFavoriteCounters();
  13024.     }, 200);
  13025.   }
  13026. };
  13027. // Vérifier que la fonction est bien définie
  13028. console.log('🔍 removeFavorite function defined:', typeof window.removeFavorite);
  13029. // (Nettoyé) Pas de délégation globale ici; les boutons utilisent des onclick simples
  13030. // Fonction pour voir un favori en grand
  13031. window.viewFavorite = function viewFavorite(itemId) {
  13032.   console.log('👁️ Viewing favorite:', itemId);
  13033.   
  13034.   // Essayer d'utiliser la fonction viewImage existante
  13035.   if (typeof window.viewImage === 'function') {
  13036.     window.viewImage(itemId, null);
  13037.   } else {
  13038.     console.log('ℹ️ viewImage function not available, opening in new tab');
  13039.     // Fallback: ouvrir dans un nouvel onglet
  13040.     const favoriteItem = document.querySelector(`.favorite-item[data-id=\"\${itemId}\"] img`);
  13041.     if (favoriteItem && favoriteItem.src) {
  13042.       window.open(favoriteItem.src, '_blank');
  13043.     }
  13044.   }
  13045. };
  13046. // Fonction de debug pour tester les compteurs
  13047. window.debugFavoriteCounters = function() {
  13048.   console.log('🔍 Debug Favorite Counters:');
  13049.   console.log('- getFavoriteCount():', window.getFavoriteCount());
  13050.   console.log('- likeCount input value:', document.getElementById('likeCount')?.value);
  13051.   console.log('- likeCount textContent:', document.getElementById('likeCount')?.textContent);
  13052.   console.log('- giftCount textContent:', document.getElementById('giftCount')?.textContent);
  13053.   console.log('- album-count textContent:', document.getElementById('album-count')?.textContent);
  13054.   console.log('- digital-count textContent:', document.getElementById('digital-count')?.textContent);
  13055.   console.log('- prints-count textContent:', document.getElementById('prints-count')?.textContent);
  13056.   console.log('- Sidebar active:', document.getElementById('ecommerce-sidebar')?.classList.contains('active'));
  13057. };
  13058. // Fonction de test pour les boutons de favoris
  13059. window.testFavoriteButtons = function() {
  13060.   console.log('🧪 Testing favorite buttons:');
  13061.   const removeButtons = document.querySelectorAll('.btn-remove-favorite');
  13062.   const viewButtons = document.querySelectorAll('.btn-view-favorite');
  13063.   
  13064.   console.log('- Remove buttons found:', removeButtons.length);
  13065.   console.log('- View buttons found:', viewButtons.length);
  13066.   
  13067.   removeButtons.forEach((btn, index) => {
  13068.     console.log(`- Remove button \${index}:`, {
  13069.       itemId: btn.dataset.itemId,
  13070.       hasClickListener: btn.onclick !== null
  13071.     });
  13072.   });
  13073.   
  13074.   viewButtons.forEach((btn, index) => {
  13075.     console.log(`- View button \${index}:`, {
  13076.       itemId: btn.dataset.itemId,
  13077.       hasClickListener: btn.onclick !== null
  13078.     });
  13079.   });
  13080. };
  13081. // Fermer le sidebar en cliquant en dehors
  13082. document.addEventListener('click', function(e) {
  13083.   const sidebar = document.getElementById('ecommerce-sidebar');
  13084.   const giftButton = document.querySelector('.gift-button');
  13085.   
  13086.   if (sidebar && sidebar.classList.contains('active') && 
  13087.       !sidebar.contains(e.target) && 
  13088.       !giftButton.contains(e.target)) {
  13089.     window.closeEcommerceSidebar();
  13090.   }
  13091. });
  13092. // Fermer avec Escape
  13093. document.addEventListener('keydown', function(e) {
  13094.   if (e.key === 'Escape') {
  13095.     window.closeEcommerceSidebar();
  13096.   }
  13097. });
  13098. // Initialisation au chargement
  13099. document.addEventListener('DOMContentLoaded', function() {
  13100.   // Vérifier que les éléments existent
  13101.   const sidebar = document.getElementById('ecommerce-sidebar');
  13102.   const giftButton = document.getElementById('gift-button-trigger');
  13103.   
  13104.   // Event listener propre pour le bouton cadeau
  13105.   if (giftButton) {
  13106.     giftButton.addEventListener('click', function(e) {
  13107.       e.preventDefault();
  13108.       e.stopPropagation();
  13109.       window.openEcommerceSidebar();
  13110.     });
  13111.   }
  13112.   
  13113.   // Définir la date de fin du séjour si disponible
  13114.   {% if sejour and sejour.dateFinSejour is defined %}
  13115.     window.setSejourEndDate('{{ sejour.dateFinSejour|date(\"Y-m-d\") }}');
  13116.   {% endif %}
  13117.   
  13118.   // Mise à jour initiale du contenu
  13119.   let favoriteCount = 0;
  13120.   try {
  13121.     if (typeof getCurrentFavoriteCount === 'function') {
  13122.       favoriteCount = getCurrentFavoriteCount();
  13123.     } else {
  13124.       // Essayer d'abord l'input likeCount
  13125.       const likeCountInput = document.getElementById('likeCount');
  13126.       if (likeCountInput && likeCountInput.value) {
  13127.         favoriteCount = parseInt(likeCountInput.value, 10) || 0;
  13128.       } else {
  13129.         // Fallback sur giftCount
  13130.         const giftCount = document.getElementById('giftCount');
  13131.         if (giftCount && giftCount.textContent) {
  13132.           favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  13133.         }
  13134.       }
  13135.     }
  13136.   } catch (e) {
  13137.     console.log('⚠️ Fallback pour favoriteCount initial:', e);
  13138.     // Fallback sur likeCount input
  13139.     const likeCountInput = document.getElementById('likeCount');
  13140.     if (likeCountInput && likeCountInput.value) {
  13141.       favoriteCount = parseInt(likeCountInput.value, 10) || 0;
  13142.     } else {
  13143.       const giftCount = document.getElementById('giftCount');
  13144.       if (giftCount && giftCount.textContent) {
  13145.         favoriteCount = parseInt(giftCount.textContent.trim()) || 0;
  13146.       }
  13147.     }
  13148.   }
  13149.   
  13150.   window.updateEcommerceSidebarContent(favoriteCount);
  13151.   
  13152. });
  13153. </script>
  13154. <!-- 🎯 DAY FILTER POPOVER (instancié une seule fois) -->
  13155. <div id=\"dayFilterPopover\" class=\"day-popover\" role=\"dialog\" aria-modal=\"true\" aria-hidden=\"true\">
  13156.   <div class=\"dp-arrow\" aria-hidden=\"true\"></div>
  13157.   <div class=\"dp-content\" role=\"group\" aria-label=\"Filtres du jour\">
  13158.     <button class=\"dp-btn\" data-filter=\"all\" title=\"Tout\" aria-pressed=\"true\">
  13159.       <i class=\"bi bi-grid-3x3-gap-fill\"></i><span class=\"dp-count dp-label\">Tout</span>
  13160.     </button>
  13161.     <button class=\"dp-btn\" data-filter=\"photos\" title=\"Photos\" aria-pressed=\"false\">
  13162.       <i class=\"bi bi-images\"></i><span class=\"dp-count\" data-bind=\"photo\">0</span>
  13163.     </button>
  13164.     <button class=\"dp-btn\" data-filter=\"audio\" title=\"Audios\" aria-pressed=\"false\">
  13165.       <i class=\"bi bi-mic-fill\"></i><span class=\"dp-count\" data-bind=\"audio\">0</span>
  13166.     </button>
  13167.     <button class=\"dp-btn\" data-filter=\"videos\" title=\"Vidéos\" aria-pressed=\"false\">
  13168.       <i class=\"bi bi-camera-video-fill\"></i><span class=\"dp-count\" data-bind=\"video\">0</span>
  13169.     </button>
  13170.     <button class=\"dp-btn\" data-filter=\"favoris\" title=\"Favoris\" aria-pressed=\"false\">
  13171.       <i class=\"bi bi-heart-fill\" style=\"color:#f56040\"></i><span class=\"dp-count\" data-bind=\"fav\">0</span>
  13172.     </button>
  13173.     <button class=\"dp-btn dp-close\" title=\"Fermer\" aria-label=\"Fermer\">
  13174.       <i class=\"bi bi-x-lg\"></i>
  13175.     </button>
  13176.   </div>
  13177. </div>
  13178. {% endblock %}
  13179. ""Parent/DetailsSejour.html.twig""/var/www/5sur5sejour/templates/Parent/DetailsSejour.html.twig");
  13180.     }
  13181. }